嵌入式linux中PCM音频编程实践

2019-07-13 01:02发布

    嵌入式设备中经常需要用的音频,音频设备最原始的数据格式就是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; }