summaryrefslogtreecommitdiff
path: root/src/plugins/pulseaudio/qpulseaudioengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/pulseaudio/qpulseaudioengine.cpp')
-rw-r--r--src/plugins/pulseaudio/qpulseaudioengine.cpp139
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()