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程序:
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 <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
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);
1、pcm播放的时候,接口snd_pcm_writei 返回 -EPIPE,为underrun原因:因为应用程序给底层驱动的速度慢造成的我的解决办法:可以通过改变snd_pcm_hw_params_set_buffer_size_near(capture_handle, c_hwparams, &exact_bufsize))中的参数来解决,具体改为多少要看实际情况,我是往大了改。2...
在 ALSA 数据传输中,最容易出现的错误是 underrun 和 overrun。
pcm 播放的时候,接口 snd_pcm_writei 返回 -EPIPE,为 underrun(不足)
录制音频的时候, 接口 snd_pcm_readi 返回 -EPIPE, 为 overrun(超载)
使用 ALSA 架构的驱动程,在实际开发使用过程中,比较常见的错误有 -EPIPE,为什么会出现呢?肯...
一、ALSA介绍:
1、简介:
高级Linux声音体系(英语:Advanced LinuxSound Architecture,缩写为ALSA)是Linux内核中,为声卡提供的驱动组件,以替代原先的OSS(开放声音系统)。
一部分的目的是支持声卡的自动配置,以及完美的处理系统中的多个声音设备,这些目的大多都已达到。另一个声音框架JACK使用ALSA提供低延迟的专业级音频编辑和混音能力。
[Loong]:之前写过基于ALSA的WAV播放录音程序,见http://blog.csdn.net/sepnic/archive/2011/01/14/6140824.aspx。现在本想好好整理一下ALSA的编程思想,但Google了一下,发现已经有同道做了类似的工作,故将其转载过来,并添加一些本人的疑问以及补充(将会继续补充,原文很多重要的ALSA参数没有提到)。
原文:http://blo
平台:ubuntu 16.04,kernel版本是4.15.0, 理论任何平台都可以,甚至是android,只要能编译通过。
需要完成的功能:传说中的回采,做过语音方案的童鞋应该能懂,就是播放的音频,录音录回去。因为是虚拟的声卡,不涉及硬件操作,也只能这样看点效果。
目的:当然是为了能更直观的理解alsa驱动框架。虚拟出一个声卡,不涉及复杂的硬件操作,不涉及复杂的硬件调试,只关心数据流怎么一步一步传给应用的。
1.数据是怎么交互的
以playback为例
驱动程序分配一个buffer
APP不断写
平台:ubuntu 16.04,kernel版本是4.15.0, 理论任何平台都可以,甚至是android,只要能编译通过。
需要完成的功能:一个进程播放音频,一个进程录音。
直接贴代码
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <alsa/asoundlib
alsa-driver 是 Linux 上的一个音频设备驱动程序。它支持各种硬件,能够让 Linux 上的应用程序通过音频设备输出声音,非常重要。
要下载 alsa-driver,首先需要确定自己使用的 Linux 发行版。很多主流的 Linux 发行版都包括 alsa-driver,所以首先可以尝试使用发行版自带的包管理器来安装。
如果没有找到 alsa-driver 或者需要编译自定义版本,可以访问官方网站 https://www.alsa-project.org/main/index.php/Download 页面,下载对应版本的源代码包。通常可以在页面底部找到最新版本的下载链接。
下载完成后,需要使用 tar 命令解压源代码包。接下来,可以根据 alsa-driver 的 README 文件或者官方网站上提供的安装指南来安装和编译。一般来说,需要安装一些必要的依赖库,然后执行 configure、make 和 make install 等命令,编译安装 alsa-driver。
总的来说,下载和安装 alsa-driver 要根据具体的情况而定,需要注意自己使用的 Linux 发行版和硬件设备的兼容性,并且要仔细阅读官方文档。