Linux驱动——ALSA

Linux驱动——ALSA

小狼@http://blog.csdn.net/xiaolangyangyang


 Control宏定义:

SOC_SINGLE_VALUE
SOC_SINGLE_VALUE_EXT
SOC_SINGLE
SOC_SINGLE_TLV
SOC_DOUBLE
SOC_DOUBLE_R
SOC_DOUBLE_TLV
SOC_DOUBLE_R_TLV
SOC_DOUBLE_S8_TLV
SOC_ENUM_DOUBLE
SOC_ENUM_SINGLE
SOC_ENUM_SINGLE_EXT
SOC_VALUE_ENUM_DOUBLE
SOC_VALUE_ENUM_SINGLE
SOC_ENUM
SOC_VALUE_ENUM
SOC_SINGLE_EXT
SOC_DOUBLE_EXT
SOC_SINGLE_EXT_TLV
SOC_DOUBLE_EXT_TLV
SOC_DOUBLE_R_EXT_TLV
SOC_SINGLE_BOOL_EXT
SOC_ENUM_EXT
SOC_DOUBLE_R_SX_TLV
SOC_ENUM_DOUBLE_DECL
SOC_ENUM_SINGLE_DECL
SOC_ENUM_SINGLE_EXT_DECL
SOC_VALUE_ENUM_DOUBLE_DECL
SOC_VALUE_ENUM_SINGLE_DECL

DAPM宏定义:

SND_SOC_DAPM_VMID
SND_SOC_DAPM_INPUT
SND_SOC_DAPM_OUTPUT
SND_SOC_DAPM_MIC
SND_SOC_DAPM_HP
SND_SOC_DAPM_SPK
SND_SOC_DAPM_LINE
SND_SOC_DAPM_PGA
SND_SOC_DAPM_OUT_DRV
SND_SOC_DAPM_MIXER
SND_SOC_DAPM_MIXER_NAMED_CTL
SND_SOC_DAPM_MICBIAS
SND_SOC_DAPM_SWITCH
SND_SOC_DAPM_MUX
SND_SOC_DAPM_VIRT_MUX
SND_SOC_DAPM_VALUE_MUX
SOC_PGA_ARRAY
SOC_MIXER_ARRAY
SOC_MIXER_NAMED_CTL_ARRAY
SND_SOC_DAPM_PGA_E
SND_SOC_DAPM_OUT_DRV_E
SND_SOC_DAPM_MIXER_E
SND_SOC_DAPM_MIXER_NAMED_CTL_E
SND_SOC_DAPM_MICBIAS_E
SND_SOC_DAPM_SWITCH_E
SND_SOC_DAPM_MUX_E
SND_SOC_DAPM_VIRT_MUX_E
SND_SOC_DAPM_PGA_S
SND_SOC_DAPM_SUPPLY_S
SOC_PGA_E_ARRAY
SOC_MIXER_E_ARRAY
SOC_MIXER_NAMED_CTL_E_ARRAY
SND_SOC_DAPM_PRE
SND_SOC_DAPM_POST
SND_SOC_DAPM_AIF_IN
SND_SOC_DAPM_AIF_IN_E
SND_SOC_DAPM_AIF_OUT
SND_SOC_DAPM_AIF_OUT_E
SND_SOC_DAPM_DAC
SND_SOC_DAPM_DAC_E
SND_SOC_DAPM_ADC
SND_SOC_DAPM_ADC_E
SND_SOC_DAPM_REG
SND_SOC_DAPM_SUPPLY
SOC_DAPM_SINGLE
SOC_DAPM_SINGLE_TLV
SOC_DAPM_ENUM
SOC_DAPM_ENUM_VIRT
SOC_DAPM_VALUE_ENUM
SOC_DAPM_PIN_SWITCH

static const struct snd_kcontrol_new wmxx_mix1_controls[] = {
	SOC_DAPM_SINGLE("SW1", WMXX_REG_SW, 1, 1, 0),
	SOC_DAPM_SINGLE("SW2", WMXX_REG_SW, 2, 0, 0),
	SOC_DAPM_SINGLE("SW3", WMXX_REG_SW, 3, 0, 0),
	SOC_DAPM_SINGLE("SW4", WMXX_REG_SW, 4, 0, 0)
};
	
static const struct snd_kcontrol_new wmxx_mix2_controls[] = {
	SOC_DAPM_SINGLE("SW5", WMXX_REG_SW, 5, 1, 0),
	SOC_DAPM_SINGLE("SW6", WMXX_REG_SW, 6, 0, 0),
	SOC_DAPM_SINGLE("SW7", WMXX_REG_SW, 7, 0, 0),
	SOC_DAPM_SINGLE("SW8", WMXX_REG_SW, 8, 0, 0)
};

static const struct snd_soc_dapm_widget wm8900_dapm_widgets[] = {
	SND_SOC_DAPM_MIXER("MIX1", WMXX_REG_MIX, 1, 0, wmxx_mix1_controls, ARRAY_SIZE(wmxx_mix1_controls)),
	SND_SOC_DAPM_MIXER("MIX2", WMXX_REG_MIX, 2, 0, wmxx_mix2_controls, ARRAY_SIZE(wmxx_mix2_controls))
};

static const struct snd_soc_dapm_route audio_map[] = {
	{"MIX1", "SW2", "ADC"},
	{"MIX2", "SW6", "MIX1"},
};

 播放器代码

#include <alsa/asoundlib.h>
#include <stdio.h>
#include <termios.h> 
#include <unistd.h>
#include <stdlib.h>

#define int8_t		char
#define int16_t		short
#define int32_t		int
#define int64_t		long
#define uint8_t		unsigned char
#define uint16_t	unsigned short
#define uint32_t	unsigned int
#define uint64_t	unsigned long

/* para of wav file */
typedef struct {
	uint32_t dwSize;
	uint16_t wFormatTag;
	uint16_t wChannels;
	uint32_t dwSamplesPerSec;
	uint32_t dwAvgBytesPerSec;
	uint16_t wBlockAlign;
	uint16_t wBitsPerSample;
} WAVEFORMAT;

/* format of wav file header */
typedef struct {
	uint8_t RiffID [4];
	uint32_t RiffSize;
	uint8_t WaveID[4];
	uint8_t FmtID[4];
	uint32_t FmtSize;
	uint16_t wFormatTag;
	uint16_t nChannels;
	uint32_t nSamplesPerSec;
	uint32_t nAvgBytesPerSec;
	uint16_t nBlockAlign;
	uint16_t wBitsPerSample;
	uint8_t DataID[4];
	uint32_t nDataBytes;
} WAVE_HEADER;

/* set hwparams */
static int32_t set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access, uint32_t ch, snd_pcm_format_t format, uint32_t rate, snd_pcm_sframes_t *period_size)
{
	snd_pcm_uframes_t size;
	uint32_t rrate;
	int32_t err, dir;
	uint32_t buffer_time = 500000;	/* ring buffer length in us */
	uint32_t period_time = 100000;	/* period time in us */
	int32_t resample = 1;	/* enable alsa-lib resampling */

	/* choose all parameters */
	err = snd_pcm_hw_params_any(handle, params);
	if (err < 0)
	{
		printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
		return err;
	}

	/* set hardware resampling */
	err = snd_pcm_hw_params_set_rate_resample(handle, params, resample);
	if (err < 0)
	{
		printf("Resampling setup failed for playback: %s\n", snd_strerror(err));
		return err;
	}

	/* set the interleaved read/write format */
	err = snd_pcm_hw_params_set_access(handle, params, access);
	if (err < 0)
	{
		printf("Access type not available for playback: %s\n", snd_strerror(err));
		return err;
	}

	/* set the sample format */
	err = snd_pcm_hw_params_set_format(handle, params, format);
	if (err < 0)
	{
		printf("Sample format not available for playback: %s\n", snd_strerror(err));
		return err;
	}

	/* set the count of channels */
	err = snd_pcm_hw_params_set_channels(handle, params, ch);
	if (err < 0)
	{
		printf("Channels count (%u) not available for playbacks: %s\n", ch, snd_strerror(err));
		return err;
	}

	/* set the stream rate */
	rrate = rate;
	err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
	if (err < 0)
	{
		printf("Rate %uHz not available for playback: %s\n", rate, snd_strerror(err));
		return err;
	}
	if (rrate != rate)
	{
		printf("Rate doesn't match (requested %uHz, get %iHz)\n", rate, err);
		return -EINVAL;
	}

	/* set the buffer time */
	err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);
	if (err < 0)
	{
		printf("Unable to set buffer time %u for playback: %s\n", buffer_time, snd_strerror(err));
		return err;
	}
	err = snd_pcm_hw_params_get_buffer_size(params, &size);
	if (err < 0)
	{
		printf("Unable to get buffer size for playback: %s\n", snd_strerror(err));
		return err;
	}
	printf("buffer_size = %ld\n", size);

	/* set the period time */ 
	err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);
	if (err < 0)
	{
		printf("Unable to set period time %u for playback: %s\n", period_time, snd_strerror(err));
		return err;
	}
	err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
	if (err < 0)
	{
		printf("Unable to get period size for playback: %s\n", snd_strerror(err));
		return err;
	}
	*period_size = size;
	printf("period_size = %ld\n", size);

	/* write the parameters to device */
	err = snd_pcm_hw_params(handle, params);
	if (err < 0)
	{
		printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
		return err;
	}

	return 0;
}

/* read wav file header*/
FILE * open_and_print_file_params(int8_t *file_name, WAVE_HEADER *g_wave_header)
{
	FILE * fp = fopen(file_name, "r");
	if (fp == NULL)
	{
		printf("can't open wav file\n");
		return NULL;
	}

	memset(g_wave_header, 0, sizeof(WAVE_HEADER));
	fread(g_wave_header, 1, sizeof(WAVE_HEADER), fp);

	printf(">> RiffID : %c%c%c%c\n", g_wave_header->RiffID[0], g_wave_header->RiffID[1], g_wave_header->RiffID[2], g_wave_header->RiffID[3]);
	printf(">> RiffSize : %d\n", g_wave_header->RiffSize);
	printf(">> WaveID : %c%c%c%c\n", g_wave_header->WaveID[0], g_wave_header->WaveID[1], g_wave_header->WaveID[2], g_wave_header->WaveID[3]);
	printf(">> FmtID : %c%c%c%c\n", g_wave_header->FmtID[0], g_wave_header->FmtID[1], g_wave_header->FmtID[2], g_wave_header->FmtID[3]);
	printf(">> FmtSize : %d\n", g_wave_header->FmtSize);
	printf(">> wFormatTag : %d\n", g_wave_header->wFormatTag);
	printf(">> nChannels : %d\n", g_wave_header->nChannels);
	printf(">> nSamplesPerSec : %d\n", g_wave_header->nSamplesPerSec);
	printf(">> nAvgBytesPerSec : %d\n", g_wave_header->nAvgBytesPerSec);
	printf(">> nBlockAlign : %d\n", g_wave_header->nBlockAlign);
	printf(">> wBitsPerSample : %d\n", g_wave_header->wBitsPerSample);
	printf(">> DataID : %c%c%c%c\n", g_wave_header->DataID[0], g_wave_header->DataID[1], g_wave_header->DataID[2], g_wave_header->DataID[3]);
	printf(">> nDataBytes : %d\n", g_wave_header->nDataBytes);

	return fp;
}

char * sctrlstr = "Digital Playback Volume";

int32_t main()
{
	int8_t *infile = "Back_to_Earth.wav";
	int8_t *device = "hw:0,0";
	snd_pcm_t *handle;
	snd_pcm_hw_params_t *hwparams;
	WAVE_HEADER g_wave_header;
	snd_pcm_format_t format;
	uint32_t ch;
	uint32_t rate;
	snd_pcm_sframes_t period_size;
	int16_t *samples;
	int32_t music_sec;
	int32_t err;
	int32_t size;
	int32_t rc;

	FILE *fp = open_and_print_file_params(infile, &g_wave_header);
	if (fp == NULL)
	{
		printf("open_and_print_file_params error\n");
		return -1;
	}

	/* set sample rate */
	rate = g_wave_header.nSamplesPerSec;

	/* set sample bit */
	if (8 == g_wave_header.FmtSize)
	{
		format = SND_PCM_FORMAT_U8;
	}
	else if (16 == g_wave_header.FmtSize)
	{
		format = SND_PCM_FORMAT_S16_LE;
	}
	else if (24 == g_wave_header.FmtSize)
	{
		format = SND_PCM_FORMAT_U24_LE;
	}
	else if (32 == g_wave_header.FmtSize)
	{
		format = SND_PCM_FORMAT_U32_LE;
	}
	else
	{
		printf("SND_PCM_FORMAT_UNKNOWN.\n");
		format = SND_PCM_FORMAT_UNKNOWN;
		return -1; 
	}

	/* set channel */
	ch = g_wave_header.nChannels;

	/* music time */
	music_sec = g_wave_header.nDataBytes / g_wave_header.nAvgBytesPerSec;
	printf("music_time : %d : %d\n", (int32_t)music_sec / 60, music_sec % 60);
	printf("Playback device is %s\n", device);
	printf("Stream parameters are %uHz, %s, %u channels\n", rate, snd_pcm_format_name(format), ch);

	err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0);
	if (err < 0) 
	{
		printf("Playback open error: %s\n", snd_strerror(err));
		return 0;
	}

	snd_pcm_hw_params_alloca(&hwparams);
	err = set_hwparams(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED, ch, format, rate, &period_size);
	if (err < 0) {
		printf("Setting of hwparams failed: %s\n", snd_strerror(err));
		return 0;
	}

	size = (period_size * ch * snd_pcm_format_physical_width(format)) / 8;
	samples = (int16_t *)malloc(size);

	while (1) 
	{
		rc = fread(samples, sizeof(int16_t), size, fp);
		if (rc == 0)
		{
			printf("end of file on input\n");
			break;
		} 
		else if (rc != size)
		{
			printf("short read: read %d bytes\n", rc);
		}

		rc = snd_pcm_writei(handle, samples, size);
		if (rc == -EPIPE)
		{
			printf("underrun occurred\n");
			err = snd_pcm_prepare(handle);
			if( err < 0)
			{
				printf("can not recover from underrun: %s\n", snd_strerror(err));
			}
		} 
		else if (rc < 0)
		{
			printf("error from writei: %s\n", snd_strerror(rc));
		}  
		else if (rc != (int32_t)size)
		{
			printf("short write, write %d frames\n", rc);
		}
	}

	if (samples != NULL)
	{
		free(samples);
	}

	snd_pcm_close(handle);

	return 0;
}

 # arm-fsl-linux-gnueabi-gcc player.c -o player -lasound -lm -I /var/alsa/include/ -L /var/alsa/lib/


Linux/Android alsa codec音频路由dapm的配置详解

DAPM之二:audio paths与dapm kcontrol

ALSA声卡16_编写ALSA声卡应用程序_学习笔记

8.声卡驱动06-自己实现alsa驱动-虚拟声卡-widget

ALSA驱动asoc框架之machine(一)

ALSA驱动asoc框架之machine(二)

ALSA驱动asoc框架之Platform

ALSA驱动asoc框架之Codec

Linux ALSA 音频系统:物理链路篇

Linux ALSA 音频系统:逻辑设备篇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值