Files
MyChat_Client/ChatClient/src/soundrecorder.cpp

132 lines
4.2 KiB
C++

#include "soundrecorder.h"
#include <QDir>
#include <QMediaDevices>
#include "model/data.h"
#include "toast.h"
/////////////////////////////////////////////
/// 单例模式
/////////////////////////////////////////////
SoundRecorder* SoundRecorder::instance = nullptr;
SoundRecorder *SoundRecorder::getInstance()
{
if (instance == nullptr) {
instance = new SoundRecorder();
}
return instance;
}
// 播放参考 https://www.cnblogs.com/tony-yang-flutter/p/16477212.html
// 录制参考 https://doc.qt.io/qt-6/qaudiosource.html
SoundRecorder::SoundRecorder(QObject *parent)
: QObject{parent}
{
// 1. 创建目录
QDir soundRootPath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
soundRootPath.mkdir("sound");
// 2. 初始化录制模块
soundFile.setFileName(RECORD_PATH);
QAudioFormat inputFormat;
inputFormat.setSampleRate(16000);
inputFormat.setChannelCount(1);
inputFormat.setSampleFormat(QAudioFormat::Int16);
QAudioDevice info = QMediaDevices::defaultAudioInput();
if (!info.isFormatSupported(inputFormat)) {
//LOG() << "录制设备, 格式不支持!";
LOG() << "指定格式不支持,尝试使用设备的最佳格式进行录音";
inputFormat = info.preferredFormat();
QAudioFormat preferredFormat = inputFormat;
// 打印查看详细的格式信息
//LOG() << "设备首选格式详情:";
//LOG() << " 采样率 (SampleRate):" << preferredFormat.sampleRate() << "Hz";48000hz
//LOG() << " 声道数 (ChannelCount):" << preferredFormat.channelCount(); 2
//LOG() << " 样本格式 (SampleFormat):" << preferredFormat.sampleFormat(); FLOAT
// 确保至少是单声道
/*if (inputFormat.channelCount() > 1) {
inputFormat.setChannelCount(1);
}*/
//return;
}
audioSource = new QAudioSource(inputFormat, this);
connect(audioSource, &QAudioSource::stateChanged, this, [=](QtAudio::State state) {
if (state == QtAudio::StoppedState) {
// 录制完毕
if (audioSource->error() != QAudio::NoError) {
LOG() << audioSource->error();
}
}
});
// 3. 初始化播放模块
outputDevices = new QMediaDevices(this);
outputDevice = outputDevices->defaultAudioOutput();
QAudioFormat outputFormat;
outputFormat.setSampleRate(16000);
outputFormat.setChannelCount(1);
outputFormat.setSampleFormat(QAudioFormat::Int16);
if (!outputDevice.isFormatSupported(outputFormat)) {
//LOG() << "播放设备, 格式不支持";
LOG() << "指定格式不支持,尝试使用设备的最佳格式进行播放";
outputFormat = outputDevice.preferredFormat();
// 确保至少是单声道
/*if (outputFormat.channelCount() > 1) {
outputFormat.setChannelCount(1);
}*/
//return;
}
audioSink = new QAudioSink(outputDevice, outputFormat);
connect(audioSink, &QAudioSink::stateChanged, this, [=](QtAudio::State state) {
if (state == QtAudio::IdleState) {
LOG() << "IdleState";
this->stopPlay();
emit this->soundPlayDone();
} else if (state == QAudio::ActiveState) {
LOG() << "ActiveState";
} else if (state == QAudio::StoppedState) {
LOG() << "StoppedState";
if (audioSink->error() != QtAudio::NoError) {
LOG() << audioSink->error();
}
}
});
}
void SoundRecorder::startRecord() {
soundFile.open( QIODevice::WriteOnly | QIODevice::Truncate );
audioSource->start(&soundFile);
}
void SoundRecorder::stopRecord() {
audioSource->stop();
soundFile.close();
emit this->soundRecordDone(RECORD_PATH);
}
void SoundRecorder::startPlay(const QByteArray& content) {
if (content.isEmpty()) {
Toast::showMessage("数据加载中, 请稍后播放");
return;
}
// 1. 把数据写入到临时文件
model::writeByteArrayToFile(PLAY_PATH, content);
// 2. 播放语音
inputFile.setFileName(PLAY_PATH);
inputFile.open(QIODevice::ReadOnly);
audioSink->start(&inputFile);
}
void SoundRecorder::stopPlay() {
audioSink->stop();
inputFile.close();
}