夜雨聆风学习资料网

ARTICLE · 1044580

安卓驱动[8]AN14音频链路与音视频同步链路

安卓驱动[8]AN14音频链路与音视频同步链路

音频链路 (Audio Pipeline) — 从上到下

1. 应用层 (Java)

JavaMediaPlayer / AudioTrack / AudioRecord

2. 框架层 (frameworks/av)

AudioTrack (音频输出客户端): frameworks/av/media/libaudioclient/AudioTrack.cpp    - AudioTrack::AudioTrack (line 243/260) 构造    - AudioTrack::getPosition (line 1676) 播放位置    - AudioTrack::getTimestamp (line 31693211) 时间戳(A/V同步用)    - AudioTrack::getTimestamp_l (line 31783217) 时间戳实现    - AudioTrack::write  (line 243,260) 构造AudioFlinger (音频服务): frameworks/av/services/audioflinger/Threads.cpp    - AudioFlinger::ThreadBase::ThreadBase (line 549) 线程构造     - AudioFlinger::MixerThread::threadLoop_write (line 5272) 写数据到 HAL    - AudioFlinger::MixerThread::threadLoop_mix (line 5399) 混音    - AudioFlinger::PlaybackThread::getTimestamp_l (line 4764) 线程时间戳    - threadloop_getHalTimestamp_l (line 4604) 取 HAL 时间戳

3. HAL层 (hardware/rockchip/audio/primary_hal/audio_hw.c)

 - out_write (line 2916) 播放写数据   - in_read (line 3653) 录音读数据  - out_get_presentation_position (line 3164) 呈现时间戳(A/V同步关键) - out_get_latency (line 2519) 时延 - start_output_stream (line 1330) 打开播放 PCM - start_input_stream (line 1753) 打开录音 PCM  - adev_open_output_stream (line 4081) 打开播放流 - adev_open_input_stream (line 4710) 打开录音流 - adev_set_parameters (line 4375) 参数(路由)  - ALSA 混音器: alsa_mixer.c, alsa_route.c

4. 内核层 (kernel-6.1/sound/soc)

 - I2S 控制器: sound/soc/rockchip/rockchip_i2s_tdm.c   - rockchip_i2s_tdm_hw_params (line 2008)  配置采样率/位宽/通道   - rockchip_i2s_tdm_trigger (line 2095) 启动/停止传输   - rockchip_i2s_tdm_startup (line 2500) 打开 substream    - rockchip_i2s_tdm_dai_probe DAI 注册 - codec:自定义 - HDMI: sound/soc/rockchip/rockchip_hdmi.c - ALSA core: sound/core/pcm_native.c (snd_pcm_*)   - sound/core/pcm_native.c — snd_pcm_pointer / snd_pcm_status(时间戳源头)   - sound/soc/soc-pcm.c — DAI 启停

二、音视频同步链路 (A/V sync)

核心原理:以音频时钟为主时钟,视频按音频时钟调度。

1. 音频时间戳的产生(芯片 → 框架)

内核 snd_pcm_pointer (sound/core/pcm_native.c)   ↓HAL out_get_presentation_position (audio_hw.c:3164)   ↓AudioFlinger threadloop_getHalTimestamp_l (Threads.cpp:4604)   ↓AudioTrack::getTimestamp_l(AudioTrack.cpp:3217)

1. AudioFlinger 提供时间戳 (HAL → 内核 → 回传)

 - HAL: out_get_presentation_position (audio_hw.c:3164 - 内核 ALSA: snd_pcm_pointer / snd_pcm_status - AudioFlinger: threadloop_getHalTimestamp_l (Threads.cpp) - AudioTrack: getTimestamp_l (AudioTrack.cpp)

2. MediaClock (A/V同步的时间基准)

 frameworks/av/media/libstagefright/MediaClock.cpp - MediaClock::updateAnchor (line 89)     更新锚点(音视频对齐) - MediaClock::getMediaTime (line 160)    取当前媒体时间 - MediaClock::getRealTimeFor (line 191)  媒体时间→真实时间 - MediaClock::setPlaybackRate (line 133) 倍速  - MediaClock::getMediaTime_l (line 170)  内部实现

3. NuPlayerRenderer (A/V同步的核心逻辑)

frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp- onDrainAudioQueue (line 1063) — 音频出队(推进 clock)- onQueueBuffer / queueBuffer (line 1537) -入队- onDrainAudioQueue (the A/V sync decision)(line 1063) 音频出队(推进主时钟) - onDrainVideoQueue (line 1397) — 视频出队(按 clock 调度)- getCurrentPosition (line 384) 当前位置- setAudioFirstAnchorTimeIfNeeded_l (line 422) 设置音频锚点- clearAnchorTime (line 430) 清锚点

4. Video 渲染按 MediaClock 调度

- MediaCodec (frameworks/av/media/libstagefright/MediaCodec.cpp)- ACodec (frameworks/av/media/libstagefright/ACodec.cpp)

三、调试入口对照表

现象

先看哪一层

具体位置

没声音/爆音

HAL + 内核

audio_hw.c:out_write 

→ rockchip_i2s_tdm.c:trigger

 音视频不同步

框架

NuPlayerRenderer.cpp:onDrainAudioQueue/onDrainVideoQueue

时间戳不对

HAL

audio_hw.c:out_get_presentation_position

路由错(扬声器/耳机)

HAL

alsa_route.c / adev_set_parameters

I2S 没时钟

内核

rockchip_i2s_tdm.c:hw_params

codec 没声音

内核

sound/soc/codecs/es8323.c

视频花屏/解码失败

MPP

drivers/video/rockchip/mpp/mpp_rkvdec2.c

 抓日志的正确定位顺序

 1.应用层  logcat -s NuPlayer NuPlayerRenderer MediaClock AudioTrack 2.框架/HAL  logcat -s audio_hw_primary AudioFlinger 3.内核  dmesg | grep -E 'i2s|es8323|codec|dai|mpp|rkvdec'

相关学习资料