diff options
Diffstat (limited to 'src/plugins/pulseaudio/qpulseaudioengine.cpp')
-rw-r--r-- | src/plugins/pulseaudio/qpulseaudioengine.cpp | 118 |
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 |