Linux audio bring up and debugging

From RidgeRun Developer Wiki


Background

If you are developing hardware with audio support, Linux will expose the hardware using Advanced Linux Sound Architecture, or alsa for short.

Board file

Since the audio support is built-in, you need to have the board file tell the kernel the audio hardware exists. For example, if you have a TI AIC3104 hardware code, then your $DEVDIR/kernel/linux-2.6.32.17-psp03.01.01.39/arch/arm/mach-davinci/board-*.c file will contain something similar to:

static struct i2c_board_info i2c_info[] = {
	{
		I2C_BOARD_INFO("tlv320aic3x", 0x18),
	},
...
};


static void dm368_tlv320aic3x_configure(void)
{
	struct clk *clkout1_clk;

	davinci_cfg_reg(DM365_CLKOUT1);

	clkout1_clk = clk_get(NULL, "clkout1");
	if (IS_ERR(clkout1_clk))
		return;
	clk_enable(clkout1_clk);

	/* (reg OCSEL) Setting OBSCLK source with Oscillator divider output enable */
	__raw_writel(0x0,IO_ADDRESS(0x01C40C00 + 0x104));

	/* (reg OSCDIV1) Setting the Oscillator divider enable with a divider ratio of 1 */
	__raw_writel(0x8000,IO_ADDRESS(0x01C40C00 + 0x124));

	/* (reg CKEN) Setting the OBSCLK clock enable */
	__raw_writel(0x02,IO_ADDRESS(0x01C40C00 + 0x148));

}


static __init void dm368_init(void)
{
...
	dm365_init_asp(&dm368_snd_data);
	dm368_tlv320aic3x_configure();
...
}

where dm365_init_asp() is defined in the processor file (dm365.c):

void __init dm365_init_asp(struct snd_platform_data *pdata)
{
	davinci_cfg_reg(DM365_MCBSP0_BDX);
	davinci_cfg_reg(DM365_MCBSP0_X);
	davinci_cfg_reg(DM365_MCBSP0_BFSX);
	davinci_cfg_reg(DM365_MCBSP0_BDR);
	davinci_cfg_reg(DM365_MCBSP0_R);
	davinci_cfg_reg(DM365_MCBSP0_BFSR);
	davinci_cfg_reg(DM365_EVT2_ASP_TX);
	davinci_cfg_reg(DM365_EVT3_ASP_RX);
	dm365_asp_device.dev.platform_data = pdata;
	platform_device_register(&dm365_asp_device);
}

Kernel configuration

To enable generic sound support, plus support for the AIC3x compatible AIC3104 hardware code, configure your kernel enabling the following:

CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_TIMER=y
CONFIG_SND_PCM=y
CONFIG_SND_DRIVERS=y
CONFIG_SND_SOC=y
CONFIG_SND_DAVINCI_SOC=y
CONFIG_SND_DAVINCI_SOC_I2S=y
CONFIG_SND_DAVINCI_SOC_EVM=y
CONFIG_SND_DM365_AIC3X_CODEC=y
CONFIG_SND_SOC_I2C_AND_SPI=y
CONFIG_SND_SOC_TLV320AIC3X=y

Kernel boot output

If the audio spport was properly enabled and registered, the kernel boot output will contain:

Advanced Linux Sound Architecture Driver Version 1.0.21.
No device for DAI tlv320aic3x
No device for DAI davinci-i2s
asoc: tlv320aic3x <-> davinci-i2s mapping ok
ALSA device list:
  #0: DaVinci DM365 EVM (tlv320aic3x)

Poking around kernel

Using the audio tools, you can list the registered audio devices

aplay --list-devices

with results similar to:

**** List of PLAYBACK Hardware Devices ****
card 0: EVM [DaVinci DM365 EVM], device 0: AIC3X tlv320aic3x-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Simple audio recording test

You can use arecord to record to a wav file. Use cntl-C to stop arecord

arecord --file-type wav /audio-capture-test.wav

Another example using GStreamer

gst-launch -e alsasrc num-buffers=300 ! 'audio/x-raw-int,rate=(int)44100,channels=(int)2' ! queue ! dmaienc_aac bitrate=128000 ! qtmux ! filesink location=/audio_aac.mp4

Simple audio playback test

You can use aplay to play the recorded wav file.

aplay --file-type wav /audio-capture-test.wav

Streaming audio

On the device, run:

AUDIO_IP_ADDR=10.111.0.4
AUDIO_UDP_PORT=5000

gst-launch -v alsasrc blocksize=40960 ! audioconvert ! audioresample ! mulawenc ! rtppcmupay ! udpsink host=$AUDIO_IP_ADDR port=$AUDIO_UDP_PORT
<pre>

and grab the caps setting for use when receiving the streaming audio.

On the host, run:

<pre>
AUDIO_UDP_PORT=5000
CAPS="application/x-rtp, media=(string)audio, clock-rate=(int)8000, encoding-name=(string)PCMU, payload=(int)0, ssrc=(uint)2514"

gst-launch udpsrc port=$AUDIO_UDP_PORT ! capsfilter caps="$CAPS" ! rtppcmudepay ! mulawdec ! pulsesink