公司动态

rk3568安卓13驱动适配-SPDIF数字音频

📅 2026/8/17 20:09:57
rk3568安卓13驱动适配-SPDIF数字音频
本文记录工作中在rk3568安卓13的SDK中适配板载外设spdif功能时具体的驱动修改和遇到的问题。目录前言一、spdif介绍二、驱动适配1.硬件原理2.设备树修改3. 内核配置4.驱动测试三.音频路由策略1.配置文件修改2.音频路由策略修改总结前言spdif功能大部分人可能不熟悉我也是第一次接触。百度后才发现在HDMI未出现之前spdif很火能无损传输数字音频仅用一根线就能打包传输Dolby Digital、DTS编码的5.1环绕声大幅简化家庭影院布线在CD机、早期DVD播放机、老款AV功放上是标配数字音频接口。本文介绍在rk3568安卓13的SDK中是如何实现spdif功能的。一、spdif介绍SPDIF 严谨写法为 S/PDIF是 Sony/Philips Digital Interface Format 的缩写中文称为索尼/飞利浦数字接口格式 。SPDIF 传输的是数字信号而非模拟信号采用双相标记编码BMC进行数据传输时钟信号嵌入在数据流中 。可传输 PCM 立体声音频及 Dolby Digital、DTS 等多声道压缩音频信号但不支持杜比 TrueHD 及 EAC-3 格式的 7.1 声道音频 。SPDIF 分为同轴电信号和光纤光信号两种物理接口传输的信号内容相同仅载体不同 。‌‌近距离传输一般选同轴长距离或电磁环境复杂时选光纤 。‌‌二、驱动适配1.硬件原理rk3568-pinctrl.dtsi文件中关于spdif引脚的定义如下,可以看出设备树中需要用spdifm2_tx这个节点kernel-5.10/arch/arm64/boot/dts/rockchip/rk3568-pinctrl.dtsi spdif { /omit-if-no-ref/ spdifm0_tx: spdifm0-tx { rockchip,pins /* spdifm0_tx */ 1 RK_PA4 4 pcfg_pull_none; }; /omit-if-no-ref/ spdifm1_tx: spdifm1-tx { rockchip,pins /* spdifm1_tx */ 3 RK_PC5 2 pcfg_pull_none; }; /omit-if-no-ref/ spdifm2_tx: spdifm2-tx { rockchip,pins /* spdifm2_tx */ 4 RK_PC4 2 pcfg_pull_none; }; };2.设备树修改rk官方参考文件rk3568-evb.dtsi中已经配置好了spdif我们只需修改将引脚对应起来就可以了。我们可以先看下官方芯片级设备树文件rk3568.dtsi中关于spdif的节点定义只有以下节点可以看出我们需要把spdif_8ch节点下的引脚改成自用的即可具体引脚名用spdifm2_tx。为保证规范我们需要到自己的板级设备树文件去改。kernel-5.10/arch/arm64/boot/dts/rockchip/rk3568.dtsi spdif_8ch: spdiffe460000 { compatible rockchip,rk3568-spdif; reg 0x0 0xfe460000 0x0 0x1000; interrupts GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH; dmas dmac1 1; dma-names tx; clock-names mclk, hclk; clocks cru MCLK_SPDIF_8CH, cru HCLK_SPDIF_8CH; #sound-dai-cells 0; pinctrl-names default; pinctrl-0 spdifm0_tx; status disabled; };kernel-5.10/arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi spdif-sound { status okay; compatible simple-audio-card; simple-audio-card,name ROCKCHIP,SPDIF; simple-audio-card,mclk-fs 128; simple-audio-card,cpu { sound-dai spdif_8ch; }; simple-audio-card,codec { sound-dai spdif_out; }; }; spdif_out: spdif-out { status okay; compatible linux,spdif-dit; #sound-dai-cells 0; }; spdif_8ch { status okay; pinctrl-names default; pinctrl-0 spdifm2_tx; //修改为自己板子上对应的引脚 };3. 内核配置还需要确保内核中关于SPDIF的驱动编译开关打开一般默认是打开的最好核对下。kernel-5.10/arch/arm64/configs/rockchip_defconfig CONFIG_SND_SOC_SPDIFy4.驱动测试这个时候打包完SDK测试就能看到驱动适配完了在安卓板子上执行以下命令预期输出以下。rk3568_t:/ # cat /proc/asound/cards 0 [rockchiprk809 ]: rockchip-rk809 - rockchip-rk809 rockchip-rk809 1 [rockchiphdmi ]: rockchip_hdmi - rockchip,hdmi rockchip,hdmi 2 [ROCKCHIPSPDIF ]: ROCKCHIP_SPDIF - ROCKCHIP,SPDIF ROCKCHIP,SPDIF但是用自带的音乐播放器播放音乐spdif还是没有输出这是因为安卓层音频路由策略的问题下一章介绍安卓音频路由策略的修改可以先用tinyplay工具指定音卡去播放测试tinyplay工具不支持MP3格式最好用wav格式音频测试执行以下命令其中-D 2表示指定序号为2的音卡上图看出就是对应的spdif这时能通过spdif正常播放音乐这说明硬件和驱动都适配完成了。rk3568_t:/ # tinyplay /data/local/tmp/bhs.wav -D 2 -d 0 Playing sample: 2 ch, 44100 hz, 16 bit 39156752 bytes三.音频路由策略1.配置文件修改音频配置文件修改因为spdif没有硬件检测功能软件上配置为常在设备即可需要修改以下文件rk3568-sdk/device/rockchip/common/audio_policy_configuration.xml attachedDevices itemSpeaker/item itemBuilt-In Mic/item itemSPDIF Out/item !--增加spdif,名字可参考文件下文 -- itemHDMIIn/item /attachedDevices2.音频路由策略修改一般插耳机的话耳机优先级最高。我这里的需求是耳机或喇叭接入时优先这俩工作但这俩没插时就spdif和hdmi同时工作。调试时发现同一个流打开多个 PCM 设备后route_pcm_card_open函数接口只允许一个“活动路径”存在因为spdif不走route_pcm_card_open接口我这里就没有修改接口以支持多个音频路由。有需求的伙伴可以去研究下如何修改route_pcm_card_open接口以支持多个设备。官方已经写好多设备同时输出的接口了调用这个函数open_sound_card_policy即可需要打开相关宏可以看到start_output_stream接口中调用open_sound_card_policy如下所示SUPPORT_MULTIAUDIO这个宏官方已经处理好了至于BOX_HAL需要修改Android.mk注释掉BOX_HAL定义前的判断条件即可。还需要修改同文件中的out_write接口以支持音频流写入多设备。//hardware/rockchip/audio/tinyalsa_hal/audio_hw.c文件中 //start_output_stream函数中通过宏定义开关调用open_sound_card_policy #ifndef SUPPORT_MULTIAUDIO #ifdef BOX_HAL open_sound_card_policy(out); #endif #endif //在open_sound_card_policy函数中新增业务逻辑如果耳机或者喇叭接入则返回只耳机或喇叭响 for (int i 0; i out-num_configs; i) { if (audio_is_bluetooth_out_sco_device(out-devices[i])) return; //新增代码 if (out-devices[i] AUDIO_DEVICE_OUT_WIRED_HEADPHONE || out-devices[i] AUDIO_DEVICE_OUT_WIRED_HEADSET || out-devices[i] AUDIO_DEVICE_OUT_SPEAKER) return; } //out_write函数中需要在调用写音频流处修改将break注释掉以支持多设备 for(i 0; i SND_OUT_SOUND_CARD_MAX; i){ if (out-pcm[i]) { if (i SND_OUT_SOUND_CARD_BT) { // HARD CODE FIXME 48000 stereo - 8000 stereo size_t inFrameCount bytes/2/2; int destRate out-config.rate; int srcRate adev-bt_wb_speech_enabled? 16000:8000; int coefficient (destRate/srcRate); size_t outFrameCount inFrameCount/coefficient; int16_t out_buffer[outFrameCount*2]; memset(out_buffer, 0x00, outFrameCount*2); out-resampler-resample_from_input(out-resampler, (const int16_t *)buffer, inFrameCount, out_buffer, outFrameCount); ret pcm_write(out-pcm[i], (void *)out_buffer, outFrameCount*2*2); if (ret ! 0) break; } else { /* * do not write hdmi/spdif snd sound if they are taken by other bitstream/multi channle pcm stream */ if((i SND_OUT_SOUND_CARD_HDMI) (adev-owner[SOUND_CARD_HDMI] ! (int*)out) (adev-owner[SOUND_CARD_HDMI] ! NULL)) || ((i SND_OUT_SOUND_CARD_SPDIF) (adev-owner[SOUND_CARD_SPDIF] ! (int*)out) (adev-owner[SOUND_CARD_SPDIF] ! NULL))){ continue; } ret pcm_write(out-pcm[i], (void *)buffer, bytes); if (ret ! 0) { ALOGD(%s:%d pcm_write error, errno %d, %s, __FUNCTION__, __LINE__, errno, pcm_get_error(out-pcm[i])); // break; //新加修改此处注释掉以支持多设备 } } } }hardware/rockchip/audio/tinyalsa_hal/Android.mk #注释掉BOX_HAL定义前的判断条件 #ifneq ($(filter box atv, $(strip $(TARGET_BOARD_PLATFORM_PRODUCT))), ) //注释掉 commonCFlags -DBOX_HAL #endif总结本文介绍了本人在rk3568安卓13的SDK中适配spdif功能时所做的具体修改点和遇到的问题。修改后的驱动代码已经过验证能实现我的需求也希望能为其他人提供参考少走弯路。