c++qtqiodevice

QAudioOutput - application size is continuously growing


I'm trying to write into buffer for QAudioOutput every 20ms. When I try to execute this code I can see the size of process increases about 4-8 kB per second. I was trying to find some function to clear internal buffer of QIODevice or DAudioOuptut but had no luck.

I'm using Qt 5.2.1

In the example below is written only silence(zeros) but it has the same effect:

#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;
}

Solution

  • When your loop runs, nothing else does. Your code should be asynchronous, and you should invert the control flow. React to a notification by the audio output device that it has processed a certain interval of samples.

    To receive the first notification, you need to prime the device with some data.

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