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>
This commit is contained in:
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
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);
|
||||
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);
|
||||
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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user