6.6 KiB
HarmonyOS OHAudio Backend
状态:Phase 3 CODE COMPLETE / DEVICE VALIDATION PENDING。
代码、OHOS arm64 交叉编译和模拟器 H.264/AAC smoke test 已完成。实体设备上的真实输出路由、延迟、A/V sync 精度、蓝牙/耳机、多声道和长时间稳定性仍未宣称完成。
Architecture
MPV decoder/filter
↓
MPV AO buffer (audio/out/buffer.c)
↓ pull callback
audio/out/ao_harmony.c
↓
OH_AudioRenderer write callback
↓
HarmonyOS audio device
ao_harmony 是 MPV pull AO。PCM 始终在 native 层流动;ArkTS 只负责播放控制和诊断展示,不参与持续 PCM 搬运。
实现文件:
audio/out/ao_harmony.c:AO、OHAudio renderer、callback、时钟和统计。audio/out/ao_harmony.h:Playback Lab 使用的只读诊断 ABI。audio/out/ao.c、meson.build、meson.options:driver 注册和harmony-audiofeature。
OHAudio API
实现以当前 API 24 SDK headers 为准:
ohaudio/native_audiostreambuilder.hohaudio/native_audiorenderer.hohaudio/native_audiostream_base.hmultimedia/native_audio_channel_layout.h- 链接库:
libohaudio.so
Builder 设置 SamplingRate、ChannelCount、ChannelLayout、SampleFormat、EncodingType(RAW)、LatencyMode(NORMAL)、RendererInfo(USAGE_MOVIE) 和 write/device/error callbacks,然后 GenerateRenderer 并销毁 Builder。Renderer 使用 Start、Pause、Stop、Flush、Release、SetVolume、GetFrameSizeInCallback、GetLatency 和 GetAudioTimestampInfo。
MPV AO / callback model
write 保持 NULL,start 触发 OHAudio。OHAudio 回调只计算 frame 数、调用 ao_read_data(..., pad_silence=true, blocking=false),不足部分填静音并更新轻量原子计数;不访问网络、不调用 N-API/ArkTS、不分配大对象、不逐回调打印日志。回调首包仅在 debug 日志中记录一次。
MPV AO buffer 是 producer,OHAudio callback 是 consumer。ao_read_data 返回的 PCM 只在当前 callback 内有效,系统提供的 audioData 由 OHAudio 所有;没有 AVFrame 或 PCM 指针跨生命周期保存。
Format / sample rate / channel layout
- 仅接受 PCM;MPV float 优先映射
AUDIOSTREAM_SAMPLE_F32LE,创建失败时回退AF_FORMAT_S16/AUDIOSTREAM_SAMPLE_S16LE。 - 采样率使用 MPV 请求值,不强制改成 48 kHz;设备拒绝时返回真实 renderer 创建错误,由 MPV 上层重新协商/重采样。
- 单声道映射
CH_LAYOUT_MONO,其余首版限制为双声道CH_LAYOUT_STEREO;超过 2 声道先通过 MPV channel map downmix 到 stereo。没有声称 5.1/7.1/Atmos/Dolby 已支持,实体设备能力仍待验证。
模拟器实际日志:请求 48 kHz、5.1、floatp,经 MPV downmix 后创建 48 kHz、2 声道、float32 renderer。
Pause / resume / stop / seek / flush
- pause:
OH_AudioRenderer_Pause。 - resume/start:
OH_AudioRenderer_Start。 - stop:MPV 的 stop/EOF 通过 AO reset/uninit 路径停止 renderer;不把 pause、stop、release 混为 destroy。
- seek/reset:先禁止新 callback,
Stop,等待 inflight callback 清零,再Flush;清空本地提交/播放 epoch,增加audioFlushCount与seekAudioResetCount,下一次start重新开始。 - release:禁止 callback → Stop → 等待 callback → 停止并 join timestamp 线程 → Release renderer;回调不会持有释放后的 player/AO 指针。
所有 OHAudio 返回值都检查;失败通过 MPV AO error/reload 路径处理,使用 AUDIO_BUILDER_FAILED、AUDIO_RENDERER_CREATE_FAILED、AUDIO_RENDERER_START_FAILED、AUDIO_FLUSH_FAILED、AUDIO_RELEASE_ERROR、AUDIO_UNSUPPORTED_FORMAT 等明确日志。
A/V clock and delay
timestamp 线程每 20 ms 调用 OH_AudioRenderer_GetAudioTimestampInfo。submittedFrames 在 callback 完成填充后递增;playedFrames 使用 renderer frame position 减去本次 Flush 的 timestamp origin,避免设备在 Flush 后继续返回旧 epoch。延迟计算为:
pending = max(submittedFrames - playedFrames, 0)
estimatedDelayMs = rendererLatencyMs + pending * 1000 / sampleRate
audioTimestamp 保留 OHAudio 的 monotonic timestamp。MPV 播放倍速仍由 MPV 音频滤镜/时钟负责,不叠加 renderer speed。算法已编译并在模拟器观察到稳定计数;绝对 A/V 偏差与设备路由连续性必须实体机测量。
Volume and underrun
Renderer volume 固定为 unity,最终音量由 MPV 软件 gain 处理,避免双重增益。API 24 当前没有可用的系统 underrun counter,因此不伪造 systemUnderrun;callback 返回帧不足时只增加 Velix-side bufferStarvation。
Playback Lab diagnostics
Playback Lab 保持原有 video-only 启动路径,新增 Audio On/Off(切换 MPV aid=auto/no)和以下 native 状态:audioBackend、sampleRate、sampleFormat、channels、channelLayout、submittedFrames、playedFrames、estimatedAudioDelayMs、audioBufferStarvation、audioFlushCount、seekAudioResetCount、audioState。返回值使用 ArkTS Number,避免 BigInt 让 Inspector 无法序列化。
Validation
- Audio-enabled:OHOS arm64
libmpv.so.2.5.0clean build,DT_NEEDED 新增libohaudio.so,Playback Lab HAP 构建成功。 - Video-only:使用
-Dharmony-audio=disabled的独立 Meson build 编译成功。 - Emulator smoke:H.264/AAC MP4 上确认 renderer create、start、callback PCM consumed、pause、resume、seek/flush、stop、release;示例观察到
starvation=0,模拟器日志无新增崩溃。 - 未验证:实体设备、真实 latency/A-V 偏差、蓝牙/有线/扬声器切换、系统 audio focus/interruption、5.1/7.1、30 分钟压力。
Known limitations and physical TODO
- 当前仅实现 OHAudio renderer;没有 OHCodec/hwdec、Vulkan、音频焦点业务和设备专属路由策略。
systemUnderrun需要 SDK 提供真实接口后再接入;当前仅有bufferStarvation。- 多声道真实 capability、采样率拒绝后的设备行为、timestamp 在路由切换后的连续性需要实体设备矩阵。
- 上层应用负责电话/音频焦点策略;Core 只接受 pause/resume 或 AO reload。
Phase 4 不在本次变更中启动。未来 OHCodec 评估至少需要单独验证 surface/buffer 同步、stride/format、fence 与生命周期、零拷贝/DRM 约束、不同设备实现差异五类风险。
License
本次仅修改 Velix-MPV-Core 内的 MPV 集成代码和 Playback Lab;MPV 原有 GPL/LGPL 许可保持不变。HarmonyOS SDK 头文件/系统库按 SDK 自身许可使用,没有复制第三方实现源码。