diff options
Diffstat (limited to 'src/plugins/pulseaudio/qpulseaudioengine.cpp')
-rw-r--r-- | src/plugins/pulseaudio/qpulseaudioengine.cpp | 139 |
1 files changed, 76 insertions, 63 deletions
diff --git a/src/plugins/pulseaudio/qpulseaudioengine.cpp b/src/plugins/pulseaudio/qpulseaudioengine.cpp index b7a3e66b7..05c8be89e 100644 --- a/src/plugins/pulseaudio/qpulseaudioengine.cpp +++ b/src/plugins/pulseaudio/qpulseaudioengine.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Toolkit. @@ -170,15 +170,17 @@ static void contextStateCallbackInit(pa_context *context, void *userdata) pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0); } -static void contextStateCallback(pa_context *context, void *userdata) +static void contextStateCallback(pa_context *c, void *userdata) { - Q_UNUSED(userdata); - Q_UNUSED(context); + QPulseAudioEngine *self = reinterpret_cast<QPulseAudioEngine*>(userdata); + pa_context_state_t state = pa_context_get_state(c); #ifdef DEBUG_PULSE - pa_context_state_t state = pa_context_get_state(context); qDebug() << QPulseAudioInternal::stateToQString(state); #endif + + if (state == PA_CONTEXT_FAILED) + QMetaObject::invokeMethod(self, "onContextFailed", Qt::QueuedConnection); } Q_GLOBAL_STATIC(QPulseAudioEngine, pulseEngine); @@ -187,40 +189,59 @@ QPulseAudioEngine::QPulseAudioEngine(QObject *parent) : QObject(parent) , m_mainLoopApi(0) , m_context(0) + , m_prepared(false) +{ + prepare(); +} + +QPulseAudioEngine::~QPulseAudioEngine() +{ + if (m_prepared) + release(); +} +void QPulseAudioEngine::prepare() { bool keepGoing = true; bool ok = true; m_mainLoop = pa_threaded_mainloop_new(); if (m_mainLoop == 0) { - qWarning("Unable to create pulseaudio mainloop"); + qWarning("PulseAudioService: unable to create pulseaudio mainloop"); return; } if (pa_threaded_mainloop_start(m_mainLoop) != 0) { - qWarning("Unable to start pulseaudio mainloop"); + qWarning("PulseAudioService: unable to start pulseaudio mainloop"); pa_threaded_mainloop_free(m_mainLoop); + m_mainLoop = 0; return; } m_mainLoopApi = pa_threaded_mainloop_get_api(m_mainLoop); - pa_threaded_mainloop_lock(m_mainLoop); + lock(); - m_context = pa_context_new(m_mainLoopApi, QString(QLatin1String("QtmPulseContext:%1")).arg(::getpid()).toLatin1().constData()); - pa_context_set_state_callback(m_context, contextStateCallbackInit, this); + m_context = pa_context_new(m_mainLoopApi, QString(QLatin1String("QtPulseAudio:%1")).arg(::getpid()).toLatin1().constData()); - if (!m_context) { - qWarning("Unable to create new pulseaudio context"); + if (m_context == 0) { + qWarning("PulseAudioService: Unable to create new pulseaudio context"); + pa_threaded_mainloop_unlock(m_mainLoop); pa_threaded_mainloop_free(m_mainLoop); + m_mainLoop = 0; + onContextFailed(); return; } - if (pa_context_connect(m_context, NULL, (pa_context_flags_t)0, NULL) < 0) { - qWarning("Unable to create a connection to the pulseaudio context"); + pa_context_set_state_callback(m_context, contextStateCallbackInit, this); + + if (pa_context_connect(m_context, 0, (pa_context_flags_t)0, 0) < 0) { + qWarning("PulseAudioService: pa_context_connect() failed"); pa_context_unref(m_context); + pa_threaded_mainloop_unlock(m_mainLoop); pa_threaded_mainloop_free(m_mainLoop); + m_mainLoop = 0; + m_context = 0; return; } @@ -241,47 +262,49 @@ QPulseAudioEngine::QPulseAudioEngine(QObject *parent) break; case PA_CONTEXT_TERMINATED: - qCritical("Context terminated."); + qCritical("PulseAudioService: Context terminated."); keepGoing = false; ok = false; break; case PA_CONTEXT_FAILED: default: - qCritical() << QString("Connection failure: %1").arg(pa_strerror(pa_context_errno(m_context))); + qCritical() << QString("PulseAudioService: Connection failure: %1").arg(pa_strerror(pa_context_errno(m_context))); keepGoing = false; ok = false; } - if (keepGoing) { + if (keepGoing) pa_threaded_mainloop_wait(m_mainLoop); - } } if (ok) { pa_context_set_state_callback(m_context, contextStateCallback, this); } else { - if (m_context) { - pa_context_unref(m_context); - m_context = 0; - } + pa_context_unref(m_context); + m_context = 0; } - pa_threaded_mainloop_unlock(m_mainLoop); + unlock(); if (ok) { - serverInfo(); - sinks(); - sources(); + updateDevices(); + m_prepared = true; + } else { + pa_threaded_mainloop_free(m_mainLoop); + m_mainLoop = 0; + onContextFailed(); } } -QPulseAudioEngine::~QPulseAudioEngine() +void QPulseAudioEngine::release() { + if (!m_prepared) + return; + if (m_context) { - pa_threaded_mainloop_lock(m_mainLoop); pa_context_disconnect(m_context); - pa_threaded_mainloop_unlock(m_mainLoop); + pa_context_unref(m_context); m_context = 0; } @@ -290,62 +313,52 @@ QPulseAudioEngine::~QPulseAudioEngine() pa_threaded_mainloop_free(m_mainLoop); m_mainLoop = 0; } + + m_prepared = false; } -void QPulseAudioEngine::serverInfo() +void QPulseAudioEngine::updateDevices() { - pa_operation *operation; - - pa_threaded_mainloop_lock(m_mainLoop); - - operation = pa_context_get_server_info(m_context, serverInfoCallback, this); + lock(); + // 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); - pa_threaded_mainloop_unlock(m_mainLoop); -} - -void QPulseAudioEngine::sinks() -{ - pa_operation *operation; - - pa_threaded_mainloop_lock(m_mainLoop); - + // 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); + // 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); - pa_threaded_mainloop_unlock(m_mainLoop); + unlock(); - // Swap the default sink to index 0 + // Swap the default output to index 0 m_sinks.removeOne(m_defaultSink); m_sinks.prepend(m_defaultSink); + + // Swap the default input to index 0 + m_sources.removeOne(m_defaultSource); + m_sources.prepend(m_defaultSource); } -void QPulseAudioEngine::sources() +void QPulseAudioEngine::onContextFailed() { - pa_operation *operation; - - pa_threaded_mainloop_lock(m_mainLoop); - - operation = pa_context_get_source_info_list(m_context, sourceInfoCallback, this); + // Give a chance to the connected slots to still use the Pulse main loop before releasing it. + emit contextFailed(); - while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) - pa_threaded_mainloop_wait(m_mainLoop); - - pa_operation_unref(operation); + release(); - pa_threaded_mainloop_unlock(m_mainLoop); - - // Swap the default source to index 0 - m_sources.removeOne(m_defaultSource); - m_sources.prepend(m_defaultSource); + // Try to reconnect later + QTimer::singleShot(3000, this, SLOT(prepare())); } QPulseAudioEngine *QPulseAudioEngine::instance() |