summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@digia.com>2013-07-25 15:43:41 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-07-25 23:09:22 +0200
commitcd11c240a614acd7fe263e86baacf25ce90df699 (patch)
treedbd0b18402478293a93c83ad7b7f4fe55477c65d
parent18d77b2b33b6784796aa89983bc209c5e7c8aaab (diff)
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>
-rw-r--r--src/multimedia/audio/qsoundeffect_pulse_p.cpp54
-rw-r--r--src/multimedia/audio/qsoundeffect_pulse_p.h1
2 files changed, 47 insertions, 8 deletions
diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.cpp b/src/multimedia/audio/qsoundeffect_pulse_p.cpp
index b3318ec94..328a3b0b3 100644
--- a/src/multimedia/audio/qsoundeffect_pulse_p.cpp
+++ b/src/multimedia/audio/qsoundeffect_pulse_p.cpp
@@ -147,9 +147,20 @@ public:
Q_SIGNALS:
void contextReady();
+ void contextFailed();
void volumeChanged();
-private:
+private Q_SLOTS:
+ void onContextFailed()
+ {
+ release();
+
+ // Try to reconnect later
+ QTimer::singleShot(30000, this, SLOT(prepare()));
+
+ emit contextFailed();
+ }
+
void prepare()
{
m_vol = PA_VOLUME_NORM;
@@ -196,12 +207,23 @@ private:
m_prepared = true;
}
+private:
void release()
{
- if (!m_prepared) return;
- pa_context_unref(m_context);
- pa_threaded_mainloop_stop(m_mainLoop);
- pa_threaded_mainloop_free(m_mainLoop);
+ if (!m_prepared)
+ return;
+
+ 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;
}
@@ -221,6 +243,9 @@ private:
#endif
QMetaObject::invokeMethod(self, "contextReady", Qt::QueuedConnection);
break;
+ case PA_CONTEXT_FAILED:
+ QMetaObject::invokeMethod(self, "onContextFailed", Qt::QueuedConnection);
+ break;
default:
break;
}
@@ -511,7 +536,8 @@ void QSoundEffectPrivate::updateVolume()
PulseDaemonLocker locker;
pa_cvolume volume;
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));
#ifdef QT_PA_DEBUG
qDebug() << this << "updateVolume =" << pa_cvolume_max(&volume);
@@ -535,7 +561,8 @@ void QSoundEffectPrivate::updateMuted()
if (m_sinkInputId < 0)
return;
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
qDebug() << this << "updateMuted = " << m_muted;
#endif
@@ -705,7 +732,7 @@ void QSoundEffectPrivate::sampleReady()
}
#endif
} 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()));
return;
}
@@ -741,6 +768,7 @@ void QSoundEffectPrivate::unloadPulseStream()
pa_stream_disconnect(m_pulseStream);
pa_stream_unref(m_pulseStream);
disconnect(pulseDaemon(), SIGNAL(volumeChanged()), this, SLOT(updateVolume()));
+ disconnect(pulseDaemon(), SIGNAL(contextFailed()), this, SLOT(contextFailed()));
m_pulseStream = 0;
m_reloadCategory = false; // category will be reloaded when we connect anyway
}
@@ -895,6 +923,9 @@ void QSoundEffectPrivate::createPulseStream()
qDebug() << this << "createPulseStream";
#endif
+ if (!pulseDaemon()->context())
+ return;
+
pa_proplist *propList = pa_proplist_new();
if (m_category.isNull()) {
// 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);
connect(pulseDaemon(), SIGNAL(volumeChanged()), this, SLOT(updateVolume()));
+ connect(pulseDaemon(), SIGNAL(contextFailed()), this, SLOT(contextFailed()));
if (stream == 0) {
qWarning("QSoundEffect(pulseaudio): Failed to create stream");
@@ -947,6 +979,12 @@ void QSoundEffectPrivate::contextReady()
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)
{
Q_UNUSED(length);
diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.h b/src/multimedia/audio/qsoundeffect_pulse_p.h
index e43bd2fdf..4dc58f0b6 100644
--- a/src/multimedia/audio/qsoundeffect_pulse_p.h
+++ b/src/multimedia/audio/qsoundeffect_pulse_p.h
@@ -111,6 +111,7 @@ private Q_SLOTS:
void sampleReady();
void uploadSample();
void contextReady();
+ void contextFailed();
void underRun();
void prepare();
void streamReady();