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);
}