如何在QT中实现简单的音频环回

时间:2016-11-28 08:44:08

标签: qt audio-recording qtmultimedia

我需要使用QT将麦克风录制的音频直接环回到扬声器(Windows上的qt 5.7 ......) - 假设我不能使用窗口的内部麦克风>扬声器环回(在麦克风面板上启用“收听此设备”。

任何方向如何做到这一点?

1 个答案:

答案 0 :(得分:4)

基于对https://forum.qt.io/topic/19960/qaudioinput-redirect-to-qaudiooutput/3

的讨论
#include <iostream>

#include <QCoreApplication>
#include <QAudioInput>
#include <QAudioOutput>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    const auto decideAudioFormat = [](const QAudioDeviceInfo& devInfo)
    {
        QAudioFormat format;
        format.setSampleRate(8000);
        format.setChannelCount(1);
        format.setSampleSize(16);
        format.setCodec("audio/pcm");
        format.setByteOrder(QAudioFormat::LittleEndian);
        format.setSampleType(QAudioFormat::SignedInt);

        if (devInfo.isFormatSupported(format))
        {
            return format;
        }
        else
        {
            std::cerr << "Raw audio format not supported by backend, cannot play audio.\n";
            throw 0;
        }
    };

    QAudioInput audioInput(decideAudioFormat(QAudioDeviceInfo::defaultInputDevice()));
    QAudioOutput audioOutput(decideAudioFormat(QAudioDeviceInfo::defaultOutputDevice()));

    audioOutput.start(audioInput.start());

    return app.exec();
}

在中间添加缓冲区

  

之前我遇到过这个问题。如果我没有弄错,read()和write()函数共享相同的pos()跟踪器。这就是:

QBuffer buffer;

buffer.open(QBuffer::ReadWrite); // buffer.pos() == 0
buffer.write(someData, 5); // Writes in positions 0 -- 4, buffer.pos() == 5;
buffer.write(someData, 5); // Writes in positions 5 -- 9, buffer.pos() == 10;
buffer.read(otherBuffer.data(), 10); // Tries to read from position 10 onwards. No data found
  

2个解决方案:

     

实现您自己的独立读取位置和写入位置跟踪器。然后,在readData()和writeData()中调用seek()来设置pos() - 在写入之前指向数据的结尾,但在读取之前指向数据的中间

     

使用2个单独的缓冲区,并将字节从输入缓冲区复制到输出缓冲区

所以,使用单独的缓冲区:

#include <iostream>
#include <cassert>

#include <QCoreApplication>
#include <QAudioInput>
#include <QAudioOutput>
#include <QBuffer>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QBuffer rdBuff;
    QBuffer wrBuff;
    wrBuff.open(QBuffer::WriteOnly);
    rdBuff.open(QBuffer::ReadOnly);

    QObject::connect(&wrBuff, &QIODevice::bytesWritten, [&wrBuff, &rdBuff](qint64)
    {
        // remove all data that was already read
        rdBuff.buffer().remove(0, rdBuff.pos());

        // set pointer to the beginning of the unread data
        const auto res = rdBuff.seek(0);
        assert(res);

        // write new data
        rdBuff.buffer().append(wrBuff.buffer());

        // remove all data that was already written
        wrBuff.buffer().clear();
        wrBuff.seek(0);
    });

    const auto decideAudioFormat = [](const QAudioDeviceInfo& devInfo)
    {
        QAudioFormat format;
        format.setSampleRate(8000);
        format.setChannelCount(1);
        format.setSampleSize(16);
        format.setCodec("audio/pcm");
        format.setByteOrder(QAudioFormat::LittleEndian);
        format.setSampleType(QAudioFormat::SignedInt);

        if (devInfo.isFormatSupported(format))
        {
            return format;
        }
        else
        {
            std::cerr << "Raw audio format not supported by backend, cannot play audio.\n";
            throw 0;
        }
    };

    QAudioInput audioInput(decideAudioFormat(QAudioDeviceInfo::defaultInputDevice()));
    QAudioOutput audioOutput(decideAudioFormat(QAudioDeviceInfo::defaultOutputDevice()));

    audioInput.start(&wrBuff);
    audioOutput.start(&rdBuff);

    return app.exec();
}