ALSA是Advanced Linux Sound Architecture 的缩写,目前已经成为了linux的主流音频体系结构。
在内核设备驱动层,ALSA提供了alsa-driver,同时在应用层,ALSA为我们提供了alsa-lib,应用程序只要调用alsa-lib提供的API,即可以完成对底层音频硬件的控制。
实现录音功能代码:
/*This example reads from the default PCM device
and writes to standard output for 5 seconds of data.*/
#include <alsa/asoundlib.h>
#include <math.h>#define BUFFERSIZE 4096
#define PERIOD_SIZE 1024
#define PERIODS 2
#define SAMPLE_RATE 16000
#define CHANNELS 2
#define FSIZE 2*CHANNELS/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_APIint main(int argc, char *argv[]) {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;if(argc ==2){file = argv[1];}else{file = "output.raw";}fd = open(file,O_WRONLY|O_CREAT,0777);if( fd ==-1){printf("open file:%s fail.\n",file);exit(1);}/* Open PCM device for recording (capture). */err = snd_pcm_open(&handle, "default",SND_PCM_STREAM_CAPTURE, 0);if (err < 0) {fprintf(stderr,"unable to open pcm device: %s\n",snd_strerror(err));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 */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) */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);}/* Set buffer time 500000. */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);}/* Write the parameters to the driver */err = snd_pcm_hw_params(handle, params);if (err < 0) {fprintf(stderr,"unable to set hw parameters: %s\n",snd_strerror(err));exit(1);}/* Use a buffer large enough to hold one period */snd_pcm_hw_params_get_period_size(params,&frames, &dir);size = frames * FSIZE; /* 2 bytes/sample, 1 channels */buffer = (char *) malloc(size);printf("period size = %d frames\n", (int)frames);printf("read buffer size = %d\n",size);/* We want to loop for 5 seconds */snd_pcm_hw_params_get_period_time(params,&val, &dir);printf("period time is: %d\n",val);loops = 100;/*print alsa config parameter*/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);while (loops > 0) {loops--;rc = snd_pcm_readi(handle, buffer, frames);if (rc == -EPIPE) {// EPIPE means overrun fprintf(stderr, "overrun occurred\n");err=snd_pcm_prepare(handle);if( err <0){fprintf(stderr, "Failed to recover form overrun : %s\n",snd_strerror(err));exit(1);}}else if (rc < 0) {fprintf(stderr,"error from read: %s\n",snd_strerror(rc));exit(1);} else if (rc != (int)frames) {fprintf(stderr, "short read, read %d frames\n", rc);}rc = write(fd, buffer, size);if (rc <0){perror("fail to write to audio file\n");}}close(fd);snd_pcm_drain(handle);snd_pcm_close(handle);free(buffer);return 0;
}
实现播放声音代码:
#define ALSA_PCM_NEW_HW_PARAMS_API
//#include "alsahead.h"
#include <alsa/asoundlib.h>
#include <math.h>#define BUFFERSIZE 4096
#define PERIOD_SIZE 1024
#define PERIODS 2
#define SAMPLE_RATE 16000
#define CHANNELS 2
#define FSIZE 2*CHANNELS/*
*Usage: play audio.raw
*
*/int main(int argc, char *argv[]) {long loops;int rc;int size;snd_pcm_t *handle;snd_pcm_hw_params_t *params;unsigned int val;int dir;snd_pcm_uframes_t frames;char *buffer;char *inFile;int fd;int err;if(argc ==2){inFile = argv[1];}else{inFile = "output.raw";}fd = open(inFile,O_RDONLY);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 */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) */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);while (loops > 0) {loops--;rc = read(fd, buffer, size);if (rc == 0) {fprintf(stderr, "end of file on input\n");break;} else if (rc != size) {fprintf(stderr,"short read: read %d bytes\n", rc);}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);}}snd_pcm_drain(handle);snd_pcm_close(handle);free(buffer);close(fd);return 0;
}