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_android7.1音频通路相关说明_第1张图片

RK3399 HDMI IN内核实现方案

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

rk3399_android7.1音频通路相关说明_第2张图片

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     }

你可能感兴趣的:(Android驱动开发,audio,rk3288,hdmiin,hdmi)