代码之家  ›  专栏  ›  技术社区  ›  rubmz

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

  •  0
  • rubmz  · 技术社区  · 9 年前

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

    有什么办法吗?

    1 回复  |  直到 9 年前
        1
  •  6
  •   Velkan    9 年前

    基于以下讨论: 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();
    }