OpenHarmony 5.0.2 音频驱动适配实战:从ADM配置到耳机/扬声器切换
1. OpenHarmony音频驱动适配背景与问题定位最近在RK3568平台上适配OpenHarmony 5.0.2的音频功能时遇到了一个典型问题使用RK809音频芯片时耳机可以正常发声但内置扬声器完全没声音而且插入耳机后扬声器也不会自动静音。这种情况在智能硬件开发中很常见特别是当硬件平台和操作系统版本更新时音频驱动往往需要重新适配。我花了三天时间排查这个问题最终发现核心原因在于ADMAudio Driver Model框架下的默认配置与RK809芯片的寄存器设置不匹配。具体来说问题出在三个关键点设备树中扬声器路径未正确启用音频路径配置文件(audio_paths.json)中Speaker1 Switch默认值为0关闭状态耳机检测GPIO配置与硬件实际连接不符通过hdf日志分析工具hdf_log -l 5可以看到当播放音频时系统确实尝试往扬声器输出信号但由于上述配置问题音频信号实际上被阻断了。这就像水管已经接好了但阀门没打开水自然流不到目的地。2. 基础环境准备与SELinux权限调整在开始具体修改前我们需要确保基础环境正确。OpenHarmony 5.0.2的默认SELinux策略可能会阻止音频驱动的某些操作建议先将系统切换到宽容模式# 修改SELinux策略配置文件 vim base/security/selinux_adapter/selinux.gni将selinux_adapter_enforce参数设为falsedeclare_args() { selinux_adapter_enforce false }编译刷机后通过hdc shell连接设备验证getenforce # 应该输出 Permissive这个步骤很关键因为在强制模式(Enforcing)下即使配置正确SELinux也可能会拦截音频设备的访问。我在第一次调试时就踩了这个坑花了半天时间才发现是权限问题而不是配置错误。3. 设备树关键配置修改设备树(DTS)是硬件与驱动之间的桥梁对于音频适配尤为重要。针对RK809芯片需要特别注意以下几个配置节点3.1 耳机检测配置rk_headset: rk-headset { compatible rockchip_headset; headset_gpio gpio1 RK_PD4 GPIO_ACTIVE_HIGH; // 根据实际硬件连接修改 pinctrl-names default; pinctrl-0 hp_det; };这里的headset_gpio必须与硬件原理图一致。有个实用技巧可以通过cat /sys/kernel/debug/gpio命令查看当前GPIO状态帮助确认连接是否正确。3.2 声卡与Codec配置rk809_sound: rk809-sound { status okay; compatible simple-audio-card; simple-audio-card,format i2s; simple-audio-card,name rockchip,rk809-codec; simple-audio-card,mclk-fs 256; simple-audio-card,cpu { sound-dai i2s1_8ch; }; simple-audio-card,codec { sound-dai rk809_codec; }; }; rk809_codec: codec { #sound-dai-cells 0; compatible rockchip,rk809-codec, rockchip,rk817-codec; clocks cru I2S1_MCLKOUT; clock-names mclk; assigned-clocks cru I2S1_MCLKOUT, cru I2S1_MCLK_TX_IOE; assigned-clock-rates 12288000; assigned-clock-parents cru I2S1_MCLKOUT_TX, cru I2S1_MCLKOUT_TX; pinctrl-names default; pinctrl-0 i2s1m0_mclk; hp-volume 3; spk-volume 20; // 扬声器默认音量 capture_volume 255; status okay; };特别注意spk-volume这个参数它决定了扬声器的初始音量。如果设为0即使其他配置正确扬声器也不会有声音。4. 音频路径配置实战ADM框架通过audio_paths.json文件定义音频路由规则这是解决扬声器无声问题的关键。我们需要修改以下文件hdf_audio_codec_primary_dev0: [ { deep-buffer-playback: [ { Headphones: [ { name: Speaker1 Switch, value: 1 // 必须改为1才能启用扬声器 } ] } ] } ]修改后需要特别注意必须删除out目录重新编译否则更改可能不会生效。这是OpenHarmony编译系统的一个特点我因为这个点浪费了两个小时的调试时间。对应的代码解析逻辑在// drivers/hdf_core/framework/model/audio/dispatch/src/audio_control_dispatch.c static int32_t ControlHostElemWrite(const struct HdfDeviceIoClient *client, struct HdfSBuf *reqData, struct HdfSBuf *rspData) { // 控制逻辑实现... }可以通过在代码中添加日志打印来验证配置是否生效HDF_LOGI(Speaker1 Switch value %d, value);5. 寄存器配置深度优化RK809芯片的寄存器配置直接影响音频输出质量默认配置可能需要针对具体硬件进行调整5.1 修改codec_config.hcsregConfig { initSeqConfig [ 0x38, 0x18, // 关键修改DAC控制寄存器 0x41, 0xf7, // 扬声器偏置电压设置 // 其他寄存器配置... ]; }这些16进制值需要参考RK809的数据手册。有个实用技巧可以先用i2c-tools读取当前寄存器值与预期值对比i2cdump -f -y 1 0x205.2 新增扬声器控制接口为了实现耳机插拔时自动切换扬声器我们需要新增控制接口// device/board/hihope/rk3568/audio_drivers/codec/rk809_codec/include/rk809_codec_impl.h int32_t Rk809DeviceSpeakerControl(uint32_t val);具体实现// device/board/hihope/rk3568/audio_drivers/codec/rk809_codec/src/rk809_codec_impl.c static const struct RegDefaultVal g_rk817SpeakerCloseReg[] { { RK817_CODEC_DDAC_MUTE_MIXCTL, 0xa0 }, { RK817_CODEC_ACLASSD_CFG1, 0x69 }, { RK817_CODEC_ACLASSD_CFG2, 0x44 }, }; static const struct RegDefaultVal g_rk817SpeakerOpenReg[] { { RK817_CODEC_DDAC_MUTE_MIXCTL, 0x18 }, { RK817_CODEC_ACLASSD_CFG1, 0xa5 }, { RK817_CODEC_ACLASSD_CFG2, 0xf7 }, }; int32_t Rk809DeviceSpeakerControl(uint32_t val) { if(val 0) { return RK809DeviceRegConfig(g_rk817SpeakerCloseRegConfig); } else if(val 1) { return RK809DeviceRegConfig(g_rk817SpeakerOpenRegConfig); } return HDF_FAILURE; }然后在耳机检测逻辑中调用这个接口static void ControlSpeakerState(int32_t level) { if(level HEADSET_IN) { Rk809DeviceSpeakerControl(0); // 插入耳机关闭扬声器 } else { Rk809DeviceSpeakerControl(1); // 拔出耳机开启扬声器 } }6. 耳机检测与设备优先级处理OpenHarmony的音频策略服务需要正确识别耳机设备状态6.1 修改音频事件定义// foundation/multimedia/audio_framework/services/audio_policy/server/include/service/manager/pnp_server/audio_pnp_param.h #define UEVENT_STATE_ANALOG_HP0 HEADPHONE0 #define UEVENT_STATE_ANALOG_HP1 HEADPHONE16.2 更新设备状态检测逻辑// foundation/multimedia/audio_framework/services/audio_policy/server/src/service/manager/pnp_server/audio_socket_thread.cpp int32_t AudioSocketThread::SetAudioPnpServerEventValue(AudioEvent *audioEvent, struct AudioPnpUevent *audioPnpUevent) { if (strstr(audioPnpUevent-state, UEVENT_STATE_ANALOG_HP0) ! NULL) { audioEvent-eventType PNP_EVENT_DEVICE_REMOVE; } else if (strstr(audioPnpUevent-state, UEVENT_STATE_ANALOG_HP1) ! NULL) { audioEvent-eventType PNP_EVENT_DEVICE_ADD; } // ... }6.3 添加默认设备类型// foundation/multimedia/audio_framework/services/audio_policy/server/src/service/audio_device_manager.cpp void AudioDeviceManager::AddDefaultDevices(const sptrAudioDeviceDescriptor devDesc) { DeviceType devType devDesc-deviceType_; if (devType DEVICE_TYPE_EARPIECE || devType DEVICE_TYPE_WIRED_HEADSET) { earpiece_ devDesc; } else if (devType DEVICE_TYPE_SPEAKER) { speaker_ devDesc; } else if (devType DEVICE_TYPE_MIC || devType DEVICE_TYPE_WIRED_HEADSET) { defalutMic_ devDesc; } }7. 验证与调试技巧完成上述修改后建议按照以下步骤验证基础功能测试播放音乐时扬声器应有声音插入耳机后扬声器应自动静音拔出耳机后扬声器应自动恢复日志分析hdf_log -l 5 | grep -i audio重点关注是否有权限错误或配置加载失败的信息寄存器状态检查cat /proc/asound/card0/codec#0确认关键寄存器值是否符合预期性能测试tinyplay /data/test.wav -D 0 -d 0 -p 1024 -n 8测试不同参数下的音频延迟和稳定性如果遇到问题可以尝试以下调试方法逐步回退修改定位问题点对比正常设备和问题设备的寄存器差异使用示波器检查I2S信号是否正常整个适配过程中最耗时的往往是硬件连接确认和寄存器配置调试。建议在开始前就准备好硬件原理图和芯片数据手册这能节省大量猜测和试错时间。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2463437.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!