summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@qt.io>2016-09-20 19:28:40 +0300
committerYoann Lopes <yoann.lopes@qt.io>2016-09-21 13:13:05 +0000
commit4bae7697257e5294721211fdd0b9bad5731f70c9 (patch)
treee001043615ec95ff762fec7aaec8950a3df7770f
parentbf5c7ca718a4a84e28a17ff69c4b18abee81ff93 (diff)
PulseAudio: make code more robust
Some asynchronous operations return a pa_operation pointer, which can be null if the operation fails. In some cases we were not checking that the returned object was non null, leading to some asserts being raised in pa_operation_unref. Change-Id: Iff1cc67b7f79b758fa81d79e658debb1d737b29f Reviewed-by: Christian Stromme <christian.stromme@qt.io>
-rw-r--r--src/multimedia/audio/qsoundeffect_pulse_p.cpp61
-rw-r--r--src/plugins/pulseaudio/qpulseaudioengine.cpp65
2 files changed, 95 insertions, 31 deletions
diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.cpp b/src/multimedia/audio/qsoundeffect_pulse_p.cpp
index 1fb10d12..5bb5119a 100644
--- a/src/multimedia/audio/qsoundeffect_pulse_p.cpp
+++ b/src/multimedia/audio/qsoundeffect_pulse_p.cpp
@@ -437,7 +437,11 @@ void QSoundEffectPrivate::setSource(const QUrl &url)
if (m_pulseStream && !pa_stream_is_corked(m_pulseStream)) {
pa_stream_set_write_callback(m_pulseStream, 0, 0);
pa_stream_set_underflow_callback(m_pulseStream, 0, 0);
- pa_operation_unref(pa_stream_cork(m_pulseStream, 1, 0, 0));
+ pa_operation *op = pa_stream_cork(m_pulseStream, 1, 0, 0);
+ if (op)
+ pa_operation_unref(op);
+ else
+ qWarning("QSoundEffect(pulseaudio): failed to cork stream");
}
setPlaying(false);
@@ -619,7 +623,11 @@ void QSoundEffectPrivate::emptyStream(EmptyStreamOptions options)
m_emptying = true;
pa_stream_set_write_callback(m_pulseStream, 0, 0);
pa_stream_set_underflow_callback(m_pulseStream, 0, 0);
- pa_operation_unref(pa_stream_flush(m_pulseStream, flushCompleteCb, m_ref->getRef()));
+ pa_operation *op = pa_stream_flush(m_pulseStream, flushCompleteCb, m_ref->getRef());
+ if (op)
+ pa_operation_unref(op);
+ else
+ qWarning("QSoundEffect(pulseaudio): failed to flush stream");
}
void QSoundEffectPrivate::emptyComplete(void *stream, bool reload)
@@ -631,8 +639,13 @@ void QSoundEffectPrivate::emptyComplete(void *stream, bool reload)
m_emptying = false;
- if ((pa_stream *)stream == m_pulseStream)
- pa_operation_unref(pa_stream_cork(m_pulseStream, 1, reload ? stream_cork_callback : 0, m_ref->getRef()));
+ if ((pa_stream *)stream == m_pulseStream) {
+ pa_operation *op = pa_stream_cork(m_pulseStream, 1, reload ? stream_cork_callback : 0, m_ref->getRef());
+ if (op)
+ pa_operation_unref(op);
+ else
+ qWarning("QSoundEffect(pulseaudio): failed to cork stream");
+ }
}
void QSoundEffectPrivate::sampleReady()
@@ -666,7 +679,11 @@ void QSoundEffectPrivate::sampleReady()
pa_buffer_attr newBufferAttr;
newBufferAttr = *bufferAttr;
newBufferAttr.prebuf = m_sample->data().size();
- pa_operation_unref(pa_stream_set_buffer_attr(m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, m_ref->getRef()));
+ pa_operation *op = pa_stream_set_buffer_attr(m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, m_ref->getRef());
+ if (op)
+ pa_operation_unref(op);
+ else
+ qWarning("QSoundEffect(pulseaudio): failed to adjust pre-buffer attribute");
} else {
streamReady();
}
@@ -679,12 +696,20 @@ void QSoundEffectPrivate::sampleReady()
newBufferAttr.minreq = bufferAttr->tlength / 2;
newBufferAttr.prebuf = -1;
newBufferAttr.fragsize = -1;
- pa_operation_unref(pa_stream_set_buffer_attr(m_pulseStream, &newBufferAttr, stream_reset_buffer_callback, m_ref->getRef()));
+ pa_operation *op = pa_stream_set_buffer_attr(m_pulseStream, &newBufferAttr, stream_reset_buffer_callback, m_ref->getRef());
+ if (op)
+ pa_operation_unref(op);
+ else
+ qWarning("QSoundEffect(pulseaudio): failed to adjust pre-buffer attribute");
} else if (bufferAttr->prebuf > uint32_t(m_sample->data().size())) {
pa_buffer_attr newBufferAttr;
newBufferAttr = *bufferAttr;
newBufferAttr.prebuf = m_sample->data().size();
- pa_operation_unref(pa_stream_set_buffer_attr(m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, m_ref->getRef()));
+ pa_operation *op = pa_stream_set_buffer_attr(m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, m_ref->getRef());
+ if (op)
+ pa_operation_unref(op);
+ else
+ qWarning("QSoundEffect(pulseaudio): failed to adjust pre-buffer attribute");
} else {
streamReady();
}
@@ -989,7 +1014,11 @@ void QSoundEffectPrivate::stream_state_callback(pa_stream *s, void *userdata)
pa_buffer_attr newBufferAttr;
newBufferAttr = *bufferAttr;
newBufferAttr.prebuf = self->m_sample->data().size();
- pa_stream_set_buffer_attr(self->m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, self->m_ref->getRef());
+ pa_operation *op = pa_stream_set_buffer_attr(self->m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, self->m_ref->getRef());
+ if (op)
+ pa_operation_unref(op);
+ else
+ qWarning("QSoundEffect(pulseaudio): failed to adjust pre-buffer attribute");
} else {
QMetaObject::invokeMethod(self, "streamReady", Qt::QueuedConnection);
}
@@ -1026,7 +1055,7 @@ void QSoundEffectPrivate::stream_reset_buffer_callback(pa_stream *s, int success
return;
if (!success)
- qWarning("QSoundEffect(pulseaudio): faild to reset buffer attribute");
+ qWarning("QSoundEffect(pulseaudio): failed to reset buffer attribute");
#ifdef QT_PA_DEBUG
qDebug() << self << "stream_reset_buffer_callback";
#endif
@@ -1036,7 +1065,11 @@ void QSoundEffectPrivate::stream_reset_buffer_callback(pa_stream *s, int success
pa_buffer_attr newBufferAttr;
newBufferAttr = *bufferAttr;
newBufferAttr.prebuf = self->m_sample->data().size();
- pa_stream_set_buffer_attr(self->m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, userdata);
+ pa_operation *op = pa_stream_set_buffer_attr(self->m_pulseStream, &newBufferAttr, stream_adjust_prebuffer_callback, userdata);
+ if (op)
+ pa_operation_unref(op);
+ else
+ qWarning("QSoundEffect(pulseaudio): failed to adjust pre-buffer attribute");
} else {
QMetaObject::invokeMethod(self, "streamReady", Qt::QueuedConnection);
}
@@ -1055,7 +1088,7 @@ void QSoundEffectPrivate::stream_adjust_prebuffer_callback(pa_stream *s, int suc
return;
if (!success)
- qWarning("QSoundEffect(pulseaudio): faild to adjust pre-buffer attribute");
+ qWarning("QSoundEffect(pulseaudio): failed to adjust pre-buffer attribute");
#ifdef QT_PA_DEBUG
qDebug() << self << "stream_adjust_prebuffer_callback";
#endif
@@ -1090,7 +1123,7 @@ void QSoundEffectPrivate::stream_cork_callback(pa_stream *s, int success, void *
return;
if (!success)
- qWarning("QSoundEffect(pulseaudio): faild to stop");
+ qWarning("QSoundEffect(pulseaudio): failed to stop");
#ifdef QT_PA_DEBUG
qDebug() << self << "stream_cork_callback";
#endif
@@ -1110,7 +1143,7 @@ void QSoundEffectPrivate::stream_flush_callback(pa_stream *s, int success, void
return;
if (!success)
- qWarning("QSoundEffect(pulseaudio): faild to drain");
+ qWarning("QSoundEffect(pulseaudio): failed to drain");
QMetaObject::invokeMethod(self, "emptyComplete", Qt::QueuedConnection, Q_ARG(void*, s), Q_ARG(bool, false));
}
@@ -1128,7 +1161,7 @@ void QSoundEffectPrivate::stream_flush_reload_callback(pa_stream *s, int success
return;
if (!success)
- qWarning("QSoundEffect(pulseaudio): faild to drain");
+ qWarning("QSoundEffect(pulseaudio): failed to drain");
QMetaObject::invokeMethod(self, "emptyComplete", Qt::QueuedConnection, Q_ARG(void*, s), Q_ARG(bool, true));
}
diff --git a/src/plugins/pulseaudio/qpulseaudioengine.cpp b/src/plugins/pulseaudio/qpulseaudioengine.cpp
index e9510fd6..b3d5044b 100644
--- a/src/plugins/pulseaudio/qpulseaudioengine.cpp
+++ b/src/plugins/pulseaudio/qpulseaudioengine.cpp
@@ -170,15 +170,30 @@ static void event_cb(pa_context* context, pa_subscription_event_type_t t, uint32
case PA_SUBSCRIPTION_EVENT_NEW:
case PA_SUBSCRIPTION_EVENT_CHANGE:
switch (facility) {
- case PA_SUBSCRIPTION_EVENT_SERVER:
- pa_operation_unref(pa_context_get_server_info(context, serverInfoCallback, userdata));
+ case PA_SUBSCRIPTION_EVENT_SERVER: {
+ pa_operation *op = pa_context_get_server_info(context, serverInfoCallback, userdata);
+ if (op)
+ pa_operation_unref(op);
+ else
+ qWarning("PulseAudioService: failed to get server info");
break;
- case PA_SUBSCRIPTION_EVENT_SINK:
- pa_operation_unref(pa_context_get_sink_info_by_index(context, index, sinkInfoCallback, userdata));
+ }
+ case PA_SUBSCRIPTION_EVENT_SINK: {
+ pa_operation *op = pa_context_get_sink_info_by_index(context, index, sinkInfoCallback, userdata);
+ if (op)
+ pa_operation_unref(op);
+ else
+ qWarning("PulseAudioService: failed to get sink info");
break;
- case PA_SUBSCRIPTION_EVENT_SOURCE:
- pa_operation_unref(pa_context_get_source_info_by_index(context, index, sourceInfoCallback, userdata));
+ }
+ case PA_SUBSCRIPTION_EVENT_SOURCE: {
+ pa_operation *op = pa_context_get_source_info_by_index(context, index, sourceInfoCallback, userdata);
+ if (op)
+ pa_operation_unref(op);
+ else
+ qWarning("PulseAudioService: failed to get source info");
break;
+ }
default:
break;
}
@@ -328,11 +343,15 @@ void QPulseAudioEngine::prepare()
pa_context_set_state_callback(m_context, contextStateCallback, this);
pa_context_set_subscribe_callback(m_context, event_cb, this);
- pa_operation_unref(pa_context_subscribe(m_context,
+ pa_operation *op = pa_context_subscribe(m_context,
pa_subscription_mask_t(PA_SUBSCRIPTION_MASK_SINK |
PA_SUBSCRIPTION_MASK_SOURCE |
PA_SUBSCRIPTION_MASK_SERVER),
- NULL, NULL));
+ NULL, NULL);
+ if (op)
+ pa_operation_unref(op);
+ else
+ qWarning("PulseAudioService: failed to subscribe to context notifications");
} else {
pa_context_unref(m_context);
m_context = 0;
@@ -376,21 +395,33 @@ void QPulseAudioEngine::updateDevices()
// Get default input and output devices
pa_operation *operation = pa_context_get_server_info(m_context, serverInfoCallback, this);
- while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
- pa_threaded_mainloop_wait(m_mainLoop);
- pa_operation_unref(operation);
+ if (operation) {
+ while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
+ pa_threaded_mainloop_wait(m_mainLoop);
+ pa_operation_unref(operation);
+ } else {
+ qWarning("PulseAudioService: failed to get server info");
+ }
// Get output devices
operation = pa_context_get_sink_info_list(m_context, sinkInfoCallback, this);
- while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
- pa_threaded_mainloop_wait(m_mainLoop);
- pa_operation_unref(operation);
+ if (operation) {
+ while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
+ pa_threaded_mainloop_wait(m_mainLoop);
+ pa_operation_unref(operation);
+ } else {
+ qWarning("PulseAudioService: failed to get sink info");
+ }
// Get input devices
operation = pa_context_get_source_info_list(m_context, sourceInfoCallback, this);
- while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
- pa_threaded_mainloop_wait(m_mainLoop);
- pa_operation_unref(operation);
+ if (operation) {
+ while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
+ pa_threaded_mainloop_wait(m_mainLoop);
+ pa_operation_unref(operation);
+ } else {
+ qWarning("PulseAudioService: failed to get source info");
+ }
unlock();
}