0

我正在尝试每 20 毫秒写入一次 QAudioOutput 的缓冲区。当我尝试执行此代码时,我可以看到进程的大小每秒增加约 4-8 kB。我试图找到一些函数来清除 QIODevice 或 DAudioOuptut 的内部缓冲区,但没有运气。

我正在使用 Qt 5.2.1

在下面的示例中,仅写入了静音(零),但具有相同的效果:

#include <QLibraryInfo>
#include <QtCore/QCoreApplication>
#include <windows.h> // for Sleep
#include <QAudioOutput>
#include <QAudioDeviceInfo>
#include <QAudioFormat>
#include <array>

class QAudioOutput;

int main(int argc, char *argv[])
{
    // Create QApplication
    QCoreApplication app(argc, argv);
    app.setApplicationName("Audiotest");
    //Initialize device
    QIODevice * _output;
    QAudioDeviceInfo _device = QAudioDeviceInfo::defaultOutputDevice();
    QAudioFormat _format;
    _format.setSampleRate(44100);
    _format.setChannelCount(2);
    _format.setSampleSize(16);
    _format.setCodec("audio/pcm");  // This codec should be supported on all platforms and plugin implementation
    _format.setByteOrder(QAudioFormat::LittleEndian);
    _format.setSampleType(QAudioFormat::SignedInt);
    if (!_device.isFormatSupported(_format)) {
        printf("Default format not supported - trying to use nearest.\n");
        _format = _device.nearestFormat(_format);
    }
    QAudioOutput * _audioOutput = new QAudioOutput(_device, _format);
    _output = _audioOutput->start();
    std::array<char, 32768> _buffer;
    _buffer.fill(0);


    for (;;) {
        const int periodSize = _audioOutput->periodSize();
        const int chunks = _audioOutput->bytesFree() / periodSize;
        for (int i = 0; i < chunks; ++i) {
            const qint64 len = periodSize;
            if (len && _output) {
                _output->write(_buffer.data(), len);
            }
            if (len != periodSize) {
                break;
            }
        }
        Sleep(20);
    }
    return 0;
}
4

2 回答 2

3

当您的循环运行时,没有其他任何事情。您的代码应该是异步的,并且您应该反转控制流。对音频输出设备发出的通知做出反应,即它已处理了一定间隔的样本。

要接收第一个通知,您需要使用一些数据来启动设备。

// https://github.com/KubaO/stackoverflown/tree/master/questions/audio-37993427
#include <QtMultimedia>
#include <array>

int main(int argc, char ** argv) {
   QCoreApplication app{argc, argv};
   auto device = QAudioDeviceInfo::defaultOutputDevice();
   QAudioFormat format;
   format.setSampleRate(44100);
   format.setChannelCount(2);
   format.setSampleSize(16);
   format.setCodec("audio/pcm");
   format.setByteOrder(QAudioFormat::LittleEndian);
   format.setSampleType(QAudioFormat::SignedInt);
   if (!device.isFormatSupported(format))
      qFatal("Default format not supported");
   QAudioOutput audioOutput{device, format};
   auto output = audioOutput.start();
   qDebug() << audioOutput.state();
   std::array<char, 32768> buffer;
   buffer.fill(0);

   auto write = [&]{
      qDebug() << "notify";
      auto periodSize = audioOutput.periodSize();
      auto chunks = audioOutput.bytesFree() / periodSize;
      for (int i = 0; i < chunks; ++i) {
         if (periodSize && output) {
            auto len = output->write(buffer.data(), periodSize);
            if (len != periodSize)
               break;
         }
      }
   };

   audioOutput.setNotifyInterval(20);
   QObject::connect(&audioOutput, &QAudioOutput::notify, write);
   write();
   return app.exec();
}
于 2016-06-23T17:23:12.280 回答
0

不要运行自己的事件循环;相反,将 QAudioOutput 的notify信号连接到您的一个 QObjects 中的插槽,并让该插槽调用 write() 一次。每当 QAudioOutput 需要播放更多音频数据时,就会发出通知信号。

所有这些都将发生在 QApplication::exec() 中,您应该调用它(在 main() 的末尾附近)为您运行 Qt 事件循环,而不是您自己的 for 循环。

于 2016-06-23T15:45:03.040 回答