rk3399_android7.1音频通路相关说明

关于音频的输出通路,可以有多重选择:HDMI-out,喇叭,耳机,LINE-in,USB声卡,蓝牙等,切换不同的通路音频就从不同的通路输出或者录入,这里主要以HDMIin为例来简单说一下相关AUDIO通路方面的内容。

RK3399 HDMI IN声卡通路选择

当前RK3399有三路i2s通道,HDMIOUT音频通路芯片内置为i2s2。当前RK3399 开发板上的音频芯片还有蓝牙、rt5651、tc358749,音频通路配置如下:

RK3399 I2S2 没有使用来作为蓝牙通话,则可以 TC358749 I2S 接口接到 RK3399的单独一个 I2S 上(I2S/PCM 不能跟其他 I2S 设备共用,否则造成 I2S 信号的干扰,声音有杂音),另外的 I2S 接口接 codec 通过功放输出 ANDROID 系统声音。

RK3399 HDMI IN 声卡通路配置

通路1:HDMIIn –> RK3399 I2S1- > RK3399 HDMI TX -> HDMI 电视机
通路2:HDMIIn –> RK3399 I2S1- > RK3399 I2S0 -> CODEC ->hp/Speaker

TC358749 I2S 信号送给 RK3399 录音,然后 RK3399 在通过播放给 HDMI TX 输出,需要注册两个声卡,TC358749 声卡,以及HDMI audio out 声卡,系统默认已经有HDMI audio out 注册,需要dts中开启即可,TC358749 需要再重新写一个声卡驱动。
在这里插入图片描述

RK3399 HDMI IN内核实现方案

该部分的总体思路是,注册东芝 tc358749x 芯片(约定以下简称 749 侧)声卡,当声卡成功注册后,打开 hdmiin apk 时,能用 tinyalsa 工具正常的进行录(tinycap)播(tinyplay)时,此部分即可调通。
rk3399 具有三组I2S 控制器,所以在硬件上连接方式有所不同。根据应用场景的不同,当 749 侧的 I2S 连接到cpu 或 codec 的 I2S 时,需区分 I2S 的主从模式,一般来说,由于 749 侧只能作为 master 模式,所以当和 749 侧连接的另一侧,则需要配置为 slave 模式

在这里插入图片描述

Android 7.1/ kernel 4.4 的 的 I2S M/S

4.4 内核使用了 simple-card 通用的 machine 驱动进行声卡的注册,为了配置主控的 I2S为 slave 模式。

    配置文件:arch/arm64/boot/dts/rockchip/rk3399-box-rev2-ne4000.dts
        tc358749x_sound:tc358749x-sound {
     		compatible = "simple-audio-card";
    		simple-audio-card,format = "i2s";
    		simple-audio-card,name = "rockchip,tc358749x-codec";
    		simple-audio-card,bitclock-master = <&sound0_master>;
    		simple-audio-card,frame-master = <&sound0_master>;
    
     		simple-audio-card,cpu {
    			sound-dai = <&spdif>;
    			sound-dai = <&i2s1>;
     		};
    		sound0_master: simple-audio-card,codec {
    			sound-dai = <&tc358749x>;
     		};
     	};
     对于rk3399具有多组 I2S 的平台,注册声卡的方式是把 749 和 codec注册成一张声卡,压缩包补丁默认是用这种方式注册的。
        rt5651-sound {
                status = "disabled";
            };
    	
    	hdmiin-sound {
    		compatible = "rockchip,rockchip-rt5651-tc358749x-sound";
    		rockchip,cpu = <&i2s0 &i2s1>;
    		rockchip,codec = <&rt5651 &tc358749x>;
     		status = "okay";
     	};
    原dts中未对tc358749对应的i2s做配置,添加i2s1配置
        +&i2s1 {
    		status = "okay";
    		rockchip,i2s-broken-burst-len;
            rockchip,playback-channels = <2>;
            rockchip,capture-channels = <2>;
            #sound-dai-cells = <0>;
        };
    当前tc358749芯片挂在i2c1下面,在i2c1下面配置tc358749
        tc358749x: tc358749x@0f {
		    #sound-dai-cells = <0>;
	        compatible = "toshiba,tc358749x";
        	reg = <0x0f>;
	        power-gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>; //GPIO4_A7
        	stanby-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; //GPIO3_C0 change to GPIO1_B5
	        reset-gpios = <&gpio3 30 GPIO_ACTIVE_HIGH>; //GPIO3_D6
        	int-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; //GPIO4_A5
   	        pinctrl-names = "default";
        	pinctrl-0 = <&hdmiin_gpios>;
	        status = "okay";
    	};
    添加当前音频配置方案,需修改音频驱动代码,根据RK提供修改方案进行修改

#测试驱动是否正常
1、tool & cmds :
mmm external/tinyalsa/ [ tinymix tinyplay tinycap ] //从sdk源码中编译出tinyalsa测试工具

    当前系统提供tinyalsa音频测试工具可直接用于音频测试
        tinymix         音频通路配置
        tinypcminfo     用于查看pcm通道的相关信息
        tinyplay        播放音频
        tinycap         录音(默认情况下该工具不安装,需在external/tinyalsa目录下编译才会生成)
    录音:tinycap 001.wav -D 1 -d 1
        001.wav 音频文件(tinycap只能录到wav格式的音频文件)
        -D  声卡 number
        -d  pcm number
        结束录音用 ctrl+c 组合键结束
播放: tinyplay 001.wav -D 0 -d 0

调试注意事项

在测试HDMI IN录音时出现无法录音的情况,检查后发现在i2s1的配置中出现GPIO口复用,需将复用的GPIO口注掉:
      i2s1 {
                i2s1_2ch_bus: i2s1-2ch-bus {
                        rockchip,pins =
                                <4 3 RK_FUNC_1 &pcfg_pull_none>,
                                <4 4 RK_FUNC_1 &pcfg_pull_none>,
                                //<4 5 RK_FUNC_1 &pcfg_pull_none>,
                                <4 6 RK_FUNC_1 &pcfg_pull_none>;
                                //<4 7 RK_FUNC_1 &pcfg_pull_none>;
                };
        };

问题调试排查的一些方法

1、通过cat /proc/asound/cards确认声卡有没有注册上

	rk3399_mid:/ # cat /proc/asound/cards
             0 [rkhdmidpsound  ]: rk-hdmi-dp-soun - rk-hdmi-dp-sound
                                  rk-hdmi-dp-sound
             1 [realtekrt5651co]: realtekrt5651co - realtekrt5651codec_hdmiin
                                  realtekrt5651codec_hdmiin

2、查看当前声卡设备:

        rk3399_mid:/ # ls /dev/snd/                                              
                controlC0 controlC1 pcmC0D0p pcmC1D0c pcmC1D0p pcmC1D1c timer 
            p   播放设备
            c   录音设备
         HDMI out:pcmC0D0p
         codec : pcmC1D0c pcmC1D0p
         HDMI IN : pcmC1D1c

3、tc358749 连接到cpu的某组i2s,其对应的pcm设备在某声卡某pcm下,比如”pcmC1D0c”,说明749对应的pcm设备在声卡1,pcm号为0,则先打开 hdmiin apk,可以这样录音:

tinycap /sdcard/test.wav -D 1 -d 0 -c 2 -r 44100 -b 16

-D:声卡 number
-d:pcm number

结束录音用 ctrl+c 组合键结束。 注:不能用 windows 的 cmd 命令窗口进行 ctrl+c 结束 。录音结束后,拷贝 test.wav 出来看看是否正常录到音。如果没有的话,确认声卡注册成功,用示波器量 tc358749 端的 i2s 信号,SDO 脚是否有信号,没有的找东芝的 FAE 咨询。

4、常用查看声卡状态和信息info 的命令操作:

	cat /proc/asound/card*/pcm*/sub*/status |grep 'stat|close' -EC1
	cat /proc/asound/card*/pcm*/sub*/info|grep id -C1|grep name -v
	cat /proc/asound/card*/pcm*/sub*/info
rk3288:/ $ cat /proc/asound/card*/pcm*/sub*/info                               
card: 0
device: 0 //输入设备类型
subdevice: 0
stream: CAPTURE //录音设备
id: RT5651 PCM rt5651-aif1-0
name: 
subname: subdevice #0
class: 0
subclass: 0
subdevices_count: 1
subdevices_avail: 1
card: 0
device: 0 //输出设备类型
subdevice: 0
stream: PLAYBACK //放音设备
id: RT5651 PCM rt5651-aif1-0
name: 
subname: subdevice #0
class: 0
subclass: 0
subdevices_count: 1
subdevices_avail: 1

RK3399 HDMIIN HAL层实现方案

    HAL 层的实现是基于音频驱动已经调好的情况下来实现的,其基本思路是用 alsa-soc lib的API 来做的,主要API如下:
        1. pcm_open
            打开指定声卡下的 pcm 设备
        2. pcm_frames_to_bytes
            返回读回帧数的总大小用字节
        3. pcm_read
            读音频数据
        4. pcm_wirte
            写音频数据
        5. pcm_close
            关闭 pcm 设备

一般的编程步骤都是按 linux 的编程习惯统一调用界面来的,也即:pcm_open - > pcm_write/
pcm_read -> pcm_close
综上,HAL 层要做的便是按上面顺序进行的,pcm_read 从某声卡 pcm 设备读取音频数据,也即是对 749 声卡进行录音,pcm_write 把读到的音频数据写到某声卡中去,也即是把得到 749的音频数据通过这张声卡播放,具体的业务逻辑依据实际需求而定。

HAL层对HDMIIN的音频通路做了单独的处理,同时对上层apk进行了修改,根据RK提供的补丁处理上层音频通路

分析HAL层log

logcat -s AudioHardwareTiny audio_hw_hdmiin alsa_route

RK3399 HDMIIN音频采样率

当前HDMIIN可读取的音频采样率为44.1khz,还无法适配其他采样率,当其他音频采样率接入时,录取的声音会出现断断续续的状态,根据RK提供的补丁进行修改

hal部分 相关函数说明

调试阶段,单独编译mmm hardware/rockchip/audio/tinyalsa_hal/ 得到
audio.primary.rk30board.so,push进机器验证即可。

out/target/product/rk3288/vendor/lib/hw/audio.primary.rk30board.so

hardware/rockchip/audio/tinyalsa_hal/audio_hw.c文件中start_output_stream函数为判断输出(声音输出)设备类型,选择音频输出通路:
根据out-> device 类型判断
if (out->device & (AUDIO_DEVICE_OUT_AUX_DIGITAL)

然后选择使用音频路由输出:
card = adev->out_card[SND_OUT_SOUND_CARD_HDMI];

然后对应打开哪张声卡:
out->pcm[SND_OUT_SOUND_CARD_HDMI]=pcm_open(card,PCM_DEVICE_HDMIOUT, PCM_OUT | PCM_MONOTONIC, &out->config);

hardware/rockchip/audio/tinyalsa_hal/audio_hw.c文件中start_input_stream函数为判断输入(声音录入)设备类型,选择音频输入通路。

audio_hw.c文件中read_in_sound_card 接口 //从节点获取声卡信息:
file = fopen(SND_CARDS_NODE,“r”);
while(get_line(file,buf,sizeof(buf)) >= 0){
if(is_mic_in_sound_card(buf)){
device->in_card[SND_IN_SOUND_CARD_MIC] = get_card_number(buf);
}

audio_hw.c文件的 adev_set_parameters 函数会去获取一些属性参数,然后设置走哪个route,route的宏定义在alsa_audio.h文件。

然后在adev_set_parameters中调用str_parms_get_str获取对应字符串的属性(下面的例子是获取字符串HDMIin_enable的属性,该属性在apk中调用原生的接口

AudioManager.setParameters("HDMIin_enable=true"))3060     /* HDMIin enable/disable */
3061     val = str_parms_get_str(parms, "HDMIin_enable", value, sizeof(value));
3062     if (0 <= val) {
3063         if (strcmp(value, "true") == 0) {
3064              ALOGD("\n##[czd]%s:-------- HDMIin_enable(%s) ---------##\n\n", __func__, value);
3065             adev->hdmiin_state = true;
3066             //route_pcm_open(HDMI_IN_NORMAL_ROUTE);
3067             route_pcm_open(HDMI_IN_CAPTURE_ROUTE);
3068             ALOGD("Enable HDMIin");
3069         } else if (strcmp(value, "false") == 0) {
3070              ALOGD("\n##[czd]%s:-------- HDMIin_disable(%s) ---------##\n\n", __func__, value);
3071             route_pcm_open(HDMI_IN_OFF_ROUTE);
3072             adev->hdmiin_state = false;
3073             ALOGD("Disable HDMIin");
3074         } else {
3075              ALOGD("\n##[czd]%s:-------- HDMIin_enable(%s) ---------##\n\n", __func__, value);
3076             ALOGE("Unknown HDMIin state %s!!!", value);
3077             ret = -EINVAL;
3078         }
3079     }
  • 2
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零意@

您的打赏将是我继续创作的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值