Linux下使用alsa-lib库实现放音和录音
参考代码:从声卡获取PCM数据,实现录音功能
下面代码在命令行通过gcc编译运行: 读取声卡数据,保存为文件,结束录音可以按下Ctrl+C即可结束。
/*
进行音频采集,采集pcm数据并直接保存pcm数据
音频参数:
声道数: 1
采样位数: 16bit、LE格式
采样频率: 44100Hz
运行示例:
$ gcc linux_pcm_save.c -lasound
$ ./a.out hw:0 123.pcm
#include <stdio.h> #include <stdlib.h> #include <alsa/asoundlib.h> #include <signal.h> #define AudioFormat SND_PCM_FORMAT_S16_LE //指定音频的格式,其他常用格式:SND_PCM_FORMAT_U24_LE、SND_PCM_FORMAT_U32_LE #define AUDIO_CHANNEL_SET 1 //1单声道 2立体声 #define AUDIO_RATE_SET 44100 //音频采样率,常用的采样频率: 44100Hz 、16000HZ、8000HZ、48000HZ、22050HZ FILE *pcm_data_file=NULL; int run_flag=0; void exit_sighandler(int sig) { run_flag=1; } int main(int argc, char *argv[]) { int i; int err; char *buffer; int buffer_frames = 1024; unsigned int rate = AUDIO_RATE_SET; snd_pcm_t *capture_handle;// 一个指向PCM设备的句柄 snd_pcm_hw_params_t *hw_params; //此结构包含有关硬件的信息,可用于指定PCM流的配置 /*注册信号捕获退出接口*/ signal(2,exit_sighandler); /*PCM的采样格式在pcm.h文件里有定义*/ snd_pcm_format_t format=AudioFormat; // 采样位数:16bit、LE格式 /*打开音频采集卡硬件,并判断硬件是否打开成功,若打开失败则打印出错误提示*/ // SND_PCM_STREAM_PLAYBACK 输出流 // SND_PCM_STREAM_CAPTURE 输入流 if ((err = snd_pcm_open (&capture_handle, argv[1],SND_PCM_STREAM_CAPTURE,0))<0) { printf("无法打开音频设备: %s (%s)\n", argv[1],snd_strerror (err)); exit(1); } printf("音频接口打开成功.\n"); /*创建一个保存PCM数据的文件*/ if((pcm_data_file = fopen(argv[2], "wb")) == NULL) { printf("无法创建%s音频文件.\n",argv[2]); exit(1); } printf("用于录制的音频文件已打开.\n"); /*分配硬件参数结构对象,并判断是否分配成功*/ if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) { printf("无法分配硬件参数结构 (%s)\n",snd_strerror(err)); exit(1); } printf("硬件参数结构已分配成功.\n"); /*按照默认设置对硬件对象进行设置,并判断是否设置成功*/ if((err=snd_pcm_hw_params_any(capture_handle,hw_params)) < 0) { printf("无法初始化硬件参数结构 (%s)\n", snd_strerror(err)); exit(1); } printf("硬件参数结构初始化成功.\n"); /* 设置数据为交叉模式,并判断是否设置成功 interleaved/non interleaved:交叉/非交叉模式。 表示在多声道数据传输的过程中是采样交叉的模式还是非交叉的模式。 对多声道数据,如果采样交叉模式,使用一块buffer即可,其中各声道的数据交叉传输; 如果使用非交叉模式,需要为各声道分别分配一个buffer,各声道数据分别传输。 */ if((err = snd_pcm_hw_params_set_access (capture_handle,hw_params,SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { printf("无法设置访问类型(%s)\n",snd_strerror(err)); exit(1); } printf("访问类型设置成功.\n"); /*设置数据编码格式,并判断是否设置成功*/ if ((err=snd_pcm_hw_params_set_format(capture_handle, hw_params,format)) < 0) { printf("无法设置格式 (%s)\n",snd_strerror(err)); exit(1); } fprintf(stdout, "PCM数据格式设置成功.\n"); /*设置采样频率,并判断是否设置成功*/ if((err=snd_pcm_hw_params_set_rate_near(capture_handle,hw_params,&rate,0))<0) { printf("无法设置采样率(%s)\n",snd_strerror(err)); exit(1); } printf("采样率设置成功\n"); /*设置声道,并判断是否设置成功*/ if((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params,AUDIO_CHANNEL_SET)) < 0) { printf("无法设置声道数(%s)\n",snd_strerror(err)); exit(1); } printf("声道数设置成功.\n"); /*将配置写入驱动程序中,并判断是否配置成功*/ if ((err=snd_pcm_hw_params (capture_handle,hw_params))<0) { printf("无法向驱动程序设置参数(%s)\n",snd_strerror(err)); exit(1); } printf("参数设置成功.\n"); /*使采集卡处于空闲状态*/ snd_pcm_hw_params_free(hw_params); /*准备音频接口,并判断是否准备好*/ if((err=snd_pcm_prepare(capture_handle))<0) { printf("无法使用音频接口 (%s)\n",snd_strerror(err)); exit(1); } printf("音频接口准备好.\n"); /*配置一个数据缓冲区用来缓冲数据*/ //snd_pcm_format_width(format) 获取样本格式对应的大小(单位是:bit) int frame_byte=snd_pcm_format_width(format)/8; buffer=malloc(buffer_frames*frame_byte*AUDIO_CHANNEL_SET); //2048 printf("缓冲区分配成功.\n"); /*开始采集音频pcm数据*/ printf("开始采集数据...\n"); while(1) { /*从声卡设备读取一帧音频数据:2048字节*/ if((err=snd_pcm_readi(capture_handle,buffer,buffer_frames))!=buffer_frames) { printf("从音频接口读取失败(%s)\n",snd_strerror(err)); exit(1); } /*写数据到文件: 音频的每帧数据样本大小是16位=2个字节*/ fwrite(buffer,(buffer_frames*AUDIO_CHANNEL_SET),frame_byte,pcm_data_file); if(run_flag) { printf("停止采集.\n"); break; } } /*释放数据缓冲区*/ free(buffer); /*关闭音频采集卡硬件*/ snd_pcm_close(capture_handle); /*关闭文件流*/ fclose(pcm_data_file); return 0; }
四、参考代码:从文件读取PCM数据,再写入到声卡设备,实现声音播放功能
下面代码在命令行通过gcc编译运行: 读取文件PCM音频数据,写入到声卡进行播放,结束播放可以按下Ctrl+C即可结束。
1 /* 2 进行音频采集,读取存放pcm数据的文件通过声卡进行播放 3 音频参数: 4 声道数: 1 5 采样位数: 16bit、LE格式 6 采样频率: 44100Hz 7 8 运行示例: 9 $ gcc linux_pcm_save.c -lasound 10 $ ./a.out hw:0 123.pcm 11 */ 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <alsa/asoundlib.h> 16 #include <signal.h> 17 18 #define AudioFormat SND_PCM_FORMAT_S16_LE //指定音频的格式,其他常用格式:SND_PCM_FORMAT_U24_LE、SND_PCM_FORMAT_U32_LE 19 #define AUDIO_CHANNEL_SET 1 //1单声道 2立体声 20 #define AUDIO_RATE_SET 44100 //音频采样率,常用的采样频率: 44100Hz 、16000HZ、8000HZ、48000HZ、22050HZ 21 22 FILE *pcm_data_file=NULL; 23 int run_flag=0; 24 void exit_sighandler(int sig) 25 { 26 run_flag=1; 27 } 28 29 30 // 31 int main(int argc, char *argv[]) 32 { 33 int i; 34 int err; 35 char *buffer; 36 int buffer_frames = 1024; 37 unsigned int rate = AUDIO_RATE_SET; 38 snd_pcm_t *capture_handle;// 一个指向PCM设备的句柄 39 snd_pcm_hw_params_t *hw_params; //此结构包含有关硬件的信息,可用于指定PCM流的配置 40 41 /*注册信号捕获退出接口*/ 42 signal(2,exit_sighandler); 43 44 /*PCM的采样格式在pcm.h文件里有定义*/ 45 snd_pcm_format_t format=AudioFormat; // 采样位数:16bit、LE格式 46 47 /*打开音频采集卡硬件,并判断硬件是否打开成功,若打开失败则打印出错误提示*/ 48 // SND_PCM_STREAM_PLAYBACK 输出流 49 // SND_PCM_STREAM_CAPTURE 输入流 50 if ((err = snd_pcm_open (&capture_handle, argv[1],SND_PCM_STREAM_PLAYBACK,0))<0) 51 { 52 printf("无法打开音频设备: %s (%s)\n", argv[1],snd_strerror (err)); 53 exit(1); 54 } 55 printf("音频接口打开成功.\n"); 56 57 /*打开存放PCM数据的文件*/ 58 if((pcm_data_file = fopen(argv[2], "rb")) == NULL) 59 { 60 printf("无法打开%s音频文件.\n",argv[2]); 61 exit(1); 62 } 63 printf("用于播放的音频文件已打开.\n"); 64 65 /*分配硬件参数结构对象,并判断是否分配成功*/ 66 if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) 67 { 68 printf("无法分配硬件参数结构 (%s)\n",snd_strerror(err)); 69 exit(1); 70 } 71 printf("硬件参数结构已分配成功.\n"); 72 73 /*按照默认设置对硬件对象进行设置,并判断是否设置成功*/ 74 if((err=snd_pcm_hw_params_any(capture_handle,hw_params)) < 0) 75 { 76 printf("无法初始化硬件参数结构 (%s)\n", snd_strerror(err)); 77 exit(1); 78 } 79 printf("硬件参数结构初始化成功.\n"); 80 81 /* 82 设置数据为交叉模式,并判断是否设置成功 83 interleaved/non interleaved:交叉/非交叉模式。 84 表示在多声道数据传输的过程中是采样交叉的模式还是非交叉的模式。 85 对多声道数据,如果采样交叉模式,使用一块buffer即可,其中各声道的数据交叉传输; 86 如果使用非交叉模式,需要为各声道分别分配一个buffer,各声道数据分别传输。 87 */ 88 if((err = snd_pcm_hw_params_set_access (capture_handle,hw_params,SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) 89 { 90 printf("无法设置访问类型(%s)\n",snd_strerror(err)); 91 exit(1); 92 } 93 printf("访问类型设置成功.\n"); 94 95 /*设置数据编码格式,并判断是否设置成功*/ 96 if ((err=snd_pcm_hw_params_set_format(capture_handle, hw_params,format)) < 0) 97 { 98 printf("无法设置格式 (%s)\n",snd_strerror(err)); 99 exit(1); 100 } 101 fprintf(stdout, "PCM数据格式设置成功.\n"); 102 103 /*设置采样频率,并判断是否设置成功*/ 104 if((err=snd_pcm_hw_params_set_rate_near(capture_handle,hw_params,&rate,0))<0) 105 { 106 printf("无法设置采样率(%s)\n",snd_strerror(err)); 107 exit(1); 108 } 109 printf("采样率设置成功\n"); 110 111 /*设置声道,并判断是否设置成功*/ 112 if((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params,AUDIO_CHANNEL_SET)) < 0) 113 { 114 printf("无法设置声道数(%s)\n",snd_strerror(err)); 115 exit(1); 116 } 117 printf("声道数设置成功.\n"); 118 119 /*将配置写入驱动程序中,并判断是否配置成功*/ 120 if ((err=snd_pcm_hw_params (capture_handle,hw_params))<0) 121 { 122 printf("无法向驱动程序设置参数(%s)\n",snd_strerror(err)); 123 exit(1); 124 } 125 printf("参数设置成功.\n"); 126 127 /*使采集卡处于空闲状态*/ 128 snd_pcm_hw_params_free(hw_params); 129 130 /*准备音频接口,并判断是否准备好*/ 131 if((err=snd_pcm_prepare(capture_handle))<0) 132 { 133 printf("无法使用音频接口 (%s)\n",snd_strerror(err)); 134 exit(1); 135 } 136 printf("音频接口准备好.\n"); 137 138 /*配置一个数据缓冲区用来缓冲数据*/ 139 //snd_pcm_format_width(format) 获取样本格式对应的大小(单位是:bit) 140 int frame_byte=snd_pcm_format_width(format)/8; 141 buffer=malloc(buffer_frames*frame_byte*AUDIO_CHANNEL_SET); 142 printf("缓冲区分配成功.\n"); 143 144 /*开始采集音频pcm数据*/ 145 printf("开始播放音频数据...\n"); 146 147 int read_cnt; 148 while(1) 149 { 150 /*从文件读取数据: 音频的每帧数据样本大小是16位-2个字节*/ 151 read_cnt=fread(buffer,1,frame_byte*(buffer_frames*AUDIO_CHANNEL_SET),pcm_data_file); 152 if(read_cnt<=0)break; 153 154 /*向声卡设备写一帧音频数据:2048字节*/ 155 if((err=snd_pcm_writei(capture_handle,buffer,buffer_frames))!=buffer_frames) 156 { 157 printf("向音频接口写数据失败(%s)\n",snd_strerror(err)); 158 exit(1); 159 } 160 161 if(run_flag) 162 { 163 printf("停止播放.\n"); 164 break; 165 } 166 } 167 printf("播放完成.\n"); 168 /*释放数据缓冲区*/ 169 free(buffer); 170 171 /*关闭音频采集卡硬件*/ 172 snd_pcm_close(capture_handle); 173 174 /*关闭文件流*/ 175 fclose(pcm_data_file); 176 return 0; 177 } 178
浙公网安备 33010602011771号