Linux音频调试示例

Posted xxccry

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux音频调试示例相关的知识,希望对你有一定的参考价值。

Linux音频调试示例

硬件设计

cpucodecperipheral interface
nvidia-jetsonmax9867line-in×1, hp×1

  codec与cpu之间通过i2c读写寄存器,i2s传输音频信号(i2s总线简介)。
  cpu作为主设备,codec作为从设备,cpu提供主时钟(aud_mclk)。
  codec连接1路line-in,1路headphone。

设备树

  因为cpu是nvidia jetson系列,所以基于Nvidia官方释放的“L4T Sources”(Jetson下载中心)修改。

在i2c节点添加设备

/ 
	i2c@c250000 		// 硬件连通的i2c通道
		status = "okay";
		max9867: codec@18 
			compatible = "maxim,max9867";		// 与官方驱动匹配
			reg = <0x18>;						// i2c地址
		;
	;

使能i2s总线

// 在tegraxx_soc_audio.dtsi中查找
/ 
	aconnect@2a41000 
		ahub 
			i2s@2901300 		// 硬件连通的i2s通道
				status = "okay";
			;
		;
	;
;

添加dai_link

/ 
	sound 
		status = "okay";
		compatible = "nvidia,tegra-audio-t186ref-mobile";		// 修改,与rt565x解绑
		nvidia,model = "tegra-snd-t19x-mobile";		// 修改,与rt565x解绑

		nvidia,audio-routing =		// 需要与codec驱动匹配,从右到左,代表数据流向
                					// x是前缀,与dai-link的name-prefix匹配
			"x LINE_IN",    "x Linein",
			"x Headphone",  "x HPOUT"
                        
		nvidia,dai-link-1 		// dai-link,与codec和i2s匹配
								// codec-dai-name与codec驱动匹配
			link-name = "max9867";
			cpu-dai = <&tegra_i2s1>;
			codec-dai = <&max9867>;
			cpu-dai-name = "I2S1";
			codec-dai-name = "max9867-aif1";
			name-prefix = "x";
		;
		// 只用到一路,其余nvidia,dai-link设置“disabled”
	;
;
// max9867.c
static struct snd_soc_dai_driver max9867_dai[] = 
        
        .name = "max9867-aif1",		// 匹配nvidia,dai-link中的codec-dai-name
		... ...
        
;

修改pinmux

/ 
	pinmux@2430000 
		pinmux_default: common 
			// audio mclk pin
			aud_mclk_ps4 
				nvidia,pins = "aud_mclk_ps4";
				nvidia,function = "aud";
				nvidia,pull = <TEGRA_PIN_PULL_NONE>;
				nvidia,tristate = <TEGRA_PIN_DISABLE>;
				nvidia,enable-input = <TEGRA_PIN_DISABLE>;
				nvidia,lpdr = <TEGRA_PIN_DISABLE>;
			;
			// i2s pins
			dap5_sclk_pt5 
				nvidia,pins = "dap5_sclk_pt5";
				nvidia,function = "rsvd2";
				nvidia,pull = <TEGRA_PIN_PULL_NONE>;
				nvidia,tristate = <TEGRA_PIN_DISABLE>;
				nvidia,enable-input = <TEGRA_PIN_DISABLE>;
				nvidia,lpdr = <TEGRA_PIN_DISABLE>;
			;
			dap5_dout_pt6 
				nvidia,pins = "dap5_dout_pt6";
				nvidia,function = "rsvd2";
				nvidia,pull = <TEGRA_PIN_PULL_NONE>;
				nvidia,tristate = <TEGRA_PIN_DISABLE>;
				nvidia,enable-input = <TEGRA_PIN_DISABLE>;
				nvidia,lpdr = <TEGRA_PIN_DISABLE>;
			;
			dap5_din_pt7 
				nvidia,pins = "dap5_din_pt7";
				nvidia,function = "rsvd3";
				nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
				nvidia,tristate = <TEGRA_PIN_ENABLE>;
				nvidia,enable-input = <TEGRA_PIN_ENABLE>;
				nvidia,lpdr = <TEGRA_PIN_DISABLE>;
			;
			dap5_fs_pu0 
				nvidia,pins = "dap5_fs_pu0";
				nvidia,function = "rsvd3";
				nvidia,pull = <TEGRA_PIN_PULL_NONE>;
				nvidia,tristate = <TEGRA_PIN_DISABLE>;
				nvidia,enable-input = <TEGRA_PIN_DISABLE>;
				nvidia,lpdr = <TEGRA_PIN_DISABLE>;
			;
			// i2c pins 未复用
		;
	;
;

驱动

code驱动

  Linux内核源码支持Maxim的多款codec(包括max9867),代码路径kernel-4.9/sound/soc/codecs/
  不需要修改。

platform驱动

  Nvidia提供,音频代码目录结构如下:platform代码路径nvidia/sound/tegra-alt

nvidia/sound/
	├── pci
	├── soc
		├── tegra-alt
			├── include
			├── machine_drivers
		├── tegra210_admaif_alt.c
		├── tegra210_i2s_alt.c
		├── tegra210_mixer_alt.c
		├── tegra210_xbar_alt.c
		├── ... ...
		├── utils
	├── tegra-virt-alt

  不需要修改。

machine驱动

  代码路径nvidia/sound/tegra-alt/machine_drivers

nvidia/sound/
	├── soc
		├── tegra-alt
			├── machine_drivers
				├── tegra_machine_driver_mobile.c
				├── tegra_t186ref_alt.c
				├── tegra_t210ref_alt.c
				├── ... ...

  Nvidia默认适配codec芯片rt5659,需要修改为实际使用的max9867。
  修改nvidia/sound/soc/tegra-alt/machine_drivers/tegra_machine_driver_mobile.c

  1. 添加codec头文件
#include "../codecs/max9867.h"
  1. 添加dapm_widgets
static const struct snd_soc_dapm_widget tegra_machine_dapm_widgets[] = 
	// 与设备树中nvidia,audio-routing匹配
	SND_SOC_DAPM_HP("x Headphone", NULL),
	SND_SOC_DAPM_LINE("x Linein", NULL),
;
  1. 添加codec的dai_link
static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
                                  unsigned int rate, unsigned int channels,
                                  u64 formats)

	... ...
	rtd = snd_soc_get_pcm_runtime(card, "max9867");		// 对应设备树中dai-link的link-name
	if (rtd) 
		dai_params =
		(struct snd_soc_pcm_stream *)rtd->dai_link->params;

		dai_params->rate_min = srate;
		dai_params->formats = (machine->fmt_via_kcontrol == 2) ?
			(1ULL << SNDRV_PCM_FORMAT_S32_LE) : formats;

		err = snd_soc_dai_set_sysclk(rtd->codec_dai, 0,
									 aud_mclk, SND_SOC_CLOCK_IN);
		if (err < 0) 
			dev_err(card->dev, "codec_dai clock not set\\n");
			return err;
		
	
	... ...

  1. 添加codec初始化(非必要)
static int tegra_machine_max9867_init(struct snd_soc_pcm_runtime *rtd)

        struct snd_soc_card *card = rtd->card;
        snd_soc_dapm_sync(&card->dapm);

        return 0;


static int codec_init(struct tegra_machine *machine)

	... ...
	for (i = 0; i < num_links; i++) 
		if (!dai_links[i].name)
			continue;

		if (strstr(dai_links[i].name, "max9867"))
			dai_links[i].init = tegra_machine_max9867_init;
		... ...
	

	return 0;

激活音频流

播放

amixer -c <sound_card> cset name='x Speaker Mode' 'Stereo Single'	# codec内开启双声道
amixer -c <sound_card> cset name="I2S1 Mux" ADMAIF1					# i2s1(设备树指定)连接到cpu内aif1_rx

aplay -Dhw:1,0 <name>.wav	# nvidia的card 0默认是hdmi的声卡,音频流参数根据音频文件自适应设置

录音

amixer -c <sound_card> cset name='x Input Mux' Line		# codec输入mux连接line接
amixer -c <sound_card> cset name="ADMAIF1 Mux" I2S1		# cpu内aif1_tx(nvidia系统默认)连接到i2s1

arecord -Dhw:1,0 -r 44100 -c 2 -f S16_LE <name>.wav		# nvidia的card 0默认是hdmi的声卡

问题定位

声卡未识别

  执行aplay -lorarecord -l,可以查询声卡列表,Jetson平台的声卡如下:

  如果未显示声卡:

  1. 检查cpu与codec之间的i2c通信
  2. 检查设备树与内核的dai-link是否匹配

  以上Linux和Nvidia源码均可打印相关log。

录音/播放失败

  如果aplayorarecord返回失败:

检查codec寄存器值

  i2cdump -f -y <i2c_num> <i2c_addr>可以返回对应地址的i2c设备的寄存器值:

检查音频流的trace

  1. 先打开trace开关:
echo 0 | sudo tee /sys/kernel/debug/tracing/trace
echo 0 | sudo tee /sys/kernel/debug/tracing/events/enable
echo 1 | sudo tee /sys/kernel/debug/tracing/tracing_on
echo 1 | sudo tee /sys/kernel/debug/tracing/events/asoc/snd_soc_dapm_path/enable
echo 1 | sudo tee /sys/kernel/debug/tracing/events/asoc/snd_soc_dapm_start/enable
echo 1 | sudo tee /sys/kernel/debug/tracing/events/asoc/snd_soc_dapm_walk_done/enable
echo 1 | sudo tee /sys/kernel/debug/tracing/events/asoc/snd_soc_dapm_widget_power/enable
  1. 然后激活音频流(aplayorarecord),查看/sys/kernel/debug/tracing/trace
root@nvidia-desktop:/sys/kernel/debug/tracing# cat trace
# tracer: nop
#
# entries-in-buffer/entries-written: 197/197   #P:4
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
 alsa-sink-ADMAI-7714  [000] ....  1252.484903: snd_soc_dapm_start: card=tegra-snd-t19x-mobile
 alsa-sink-ADMAI-7714  [000] ....  1252.484978: snd_soc_dapm_widget_power: widget=Playback 1 val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.484980: snd_soc_dapm_widget_power: widget=ADMAIF1 Receive val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.484983: snd_soc_dapm_path: *ADMAIF1 RX <- (direct) <- ADMAIF1 Receive
 alsa-sink-ADMAI-7714  [000] ....  1252.485010: snd_soc_dapm_widget_power: widget=ADMAIF1 RX val=1
														 ....
 alsa-sink-ADMAI-7714  [000] ....  1252.485252: snd_soc_dapm_path: *I2S1 Mux <- ADMAIF1 <- ADMAIF1 RX
 alsa-sink-ADMAI-7714  [000] ....  1252.485254: snd_soc_dapm_widget_power: widget=I2S1 Mux val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485256: snd_soc_dapm_path: *I2S1 TX <- (direct) <- I2S1 Mux
 alsa-sink-ADMAI-7714  [000] ....  1252.485258: snd_soc_dapm_widget_power: widget=I2S1 TX val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485259: snd_soc_dapm_path: *I2S1 Transmit <- (direct) <- I2S1 TX
 alsa-sink-ADMAI-7714  [000] ....  1252.485261: snd_soc_dapm_widget_power: widget=I2S1 Transmit val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485262: snd_soc_dapm_path: *I2S1 Transmit-I2S1 CIF Receive <- (direct) <- I2S1 Transmit
 alsa-sink-ADMAI-7714  [000] ....  1252.485264: snd_soc_dapm_widget_power: widget=I2S1 Transmit-I2S1 CIF Receive val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485266: snd_soc_dapm_path: *I2S1 CIF Receive <- (direct) <- I2S1 Transmit-I2S1 CIF Receive
 alsa-sink-ADMAI-7714  [000] ....  1252.485267: snd_soc_dapm_widget_power: widget=I2S1 CIF Receive val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485269: snd_soc_dapm_path: *I2S1 CIF RX <- (direct) <- I2S1 CIF Receive
 alsa-sink-ADMAI-7714  [000] ....  1252.485271: snd_soc_dapm_widget_power: widget=I2S1 CIF RX val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485272: snd_soc_dapm_path: *I2S1 DAP TX <- (direct) <- I2S1 CIF RX
 alsa-sink-ADMAI-7714  [000] ....  1252.485274: snd_soc_dapm_widget_power: widget=I2S1 DAP TX val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485275: snd_soc_dapm_path: *I2S1 DAP Transmit <- (direct) <- I2S1 DAP TX
 alsa-sink-ADMAI-7714  [000] ....  1252.485277: snd_soc_dapm_widget_power: widget=I2S1 DAP Transmit val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485279: snd_soc_dapm_path: *I2S1 DAP Transmit-x HiFi Playback <- (direct) <- I2S1 DAP Transmit
 alsa-sink-ADMAI-7714  [000] ....  1252.485280: snd_soc_dapm_widget_power: widget=I2S1 DAP Transmit-x HiFi Playback val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485282: snd_soc_dapm_path: *x HiFi Playback <- (direct) <- I2S1 DAP Transmit-x HiFi Playback
 alsa-sink-ADMAI-7714  [000] ....  1252.485284: snd_soc_dapm_widget_power: widget=x HiFi Playback val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485285: snd_soc_dapm_path: *x DAI_OUT <- (direct) <- x HiFi Playback
 alsa-sink-ADMAI-7714  [000] ....  1252.485287: snd_soc_dapm_widget_power: widget=x DAI_OUT val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485289: snd_soc_dapm_path: *x Right DAC <- (direct) <- x DAI_OUT
 alsa-sink-ADMAI-7714  [000] ....  1252.485290: snd_soc_dapm_widget_power: widget=x Right DAC val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485292: snd_soc_dapm_path: *x Left DAC <- (direct) <- x DAI_OUT
 alsa-sink-ADMAI-7714  [000] ....  1252.485294: snd_soc_dapm_widget_power: widget=x Left DAC val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485296: snd_soc_dapm_widget_power: widget=x SHDN val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485297: snd_soc_dapm_path: *x Output Mixer <- (direct) <- x Right DAC
 alsa-sink-ADMAI-7714  [000] ....  1252.485299: snd_soc_dapm_path: *x Output Mixer <- (direct) <- x Left DAC
 alsa-sink-ADMAI-7714  [000] ....  1252.485300: snd_soc_dapm_widget_power: widget=x Output Mixer val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485302: snd_soc_dapm_path: *x HPOUT <- (direct) <- x Output Mixer
 alsa-sink-ADMAI-7714  [000] ....  1252.485303: snd_soc_dapm_widget_power: widget=x HPOUT val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485305: snd_soc_dapm_path: *x Headphone <- (direct) <- x HPOUT
 alsa-sink-ADMAI-7714  [000] ....  1252.485306: snd_soc_dapm_widget_power: widget=x Headphone val=1
 alsa-sink-ADMAI-7714  [000] ....  1252.485356: snd_soc_dapm_walk_done: tegra-snd-t19x-mobile: checks 23 power, 20 path, 179 neighbour

  alsa在录音/播放前会先检查snd_soc_dapm_path(带"*")能否连成一路完整的routing,如果失败,录音/播放的进程会自动停止。

  1. 如果录音/播放的trace不完整,检查codec代码中的snd_soc_dapm_route从右到左,能否连接成一路完整的routing:
static const struct snd_soc_dapm_route max9867_audio_map[] = 
        "Left DAC", NULL, "SHDN",
        "Right DAC", NULL, "SHDN",
        "Left DAC", NULL, "DAI_OUT",
        "Right DAC", NULL, "DAI_OUT",
        "Output Mixer", NULL, "Left DAC",
        "Output Mixer", NULL, "Right DAC",
        "HPOUT", NULL, "Output Mixer",

        "DAI_IN", NULL, "SHDN",
        "DAI_IN", NULL, "Left ADC",
        "DAI_IN", NULL, "Right ADC",
        "Left ADC", NULL, "Input Mux",
        "Right ADC", NULL, "Input Mux",
        "Input Mux", "Mic", "Line Input",
        "Input Mux", "Line", "Line Input",
        "Input Mux", "Mic_Line", "Line Input",
        "Line Input", NULL, "LINE_IN",
;

RK3588平台开发系列讲解(AUDIO篇)Linux音频调试--alsa-utils 工具

平台 内核版本 安卓版本
RK3588 Linux 5.10 Android 12

文章目录

沉淀、分享、成长,让自己和他人都能有所收获!

以上是关于Linux音频调试示例的主要内容,如果未能解决你的问题,请参考以下文章

Linux ALSA 音频库 配置和使用

Linux音频子系统 - ALSA ASoC

RK3588平台开发系列讲解(AUDIO篇)Android音频调试--tiny-alsa 工具

RK3588平台开发系列讲解(AUDIO篇)Android音频调试--tiny-alsa 工具

Linux应用开发第八章ALSA应用开发

linux下ALSA音频驱动软件开发