简介
linux环境使用ALSA实现声音录制,保存pcm到本地文件。
代码
void AudioCapture::run()
{
qDebug() << "AudioCapture start";
snd_pcm_t *pcm_st_ = nullptr;
std::string device_name = "default";
int ret = snd_pcm_open(&pcm_st_, device_name.c_str(), SND_PCM_STREAM_CAPTURE, 0);
if(ret < 0)
{
qDebug("error capture snd_pcm_open %s\n", device_name.c_str());
return ;
}
snd_pcm_hw_params_t *param = nullptr;
snd_pcm_hw_params_malloc(¶m);
snd_pcm_hw_params_any(pcm_st_, param);
//设置参数
unsigned int sample_rate = 16000;
int channel = 1;
snd_pcm_format_t pcmFormat = SND_PCM_FORMAT_S16_LE;
ret = snd_pcm_hw_params_set_access(pcm_st_, param, SND_PCM_ACCESS_RW_INTERLEAVED);
if(ret < 0)
{
qDebug("snd_pcm_hw_params_set_access SND_PCM_ACCESS_RW_INTERLEAVED\n");
return;
}
ret = snd_pcm_hw_params_set_format(pcm_st_, param, pcmFormat);
if(ret < 0)
{
qDebug("snd_pcm_hw_params_set_format SND_PCM_FORMAT_S16_LE\n");
return;
}
ret = snd_pcm_hw_params_set_channels(pcm_st_, param, channel);
if(ret < 0)
{
qDebug("snd_pcm_hw_params_set_channels\n");
return;
}
int dir = 0;
ret = snd_pcm_hw_params_set_rate_near(pcm_st_, param, &sample_rate, &dir);
if(ret < 0)
{
qDebug("snd_pcm_hw_params_set_rate_near %d\n", sample_rate);
return;
}
//设置缓存采样点数
dir = 0;
snd_pcm_uframes_t frames = 512;
ret = snd_pcm_hw_params_set_period_size_near(pcm_st_, param, &frames, &dir);
if(ret < 0)
{
qDebug("snd_pcm_hw_params_set_period_size_near\n");
return;
}
snd_pcm_uframes_t buffer_frames = frames ;
ret = snd_pcm_hw_params_set_buffer_size_near(pcm_st_, param, &buffer_frames);
if(ret < 0)
{
qDebug("snd_pcm_hw_params_set_buffer_size_near\n");
return;
}
ret = snd_pcm_hw_params(pcm_st_, param);
if(ret < 0)
{
qDebug("snd_pcm_hw_params\n");
return;
}
// 设置缓存buffer 2倍大小 frames*2字节(单采样点16bit)*声道数
int bufferSize = frames * channel * 2;
uint8_t *audio_buffer = (uint8_t *)malloc(bufferSize * 2);
if(! audio_buffer)
{
qDebug("malloc audio buffer\n");
return;
}
//创建pcm文件
FILE *file = fopen("./16000_1_s16.pcm", "wb");
if(!file)
{
qDebug("fopen pcm error\n");
m_isRun = false;
}
// 开始捕捉
snd_pcm_start(pcm_st_);
// 读取音频数据
while (m_isRun)
{
// 阻塞读取一次数据
/**
* if the blocking behaviour was selected and it is running, then routine waits until all requested frames are filled
* the returned number of frames can be less only a signal or underrun occurred
*/
int readFrames = snd_pcm_readi(pcm_st_, audio_buffer, frames);
if(readFrames == -EPIPE)
{
ret = snd_pcm_prepare(pcm_st_);
if(ret < 0)
{
qDebug("failed to recover form overrun");
}
}
else if(ret < 0)
{
qDebug("error from read:%s\n", snd_strerror(ret));
return;
}
//处理数据
int readSize = readFrames * 2 * channel;
fwrite(audio_buffer, readSize, 1, file);
}
// 释放硬件参数内存
snd_pcm_hw_params_free(param);
// 关闭捕捉设备
snd_pcm_close(pcm_st_);
//关闭文件
fclose(file);
if(audio_buffer)
{
free(audio_buffer);
audio_buffer = nullptr;
}
qDebug() << "AudioCapture stop";
}