#include "record.h"
Record::Record(QObject *parent) : QThread(parent)
{
}
int Record::snd_pcm_init()
{
snd_pcm_hw_params_t *hwparams = NULL;
int ret;
/* 打开PCM设备 */
ret = snd_pcm_open(&pcm, PCM_PLAYBACK_DEV, SND_PCM_STREAM_CAPTURE, 0);
if (0 > ret) {
fprintf(stderr, "snd_pcm_open error: %s: %s\n",
PCM_PLAYBACK_DEV, snd_strerror(ret));
return -1;
}
/* 实例化hwparams对象 */
snd_pcm_hw_params_malloc(&hwparams);
/* 获取PCM设备当前硬件配置,对hwparams进行初始化 */
ret = snd_pcm_hw_params_any(pcm, hwparams);
if (0 > ret) {
fprintf(stderr, "snd_pcm_hw_params_any error: %s\n", snd_strerror(ret));
snd_pcm_hw_params_free(hwparams); //释放内存
snd_pcm_close(pcm);
return -1;
}
/**************
设置参数
***************/
/* 设置访问类型: 交错模式 */
ret = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
if (0 > ret) {
fprintf(stderr, "snd_pcm_hw_params_set_access error: %s\n", snd_strerror(ret));
snd_pcm_hw_params_free(hwparams); //释放内存
snd_pcm_close(pcm);
return -1;
}
/* 设置数据格式: 有符号16位、小端模式 */
ret = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE);
if (0 > ret) {
fprintf(stderr, "snd_pcm_hw_params_set_format error: %s\n", snd_strerror(ret));
snd_pcm_hw_params_free(hwparams); //释放内存
snd_pcm_close(pcm);
return -1;
}
/* 设置采样率 */
ret = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &head.fmt.SampleRate, 0);
if (0 > ret) {
fprintf(stderr, "snd_pcm_hw_params_set_rate error: %s\n", snd_strerror(ret));
snd_pcm_hw_params_free(hwparams); //释放内存
snd_pcm_close(pcm);
return -1;
}
/* 设置声道数: 双声道 */
ret = snd_pcm_hw_params_set_channels(pcm, hwparams, head.fmt.NumChannels);
if (0 > ret) {
fprintf(stderr, "snd_pcm_hw_params_set_channels error: %s\n", snd_strerror(ret));
snd_pcm_hw_params_free(hwparams); //释放内存
snd_pcm_close(pcm);
return -1;
}
snd_pcm_uframes_t frames_per_buffer = 0;
snd_pcm_hw_params_get_buffer_size_max(hwparams, &frames_per_buffer);
ret = snd_pcm_hw_params_set_buffer_size_near(pcm, hwparams, &frames_per_buffer);
if(ret < 0)
{
qDebug() << "error";
}
period_size = frames_per_buffer / 4;
/* 设置周期大小: period_size */
ret = snd_pcm_hw_params_set_period_size_near(pcm, hwparams, &period_size, 0);
if (0 > ret) {
fprintf(stderr, "snd_pcm_hw_params_set_period_size error: %s\n", snd_strerror(ret));
snd_pcm_hw_params_free(hwparams); //释放内存
snd_pcm_close(pcm);
return -1;
}
/* 使配置生效 */
ret = snd_pcm_hw_params(pcm, hwparams);
snd_pcm_hw_params_free(hwparams); //释放hwparams对象占用的内存
if (0 > ret) {
fprintf(stderr, "snd_pcm_hw_params error: %s\n", snd_strerror(ret));
snd_pcm_close(pcm);
return -1;
}
snd_pcm_hw_params_get_period_size(hwparams,&period_size, 0);
buf_bytes = period_size * head.fmt.BlockAlign; //变量赋值,一个周期的字节大小
return 0;
}
void Record::Start(const char *file)
{
if(open_wav_file(file) >= 0)
{
if(snd_pcm_init() >= 0)
{
qDebug() << "start record";
isRecord = true;
start();
}
}
}
void Record::Stop()
{
isRecord = false;
}
int Record::open_wav_file(const char *file)
{
int ret = 0;
fd = open(file, O_CREAT | O_WRONLY, 0666);
if (0 > fd)
{
fprintf(stderr, "open error: %s: %s\n", file, strerror(errno));
return -1;
}
memcpy(head.riff.ChunkID, "RIFF", strlen("RIFF"));
head.riff.size = 0; //后面填
memcpy(head.riff.Format, "WAVE", strlen("WAVE"));
memcpy(head.fmt.Subchunk1ID, "fmt ", strlen("fmt "));
head.fmt.Subchunk1Size = 16;
head.fmt.AudioFormat = 1;
head.fmt.NumChannels = channels;
head.fmt.SampleRate = samplerate;
head.fmt.ByteRate = samplerate * (channels * bits / 8);
head.fmt.BlockAlign = channels * bits / 8;
head.fmt.BitsPerSample = bits;
memcpy(head.data.Subchunk2ID, "data ", strlen("data"));
head.data.Subchunk2Size = 0; //后面填
write(fd, &head, sizeof(head));
return ret;
}
void Record::run()
{
unsigned char *buf = (unsigned char *)malloc(buf_bytes);
unsigned long size = 0;
while (isRecord)
{
memset(buf, 0x00, buf_bytes); //buf清零
int ret = snd_pcm_readi(pcm, buf, period_size);//读取PCM数据 一个周期
if (ret == -EPIPE)
{
/* EPIPE means overrun */
fprintf(stderr, "overrun occurred\n");
snd_pcm_prepare(pcm);
}
else if (ret < 0)
{
fprintf(stderr, "snd_pcm_readi error: %s\n", snd_strerror(ret));
break;
}
else if (ret != (int)period_size)
{
fprintf(stderr, "short read, read %d frames\n", ret);
}
/*
for(int i=0; i<buf_bytes; i++)
{
buf[i] *= 1.5;
}
*/
// snd_pcm_readi的返回值ret等于实际读取的帧数 * 4 转为字节数
ret = write(fd, buf, ret * (channels * bits / 8)); //将读取到的数据写入文件中
if (ret <= 0)
{
perror("write fail\n");
break;
}
size += ret;
msleep(10);
}
head.riff.size = size + sizeof(struct Wav_t) - 8;
head.data.Subchunk2Size = size;
// 将文件偏移量移动到文件开头
int offset = lseek(fd, 0, SEEK_SET);
if (offset == -1)
{
perror("lseek error");
}
else
{
write(fd, &head, sizeof(head));
printf("OK\n");
}
close(fd);
free(buf);
snd_pcm_drain(pcm);
snd_pcm_close(pcm);
}