碰到一个开发 板录音的项目,结合网上的资料,自己总结 了一篇
头文件
#ifndef __RECORD_H
#define __RECORD_H
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include "threadsafe_queue.h"
typedef long long off64_t;
typedef struct SNDPCMContainer {
snd_pcm_t *handle;
snd_output_t *log;
snd_pcm_uframes_t chunk_size;
snd_pcm_uframes_t buffer_size;
snd_pcm_format_t format;
uint16_t channels;//声道
size_t chunk_bytes;
uint32_t sample_rate;//采样率
size_t bits_per_sample;//比特率
size_t bits_per_frame;
uint8_t *data_buf;
//uint16_t isrecord;
} SNDPCMContainer_t;
ssize_t SND_ReadPcm(SNDPCMContainer_t *sndpcm, size_t rcount);
void SND_Record(SNDPCMContainer_t *sndpcm, int duration_time, int fd);
int SND_SetParams(SNDPCMContainer_t *sndpcm, uint32_t sample_rate,uint16_t channels,uint16_t bits);
ssize_t SNDWAV_ReadPcm(SNDPCMContainer_t *sndpcm, size_t rcount);
#endif
实现文件
#include <stdio.h>#include <malloc.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <time.h>
#include <locale.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "record.h"
#include <assert.h>
#include <sys/time.h>
#include "common.h"
#define DEFAULT_CHANNELS (8)
#define DEFAULT_SAMPLE_RATE (96000)
#define DEFAULT_BITS (32)
#define DEFAULT_DURATION_TIME (10)
ssize_t SND_ReadPcm(SNDPCMContainer_t *sndpcm, size_t rcount)
{
ssize_t r;
size_t result = 0;
size_t count = rcount;
uint8_t *data = sndpcm->data_buf;
if (count != sndpcm->chunk_size) {
count = sndpcm->chunk_size;
}
while (count > 0) {
r = snd_pcm_readi(sndpcm->handle, data, count);
if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {
snd_pcm_wait(sndpcm->handle, 1000);
} else if (r == -EPIPE) {
snd_pcm_prepare(sndpcm->handle);
fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
} else if (r == -ESTRPIPE) {
fprintf(stderr, "<<<<<<<<<<<<<<< Need suspend >>>>>>>>>>>>>>>\n");
} else if (r < 0) {
fprintf(stderr, "Error snd_pcm_writei: [%s]", snd_strerror(r));
return -1;
}
if (r > 0) {
result += r;
count -= r;
data += r * sndpcm->bits_per_frame / 8;
}
}
return rcount;
}
int SND_SetParams(SNDPCMContainer_t *sndpcm, uint32_t sample_rate,uint16_t channels,uint16_t bits )
{
snd_pcm_hw_params_t *hwparams;
snd_pcm_format_t format;
switch (bits) {
case 16:
format = SND_PCM_FORMAT_S16_LE;
break;
case 8:
format = SND_PCM_FORMAT_U8;
break;
case 32:
format = SND_PCM_FORMAT_S32_LE;
break;
default:
format = SND_PCM_FORMAT_UNKNOWN;
break;
}
uint32_t exact_rate;
uint32_t buffer_time, period_time;
/* Allocate the snd_pcm_hw_params_t structure on the stack. */
snd_pcm_hw_params_alloca(&hwparams);
/* Init hwparams with full configuration space */
if (snd_pcm_hw_params_any(sndpcm->handle, hwparams) < 0) {
fprintf(stderr, "Error snd_pcm_hw_params_any\n");
goto ERR_SET_PARAMS;
}
if (snd_pcm_hw_params_set_access(sndpcm->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
fprintf(stderr, "Error snd_pcm_hw_params_set_access\n");
goto ERR_SET_PARAMS;
}
if (snd_pcm_hw_params_set_format(sndpcm->handle, hwparams, format) < 0) {
fprintf(stderr, "Error snd_pcm_hw_params_set_format\n");
goto ERR_SET_PARAMS;
}
sndpcm->format = format;
/* Set number of channels */
if (snd_pcm_hw_params_set_channels(sndpcm->handle, hwparams, channels) < 0) {
fprintf(stderr, "Error snd_pcm_hw_params_set_channels\n");
goto ERR_SET_PARAMS;
}
sndpcm->channels = channels;
/* Set sample rate. If the exact rate is not supported */
/* by the hardware, use nearest possible rate. */
exact_rate = sample_rate;
if (snd_pcm_hw_params_set_rate_near(sndpcm->handle, hwparams, &exact_rate, 0) < 0) {
fprintf(stderr, "Error snd_pcm_hw_params_set_rate_near\n");
goto ERR_SET_PARAMS;
}
if (sample_rate != exact_rate) {
fprintf(stderr, "The rate %d Hz is not supported by your hardware.\n ==> Using %d Hz instead.\n",
sample_rate, exact_rate);
}
sndpcm->sample_rate = exact_rate;
if (snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0) < 0) {
fprintf(stderr, "Error snd_pcm_hw_params_get_buffer_time_max\n");
goto ERR_SET_PARAMS;
}
//printf("buffer_time = %ld\n",buffer_time);
if (buffer_time > 40000) buffer_time = 40000;
//printf("buffer_time2 = %ld\n",buffer_time);
period_time = buffer_time / 4;
if (snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, hwparams, &buffer_time, 0) < 0) {
fprintf(stderr, "Error snd_pcm_hw_params_set_buffer_time_near\n");
goto ERR_SET_PARAMS;
}
if (snd_pcm_hw_params_set_period_time_near(sndpcm->handle, hwparams, &period_time, 0) < 0) {
fprintf(stderr, "Error snd_pcm_hw_params_set_period_time_near\n");
goto ERR_SET_PARAMS;
}
/* Set hw params */
if (snd_pcm_hw_params(sndpcm->handle, hwparams) < 0) {
fprintf(stderr, "Error snd_pcm_hw_params(handle, params)\n");
goto ERR_SET_PARAMS;
}
snd_pcm_hw_params_get_period_size(hwparams, &sndpcm->chunk_size, 0);
snd_pcm_hw_params_get_buffer_size(hwparams, &sndpcm->buffer_size);
if (sndpcm->chunk_size == sndpcm->buffer_size) {
fprintf(stderr, ("Can't use period equal to buffer size (%lu == %lu)\n"), sndpcm->chunk_size, sndpcm->buffer_size);
goto ERR_SET_PARAMS;
}
sndpcm->bits_per_sample = snd_pcm_format_physical_width(format);
sndpcm->bits_per_frame = sndpcm->bits_per_sample * channels;
sndpcm->chunk_bytes = sndpcm->chunk_size * sndpcm->bits_per_frame / 8;
/* Allocate audio data buffer */
sndpcm->data_buf = (uint8_t *)malloc(sndpcm->chunk_bytes);
if (!sndpcm->data_buf) {
fprintf(stderr, "Error malloc: [data_buf]\n");
goto ERR_SET_PARAMS;
}
return 0;
ERR_SET_PARAMS:
return -1;
}
int main(){
char curtime[20] = {'\0'};
int recordState = 1;
const char *devicename = "hw:0,0";
SNDPCMContainer_t sndpcm;
memset(&sndpcm, 0x0, sizeof(sndpcm));
const char *filename;
filename = "test.pcm";
int fd;
if ((fd = open(filename, O_WRONLY | O_CREAT, 0644)) == -1) {
fprintf(stderr, "Error open: [%s]/n", filename);
return -1;
}
if (snd_output_stdio_attach(&sndpcm.log, stderr, 0) < 0) {
fprintf(stderr, "Error snd_output_stdio_attach\n");
snd_pcm_drain(sndpcm.handle);
free(sndpcm.data_buf);
snd_output_close(sndpcm.log);
snd_pcm_close(sndpcm.handle);
return -1;
}
if (snd_pcm_open(&sndpcm.handle, devicename, SND_PCM_STREAM_CAPTURE, 0) < 0) {
fprintf(stderr, "Error snd_pcm_open [ %s]\n", devicename);
snd_pcm_drain(sndpcm.handle);
free(sndpcm.data_buf);
snd_output_close(sndpcm.log);
snd_pcm_close(sndpcm.handle);
return -1;
}
uint16_t channels = DEFAULT_CHANNELS;
uint32_t sample_rate = DEFAULT_SAMPLE_RATE;
uint16_t bits = DEFAULT_BITS;
uint32_t duration_time = DEFAULT_DURATION_TIME;
if (SND_SetParams(&sndpcm, sample_rate,channels,bits ) < 0) {
fprintf(stderr, "Error set_snd_pcm_params\n");
snd_pcm_drain(sndpcm.handle);
free(sndpcm.data_buf);
snd_output_close(sndpcm.log);
snd_pcm_close(sndpcm.handle);
return -1;
}
snd_pcm_dump(sndpcm.handle, sndpcm.log);
uint32_t c,frame_size;
getTime(curtime);
printf("%s 准备进入录音流程,录音状态码=%d\n",curtime,*(pcapture_info->isrecord));
while (recordState) {
//printf("进入录音流程,录音状态码=%d\n",*(pcapture_info->isrecord));
c = sndpcm.chunk_bytes;
frame_size = sndpcm.chunk_bytes * 8 / sndpcm.bits_per_frame;
if (SND_ReadPcm(&sndpcm, frame_size) != frame_size){
getTime(curtime);
printf("%s 读PCM失败\n",curtime);
snd_pcm_drain(sndpcm.handle);
free(sndpcm.data_buf);
snd_output_close(sndpcm.log);
snd_pcm_close(sndpcm.handle);
return -2;
}
write(fd, sndpcm.data_buf, c);
}
close(fd);
snd_pcm_drain(sndpcm.handle);
free(sndpcm.data_buf);
snd_output_close(sndpcm.log);
snd_pcm_close(sndpcm.handle);
getTime(curtime);
printf("%s 录音任务结束,文件关闭!\n",curtime);
return 0;
}
编译
arm-linux-g++ -o record record.cpp -lasound -std=c++11