[SOLVED] QAudioOutput playback doesn't work on OSX
-
Hi again, this is my third post about a QtMultimedia issue. I'm afraid to say it's really painful to use it.
This time I've found that a method working fine on Linux and Windows, doesn't work on OSX.
I'm using Qt 5.2.1 on OSX 10.8.1Here it is:
@
bool AudioRendererQt::initialize(quint32 freq, int chan, AudioFormat format)
{
QAudioDeviceInfo audioDevice = QAudioDeviceInfo::defaultOutputDevice();
m_format.setChannelCount(chan);
m_format.setSampleRate(freq);
m_format.setCodec("audio/pcm");switch (format) { case PCM_S8: m_format.setSampleSize(8); m_format.setSampleType(QAudioFormat::UnSignedInt); break; case PCM_S16LE: m_format.setSampleSize(16); m_format.setSampleType(QAudioFormat::SignedInt); m_format.setByteOrder(QAudioFormat::LittleEndian); break; case PCM_S24LE: m_format.setSampleSize(24); m_format.setSampleType(QAudioFormat::SignedInt); m_format.setByteOrder(QAudioFormat::LittleEndian); break; case PCM_S32LE: m_format.setSampleSize(32); m_format.setSampleType(QAudioFormat::SignedInt); m_format.setByteOrder(QAudioFormat::LittleEndian); break; default: qWarning("AudioRendererQt: unsupported format detected"); return false; } if (!audioDevice.isFormatSupported(m_format)) { qWarning() << "Default format not supported - trying to use nearest"; m_format = audioDevice.nearestFormat(m_format); qDebug() << "New format:" << m_format.sampleRate() << m_format.channelCount() << m_format.sampleSize(); } m_audioOutput = new QAudioOutput(audioDevice, m_format, this); if( m_audioOutput == NULL ) { qWarning() << "Cannot open audio output stream from device" << audioDevice.deviceName(); return false; } m_audioOutput->setBufferSize(8192 * 4); m_output = m_audioOutput->start(); if( m_audioOutput->error() != QAudio::NoError ) { qDebug() << "Error in starting QAudioOutput"; return false; } return true;
}
@Even if I try to play an audio file with sample rate 44.1Khz, 2 channels, 16 bit (very standard), OSX falls into a non supported format.
When it tries to use the nearest format, the method gets stuck (I don't see the debug message after it)Anyone has a clue ?
Thanks
-
Hi,
Can you post a code sample that shows the behavior ?
-
The code is in my post
-
But it's not self-contained, so a rewrite is needed in order to try to reproduce your problem so the initial conditions are not the same and the failure might not occur.
-
Have had a deeper look into this and it seems to be a deployment issue.
The code above works fine if it's not bundled or if it is bundled with macdeployqt (which is the most inefficient tool I've ever seen: a 42MB DMG for a 50 lines app !)Unfortunately I still haven't figured how to correctly deploy QtMultimedia 5.3.2 and plugins on OSX. It's a nightmare.
No errors, nothing at all to understand what I'm missing.
The documentation is as well inappropriate. It still refers to Qt4 even if it's in the Qt5 docs:
http://qt-project.org/doc/qt-5/macosx-deployment.html -
Depending on what your application uses e.g. network + multimedia + widgets + gui and there you have the size.
Compare the plugins/mediaservice content of your bundle with the plugins/mediaservice in your Qt installation. Do they contain the same libraries ?
-
@SGaist: 42 megs was referring to the self-contained 50-lines-code example + macdeployqt. If you like I can share it here later.
My application (http://qlcplus.sourceforge.net/) is much more complex. It uses a lot of Qt libraries and on Qt4 it deploys in a DMG around 18megs.
The thing is that the deployment is done "manually" via nametool commands in the .pro files.
What I haven't able to figure out is how to include the Qt5 multimedia plugins. They are all there and they get copied in the right folder but it seems they're not loaded at runtime once bundled in a DMG.On the other hand, the Qt5 platform plugin (which is mandatory otherwise the app wouldn't even start) is correctly bundled and loaded.
I'm getting crazy to figure this out. Seems I'm missing something but I don't understand what.
-
Did you check the paths of the multimedia plugins using otool -L ?
-
I solved it. You couldn't believe what it was.
Basically, in my code the "initialize" method and the "writeAudio" method are called from different threads.
This works fine on Linux and Windows, but not on OSX.
It seems that when you create a QAudioOutput and start it, the underneath platform code (CoreAudio) stores somewhere a reference to the thread that created the object. So any data pushed from a different thread is simply ignored or not processed.The workaround is simple, even if it took months to figure it out.
I just need to push some empty data right after the QAudioOutput creation:
m_output->write(QByteArray(2048, 0));Now, I tried different amount of data and I don't really know how much is needed for this to work. Surely pushing just 1 byte doesn't work.
This is absolutely ridiculous for two reasons:
1- there is no cross platform compatibility
2- there is no explanation at all for this behavior. All that I've written before it's just my guessing.I'd appreciate if someone can give any sense to this.
-
Multithreading is one complex piece that changes for each platform.
One of the important thing is thread affinity, like e.g. GUI operation: they can only happen in the GUI thread which is generally the application main thread. Or the QTimer and QTcpSocket class which affinity must be with the same thread that uses them e.g. using moveToThread