alsa的调试,underrun和underrun

1、pcm播放的时候,接口snd_pcm_writei 返回 -EPIPE,为underrun
原因:因为应用程序给底层驱动的速度慢造成的
我的解决办法:可以通过改变snd_pcm_hw_params_set_buffer_size_near(capture_handle, c_hwparams, &exact_bufsize))中的参数来解决,具体改为多少要看实际情况,我是往大了改。
2、录制音频的时候, 接口snd_pcm_readi 返回 -EPIPE, 为underrun
原因:因为采集到的数据已经把底层的容量占满了,数据还没有被读走
我的解决办法:当时出现这个问题是在录后就立即去读,出现这个问题。根据芯片使用手册播放前需要执行一条命令amixer cset numid=17,iface=MIXER,name=‘Speaker Function’ 0",我猜是关闭扩音器,使用耳机作为输出,因为我的板子上没有扩音器,只有耳机孔。numid=17是设置音量。
下面是我用v3s作为客户端,使用虚拟机的ubuntu作为服务,v3s采集发送到ubuntu。
v3s程序:

#include 
#include 
#include 
#include 
#include 

int client_sd;

int main(void){
       /*Name of the PCM device ,like "default"*/
       char    *dev_name;
       int     rate = 8000;/*Sample rate*/
         int     exact_rate;/*Sample rate returned by*/
         int     dir;/*(1)exact_rate == rate --> dir=0,(2)exact_rate < rate --> dir=-1,(3)exact_rate > rate*/
         long unsigned int     periods = 3;/*Number of periods*/
         unsigned long bufsize = 8190;
        unsigned long exact_bufsize;
         int     err;
         int     size;
         int     pcmreturn;
 //      snd_pcm_uframes_t       periodsize = 8192;
         snd_pcm_uframes_t       periodsize = 320;
         snd_pcm_t       *capture_handle;
         snd_pcm_stream_t        capture_stream = SND_PCM_STREAM_CAPTURE;
         /*This structure contains information about */
         /*the hardware and can be used to specify the */
         /*configuration to be used for the PCM stream*/
         snd_pcm_hw_params_t     *c_hwparams;
         /*Init dev_name, Of course, later you will make this configure*/
         dev_name = strdup("default");
         /*Allocate the snd_pcm_hw_params_t structure on the stack*/
         snd_pcm_hw_params_alloca(&c_hwparams);
         FILE *out;
         FILE *comm_fp = NULL;
 				 char comm_ret[100] = {'0'};
 				 //socket
 				 socklen_t len;
				 pthread_t send_id;
				 pthread_t recv_id;
				 struct sockaddr_in server_addr;		
				 int ret;		 
 				 
 				 /*shell command*/
 					comm_fp = popen("amixer cset numid=10,iface=MIXER,name='Audio main mic' 1", "r");
 					if(comm_fp == NULL){
 						printf("shell error\n");
 						return 0;
 						}
 					while(fgets(comm_ret, sizeof(comm_ret) - 1, comm_fp) != NULL)
 						printf("amixer:\n%s\n", comm_ret);
 					pclose(comm_fp);
         /* Open PCM. The last parameter of this function is the mode. */
         /* If this is set to 0, the standard mode is used. Possible   */
         /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC.       */
         /* If SND_PCM_NONBLOCK is used, read / write access to the    */
         /* PCM device will return immediately. If SND_PCM_ASYNC is    */
         /* specified, SIGIO will be emitted whenever a period has     */
         /* been completely processed by the soundcard.                */

         if (snd_pcm_open(&capture_handle, dev_name, capture_stream, 0) < 0) {
                 fprintf(stderr, "Error opening PCM device %s\n", dev_name);
                 return(-1);
         }
         if (snd_pcm_hw_params_any(capture_handle, c_hwparams) < 0) {
                 fprintf(stderr, "Can not configure this PCM device.\n");
                 return(-1);
         }
         /* Set access type. This can be either    */
         /* SND_PCM_ACCESS_RW_INTERLEAVED or       */
         /* SND_PCM_ACCESS_RW_NONINTERLEAVED.      */
         /* There are also access types for MMAPed */
         /* access, but this is beyond the scope   */
         /* of this introduction.                  */

         if (snd_pcm_hw_params_set_access(capture_handle, c_hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
                 fprintf(stderr, "Error setting access.\n");
                 return(-1);
         }
         /* Set sample format */

         if (snd_pcm_hw_params_set_format(capture_handle, c_hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
                 fprintf(stderr, "Error setting format.\n");
                 return(-1);
         }
         exact_rate = rate;
         if (snd_pcm_hw_params_set_rate_near(capture_handle, c_hwparams, &exact_rate, 0) < 0) {
                 fprintf(stderr, "Error setting rate.\n");
                 return(-1);
         }
         if (rate != exact_rate) {
                 fprintf(stderr, "The rate %d Hz is not supported by your hardware.\
                        ==> Using %d Hz instead.\n", rate, exact_rate);
         }
 
         /* Set number of channels */
         if (snd_pcm_hw_params_set_channels(capture_handle, c_hwparams, 1) < 0) {
                 fprintf(stderr, "Error setting channels.\n");
                 return(-1);
         }
         if (snd_pcm_hw_params_set_periods(capture_handle, c_hwparams, periods, 0) < 0) {
                 fprintf(stderr, "Error setting periods.\n");
                 return(-1);
         }
         /* Set buffer size (in frames). The resulting latency is given by */
         /* latency = periodsize * periods / (rate * bytes_per_frame)     */
       if(snd_pcm_hw_params_get_buffer_size_max(c_hwparams,&periodsize) < 0)
       {
               fprintf(stderr,"Error get buffer size\n");
       }
       printf("periodsize=%lu\n",periodsize);
 
       /*  if (snd_pcm_hw_params_set_buffer_size(capture_handle, c_hwparams, (periodsize * periods)) < 0) {
                 fprintf(stderr, "Error setting buffersize.\n");
                 return(-1);
         }*/
        exact_bufsize = bufsize;
        if(snd_pcm_hw_params_set_buffer_size_near(capture_handle, c_hwparams, &exact_bufsize)){
        		fprintf(stderr, "Error setting buffsize.\n");
        	}
        if(exact_bufsize != bufsize){
        	printf("exact_bufsize:%ld,bufsize:%ld\n", exact_bufsize, bufsize);
        	}
         /* Apply HW parameter settings to */
         /* PCM device and prepare device  */

         if (snd_pcm_hw_params(capture_handle, c_hwparams) < 0) {
                 fprintf(stderr, "Error setting HW params.\n");
                 return(-1);
         }
 //      snd_pcm_hw_params_free(hwparams);
 //      snd_pcm_hw_params_free(c_hwparams);
         if ((err = snd_pcm_prepare (capture_handle)) < 0) {
                 fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
                                  snd_strerror (err));
                 exit (1);
         }
         snd_pcm_hw_params_get_period_size(c_hwparams, &periods,0);
         printf("periods=%d\n",periods);
         char *data_buf = (char*)malloc(periods*4);
         if(!data_buf){
                 fprintf(stderr, "Cannot malloc buffer for data\n");
         }
         //socket
        client_sd = socket(AF_INET,SOCK_STREAM,0);
				if(client_sd < 0){
					perror("socket");
					return 0;
				}
				server_addr.sin_family = AF_INET;
				server_addr.sin_port = htons(8888);
				inet_aton("192.168.31.168",&server_addr.sin_addr);
				//2、连接服务器
				ret = connect(client_sd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
				if(ret<0){
					perror("connect");
					return 0;
				}
				
         out = fopen("capt.pcm", "w");
         
         while(1)
 
         {
                 pcmreturn = snd_pcm_readi( capture_handle, data_buf, 2047);
                 if( pcmreturn == -EPIPE )
                 {
                         snd_pcm_prepare( capture_handle );
                         fprintf (stderr, "<<<<<<<<<<<<<<<<<<< Buffer Overrun >>>>>>>>>>>>>>>>>\n");
                         continue;
                 }else if( pcmreturn == -EBADFD ){
                         fprintf(stderr, "<<<<<<<<<<<<<<<<<<<< readi error -EBADFD >>>>>>>>>>>>>\n");
                         continue;
                 }else if( pcmreturn == -ESTRPIPE ){
                         fprintf(stderr, "<<<<<<<<<<<<<<<<<<<< readi error -ESTRPIPE >>>>>>>>>>>>>\n");
                 }
                 send(client_sd, data_buf , 2047 * 4, 0);
                 printf("pcmreturn = %d\n",pcmreturn);
                 fwrite(data_buf, sizeof(char), 2047 * 4, out);
				 }
 					fclose(out);
 
 }

ubuntu程序:
#include
#include
#include
#include
#include
#include

int server_sd, client_sd;

int main(int argv, char *argc){
/Name of the PCM device ,like “default”/
char dev_name;
int rate = 8000;/Sample rate/
int exact_rate;/Sample rate returned by/
int dir;/
(1)exact_rate == rate --> dir=0,(2)exact_rate < rate --> dir=-1,(3)exact_rate > rate
/
long unsigned int periods = 4;/Number of periods/
unsigned long bufsize=8190;
unsigned long exact_bufsize;
int err;
int size;
int pcmreturn;
// snd_pcm_uframes_t periodsize = 8192;
snd_pcm_uframes_t periodsize = 320;
snd_pcm_t *play_handle;
snd_pcm_stream_t play_stream = SND_PCM_STREAM_PLAYBACK;
/*This structure contains information about */
/*the hardware and can be used to specify the */
/configuration to be used for the PCM stream/
snd_pcm_hw_params_t *hwparams;

     /*Init dev_name, Of course, later you will make this configure*/
     dev_name = strdup("default");
     /*Allocate the snd_pcm_hw_params_t structure on the stack*/
     snd_pcm_hw_params_alloca(&hwparams);
     FILE *file_in;
	int ret;
	FILE *comm_fp = NULL;
	char comm_ret[100] = {'0'};

//socket
char buff[512];
struct sockaddr_in server_addr,client_addr;
int len = sizeof(struct sockaddr);

			 /*shell command*/
				/*comm_fp = popen("amixer cset numid=50,iface=MIXER,name='Speaker Function' 0", "r");
				if(comm_fp == NULL){
					printf("shell error\n");
					return 0;
					}
				while(fgets(comm_ret, sizeof(comm_ret) - 1, comm_fp) != NULL)
					printf("amixer:\n%s\n", comm_ret);
				pclose(comm_fp);*/
				
		

     /* Open PCM. The last parameter of this function is the mode. */
     /* If this is set to 0, the standard mode is used. Possible   */
     /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC.       */
     /* If SND_PCM_NONBLOCK is used, read / write access to the    */
     /* PCM device will return immediately. If SND_PCM_ASYNC is    */
     /* specified, SIGIO will be emitted whenever a period has     */
     /* been completely processed by the soundcard.                */
     if (snd_pcm_open(&play_handle, dev_name, play_stream, 0) < 0) {
             fprintf(stderr, "Error opening PCM device %s\n", dev_name);
             return(-1);
     }

     /* Init hwparams with full configuration space */
     if (snd_pcm_hw_params_any(play_handle, hwparams) < 0) {
             fprintf(stderr, "Can not configure this PCM device.\n");
             return(-1);
     }
     /* Set access type. This can be either    */
     /* SND_PCM_ACCESS_RW_INTERLEAVED or       */
     /* SND_PCM_ACCESS_RW_NONINTERLEAVED.      */
     /* There are also access types for MMAPed */
     /* access, but this is beyond the scope   */
     /* of this introduction.                  */
     if (snd_pcm_hw_params_set_access(play_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
             fprintf(stderr, "Error setting access.\n");
             return(-1);
     }
     /* Set sample format */
     if (snd_pcm_hw_params_set_format(play_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
             fprintf(stderr, "Error setting format.\n");
             return(-1);
     }
     exact_rate = rate;
     if (snd_pcm_hw_params_set_rate_near(play_handle, hwparams, &exact_rate, 0) < 0) {
             fprintf(stderr, "Error setting rate.\n");
             return(-1);
     }
     if (rate != exact_rate) {
             fprintf(stderr, "The rate %d Hz is not supported by your hardware.\
                    ==> Using %d Hz instead.\n", rate, exact_rate);
     }

     /* Set number of channels */
     if (snd_pcm_hw_params_set_channels(play_handle, hwparams, 1) < 0) {
             fprintf(stderr, "Error setting channels.\n");
             return(-1);
     }

     /* Set number of periods. Periods used to be called fragments. */
     if (snd_pcm_hw_params_set_periods(play_handle, hwparams, periods, 0) < 0) {
             fprintf(stderr, "Error setting periods.\n");
             return(-1);
     }
     /* Set buffer size (in frames). The resulting latency is given by */
     /* latency = periodsize * periods / (rate * bytes_per_frame)     */
   if(snd_pcm_hw_params_get_buffer_size_max(hwparams,&periodsize) < 0)
   {
           fprintf(stderr,"Error get buffer size\n");
   }
   printf("MAX_periodsize=%lu\n",periodsize);

/* if (snd_pcm_hw_params_set_buffer_size(play_handle, hwparams, (periodsize * periods)) < 0) {
fprintf(stderr, “Error setting buffersize.\n”);
return(-1);
}*/
exact_bufsize = bufsize;
if (snd_pcm_hw_params_set_buffer_size_near(play_handle, hwparams, &exact_bufsize) < 0) {
fprintf(stderr, “Error setting buffersize.\n”);
return(-1);
}
if (exact_bufsize != bufsize){
printf(“exact_bufsize:%ld,bufsize:%ld\n”, exact_bufsize, bufsize);
}

     /* Apply HW parameter settings to */
     /* PCM device and prepare device  */
     if (snd_pcm_hw_params(play_handle, hwparams) < 0) {
             fprintf(stderr, "Error setting HW params.\n");
             return(-1);
     }

// snd_pcm_hw_params_free(hwparams);
// snd_pcm_hw_params_free(c_hwparams);
if ((err = snd_pcm_prepare (play_handle)) < 0) {
fprintf (stderr, “cannot prepare audio interface for use (%s)\n”,
snd_strerror (err));
exit (1);
}
snd_pcm_hw_params_get_period_size(hwparams, &periods, 0);
printf(“periods=%ld\n”,periods);
char data_buf = (char)malloc(periods*4);
if(!data_buf){
fprintf(stderr, “Cannot malloc buffer for data\n”);
}

	 //1、创建套接字
server_sd = socket(AF_INET,SOCK_STREAM,0);
if(server_sd < 0)
{
	perror("socket");
	return 0;
}
int reuse=1;
setsockopt(server_sd,SOL_SOCKET ,SO_REUSEADDR,(const char*)& reuse,sizeof(int));
//2、绑定ip 端口号
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
inet_aton("192.168.31.168",&server_addr.sin_addr);
ret = bind(server_sd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr));
if(ret < 0)
{
	perror("bind");
	return 0;
}
//3、设置监听个数
ret=listen(server_sd,2);
if(ret < 0)
{
	perror("listen");
	return 0;
}
//4、等待客户端连接
printf("wait accept \n");
client_sd = accept(server_sd,(struct sockaddr *)&client_addr,&len);
if(client_sd<0)
{
	perror("accept");
	return 0;
}
	 
// file_in = fopen("capt.pcm", "r");
     
	 
     while(1)
      {
      	/* ret = fread(data_buf, sizeof(char), 320*4, file_in);
      	 if(ret == 0)
      	 {
      	 	printf("end of file\n");			
      	 }else if(ret != 320 * 4)
      	 {
      	 	printf("short read\n");	
      	 }
      	 
      	 if(feof(file_in))
      	 	break;
 				 printf("ret=%d\n",ret);*/
		 recv(client_sd, data_buf, 2047 * 4, 0);
         pcmreturn = snd_pcm_writei(play_handle, data_buf, 2047);
         if( pcmreturn == -EPIPE ){
         	/*在播放例子中,如果应用程序写入数据到缓存区中的速度不够快,缓存区将会"饿死"。这样的错误被称 为"underrun"*/
                 fprintf(stderr, "<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>\n");
                 snd_pcm_prepare( play_handle );
 //              continue;
         }else if( pcmreturn == -ESTRPIPE ){
         	
                 fprintf(stderr, "<<<<<<<<<<<< writei error -ESTRPIPE >>>>>>>>>>>\n");
         }else if( pcmreturn == -EBADFD ){
                 fprintf(stderr, "<<<<<<<<<<<< writei error -EABDFD >>>>>>>>>>>>\n");
         }
         printf("pcmreturn = %d\n",pcmreturn);

     }
 //   fclose(file_in);

}

你可能感兴趣的:(嵌入式,alsa)