Воспроизведение аудиоданных с помощью QIODevice (Qt4.6 с VС++)

Я работаю над воспроизведением звука из аудиопотока с помощью VС++ с помощью библиотеки QtMultimedia. Поскольку я не слишком разбираюсь в библиотеках Qt, я начал с чтения в WAV файле и записал его в буфер:

ifstream wavFile;
char* file = "error_ex.wav";
wavFile.open( file, ios::binary );

После этого я использовал функцию ifstream.read() и записывал все данные в буфер. После того, как буфер записан, он отправляется в аудиозапись, которая готовит его для Qt:

QByteArray fData;

for( int i = 0; i < (int)data.size(); ++i )
{
    fData.push_back(data.at(i));
}

m_pBuffer->open(QIODevice::ReadWrite);
m_pBuffer->write( fData );

m_pBuffer->close();

(m_pBuffer имеет тип QBuffer)

Как только QBuffer готов, я пытаюсь воспроизвести буфер:

QIODevice* ioDevice = m_pAudioOut->start();
ioDevice->write( m_pBuffer->buffer() );

(m_pAudioOut имеет тип QAudioOutput)

В результате получается небольшая поп-запись из динамиков, после чего она перестает играть. Любые идеи, почему?

Запуск Visual Studios 2008 на Windows XP с пакетом обновления 2 (SP2) с использованием Qt-библиотеки 4.6.3.

Ответ 1

Как заметил Фрэнк, если ваше требование - просто воспроизвести аудиоданные из файла, API более высокого уровня выполнит эту работу и упростит ваш код приложения. Phonon будет одним из вариантов; альтернативно, проект QtMobility предоставляет API QMediaPlayer для высокоуровневых случаев использования.

Учитывая, что вопрос конкретно связан с использованием QIODevice, и что вы упомянули, что чтение из WAV файла было вашим интимным подходом, Я предполагаю, что вам действительно нужен потоковый API, то есть тот, который позволяет клиенту контролировать буферизацию, а не передавать этот элемент управления на абстракцию более высокого уровня, такую ​​как Phonon.

QAudioOutput может использоваться в двух разных режимах, в зависимости от того, какая перегрузка start() вызывается:

  • "Pull mode": void QAudioOutput::start(QIODevice *)

    В этом режиме QAudioOutput будет извлекать данные из предоставленного QIODevice без дополнительного вмешательства со стороны клиента. Это хороший выбор, если используется QIODevice, который предоставляется Qt (например, QFile, QAbstractSocket и т.д.).

  • "Режим Push": QIODevice* QAudioOutput::start()

    В этом режиме клиент QAudioOutput должен нажать режим на аудиоустройство, вызвав QIODevice::write(). Это нужно сделать в цикле, например:

    qint64 dataRemaining = ... // assign correct value here
    while (dataRemaining) {
        qint64 bytesWritten = audioOutput->write(buffer, dataRemaining);
        dataRemaining -= bytesWritten;
        buffer += bytesWritten;
        // Then wait for a short time
    }
    

    Как ожидание будет реализовано, будет зависеть от контекста вашего приложения - если звук записывается из выделенного потока, он может просто sleep(). В качестве альтернативы, если звук записывается из основного потока, вы, вероятно, захотите, чтобы запись запускалась с помощью QTimer.

    Поскольку вы ничего не упоминаете об использовании цикла вокруг вызовов write() в вашем приложении, похоже, что происходит то, что вы пишете короткий сегмент данных (который играет как поп), t пишите.

Вы можете видеть код, используя оба режима в приложении examples/multimedia/audiooutput, которое поставляется с Qt.

Ответ 2

Вы уверены, что используете правильный (высокоуровневый) API? Было бы странно, если бы вам пришлось вручную обрабатывать потоки данных и буферизировать. Кроме того, QIODevice:: write() не обязательно записывает весь буфер, но может останавливаться после n байтов, как и POSIX write() (поэтому всегда нужно проверять возвращаемое значение).

Я еще не смотрел в QtMultimedia, но использование более зрелого звука Phonon, видео и аудио работало для меня в прошлом. Он работает следующим образом:

  • Создать объект Phonon:: AudioOutput
  • Создать объект Phonon:: MediaObject
  • Phonon:: createPath (mediaObject, audioObject)
  • mediaObject- > setCurrentSource (Phonon:: MediaSource (путь));
  • mediaObject- > играть();

В Qt также есть примеры.