Reputation: 2483
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.
Upvotes: 11
Views: 8223
Reputation: 3122
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.
Upvotes: 12
Reputation: 25165
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:
There are also examples in Qt.
Upvotes: 2