Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play audio data using QIODevice (Qt4.6 with VC++)

I'm working on playing audio from an audio stream using VC++ with the QtMultimedia library. Since I'm not too experienced with Qt's libraries I started by reading in a .wav file and writing it to a buffer:

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

After that, I used ifstream's .read() function and write all the data into a buffer. After the buffer is written it's sent off to the audio writer that prepares it for 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 is of type QBuffer)

Once the QBuffer is ready I attempt to play the buffer:

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

(m_pAudioOut is of type QAudioOutput)

This results in a small pop from the speakers and then it stops playing. Any ideas why?

Running Visual Studios 2008 on Windows XP SP2 using Qt library 4.6.3.

like image 852
Tony Avatar asked Aug 06 '10 19:08

Tony


2 Answers

As Frank pointed out, if your requirement is simply to play audio data from a file, a higher-level API would do the job, and would simplify your application code. Phonon would be one option; alternatively, the QtMobility project provides the QMediaPlayer API for high-level use cases.

Given that the question is specifically about using QIODevice however, and that you mentioned that reading from a WAV file was just your intitial approach, I'll assume that you actually need a streaming API, i.e. one which allows the client to control the buffering, rather than handing over this control to a higher-level abstraction such as Phonon.

QAudioOutput can be used in two different modes, depending on which overload of start() is called:

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

    In this mode, QAudioOutput will pull data from the supplied QIODevice without further intervention from the client. It is a good choice if the QIODevice being used is one which is provided by Qt (e.g. QFile, QAbstractSocket etc).

  • "Push mode": QIODevice* QAudioOutput::start()

    In this mode, the QAudioOutput client must push mode to the audio device by calling QIODevice::write(). This will need to be done in a loop, something like:

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

    How the wait is implemented will depend on the context of your application - if audio is being written from a dedicated thread, it could simply sleep(). Alternatively, if audio is being written from the main thread, you will probably want the write to be triggered by a QTimer.

    Since you don't mention anything about using a loop around the write() calls in your app, it looks like what is happening is that you write a short segment of data (which plays as a pop), then don't write any more.

You can see code using both modes in the examples/multimedia/audiooutput app which is delivered with Qt.

like image 108
Gareth Stockwell Avatar answered Nov 18 '22 04:11

Gareth Stockwell


Are you sure you use the right (high-level) API? It would be weird if you had to handle data streams and buffering manually. Also, QIODevice::write() doesn't necessarily write the whole buffer but might stop after n bytes, just like POSIX write() (that's why one always should check the return value).

I didn't look into QtMultimedia yet, but using the more mature Phonon, video and audio output worked just fine for me in the past. It works like this:

  1. Create a Phonon::AudioOutput object
  2. Create a Phonon::MediaObject object
  3. Phonon::createPath( mediaObject, audioObject )
  4. mediaObject->setCurrentSource( Phonon::MediaSource( path ) );
  5. mediaObject->play();

There are also examples in Qt.

like image 2
Frank Osterfeld Avatar answered Nov 18 '22 06:11

Frank Osterfeld