【问题标题】:How to implement simple audio loopback in QT如何在 QT 中实现简单的音频环回
【发布时间】:2017-04-11 22:18:52
【问题描述】:

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

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

【问题讨论】:

  • 您可以将这些链接在一起:QAudioInputQBufferQAudioOutput。这周我正在做一个类似的任务(中间有声音修改),所以请随时发布代码。或者我发布我将要制作的内容。

标签: qt audio-recording qtmultimedia


【解决方案1】:

基于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();
}

【讨论】:

  • 哇!多么棒的答案!谢谢一百万:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多