Qt - 重新实现QIODevice,实时听到我自己的声音

Qt - Reimplementation of QIODevice to hear my own voice in realtime

本文关键字:实时 我自己 声音 自己的 QIODevice 新实现 实现 Qt      更新时间:2023-10-16

我正在对QIODevice类进行子类化,以通过QAudioInputQAudioOutput实例写入和读取语音。但是当我在耳机里读到它时,声音每隔几毫秒就会有一点点的削减。它发出的声音非常糟糕,如果我保持麦克风打开,当我关闭它时,声音会持续很长时间。

换句话说:

  • 我在麦克风里说"AAAAAA">
  • 我在耳机中听到"AA - AA - AA">

我已经尝试使用其他QIODevice实现,例如QFile并且效果很好,声音很好。这意味着问题不在我的QAudioInputQAudioOutput实例中。

当我想听到我的声音时,我唯一要做的就是:

void startrecording()
{
_audioInput->start(_audioBuffer);
_audioOutput->start(_audioBuffer);
// Start the output after didn't really change the sound
// QTimer::singleShot(500, [this] { _audioOutput->start(_audioBuffer); });
}

现在这是我的AudioBuffer

// .h
class AudioBuffer : public QIODevice
{
Q_OBJECT
public:
AudioBuffer();
protected:
qint64 writeData(const char* data, qint64 len) override;
qint64 readData(char* data, qint64 maxlen) override;
private:
static const int MAXSIZE = 1024 * 1024;
std::array<char, MAXSIZE> _buffer;
qint64                    _writePosition;
qint64                    _readPosition;
qint64                    _currentBufferLength;
};
// .cpp
AudioBuffer::AudioBuffer()
{
_writePosition       = 0;
_readPosition        = 0;
_currentBufferLength = 0;
}
qint64 AudioBuffer::writeData(const char* data, qint64 len)
{
qDebug() << "--- writing ---" << data;
std::string content = data;
if ((_writePosition + content.size()) > MAXSIZE)
{
qint64 firstData = MAXSIZE - _writePosition;
memcpy(&_buffer[_writePosition], content.data(), firstData);
memcpy(&_buffer[0], content.data() + firstData, content.size() - firstData);
}
else
{
memcpy(&_buffer[_writePosition], content.data(), content.size());
}
_writePosition = (_writePosition + content.size()) % MAXSIZE;
_currentBufferLength += content.size();
return len;
}
qint64 AudioBuffer::readData(char* data, qint64 maxlen)
{
if (_currentBufferLength <= 0) return 0;
qint64 writeLen = std::min(maxlen, _currentBufferLength);
if ((writeLen + _readPosition) > MAXSIZE)
{
qint64 firstData = MAXSIZE - _readPosition;
memcpy(data, &_buffer[_readPosition], firstData);
memcpy(data + firstData, &_buffer[0], writeLen - firstData);
}
else
{
memcpy(data, &_buffer[_readPosition], writeLen);
}
qDebug() << "--- reading ---" << data;
_readPosition = (_readPosition + writeLen) % MAXSIZE;
_currentBufferLength -= writeLen;
return writeLen;
}

两个qDebug数据返回相同的输出,只是调用readData小于writeData但缓冲区被正确读取。

输出(不含数据(如下(5 秒(。 我不知道这是否意味着什么,但时间过去了,与readData相比,更多的writeData

被称为
--- writing --- x1
--- reading --- x1
--- writing --- x1
--- reading --- x1
--- writing --- x2
--- reading --- x1
--- writing --- x1
--- reading --- x1
--- writing --- x1
--- reading --- x1
--- writing --- x1
--- reading --- x1
--- writing --- x1
--- reading --- x1
--- writing --- x3
--- reading --- x1
--- writing --- x1
--- reading --- x1
--- writing --- x6
--- reading --- x1
--- writing --- x9
--- reading --- x1
--- writing --- x13
--- reading --- x1
--- writing --- x1
--- reading --- x1
--- writing --- x20
--- reading --- x1
--- writing --- x1
--- reading --- x1
--- writing --- x26
--- reading --- x1
--- writing --- x26
--- reading --- x1
--- writing --- x4
input stop
--- reading --- x2

所以经过一些试验, 在这种情况下,似乎使用QBuffer可以代替我的AudioBuffer

然后,要小心,因为如果您在同一线程中同时读取和写入,则会导致一些滞后。

但就我而言,我需要将数据发送到服务器,然后服务器将音频发送给每个能够听到它的客户端。所以QBuffer还不够。

所以这是我的新实现

// Moving in different thread
_audioInput->moveToThread(&_inputThread);
_audioOutput->moveToThread(&_outputThread);
_audioInput->start(_audioBuffer);
_audioOutput->start(_audioBuffer);
// .cpp
class AudioBuffer : public QBuffer
{
Q_OBJECT
public:
AudioBuffer(/* Whatever you need for your server connection */);
protected:
/// Override the QBuffer method
qint64 writeData(const char* data, qint64 len) override;
/// Connect this method with the signal emit when your server send new audio
/// This is a string but it can be whatever you want according to your server
void getServerAudio(const std::string& audio);
};
// .h
AudioBuffer::AudioBuffer(/* Whatever you need for your server connection */)
{
// Connect your server with AudioBuffer::getServerAudio
}
qint64 AudioBuffer::writeData(const char* data, qint64 len)
{
// Send that the client send a new audio to the server
std::string audio = data;
// This is an example
sendAudioToServer(audio);
return len;
}
void AudioBuffer::getServerAudio(const std::string& audio)
{
// When you get a new audio from the server, you can hear it (so you write data into the buffer)
QBuffer::writeData(audio.c_str(), audio.size());
}