红联Linux门户
Linux帮助

关于Linux下alsa录音程序移植出现的奇怪问题

发布时间:2017-03-19 10:43:27来源:linux网站作者:放羊娃
以下程序是可以正常运行的:
#include <alsa/asoundlib.h>
#include <math.h>
#include <pthread.h>
#include <string.h>
#define BUFFERSIZE 4096
#define PERIOD_SIZE 1024
#define PERIODS 2
#define SAMPLE_RATE 16000
#define CHANNELS 1
#define FSIZE 2*CHANNELS
/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API
 
long loops; //define the record time.
int rc;//return code.
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;//定义参数变量
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
int err;
char *file;
int fd_pcm;
int read_flag1=0;
 
/*放音初始化*/
int init_pcm_play_dri(void)
{
/*snd_pcm_open (&pcm_handle, “default” , mode , 0)
snd_pcm_open是Alsa库提供的打开设备调用函数,
这里我们指定打开缺省的音频设备,并根据参数mode将
设备置为录音或是播放状态,如果设备打开成功,
pcm_handle便指向该设备句柄,我们用全局变量保存
起来,方便以后使用。*/
rc = snd_pcm_open(&handle, "default",SND_PCM_STREAM_PLAYBACK, 0);
if (rc < 0) {
fprintf(stderr,"unable to open pcm device: %s\n",snd_strerror(rc));
exit(1);
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(¶ms);//为参数变量分配空间
/* Fill it in with default values. */
err=snd_pcm_hw_params_any(handle, params);//参数初始化
if (err < 0) {
fprintf(stderr, "Can not configure this PCM device: %s\n",
snd_strerror(err));
exit(1);
}
/* Set the desired hardware parameters. */
/* Interleaved mode *///设置为交错模式
err=snd_pcm_hw_params_set_access(handle, params,SND_PCM_ACCESS_RW_INTERLEAVED);
if (err < 0) {
fprintf(stderr,
"Failed to set PCM device to interleaved: %s\n",
snd_strerror(err));
exit(1);
}
/* Signed 16-bit little-endian format *///使用用16位样本
err=snd_pcm_hw_params_set_format(handle, params,SND_PCM_FORMAT_S16_LE);
if (err < 0) {
fprintf(stderr,
"Failed to set PCM device to 16-bit signed PCM: %s\n",
snd_strerror(err));
exit(1);
}
/* One channels (mono) *///设置通道
err=snd_pcm_hw_params_set_channels(handle, params, CHANNELS);
if (err < 0) {
fprintf(stderr, "Failed to set PCM device to mono: %s\n",
snd_strerror(err));
exit(1);
}
/* 16000 bits/second sampling rate (CD quality) */ //设置采样率为16KHz
val = SAMPLE_RATE;
err=snd_pcm_hw_params_set_rate_near(handle, params,&val, &dir);
if (err < 0) {
fprintf(stderr, "Failed to set PCM device to sample rate =%d: %s\n",
val,snd_strerror(err));
exit(1);
}
/*
frames = PERIOD_SIZE;
snd_pcm_hw_params_set_period_size_near(handle,params, &frames, &dir);
*/
/*
snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0);
period_time = buffer_time / 4;
err=snd_pcm_hw_params_set_period_time_near(handle, params,&period_time, 0);
if (err < 0) {
fprintf(stderr,"Failed to set PCM device to period time =%u: %s\n",
period_time,snd_strerror(err));
exit(1);
}
*/
unsigned int buffer_time,period_time;
snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0);
if ( buffer_time >500000)
buffer_time = 500000;
period_time = buffer_time / 4;
err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0);
if (err < 0) 
{
fprintf(stderr, "Failed to set PCM device to buffer time =%d: %s\n",
buffer_time,snd_strerror(err));
exit(1);
}
err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, 0);
if (err < 0) {
fprintf(stderr, "Failed to set PCM device to period time =%d: %s\n",
period_time,snd_strerror(err));
exit(1);
}
rc = snd_pcm_hw_params(handle, params);//设置参数
if (rc < 0) {
fprintf(stderr,"unable to set hw parameters: %s\n",snd_strerror(rc));
exit(1);
}
snd_pcm_hw_params_get_period_size(params, &frames,&dir);//获取周期长度
size = frames * FSIZE;
buffer = (char *) malloc(size);
printf("period size = %d frames\n", (int)frames);
printf("read buffer size = %d\n",size);
snd_pcm_hw_params_get_period_time(params,&val, &dir);
printf("period time is: %d\n",val);
//loops = 100;
snd_pcm_hw_params_get_buffer_time(params,&val, &dir);
printf("buffer time = %d us\n", val);
snd_pcm_hw_params_get_buffer_size(params,(snd_pcm_uframes_t *) &val);
printf("buffer size = %d frames\n", val);
snd_pcm_hw_params_get_periods(params, &val, &dir);
printf("periods per buffer = %d frames\n", val);
printf("start playing !\n");
file = "output_test.wav";
fd_pcm = open(file,O_RDONLY);
do
{
read_flag1 = read(fd_pcm, buffer, size);
if(read_flag1 == 0)
{
fprintf(stderr, "end of file on input\n");
break;
}  
else if (read_flag1 != size) 
{
fprintf(stderr,"short read: read %d bytes\n", read_flag1);
}
rc = snd_pcm_writei(handle, buffer, frames);
if (rc == -EPIPE) 
{
fprintf(stderr, "underrun occurred\n");
err=snd_pcm_prepare(handle);
if( err <0)
{
fprintf(stderr, "can not recover from underrun: %s\n",snd_strerror(err));
}
else if (rc < 0) 
{
fprintf(stderr,"error from writei: %s\n",snd_strerror(rc));
}  
else if (rc != (int)frames)
{
fprintf(stderr,"short write, write %d frames\n", rc);
}
printf("recording.......................................\n");
}while(read_flag1);
//close(fd_pcm);
//snd_pcm_drain(handle);
//snd_pcm_close(handle);
//free(buffer);
return 1;
}
 
以上程序运行时没问题的,但是将所有的变量都放在函数init_pcm_play_dri()里面,就会出问题,在友善之臂210的开发板上运行的时候报错:在这里报错:
rc = snd_pcm_hw_params(handle, params);//设置参数
if (rc < 0) {
fprintf(stderr,"unable to set hw parameters: %s\n",snd_strerror(rc));
exit(1);
}
 
打印出rc的值为-22,报的错误是非法的参数。
 
最后发现变量read_flag1必须在这个函数体的外面(即全局变量)或者在函数体内部声明成静态变量才不会报这个错误。
 
本文永久更新地址:http://www.linuxdiyf.com/linux/29299.html