Android AudioFlinger 写音频数据到 HAL 详细流程

一、整体架构

应用层 (AudioTrack.write) → AudioFlinger (PlaybackThread) → AudioStreamOut (HAL) → 硬件驱动 → DAC

二、核心代码路径

2.1 音频写入的起点

// frameworks/av/services/audioflinger/AudioFlinger.cpp
sp<IAudioTrack> AudioFlinger::createTrack(...) {
    // 1. 创建 Track
    sp<PlaybackThread::Track> track = thread->createTrack_l(...);
    // 2. 返回 IAudioTrack 接口给应用
    return track;
}

2.2 AudioFlinger 线程架构

frameworks/av/services/audioflinger/
├── Threads.cpp           # PlaybackThread 实现
├── Tracks.cpp           # Track 实现
├── AudioMixer.cpp       # 混音器
├── AudioFlinger.cpp     # AudioFlinger 主类
└── include/
    └── Threads.h        # 线程定义

三、详细写入流程

3.1 Step 1: 应用层写入

// 应用调用 AudioTrack.write()
// frameworks/av/media/libaudioclient/AudioTrack.cpp
ssize_t AudioTrack::write(const void* buffer, size_t size) {
    // 写入共享内存
    audio_track_cblk_t* cblk = mCblk;
    uint8_t* dst = cblk->buffer(uint8_t*) + cblk->user;
    memcpy(dst, buffer, size);
    cblk->stepUser(size);
}

3.2 Step 2: PlaybackThread 主循环

// frameworks/av/services/audioflinger/Threads.cpp
bool AudioFlinger::PlaybackThread::threadLoop() {
    while (!exitPending()) {
        // 1. 收集活跃的 Track
        Vector< sp<Track> > activeTracks;
        collectActiveTracks_l(&activeTracks);
        
        // 2. 准备混音
        prepareTracks_l(activeTracks);
        
        // 3. 执行混音
        mAudioMixer->process();
        
        // 4. 写入 HAL
        ssize_t bytesWritten = threadLoop_write();
        
        // 5. 更新状态
        updateTracks_l(activeTracks);
    }
    return false;
}

3.3 Step 3: 混音处理

// frameworks/av/services/audioflinger/AudioMixer.cpp
void AudioMixer::process() {
    // 重置混音缓冲区
    memset(mMixBuffer, 0, mMixBufferSize);
    
    // 处理每个活跃轨道
    for (int i = 0; i < mNumTracks; i++) {
        track_t& t = mTracks[i];
        if (t.enable) {
            // 获取音频数据
            AudioBufferProvider::Buffer buffer;
            t.bufferProvider->getNextBuffer(&buffer);
            
            // 混音
            switch (t.format) {
                case AUDIO_FORMAT_PCM_16_BIT:
                    process__16Bits(t, buffer.raw);
                    break;
                case AUDIO_FORMAT_PCM_FLOAT:
                    process__genericNoResampling(t, buffer.raw);
                    break;
            }
            
            t.bufferProvider->releaseBuffer(&buffer);
        }
    }
}

3.4 Step 4: 写入 HAL

// frameworks/av/services/audioflinger/Threads.cpp
ssize_t AudioFlinger::PlaybackThread::threadLoop_write() {
    // 获取混音后的数据
    void* buffer = mMixBuffer;
    size_t bytes = mMixBufferSize;
    
    // 应用效果处理
    if (mEffectBufferValid) {
        processEffects_l();
    }
    
    // 写入 HAL
    ssize_t bytesWritten = mOutput->write(buffer, bytes);
    
    // 错误处理
    if (bytesWritten < 0) {
        handleWriteError(bytesWritten);
    }
    
    // 统计
    mBytesWritten += bytesWritten;
    mFramesWritten += bytesWritten / mFrameSize;
    
    return bytesWritten;
}

四、HAL 层接口

4.1 AudioStreamOut HAL 定义

// hardware/libhardware/include/hardware/audio.h
struct audio_stream_out {
    // 写入接口
    ssize_t (*write)(struct audio_stream_out *stream,
                     const void* buffer,
                     size_t bytes);
    
    // 其他接口
    uint32_t (*get_latency)(const struct audio_stream_out *stream);
    int (*get_render_position)(const struct audio_stream_out *stream,
                              uint32_t *dsp_frames);
    int (*set_volume)(struct audio_stream_out *stream,
                     float left, float right);
};

4.2 HAL 实现路径

hardware/libhardware/modules/audio/
├── audio_hw.c          # 通用 HAL 实现
└── primary/
    ├── audio_hw.c      # 主音频 HAL
    └── ...

4.3 HAL write 实现示例

// hardware/libhardware/modules/audio/primary/audio_hw.c
static ssize_t out_write(struct audio_stream_out *stream,
                        const void* buffer,
                        size_t bytes) {
    struct stream_out *out = (struct stream_out *)stream;
    
    // 检查待机状态
    if (out->standby) {
        // 退出待机
        pthread_mutex_lock(&out->lock);
        do_out_standby_l(out, false);
        pthread_mutex_unlock(&out->lock);
    }
    
    // 写入 PCM 数据
    ssize_t written = 0;
    const uint8_t* p = (const uint8_t*)buffer;
    
    while (written < (ssize_t)bytes) {
        // 调用平台特定的写入
        ssize_t ret = pcm_write(out->pcm, p + written, bytes - written);
        
        if (ret < 0) {
            // 错误处理
            if (ret == -EPIPE) {
                // 下溢,尝试恢复
                pcm_prepare(out->pcm);
                continue;
            }
            ALOGE("pcm_write failed: %s", pcm_get_error(out->pcm));
            break;
        }
        written += ret;
    }
    
    // 更新统计
    out->written += written;
    
    return written;
}

五、平台特定的 HAL 实现

5.1 Qualcomm 平台

// hardware/qcom/audio/hal/audio_hw.c
static ssize_t qcom_out_write(struct audio_stream_out *stream,
                             const void* buffer,
                             size_t bytes) {
    struct qcom_stream_out *out = (struct qcom_stream_out *)stream;
    
    // 1. 检查是否在快速模式
    if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
        return qcom_out_write_fast(out, buffer, bytes);
    }
    
    // 2. 正常写入
    return qcom_out_write_normal(out, buffer, bytes);
}

static ssize_t qcom_out_write_fast(struct qcom_stream_out *out,
                                  const void* buffer,
                                  size_t bytes) {
    // 低延迟路径
    struct pcm *pcm = out->pcm;
    
    // 使用小缓冲区
    size_t frames = bytes / audio_stream_out_frame_size(&out->stream.common);
    size_t period_frames = pcm_get_buffer_size(pcm) / 4;  // 1/4 缓冲区
    
    // 分块写入
    ssize_t written = 0;
    while (frames > 0) {
        size_t to_write = MIN(frames, period_frames);
        int ret = pcm_writei(pcm, buffer, to_write);
        if (ret < 0) {
            return ret;
        }
        written += ret * audio_stream_out_frame_size(&out->stream.common);
        frames -= ret;
        buffer = (const char*)buffer + ret * audio_stream_out_frame_size(&out->stream.common);
    }
    
    return written;
}

5.2 ALSA PCM 写入

// hardware/libhardware/modules/audio/alsa/audio_hw.c
static ssize_t alsa_out_write(struct audio_stream_out *stream,
                             const void* buffer,
                             size_t bytes) {
    struct alsa_stream_out *out = (struct alsa_stream_out *)stream;
    
    // 转换为帧数
    snd_pcm_uframes_t frames = bytes / audio_stream_out_frame_size(stream);
    
    // 写入 ALSA
    snd_pcm_sframes_t written = snd_pcm_writei(out->handle, buffer, frames);
    
    if (written < 0) {
        // 处理错误
        if (written == -EPIPE) {
            // 下溢
            snd_pcm_prepare(out->handle);
            written = snd_pcm_writei(out->handle, buffer, frames);
        }
    }
    
    if (written > 0) {
        return written * audio_stream_out_frame_size(stream);
    }
    
    return written;
}

六、缓冲区管理

6.1 双缓冲区机制

// PlaybackThread 使用双缓冲区
class AudioFlinger::PlaybackThread {
private:
    // 混音缓冲区
    void* mMixBuffer;
    size_t mMixBufferSize;
    
    // 沉默缓冲区(用于欠载时填充)
    void* mSilenceBuffer;
    
    // 重试缓冲区
    void* mRetryBuffer;
};

6.2 缓冲区分配

void AudioFlinger::PlaybackThread::initBuffer() {
    // 计算缓冲区大小
    size_t frameCount = mNormalFrameCount;
    if (mType == MIXER) {
        frameCount = mFrameCount;
    }
    
    // 分配混音缓冲区
    mMixBufferSize = frameCount * mFrameSize;
    mMixBuffer = calloc(1, mMixBufferSize);
    
    // 分配沉默缓冲区
    mSilenceBuffer = calloc(1, mMixBufferSize);
    memset(mSilenceBuffer, 0, mMixBufferSize);
}

七、错误处理和恢复

7.1 写入错误处理

ssize_t AudioFlinger::PlaybackThread::threadLoop_write() {
    ssize_t bytesWritten = mOutput->write(mMixBuffer, mMixBufferSize);
    
    if (bytesWritten < 0) {
        // 错误分类处理
        switch (bytesWritten) {
            case -EPIPE:  // 下溢
                handleUnderrun();
                break;
            case -ENODEV:  // 设备移除
                handleDeviceRemoved();
                break;
            case -EIO:  // I/O 错误
                handleIOError();
                break;
            default:
                ALOGE("write error: %zd", bytesWritten);
                bytesWritten = 0;
        }
        
        // 写入沉默数据
        if (mSilenceBuffer) {
            mOutput->write(mSilenceBuffer, mMixBufferSize);
        }
    }
    
    return bytesWritten;
}

7.2 下溢处理

void AudioFlinger::PlaybackThread::handleUnderrun() {
    AutoMutex _l(mLock);
    
    mNumUnderruns++;
    
    if (mNumUnderruns >= kMaxUnderrunWarnings) {
        ALOGW("Multiple underruns occurred: %u", mNumUnderruns);
    }
    
    // 重置 HAL
    mOutput->standby();
    
    // 重新准备输出
    mOutput->write(mSilenceBuffer, mMixBufferSize);
    
    // 重新开始
    mOutput->write(mMixBuffer, mMixBufferSize);
}

八、性能优化

8.1 快速混音线程

// FastMixer 用于低延迟场景
void AudioFlinger::FastMixer::onWork() {
    // 快速混合
    for (size_t i = 0; i < mNumTracks; i++) {
        FastTrack* fastTrack = &mFastTracks[i];
        if (fastTrack->mBufferProvider != NULL) {
            // 获取数据
            AudioBufferProvider::Buffer buffer;
            fastTrack->mBufferProvider->getNextBuffer(&buffer);
            
            // 快速混合
            mFastMixerBuffer = mixOneTrack(fastTrack, buffer.raw, mFastMixerBuffer);
        }
    }
    
    // 快速写入
    mOutputSink->write(mFastMixerBuffer, mFrameCount * mFrameSize);
}

8.2 直接写入优化

// 当只有一个活跃轨道时,使用直接写入
ssize_t AudioFlinger::PlaybackThread::threadLoop_write() {
    if (mActiveTracks.size() == 1) {
        // 直接写入,跳过混音
        sp<Track> track = mActiveTracks[0].promote();
        if (track != 0) {
            AudioBufferProvider::Buffer buffer;
            buffer.frameCount = mFrameCount;
            status_t status = track->getNextBuffer(&buffer);
            
            if (status == OK) {
                // 直接写入 HAL
                ssize_t written = mOutput->write(buffer.raw, buffer.frameCount * mFrameSize);
                track->releaseBuffer(&buffer);
                return written;
            }
        }
    }
    
    // 正常混音路径
    return threadLoop_write_mix();
}

九、调试和监控

9.1 调试命令

# 查看 AudioFlinger 状态
adb shell dumpsys media.audio_flinger

# 查看活跃线程
adb shell dumpsys media.audio_flinger | grep "Output thread"

# 查看写入统计
adb shell dumpsys media.audio_flinger | grep -A5 "Bytes written"

# 查看 HAL 状态
adb shell dumpsys media.audio_flinger | grep -A10 "HAL"

9.2 性能监控

// 在 PlaybackThread 中添加性能统计
class PlaybackThread {
private:
    // 性能统计
    struct WriteStats {
        uint64_t totalBytesWritten;
        uint64_t totalWriteTime;
        uint32_t maxWriteTime;
        uint32_t minWriteTime;
        uint32_t writeErrors;
    } mWriteStats;
    
    void recordWriteStat(ssize_t bytes, uint32_t timeUs) {
        mWriteStats.totalBytesWritten += bytes;
        mWriteStats.totalWriteTime += timeUs;
        
        if (timeUs > mWriteStats.maxWriteTime) {
            mWriteStats.maxWriteTime = timeUs;
        }
        if (timeUs < mWriteStats.minWriteTime || mWriteStats.minWriteTime == 0) {
            mWriteStats.minWriteTime = timeUs;
        }
    }
};

十、完整数据流程图

多轨道
单轨道
AudioTrack.write
写入共享内存
AudioFlinger 读取
AudioMixer 混音
混合所有音频
直接传递
应用音效处理
跳过混音
调用 HAL write
HAL 实现
平台驱动
硬件 DMA
DAC 输出

十一、关键数据结构

11.1 Track 控制块

// audio_track_cblk_t
struct audio_track_cblk_t {
    // 生产者/消费者指针
    volatile    int32_t     user;        // 生产者位置
    volatile    int32_t     server;      // 消费者位置
    
    // 缓冲区信息
    uint32_t    frameCount;             // 总帧数
    uint32_t    frameSize;              // 帧大小
    uint8_t*    buffers;                // 数据缓冲区
};

11.2 混音器配置

// AudioMixer 的 track_t
struct track_t {
    AudioBufferProvider*    bufferProvider;
    audio_format_t         format;
    uint32_t               sampleRate;
    uint32_t               channelCount;
    audio_channel_mask_t   channelMask;
    float                  volume[MAX_NUM_VOLUMES];
    uint32_t               needs;
    bool                   enabled;
};

总结

AudioFlinger 写入 HAL 的核心流程:

  1. 数据准备:从 AudioTrack 共享内存读取数据
  2. 混音处理:AudioMixer 混合多个音轨
  3. 效果处理:应用音效和音量控制
  4. HAL 调用:通过 audio_stream_out->write() 接口
  5. 硬件写入:平台特定的 PCM 写入
  6. 错误恢复:处理下溢、设备移除等错误

性能关键

  • 快速混音路径优化
  • 直接写入避免混音
  • 低延迟 HAL 配置
  • 智能缓冲区管理

调试要点

  • 监控写入延迟
  • 检查缓冲区状态
  • 跟踪 HAL 错误
  • 分析性能瓶颈
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐