简介
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";
}