嵌入式设备中经常需要用的音频,音频设备最原始的数据格式就是PCM,也就是大家常见的WAV,在linux中,音频编程使用最多的就是alsa框架,下面就来看一下pcm音频的编程实例吧。
首先需要包含头文件:
#include
定义产量与结构体
snd_pcm_t *alsaplayhdl;
snd_pcm_t *alsacapturehdl;
snd_mixer_t *mixerfd;
snd_mixer_elem_t *elem;
pthread_mutex_t alsa_play_mutex;
pthread_mutex_t alsa_cap_mutex;
snd_pcm_hw_params_t *dispalsa_hwparams;
snd_pcm_sw_params_t *dispalsa_swparams;
snd_pcm_hw_params_t *capturehwparams;
snd_pcm_sw_params_t *captureswparams;
定义设备号:
#define ALSADEVNAME "default"
打开设备:
void open_dev(void)
{
int ret = -1;
ret = snd_pcm_open(&alsaplayhdl,ALSADEVNAME,SND_PCM_STREAM_PLAYBACK,0);
if(ret < 0)
{
printf("open alsa display failture
");
}
}
关闭设备:
void close_dev(void)
{
int ret = -1;
pthread_t tid;
if(alsaplayhdl != NULL)
{
snd_pcm_drop(alsaplayhdl);
ret = snd_pcm_close(alsaplayhdl);
if(ret < 0)
{
printf("alsa close dev failture
");
}
alsaplayhdl = NULL;
}
}
写入音频数据
int alsa_write(char* buf, int length)
{
int frames;
int ret=0;
int write = 0,size;
long int audiodisplay[2];
audiodisplay[0]++; //正常情况下,alsa_write_audiobuf()调用一次,sysglobaldata_status.audiodisplay[0]的值增加1。如果该值长久没有变化时表明声音播放异常
frames = snd_pcm_writei(alsaplayhdl, buf, length/2);
if(frames == -EPIPE)
{
printf("apps write buff too Slow!-EPIPE
");
snd_pcm_prepare(alsaplayhdl);
frames = snd_pcm_writei(alsaplayhdl, buf, length/2);
}
else if(frames < 0)
{
printf("snd_pcm_writei call failure:%s
", snd_strerror(ret));
frames = snd_pcm_recover(alsaplayhdl, frames, 0);
}
ret = frames*2;
err:
return ret;
}
读取设备音频数据
int alsa_read(char* buf, int length)
{
int frames;
int ret = -1;
int read;
pthread_mutex_lock(&alsa_cap_mutex);
frames = snd_pcm_avail(alsacapturehdl);
if(frames <= 0)
{
goto err;
}
read = frames *2 > length ? length : frames * 2;
frames = snd_pcm_readi(alsacapturehdl, buf, read/2);
if(frames < 0)
{
goto err;
}
ret = frames * 2;
err:
pthread_mutex_unlock(&alsa_cap_mutex);
return ret;
}
打开混音器
int open_mixer(void)
{
int ret;
unsigned char mixercount;
if(mixercount <= 0)
{
ret = snd_mixer_open(&mixerfd,0); // 打开混音器
if(ret < 0)
{
printf("alsa mixer open failture
");
return -1;
}
ret = snd_mixer_attach(mixerfd,"default"); // 先设定为默认
if(ret < 0)
{
printf("alsa mixer attach failture
");
return -2;
}
ret = snd_mixer_selem_register(mixerfd,NULL,NULL); // 注册混音器
if(ret < 0)
{
printf("alsa mixer register failture
");
return -3;
}
ret = snd_mixer_load(mixerfd);
if(ret < 0)
{
printf("alsa mixer load failture
");
return -4;
}
mixercount = 0;
}
mixercount ++;
return mixercount;
}
设置设备音量
int set_volume(int volume)
{
int err;
int orig_volume = 0;
static snd_ctl_t *handle = NULL;
snd_ctl_elem_info_t *info;
snd_ctl_elem_id_t *id;
snd_ctl_elem_value_t *control;
unsigned int count;
snd_ctl_elem_type_t type;
snd_ctl_elem_info_alloca(&info);
snd_ctl_elem_id_alloca(&id);
snd_ctl_elem_value_alloca(&control);
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
snd_ctl_elem_id_set_name(id, "Mic Capture Volume");
if ((err = snd_ctl_open(&handle, "default", 0)) < 0) {
printf("open ctl device failed
");
return -1;
}
snd_ctl_elem_info_set_id(info, id);
if ((err = snd_ctl_elem_info(handle, info)) < 0) {
printf("snd_ctl_elem_info failed
");
snd_ctl_close(handle);
handle = NULL;
return -1;
}
type = snd_ctl_elem_info_get_type(info);
count = snd_ctl_elem_info_get_count(info);
snd_ctl_elem_value_set_id(control, id);
if (!snd_ctl_elem_read(handle, control)) {
orig_volume = snd_ctl_elem_value_get_integer(control, 0);
}
if(volume != orig_volume) {
//snd_ctl_elem_value_set_integer(control, 0, static_cast(volume));
snd_ctl_elem_value_set_integer(control, 0,volume);
snd_ctl_elem_value_set_integer(control, 1,volume);
if ((err = snd_ctl_elem_write(handle, control)) < 0)
{
printf("snd_ctl_elem_write failed
");
snd_ctl_close(handle);
handle = NULL;
return -1;
}
}
snd_ctl_close(handle);
handle = NULL;
return 1;
}