summaryrefslogtreecommitdiffstats
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.cpp118
1 files changed, 96 insertions, 22 deletions
diff --git a/src/plugins/pulseaudio/qpulseaudioengine.cpp b/src/plugins/pulseaudio/qpulseaudioengine.cpp
index 9b9da6b62..e9510fd6a 100644
--- a/src/plugins/pulseaudio/qpulseaudioengine.cpp
+++ b/src/plugins/pulseaudio/qpulseaudioengine.cpp
@@ -75,8 +75,10 @@ static void serverInfoCallback(pa_context *context, const pa_server_info *info,
#endif
QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine*>(userdata);
+ pulseEngine->m_serverLock.lockForWrite();
pulseEngine->m_defaultSink = info->default_sink_name;
pulseEngine->m_defaultSource = info->default_source_name;
+ pulseEngine->m_serverLock.unlock();
pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
}
@@ -84,11 +86,6 @@ static void serverInfoCallback(pa_context *context, const pa_server_info *info,
static void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int isLast, void *userdata)
{
QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine*>(userdata);
- QMap<pa_sink_state, QString> stateMap;
- stateMap[PA_SINK_INVALID_STATE] = "n/a";
- stateMap[PA_SINK_RUNNING] = "RUNNING";
- stateMap[PA_SINK_IDLE] = "IDLE";
- stateMap[PA_SINK_SUSPENDED] = "SUSPENDED";
if (isLast < 0) {
qWarning() << QString("Failed to get sink information: %s").arg(pa_strerror(pa_context_errno(context)));
@@ -103,6 +100,12 @@ static void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int
Q_ASSERT(info);
#ifdef DEBUG_PULSE
+ QMap<pa_sink_state, QString> stateMap;
+ stateMap[PA_SINK_INVALID_STATE] = "n/a";
+ stateMap[PA_SINK_RUNNING] = "RUNNING";
+ stateMap[PA_SINK_IDLE] = "IDLE";
+ stateMap[PA_SINK_SUSPENDED] = "SUSPENDED";
+
qDebug() << QString("Sink #%1\n"
"\tState: %2\n"
"\tName: %3\n"
@@ -114,8 +117,10 @@ static void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int
#endif
QAudioFormat format = QPulseAudioInternal::sampleSpecToAudioFormat(info->sample_spec);
+
+ QWriteLocker locker(&pulseEngine->m_sinkLock);
pulseEngine->m_preferredFormats.insert(info->name, format);
- pulseEngine->m_sinks.append(info->name);
+ pulseEngine->m_sinks.insert(info->index, info->name);
}
static void sourceInfoCallback(pa_context *context, const pa_source_info *info, int isLast, void *userdata)
@@ -123,12 +128,6 @@ static void sourceInfoCallback(pa_context *context, const pa_source_info *info,
Q_UNUSED(context)
QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine*>(userdata);
- QMap<pa_source_state, QString> stateMap;
- stateMap[PA_SOURCE_INVALID_STATE] = "n/a";
- stateMap[PA_SOURCE_RUNNING] = "RUNNING";
- stateMap[PA_SOURCE_IDLE] = "IDLE";
- stateMap[PA_SOURCE_SUSPENDED] = "SUSPENDED";
-
if (isLast) {
pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
return;
@@ -137,6 +136,12 @@ static void sourceInfoCallback(pa_context *context, const pa_source_info *info,
Q_ASSERT(info);
#ifdef DEBUG_PULSE
+ QMap<pa_source_state, QString> stateMap;
+ stateMap[PA_SOURCE_INVALID_STATE] = "n/a";
+ stateMap[PA_SOURCE_RUNNING] = "RUNNING";
+ stateMap[PA_SOURCE_IDLE] = "IDLE";
+ stateMap[PA_SOURCE_SUSPENDED] = "SUSPENDED";
+
qDebug() << QString("Source #%1\n"
"\tState: %2\n"
"\tName: %3\n"
@@ -148,8 +153,57 @@ static void sourceInfoCallback(pa_context *context, const pa_source_info *info,
#endif
QAudioFormat format = QPulseAudioInternal::sampleSpecToAudioFormat(info->sample_spec);
+
+ QWriteLocker locker(&pulseEngine->m_sourceLock);
pulseEngine->m_preferredFormats.insert(info->name, format);
- pulseEngine->m_sources.append(info->name);
+ pulseEngine->m_sources.insert(info->index, info->name);
+}
+
+static void event_cb(pa_context* context, pa_subscription_event_type_t t, uint32_t index, void* userdata)
+{
+ QPulseAudioEngine *pulseEngine = static_cast<QPulseAudioEngine*>(userdata);
+
+ int type = t & PA_SUBSCRIPTION_EVENT_TYPE_MASK;
+ int facility = t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
+
+ switch (type) {
+ 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));
+ break;
+ case PA_SUBSCRIPTION_EVENT_SINK:
+ pa_operation_unref(pa_context_get_sink_info_by_index(context, index, sinkInfoCallback, userdata));
+ break;
+ case PA_SUBSCRIPTION_EVENT_SOURCE:
+ pa_operation_unref(pa_context_get_source_info_by_index(context, index, sourceInfoCallback, userdata));
+ break;
+ default:
+ break;
+ }
+ break;
+ case PA_SUBSCRIPTION_EVENT_REMOVE:
+ switch (facility) {
+ case PA_SUBSCRIPTION_EVENT_SINK:
+ pulseEngine->m_sinkLock.lockForWrite();
+ pulseEngine->m_preferredFormats.remove(pulseEngine->m_sinks.value(index));
+ pulseEngine->m_sinks.remove(index);
+ pulseEngine->m_sinkLock.unlock();
+ break;
+ case PA_SUBSCRIPTION_EVENT_SOURCE:
+ pulseEngine->m_sourceLock.lockForWrite();
+ pulseEngine->m_preferredFormats.remove(pulseEngine->m_sources.value(index));
+ pulseEngine->m_sources.remove(index);
+ pulseEngine->m_sourceLock.unlock();
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
}
static void contextStateCallbackInit(pa_context *context, void *userdata)
@@ -272,6 +326,13 @@ void QPulseAudioEngine::prepare()
if (ok) {
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_subscription_mask_t(PA_SUBSCRIPTION_MASK_SINK |
+ PA_SUBSCRIPTION_MASK_SOURCE |
+ PA_SUBSCRIPTION_MASK_SERVER),
+ NULL, NULL));
} else {
pa_context_unref(m_context);
m_context = 0;
@@ -332,14 +393,6 @@ void QPulseAudioEngine::updateDevices()
pa_operation_unref(operation);
unlock();
-
- // 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::onContextFailed()
@@ -360,7 +413,28 @@ QPulseAudioEngine *QPulseAudioEngine::instance()
QList<QByteArray> QPulseAudioEngine::availableDevices(QAudio::Mode mode) const
{
- return mode == QAudio::AudioOutput ? m_sinks : m_sources;
+ QList<QByteArray> devices;
+ QByteArray defaultDevice;
+
+ m_serverLock.lockForRead();
+
+ if (mode == QAudio::AudioOutput) {
+ QReadLocker locker(&m_sinkLock);
+ devices = m_sinks.values();
+ defaultDevice = m_defaultSink;
+ } else {
+ QReadLocker locker(&m_sourceLock);
+ devices = m_sources.values();
+ defaultDevice = m_defaultSource;
+ }
+
+ m_serverLock.unlock();
+
+ // Swap the default device to index 0
+ devices.removeOne(defaultDevice);
+ devices.prepend(defaultDevice);
+
+ return devices;
}
QT_END_NAMESPACE