Linux下基于alsa录制wav文件
#include "alsa/asoundlib.h"
/* this buffer holds the digitized audio */
//unsigned char buf[LENGTH*RATE*SIZE*CHANNELS/8];
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef unsigned int FOURCC; /* a four character code */
/* flags for 'wFormatTag' field of WAVEFORMAT */
#define WAVE_FORMAT_PCM 1
/* MMIO macros */
#define mmioFOURCC(ch0, ch1, ch2, ch3) \
((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
#define FOURCC_RIFF mmioFOURCC ('R', 'I', 'F', 'F')
#define FOURCC_LIST mmioFOURCC ('L', 'I', 'S', 'T')
#define FOURCC_WAVE mmioFOURCC ('W', 'A', 'V', 'E')
#define FOURCC_FMT mmioFOURCC ('f', 'm', 't', ' ')
#define FOURCC_DATA mmioFOURCC ('d', 'a', 't', 'a')
typedef struct CHUNKHDR {
FOURCC ckid; /* chunk ID */
DWORD dwSize; /* chunk size */
} CHUNKHDR;
/* simplified Header for standard WAV files */
typedef struct WAVEHDR {
CHUNKHDR chkRiff;
FOURCC fccWave;
CHUNKHDR chkFmt;
WORD wFormatTag; /* format type */
WORD nChannels; /* number of channels (i.e. mono, stereo, etc.) */
DWORD nSamplesPerSec; /* sample rate */
DWORD nAvgBytesPerSec; /* for buffer estimation */
WORD nBlockAlign; /* block size of data */
WORD wBitsPerSample;
CHUNKHDR chkData;
} WAVEHDR;
#if BYTE_ORDER == BIG_ENDIAN
# define cpu_to_le32(x) SWAP4((x))
# define cpu_to_le16(x) SWAP2((x))
# define le32_to_cpu(x) SWAP4((x))
# define le16_to_cpu(x) SWAP2((x))
#else
# define cpu_to_le32(x) (x)
# define cpu_to_le16(x) (x)
# define le32_to_cpu(x) (x)
# define le16_to_cpu(x) (x)
#endif
static void wav_init_header(WAVEHDR *fileheader)
{
/* stolen from cdda2wav */
int nBitsPerSample = 16;
int channels = 2;
int rate = 44100;
unsigned long nBlockAlign = channels * ((nBitsPerSample + 7) / 8);
unsigned long nAvgBytesPerSec = nBlockAlign * rate;
unsigned long temp = /* data length */ 0 +
sizeof(WAVEHDR) - sizeof(CHUNKHDR);
fileheader->chkRiff.ckid = cpu_to_le32(FOURCC_RIFF);
fileheader->fccWave = cpu_to_le32(FOURCC_WAVE);
fileheader->chkFmt.ckid = cpu_to_le32(FOURCC_FMT);
fileheader->chkFmt.dwSize = cpu_to_le32(16);
fileheader->wFormatTag = cpu_to_le16(WAVE_FORMAT_PCM);
fileheader->nChannels = cpu_to_le16(channels);
fileheader->nSamplesPerSec = cpu_to_le32(rate);
fileheader->nAvgBytesPerSec = cpu_to_le32(nAvgBytesPerSec);
fileheader->nBlockAlign = cpu_to_le16(nBlockAlign);
fileheader->wBitsPerSample = cpu_to_le16(nBitsPerSample);
fileheader->chkData.ckid = cpu_to_le32(FOURCC_DATA);
fileheader->chkRiff.dwSize = cpu_to_le32(temp);
fileheader->chkData.dwSize = cpu_to_le32(0 /* data length */);
}
static void wav_start_write(FILE* fd, WAVEHDR *fileheader)
{
wav_init_header(fileheader);
fwrite(fileheader,1, sizeof(WAVEHDR), fd);
}
static void wav_stop_write(FILE* fd, WAVEHDR *fileheader, int wav_size)
{
unsigned long temp = wav_size + sizeof(WAVEHDR) - sizeof(CHUNKHDR);
fileheader->chkRiff.dwSize = cpu_to_le32(temp);
fileheader->chkData.dwSize = cpu_to_le32(wav_size);
fseek(fd,0,SEEK_SET);
fwrite(fileheader,1, sizeof(WAVEHDR), fd);
}
int init_pcm_capture(snd_pcm_t **handle,snd_pcm_uframes_t *frame)
{
//1.定义pcm句柄
//snd_pcm_t *handle = NULL;
snd_pcm_hw_params_t *params = NULL;
//2.打开pcm设备---采集方式打开
//(SND_PCM_STREAM_CAPTURE:打开模式)
snd_pcm_open(handle, "default", SND_PCM_STREAM_CAPTURE, 0);
//3 分配参数空间, 设置默认参数
snd_pcm_hw_params_alloca(¶ms);
//分配空间
snd_pcm_hw_params_any(*handle, params); //默认值
//4.设置交错模式
snd_pcm_hw_params_set_access(*handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
//5设置量化
snd_pcm_hw_params_set_format(*handle, params, SND_PCM_FORMAT_S16_LE);
//6设置通道数据
snd_pcm_hw_params_set_channels(*handle, params, 2);
//7设置采样率
int val = 44100;
snd_pcm_hw_params_set_rate_near(*handle, params, &val,0);
//8把设置好的参数设置到pcm设备
snd_pcm_hw_params(*handle,params);
//9.分配一个周期空间
//获取一个周期的帧数
snd_pcm_hw_params_get_period_size(params, frame, 0);
}
int main(void)
{
WAVEHDR wavheader;
int total_len = 0;
int ret;
snd_pcm_t *handle = NULL;
snd_pcm_uframes_t frame = 0;
init_pcm_capture(&handle,&frame);
int size = frame * 4;//计算一个周期所需要的存储空间
unsigned char *buffer = malloc(size);//分配一个周期的空间
FILE *fp = fopen("rec.wav","wb");
wav_start_write(fp, &wavheader);
int t = (int)(44100 * 5.0)/frame;//计算1s内的周期
while(t --)
{
snd_pcm_readi(handle, buffer, frame);//采集一个周期数据
ret = fwrite(buffer,1,size,fp);
total_len += size;
if(ret != size)
{
printf("size is %d\n",size);
printf("short wrote:%d\n",size-ret);
printf("fwrite data error\n");
}
}
wav_stop_write(fp, &wavheader, total_len);
//销毁pcm句柄
snd_pcm_drain(handle);
//关闭pcm设备
snd_pcm_close(handle);
//释放堆空间(存储一个周期数据)
free(buffer);
fclose(fp);
return 0;
}