Android-Audio-AudioFlinger-写音频数据到HAL流程
·
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;
}
}
};
十、完整数据流程图
十一、关键数据结构
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 的核心流程:
- 数据准备:从 AudioTrack 共享内存读取数据
- 混音处理:AudioMixer 混合多个音轨
- 效果处理:应用音效和音量控制
- HAL 调用:通过 audio_stream_out->write() 接口
- 硬件写入:平台特定的 PCM 写入
- 错误恢复:处理下溢、设备移除等错误
性能关键:
- 快速混音路径优化
- 直接写入避免混音
- 低延迟 HAL 配置
- 智能缓冲区管理
调试要点:
- 监控写入延迟
- 检查缓冲区状态
- 跟踪 HAL 错误
- 分析性能瓶颈
更多推荐


所有评论(0)