diff --git a/kcms/phonon/audiosetup.cpp b/kcms/phonon/audiosetup.cpp index c9148cbe6..e8a82549c 100644 --- a/kcms/phonon/audiosetup.cpp +++ b/kcms/phonon/audiosetup.cpp @@ -1,884 +1,884 @@ /* This file is part of the KDE project Copyright (C) 2010 Colin Guthrie Copyright (C) 2011 Harald Sitter This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "audiosetup.h" #include #include "phonon_debug.h" #include #include #include #include #include #include #include "testspeakerwidget.h" #define SS_DEFAULT_ICON "audio-card" #define THAT(userdata) Q_ASSERT(userdata); AudioSetup *ss = static_cast(userdata) static pa_glib_mainloop *s_mainloop = NULL; static pa_context *s_context = NULL; QMap s_Cards; QMap s_Sinks; QMap s_Sources; static void card_cb(pa_context *c, const pa_card_info *i, int eol, void *userdata) { Q_ASSERT(c); THAT(userdata); if (eol < 0) { if (pa_context_errno(c) == PA_ERR_NOENTITY) return; qCDebug(KCM_PHONON_LOG) << "Card callback failure"; return; } if (eol > 0) { ss->updateFromPulse(); return; } Q_ASSERT(i); ss->updateCard(i); } static void sink_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata) { Q_ASSERT(c); THAT(userdata); if (eol < 0) { if (pa_context_errno(c) == PA_ERR_NOENTITY) return; qCDebug(KCM_PHONON_LOG) << "Sink callback failure"; return; } if (eol > 0) { ss->updateIndependantDevices(); ss->updateFromPulse(); return; } Q_ASSERT(i); ss->updateSink(i); } static void source_cb(pa_context *c, const pa_source_info *i, int eol, void *userdata) { Q_ASSERT(c); THAT(userdata); if (eol < 0) { if (pa_context_errno(c) == PA_ERR_NOENTITY) return; qCDebug(KCM_PHONON_LOG) << "Source callback failure"; return; } if (eol > 0) { ss->updateIndependantDevices(); ss->updateFromPulse(); return; } Q_ASSERT(i); ss->updateSource(i); } static void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata) { Q_ASSERT(c); THAT(userdata); switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { case PA_SUBSCRIPTION_EVENT_CARD: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { ss->removeCard(index); } else { pa_operation *operation = pa_context_get_card_info_by_index(c, index, card_cb, ss); if (!operation) { qCDebug(KCM_PHONON_LOG) << "pa_context_get_card_info_by_index() failed"; return; } pa_operation_unref(operation); } break; case PA_SUBSCRIPTION_EVENT_SINK: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { ss->removeSink(index); } else { pa_operation *operation = pa_context_get_sink_info_by_index(c, index, sink_cb, ss); if (!operation) { qCDebug(KCM_PHONON_LOG) << "pa_context_get_sink_info_by_index() failed"; return; } pa_operation_unref(operation); } break; case PA_SUBSCRIPTION_EVENT_SOURCE: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { ss->removeSource(index); } else { pa_operation *o; if (!(o = pa_context_get_source_info_by_index(c, index, source_cb, ss))) { qCDebug(KCM_PHONON_LOG) << "pa_context_get_source_info_by_index() failed"; return; } pa_operation_unref(o); } break; } } static void context_state_callback(pa_context *c, void *userdata) { Q_ASSERT(c); THAT(userdata); qCDebug(KCM_PHONON_LOG) << "context_state_callback" << pa_context_get_state(c); pa_context_state_t state = pa_context_get_state(c); if (state == PA_CONTEXT_READY) { // Attempt to load things up pa_operation *o; pa_context_set_subscribe_callback(c, subscribe_cb, ss); if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t) (PA_SUBSCRIPTION_MASK_CARD| PA_SUBSCRIPTION_MASK_SINK| PA_SUBSCRIPTION_MASK_SOURCE), NULL, NULL))) { qCDebug(KCM_PHONON_LOG) << "pa_context_subscribe() failed"; return; } pa_operation_unref(o); if (!(o = pa_context_get_card_info_list(c, card_cb, ss))) { qCDebug(KCM_PHONON_LOG) << "pa_context_get_card_info_list() failed"; return; } pa_operation_unref(o); if (!(o = pa_context_get_sink_info_list(c, sink_cb, ss))) { qCDebug(KCM_PHONON_LOG) << "pa_context_get_sink_info_list() failed"; return; } pa_operation_unref(o); if (!(o = pa_context_get_source_info_list(c, source_cb, ss))) { qCDebug(KCM_PHONON_LOG) << "pa_context_get_source_info_list() failed"; return; } pa_operation_unref(o); ss->load(); } else if (!PA_CONTEXT_IS_GOOD(state)) { // If this is our probe phase, exit our context immediately if (s_context != c) pa_context_disconnect(c); else { qCWarning(KCM_PHONON_LOG) << "PulseAudio context lost. Scheduling reconnect in eventloop."; pa_context_unref(s_context); s_context = 0; QMetaObject::invokeMethod(ss, "connectToDaemon", Qt::QueuedConnection); } } } static void suspended_callback(pa_stream *s, void *userdata) { THAT(userdata); if (pa_stream_is_suspended(s)) ss->updateVUMeter(-1); } static void read_callback(pa_stream *s, size_t length, void *userdata) { THAT(userdata); const void *data; int v; if (pa_stream_peek(s, &data, &length) < 0) { qCDebug(KCM_PHONON_LOG) << "Failed to read data from stream"; return; } Q_ASSERT(length > 0); Q_ASSERT(length % sizeof(float) == 0); v = ((const float*) data)[length / sizeof(float) -1] * 100; pa_stream_drop(s); if (v < 0) v = 0; if (v > 100) v = 100; ss->updateVUMeter(v); } AudioSetup::AudioSetup(QWidget *parent) : QWidget(parent) , m_OutstandingRequests(3) , m_Canberra(0) , m_VUStream(0) , m_VURealValue(0) { setupUi(this); cardLabel->setEnabled(false); cardBox->setEnabled(false); profileLabel->setVisible(false); profileBox->setVisible(false); deviceLabel->setEnabled(false); deviceBox->setEnabled(false); portLabel->setVisible(false); portBox->setVisible(false); for (int i = 0; i < 5; ++i) placementGrid->setColumnStretch(i, 1); for (int i = 0; i < 3; ++i) placementGrid->setRowStretch(i, 1); m_icon = new QLabel(this); m_icon->setPixmap(QPixmap(KUser().faceIconPath())); if (m_icon->pixmap()->isNull()) m_icon->setPixmap(QIcon::fromTheme("system-users").pixmap(KIconLoader::SizeHuge, KIconLoader::SizeHuge)); m_icon->setMaximumSize(KIconLoader::SizeHuge, KIconLoader::SizeHuge); m_icon->setScaledContents(true); placementGrid->addWidget(m_icon, 1, 2, Qt::AlignCenter); update(); connect(cardBox, static_cast(&KComboBox::currentIndexChanged), this, &AudioSetup::cardChanged); connect(profileBox, static_cast(&KComboBox::currentIndexChanged), this, &AudioSetup::profileChanged); connect(deviceBox, static_cast(&KComboBox::currentIndexChanged), this, &AudioSetup::deviceChanged); connect(portBox, static_cast(&KComboBox::currentIndexChanged), this, &AudioSetup::portChanged); m_VUTimer = new QTimer(this); m_VUTimer->setInterval(10); connect(m_VUTimer, &QTimer::timeout, this, &AudioSetup::reallyUpdateVUMeter); // We require a glib event loop const QByteArray eventDispatcher( QAbstractEventDispatcher::instance()->metaObject()->className()); if (!eventDispatcher.contains("EventDispatcherGlib")) { qCDebug(KCM_PHONON_LOG) << "Disabling PulseAudio integration for lack of GLib event loop."; return; } int ret = ca_context_create(&m_Canberra); if (ret < 0) { qCDebug(KCM_PHONON_LOG) << "Disabling PulseAudio integration. Canberra context failed."; return; } s_mainloop = pa_glib_mainloop_new(NULL); if (!s_mainloop) { qCDebug(KCM_PHONON_LOG) << "Disabling PulseAudio integration for lack of working GLib event loop."; ca_context_destroy(m_Canberra); m_Canberra = 0; return; } connectToDaemon(); } AudioSetup::~AudioSetup() { if (m_Canberra) ca_context_destroy(m_Canberra); if (s_context) { pa_context_unref(s_context); s_context = 0; } if (s_mainloop) { pa_glib_mainloop_free(s_mainloop); s_mainloop = 0; } s_Cards.clear(); s_Sinks.clear(); s_Sources.clear(); } void AudioSetup::load() { } void AudioSetup::save() { } void AudioSetup::defaults() { } void AudioSetup::updateCard(const pa_card_info *pInfo) { cardInfo info; info.index = pInfo->index; const char *description = pa_proplist_gets(pInfo->proplist, PA_PROP_DEVICE_DESCRIPTION); if(description) info.name = QString::fromUtf8(description); else info.name = QString::fromUtf8(pInfo->name); const char *icon = pa_proplist_gets(pInfo->proplist, PA_PROP_DEVICE_ICON_NAME); if (icon) info.icon = QString::fromUtf8(icon); else info.icon = QString::fromUtf8(SS_DEFAULT_ICON); for (quint32 i = 0; i < pInfo->n_profiles; ++i) { const pa_card_profile_info *profile = &(pInfo->profiles[i]); const quint32 priority = profile->priority; const QPair name(profile->name ? QString::fromUtf8(profile->name) : QString(), profile->description ? QString::fromUtf8(profile->description) : QString()); info.profiles.insert(priority, name); } if (pInfo->active_profile) info.activeProfile = pInfo->active_profile->name; cardBox->blockSignals(true); if (s_Cards.contains(pInfo->index)) { int idx = cardBox->findData(pInfo->index); if (idx >= 0) { cardBox->setItemIcon(idx, QIcon::fromTheme(info.icon)); cardBox->setItemText(idx, info.name); } } else { cardBox->addItem(QIcon::fromTheme(info.icon), info.name, pInfo->index); } cardBox->blockSignals(false); s_Cards[pInfo->index] = info; cardChanged(); qCDebug(KCM_PHONON_LOG) << "Got info about card" << info.name; } void AudioSetup::removeCard(uint32_t index) { s_Cards.remove(index); updateFromPulse(); const int idx = cardBox->findData(index); if (idx >= 0) cardBox->removeItem(idx); } void AudioSetup::updateSink(const pa_sink_info* i) { deviceInfo info; info.index = i->index; info.cardIndex = i->card; info.name = QString::fromUtf8(i->description); const char *icon = pa_proplist_gets(i->proplist, PA_PROP_DEVICE_ICON_NAME); info.icon = icon ? icon : SS_DEFAULT_ICON; info.channelMap = i->channel_map; for (uint32_t j = 0; j < i->n_ports; ++j) info.ports[i->ports[j]->priority] = QPair(i->ports[j]->name, QString::fromUtf8(i->ports[j]->description)); if (i->active_port) info.activePort = i->active_port->name; s_Sinks[i->index] = info; // Need to update the currently displayed port if this sink is the currently displayed one. if (info.ports.size()) { int idx = deviceBox->currentIndex(); if (idx >= 0) { qint64 index = deviceBox->itemData(idx).toInt(); if (index >= 0 && index == i->index) { portBox->blockSignals(true); portBox->setCurrentIndex(portBox->findData(info.activePort)); portBox->blockSignals(false); } } } qCDebug(KCM_PHONON_LOG) << "Got info about sink" << info.name; } void AudioSetup::removeSink(uint32_t index) { s_Sinks.remove(index); updateIndependantDevices(); updateFromPulse(); int idx = deviceBox->findData(index); if (idx >= 0) deviceBox->removeItem(idx); } void AudioSetup::updateSource(const pa_source_info* i) { if (i->monitor_of_sink != PA_INVALID_INDEX) return; deviceInfo info; info.index = i->index; info.cardIndex = i->card; info.name = QString::fromUtf8(i->description); const char* icon = pa_proplist_gets(i->proplist, PA_PROP_DEVICE_ICON_NAME); info.icon = icon ? icon : SS_DEFAULT_ICON; info.channelMap = i->channel_map; for (uint32_t j = 0; j < i->n_ports; ++j) info.ports[i->ports[j]->priority] = QPair(i->ports[j]->name, QString::fromUtf8(i->ports[j]->description)); if (i->active_port) info.activePort = i->active_port->name; s_Sources[i->index] = info; // Need to update the currently displayed port if this source is the currently displayed one. if (false && info.ports.size()) { int idx = deviceBox->currentIndex(); if (idx >= 0) { qint64 index = deviceBox->itemData(idx).toInt(); if (index < 0 && ((-1*index) - 1) == i->index) { portBox->blockSignals(true); portBox->setCurrentIndex(portBox->findData(info.activePort)); portBox->blockSignals(false); } } } qCDebug(KCM_PHONON_LOG) << "Got info about source" << info.name; } void AudioSetup::removeSource(uint32_t index) { s_Sources.remove(index); updateIndependantDevices(); updateFromPulse(); int idx = deviceBox->findData(index); if (false && idx >= 0) deviceBox->removeItem(idx); } void AudioSetup::updateFromPulse() { bool setupReady = false; if (m_OutstandingRequests > 0) { if (0 == --m_OutstandingRequests) { // Work out which seclector to pick by default (we want to choose a real Card if possible) if (s_Cards.size() != cardBox->count()) cardBox->setCurrentIndex(1); setupReady = true; } } if (!m_OutstandingRequests) { if (!s_Cards.size() && !s_Sinks.size()) { cardLabel->setEnabled(false); cardBox->setEnabled(false); profileLabel->setVisible(false); profileBox->setVisible(false); deviceLabel->setEnabled(false); deviceBox->setEnabled(false); portLabel->setVisible(false); portBox->setVisible(false); } if (s_Cards.size() && !cardBox->isEnabled()) { cardLabel->setEnabled(true); cardBox->setEnabled(true); cardChanged(); } if (s_Sinks.size() && !deviceBox->isEnabled()) { deviceLabel->setEnabled(true); deviceBox->setEnabled(true); deviceChanged(); } if (setupReady) { emit ready(); } } } void AudioSetup::cardChanged() { int idx = cardBox->currentIndex(); if (idx < 0) { profileLabel->setVisible(false); profileBox->setVisible(false); return; } uint32_t card_index = cardBox->itemData(idx).toUInt(); Q_ASSERT(PA_INVALID_INDEX == card_index || s_Cards.contains(card_index)); bool show_profiles = (PA_INVALID_INDEX != card_index && s_Cards[card_index].profiles.size()); if (show_profiles) { cardInfo &card_info = s_Cards[card_index]; profileBox->blockSignals(true); profileBox->clear(); QMap >::const_iterator it; for (it = card_info.profiles.constBegin(); it != card_info.profiles.constEnd(); ++it) profileBox->insertItem(0, it.value().second, it.value().first); profileBox->setCurrentIndex(profileBox->findData(card_info.activeProfile)); profileBox->blockSignals(false); } profileLabel->setVisible(show_profiles); profileBox->setVisible(show_profiles); deviceBox->blockSignals(true); deviceBox->clear(); QMap::const_iterator it; for (it = s_Sinks.constBegin(); it != s_Sinks.constEnd(); ++it) { if (it->cardIndex == card_index) deviceBox->addItem(QIcon::fromTheme(it->icon), i18n("Playback (%1)", it->name), it->index); } for (it = s_Sources.constBegin(); it != s_Sources.constEnd(); ++it) { if (it->cardIndex == card_index) deviceBox->addItem(QIcon::fromTheme(it->icon), i18n("Recording (%1)", it->name), ((-1*it->index) - 1)); } deviceBox->blockSignals(false); deviceGroupBox->setEnabled(!!deviceBox->count()); deviceChanged(); qCDebug(KCM_PHONON_LOG) << "Doing update" << cardBox->currentIndex(); emit changed(); } void AudioSetup::profileChanged() { quint32 card_index = cardBox->itemData(cardBox->currentIndex()).toUInt(); Q_ASSERT(PA_INVALID_INDEX != card_index); QString profile = profileBox->itemData(profileBox->currentIndex()).toString(); qCDebug(KCM_PHONON_LOG) << "Changing profile to" << profile; Q_ASSERT(s_Cards[card_index].profiles.size()); pa_operation *operation = pa_context_set_card_profile_by_index(s_context, card_index, qPrintable(profile), NULL, NULL); if (!operation) qCDebug(KCM_PHONON_LOG) << "pa_context_set_card_profile_by_name() failed"; else pa_operation_unref(operation); emit changed(); } void AudioSetup::updateIndependantDevices() { // Should we display the "Independent Devices" drop down? // Count all the sinks without cards bool showID = false; QMap::const_iterator it; for (it = s_Sinks.constBegin(); it != s_Sinks.constEnd(); ++it) { if (PA_INVALID_INDEX == it->cardIndex) { showID = true; break; } } bool haveID = (PA_INVALID_INDEX == cardBox->itemData(0).toUInt()); qCDebug(KCM_PHONON_LOG) << QString("Want ID: %1; Have ID: %2").arg(showID?"Yes":"No").arg(haveID?"Yes":"No"); cardBox->blockSignals(true); if (haveID && !showID) cardBox->removeItem(0); else if (!haveID && showID) cardBox->insertItem(0, QIcon::fromTheme(SS_DEFAULT_ICON), i18n("Independent Devices"), PA_INVALID_INDEX); cardBox->blockSignals(false); } void AudioSetup::updateVUMeter(int vol) { if (vol < 0) { inputLevels->setEnabled(false); inputLevels->setValue(0); m_VURealValue = 0; } else { inputLevels->setEnabled(true); if (vol > inputLevels->value()) inputLevels->setValue(vol); m_VURealValue = vol; } } void AudioSetup::reallyUpdateVUMeter() { int val = inputLevels->value(); if (val > m_VURealValue) inputLevels->setValue(val-1); } bool AudioSetup::connectToDaemon() { pa_mainloop_api *api = pa_glib_mainloop_get_api(s_mainloop); s_context = pa_context_new(api, i18n("KDE Audio Hardware Setup").toUtf8().constData()); if (pa_context_connect(s_context, NULL, PA_CONTEXT_NOFAIL, 0) < 0) { qCDebug(KCM_PHONON_LOG) << "Disabling PulseAudio integration. Context connection failed: " << pa_strerror(pa_context_errno(s_context)); pa_context_unref(s_context); s_context = 0; pa_glib_mainloop_free(s_mainloop); s_mainloop = 0; ca_context_destroy(m_Canberra); m_Canberra = 0; setEnabled(false); return false; } pa_context_set_state_callback(s_context, &context_state_callback, this); setEnabled(true); return true; } static deviceInfo &getDeviceInfo(qint64 index) { if (index >= 0) { Q_ASSERT(s_Sinks.contains(index)); return s_Sinks[index]; } index = (-1 * index) - 1; Q_ASSERT(s_Sources.contains(index)); return s_Sources[index]; } void AudioSetup::deviceChanged() { int idx = deviceBox->currentIndex(); if (idx < 0) { portLabel->setVisible(false); portBox->setVisible(false); _updatePlacementTester(); return; } qint64 index = deviceBox->itemData(idx).toInt(); deviceInfo &device_info = getDeviceInfo(index); qCDebug(KCM_PHONON_LOG) << QString("Updating ports for device '%1' (%2 ports available)") .arg(device_info.name) .arg(device_info.ports.size()); bool showPorts = !!device_info.ports.size(); if (showPorts) { portBox->blockSignals(true); portBox->clear(); QMap >::const_iterator it; for (it = device_info.ports.constBegin(); it != device_info.ports.constEnd(); ++it) portBox->insertItem(0, it.value().second, it.value().first); portBox->setCurrentIndex(portBox->findData(device_info.activePort)); portBox->blockSignals(false); } portLabel->setVisible(showPorts); portBox->setVisible(showPorts); if (deviceBox->currentIndex() >= 0) { if (index < 0) _createMonitorStreamForSource((-1*index) - 1); else if (m_VUStream) { pa_stream_disconnect(m_VUStream); m_VUStream = NULL; } _updatePlacementTester(); } emit changed(); } void AudioSetup::portChanged() { qint64 index = deviceBox->itemData(deviceBox->currentIndex()).toInt(); QString port = portBox->itemData(portBox->currentIndex()).toString(); qCDebug(KCM_PHONON_LOG) << "Changing port to" << port; #ifndef QT_NO_DEBUG deviceInfo &device_info = getDeviceInfo(index); Q_ASSERT(device_info.ports.size()); #endif /* QT_NO_DEBUG */ pa_operation *o; if (index >= 0) { if (!(o = pa_context_set_sink_port_by_index(s_context, (uint32_t)index, port.toLatin1().constData(), NULL, NULL))) qCDebug(KCM_PHONON_LOG) << "pa_context_set_sink_port_by_index() failed"; else pa_operation_unref(o); } else { if (!(o = pa_context_set_source_port_by_index(s_context, (uint32_t)((-1*index) - 1), port.toLatin1().constData(), NULL, NULL))) qCDebug(KCM_PHONON_LOG) << "pa_context_set_source_port_by_index() failed"; else pa_operation_unref(o); } emit changed(); } void AudioSetup::_updatePlacementTester() { static const int position_table[] = { /* Position, X, Y */ PA_CHANNEL_POSITION_FRONT_LEFT, 0, 0, PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, 1, 0, PA_CHANNEL_POSITION_FRONT_CENTER, 2, 0, PA_CHANNEL_POSITION_MONO, 2, 0, PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, 3, 0, PA_CHANNEL_POSITION_FRONT_RIGHT, 4, 0, PA_CHANNEL_POSITION_SIDE_LEFT, 0, 1, PA_CHANNEL_POSITION_SIDE_RIGHT, 4, 1, PA_CHANNEL_POSITION_REAR_LEFT, 0, 2, PA_CHANNEL_POSITION_REAR_CENTER, 2, 2, PA_CHANNEL_POSITION_REAR_RIGHT, 4, 2, PA_CHANNEL_POSITION_LFE, 3, 2 }; QLayoutItem* w; while ((w = placementGrid->takeAt(0))) { if (w->widget() != m_icon) { if (w->widget()) delete w->widget(); delete w; } } placementGrid->addWidget(m_icon, 1, 2, Qt::AlignCenter); int idx = deviceBox->currentIndex(); if (idx < 0) return; qint64 index = deviceBox->itemData(idx).toInt(); deviceInfo& sink_info = getDeviceInfo(index); if (index < 0) { playbackOrCaptureStack->setCurrentIndex(1); m_VUTimer->start(); return; } playbackOrCaptureStack->setCurrentIndex(0); m_VUTimer->stop(); for (int i = 0; i < 36; i += 3) { pa_channel_position_t pos = (pa_channel_position_t)position_table[i]; // Check to see if we have this item in our current channel map. bool have = false; for (uint32_t j = 0; j < sink_info.channelMap.channels; ++j) { if (sink_info.channelMap.map[j] == pos) { have = true; break; } } if (!have) { continue; } QPushButton *btn = new TestSpeakerWidget(pos, m_Canberra, this); placementGrid->addWidget(btn, position_table[i+2], position_table[i+1], Qt::AlignCenter); } } void AudioSetup::_createMonitorStreamForSource(uint32_t source_idx) { if (m_VUStream) { pa_stream_disconnect(m_VUStream); m_VUStream = NULL; } char t[16]; pa_buffer_attr attr; pa_sample_spec ss; ss.channels = 1; ss.format = PA_SAMPLE_FLOAT32; ss.rate = 25; memset(&attr, 0, sizeof(attr)); attr.fragsize = sizeof(float); attr.maxlength = static_cast(-1); snprintf(t, sizeof(t), "%u", source_idx); m_VUStream = pa_stream_new(s_context, "Peak detect", &ss, NULL); if (!m_VUStream) { qCDebug(KCM_PHONON_LOG) << "Failed to create monitoring stream"; return; } pa_stream_set_read_callback(m_VUStream, read_callback, this); pa_stream_set_suspended_callback(m_VUStream, suspended_callback, this); if (pa_stream_connect_record(m_VUStream, t, &attr, (pa_stream_flags_t) (PA_STREAM_DONT_MOVE|PA_STREAM_PEAK_DETECT|PA_STREAM_ADJUST_LATENCY)) < 0) { qCDebug(KCM_PHONON_LOG) << "Failed to connect monitoring stream"; pa_stream_unref(m_VUStream); m_VUStream = NULL; } } quint32 AudioSetup::getCurrentSinkIndex() { int idx = deviceBox->currentIndex(); if (idx < 0) return PA_INVALID_INDEX; qint64 index = deviceBox->itemData(idx).toInt(); if (index >= 0) return static_cast(index); return PA_INVALID_INDEX; } QDebug operator<<(QDebug dbg, const pa_context_state_t &state) { QString name; switch (state) { - case PA_CONTEXT_UNCONNECTED: name = QLatin1Literal("Unconnected"); - case PA_CONTEXT_CONNECTING: name = QLatin1Literal("Connecting"); - case PA_CONTEXT_AUTHORIZING: name = QLatin1Literal("Authorizing"); - case PA_CONTEXT_SETTING_NAME: name = QLatin1Literal("Setting Name"); - case PA_CONTEXT_READY: name = QLatin1Literal("Ready"); - case PA_CONTEXT_FAILED: name = QLatin1Literal("Failed"); - case PA_CONTEXT_TERMINATED: name = QLatin1Literal("Terminated"); + case PA_CONTEXT_UNCONNECTED: name = QLatin1Literal("Unconnected"); break; + case PA_CONTEXT_CONNECTING: name = QLatin1Literal("Connecting"); break; + case PA_CONTEXT_AUTHORIZING: name = QLatin1Literal("Authorizing"); break; + case PA_CONTEXT_SETTING_NAME: name = QLatin1Literal("Setting Name"); break; + case PA_CONTEXT_READY: name = QLatin1Literal("Ready"); break; + case PA_CONTEXT_FAILED: name = QLatin1Literal("Failed"); break; + case PA_CONTEXT_TERMINATED: name = QLatin1Literal("Terminated"); break; } if (name.isEmpty()) - name = QString("Unknown state(%0)").arg(state); + name = QString("Unknown state(%1)").arg(state); dbg.nospace() << name; return dbg; }