Make PulseAudio implementation of QSoundEffect more robust.
It was crashing when the PulseAudio daemon was not running or was killed. When the connection to the daemon fails (or is terminated), it now tries to reconnect every 30 seconds. Sounds created before a connection loss will be recreated after reconnection. Task-number: QTBUG-32487 Change-Id: Ia63707aa5c70434b834b3079a9950a9b35057b26 Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
This commit is contained in:
committed by
The Qt Project
parent
18d77b2b33
commit
cd11c240a6
@@ -147,9 +147,20 @@ public:
|
|||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void contextReady();
|
void contextReady();
|
||||||
|
void contextFailed();
|
||||||
void volumeChanged();
|
void volumeChanged();
|
||||||
|
|
||||||
private:
|
private Q_SLOTS:
|
||||||
|
void onContextFailed()
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
|
||||||
|
// Try to reconnect later
|
||||||
|
QTimer::singleShot(30000, this, SLOT(prepare()));
|
||||||
|
|
||||||
|
emit contextFailed();
|
||||||
|
}
|
||||||
|
|
||||||
void prepare()
|
void prepare()
|
||||||
{
|
{
|
||||||
m_vol = PA_VOLUME_NORM;
|
m_vol = PA_VOLUME_NORM;
|
||||||
@@ -196,12 +207,23 @@ private:
|
|||||||
m_prepared = true;
|
m_prepared = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
void release()
|
void release()
|
||||||
{
|
{
|
||||||
if (!m_prepared) return;
|
if (!m_prepared)
|
||||||
pa_context_unref(m_context);
|
return;
|
||||||
pa_threaded_mainloop_stop(m_mainLoop);
|
|
||||||
pa_threaded_mainloop_free(m_mainLoop);
|
if (m_context) {
|
||||||
|
pa_context_unref(m_context);
|
||||||
|
m_context = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_mainLoop) {
|
||||||
|
pa_threaded_mainloop_stop(m_mainLoop);
|
||||||
|
pa_threaded_mainloop_free(m_mainLoop);
|
||||||
|
m_mainLoop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
m_prepared = false;
|
m_prepared = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,6 +243,9 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
QMetaObject::invokeMethod(self, "contextReady", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(self, "contextReady", Qt::QueuedConnection);
|
||||||
break;
|
break;
|
||||||
|
case PA_CONTEXT_FAILED:
|
||||||
|
QMetaObject::invokeMethod(self, "onContextFailed", Qt::QueuedConnection);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -511,7 +536,8 @@ void QSoundEffectPrivate::updateVolume()
|
|||||||
PulseDaemonLocker locker;
|
PulseDaemonLocker locker;
|
||||||
pa_cvolume volume;
|
pa_cvolume volume;
|
||||||
volume.channels = m_pulseSpec.channels;
|
volume.channels = m_pulseSpec.channels;
|
||||||
pa_operation_unref(pa_context_set_sink_input_volume(pulseDaemon()->context(), m_sinkInputId, pulseDaemon()->calcVolume(&volume, m_volume), setvolume_callback, m_ref->getRef()));
|
if (pulseDaemon()->context())
|
||||||
|
pa_operation_unref(pa_context_set_sink_input_volume(pulseDaemon()->context(), m_sinkInputId, pulseDaemon()->calcVolume(&volume, m_volume), setvolume_callback, m_ref->getRef()));
|
||||||
Q_ASSERT(pa_cvolume_valid(&volume));
|
Q_ASSERT(pa_cvolume_valid(&volume));
|
||||||
#ifdef QT_PA_DEBUG
|
#ifdef QT_PA_DEBUG
|
||||||
qDebug() << this << "updateVolume =" << pa_cvolume_max(&volume);
|
qDebug() << this << "updateVolume =" << pa_cvolume_max(&volume);
|
||||||
@@ -535,7 +561,8 @@ void QSoundEffectPrivate::updateMuted()
|
|||||||
if (m_sinkInputId < 0)
|
if (m_sinkInputId < 0)
|
||||||
return;
|
return;
|
||||||
PulseDaemonLocker locker;
|
PulseDaemonLocker locker;
|
||||||
pa_operation_unref(pa_context_set_sink_input_mute(pulseDaemon()->context(), m_sinkInputId, m_muted, setmuted_callback, m_ref->getRef()));
|
if (pulseDaemon()->context())
|
||||||
|
pa_operation_unref(pa_context_set_sink_input_mute(pulseDaemon()->context(), m_sinkInputId, m_muted, setmuted_callback, m_ref->getRef()));
|
||||||
#ifdef QT_PA_DEBUG
|
#ifdef QT_PA_DEBUG
|
||||||
qDebug() << this << "updateMuted = " << m_muted;
|
qDebug() << this << "updateMuted = " << m_muted;
|
||||||
#endif
|
#endif
|
||||||
@@ -705,7 +732,7 @@ void QSoundEffectPrivate::sampleReady()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
if (pa_context_get_state(pulseDaemon()->context()) != PA_CONTEXT_READY) {
|
if (!pulseDaemon()->context() || pa_context_get_state(pulseDaemon()->context()) != PA_CONTEXT_READY) {
|
||||||
connect(pulseDaemon(), SIGNAL(contextReady()), SLOT(contextReady()));
|
connect(pulseDaemon(), SIGNAL(contextReady()), SLOT(contextReady()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -741,6 +768,7 @@ void QSoundEffectPrivate::unloadPulseStream()
|
|||||||
pa_stream_disconnect(m_pulseStream);
|
pa_stream_disconnect(m_pulseStream);
|
||||||
pa_stream_unref(m_pulseStream);
|
pa_stream_unref(m_pulseStream);
|
||||||
disconnect(pulseDaemon(), SIGNAL(volumeChanged()), this, SLOT(updateVolume()));
|
disconnect(pulseDaemon(), SIGNAL(volumeChanged()), this, SLOT(updateVolume()));
|
||||||
|
disconnect(pulseDaemon(), SIGNAL(contextFailed()), this, SLOT(contextFailed()));
|
||||||
m_pulseStream = 0;
|
m_pulseStream = 0;
|
||||||
m_reloadCategory = false; // category will be reloaded when we connect anyway
|
m_reloadCategory = false; // category will be reloaded when we connect anyway
|
||||||
}
|
}
|
||||||
@@ -895,6 +923,9 @@ void QSoundEffectPrivate::createPulseStream()
|
|||||||
qDebug() << this << "createPulseStream";
|
qDebug() << this << "createPulseStream";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!pulseDaemon()->context())
|
||||||
|
return;
|
||||||
|
|
||||||
pa_proplist *propList = pa_proplist_new();
|
pa_proplist *propList = pa_proplist_new();
|
||||||
if (m_category.isNull()) {
|
if (m_category.isNull()) {
|
||||||
// Meant to be one of the strings "video", "music", "game", "event", "phone", "animation", "production", "a11y", "test"
|
// Meant to be one of the strings "video", "music", "game", "event", "phone", "animation", "production", "a11y", "test"
|
||||||
@@ -906,6 +937,7 @@ void QSoundEffectPrivate::createPulseStream()
|
|||||||
pa_proplist_free(propList);
|
pa_proplist_free(propList);
|
||||||
|
|
||||||
connect(pulseDaemon(), SIGNAL(volumeChanged()), this, SLOT(updateVolume()));
|
connect(pulseDaemon(), SIGNAL(volumeChanged()), this, SLOT(updateVolume()));
|
||||||
|
connect(pulseDaemon(), SIGNAL(contextFailed()), this, SLOT(contextFailed()));
|
||||||
|
|
||||||
if (stream == 0) {
|
if (stream == 0) {
|
||||||
qWarning("QSoundEffect(pulseaudio): Failed to create stream");
|
qWarning("QSoundEffect(pulseaudio): Failed to create stream");
|
||||||
@@ -947,6 +979,12 @@ void QSoundEffectPrivate::contextReady()
|
|||||||
createPulseStream();
|
createPulseStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QSoundEffectPrivate::contextFailed()
|
||||||
|
{
|
||||||
|
unloadPulseStream();
|
||||||
|
connect(pulseDaemon(), SIGNAL(contextReady()), this, SLOT(contextReady()));
|
||||||
|
}
|
||||||
|
|
||||||
void QSoundEffectPrivate::stream_write_callback(pa_stream *s, size_t length, void *userdata)
|
void QSoundEffectPrivate::stream_write_callback(pa_stream *s, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
Q_UNUSED(length);
|
Q_UNUSED(length);
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ private Q_SLOTS:
|
|||||||
void sampleReady();
|
void sampleReady();
|
||||||
void uploadSample();
|
void uploadSample();
|
||||||
void contextReady();
|
void contextReady();
|
||||||
|
void contextFailed();
|
||||||
void underRun();
|
void underRun();
|
||||||
void prepare();
|
void prepare();
|
||||||
void streamReady();
|
void streamReady();
|
||||||
|
|||||||
Reference in New Issue
Block a user