summaryrefslogtreecommitdiffstats
path: root/redhat/tdemultimedia/tdemultimedia-3.5.13.2-kmix_pulseaudio.patch
diff options
context:
space:
mode:
Diffstat (limited to 'redhat/tdemultimedia/tdemultimedia-3.5.13.2-kmix_pulseaudio.patch')
-rw-r--r--redhat/tdemultimedia/tdemultimedia-3.5.13.2-kmix_pulseaudio.patch1519
1 files changed, 0 insertions, 1519 deletions
diff --git a/redhat/tdemultimedia/tdemultimedia-3.5.13.2-kmix_pulseaudio.patch b/redhat/tdemultimedia/tdemultimedia-3.5.13.2-kmix_pulseaudio.patch
deleted file mode 100644
index 0759d6ebb..000000000
--- a/redhat/tdemultimedia/tdemultimedia-3.5.13.2-kmix_pulseaudio.patch
+++ /dev/null
@@ -1,1519 +0,0 @@
-diff -Nuar ./kmix-tde-ori/kmix-platforms.cpp ./kmix/kmix-platforms.cpp
---- ./kmix-tde-ori/kmix-platforms.cpp 2013-05-09 17:10:41.010638051 +0200
-+++ ./kmix/kmix-platforms.cpp 2013-05-09 17:18:23.202075902 +0200
-@@ -46,8 +46,10 @@
- #define ALSA_MIXER
- #endif
-
-+#define PULSE_MIXER
-+
- #define OSS_MIXER
--#endif
-+#endif // __linux__
-
- #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(_UNIXWARE) || defined(__DragonFly__)
- #define OSS_MIXER
-@@ -79,6 +81,10 @@
- #include "mixer_alsa9.cpp"
- #endif
-
-+#if defined(PULSE_MIXER)
-+#include "mixer_pulse.cpp"
-+#endif
-+
- #if defined(OSS_MIXER)
- #include "mixer_oss.cpp"
-
-@@ -91,7 +97,7 @@
- #define OSS4_MIXER
- #endif
-
--#endif
-+#endif // OSS_MIXER
-
- #if defined(OSS4_MIXER)
- #include "mixer_oss4.cpp"
-@@ -137,6 +143,10 @@
- { ALSA_getMixer, ALSA_getDriverName, ALSA_getDevIterator },
- #endif
-
-+#if defined(PULSE_MIXER)
-+ { PULSE_getMixer, PULSE_getDriverName, NULL },
-+#endif
-+
- #if defined(OSS4_MIXER)
- { OSS4_getMixer, OSS4_getDriverName, NULL },
- #endif
-diff -Nuar ./kmix-tde-ori/Makefile.am ./kmix/Makefile.am
---- ./kmix-tde-ori/Makefile.am 2013-05-09 17:10:41.010638051 +0200
-+++ ./kmix/Makefile.am 2013-05-21 23:47:47.607546135 +0200
-@@ -41,7 +41,7 @@
- verticaltext.cpp mixerIface.skel colorwidget.ui dialogviewconfiguration.cpp \
- kmixtoolbox.cpp mixertoolbox.cpp dialogselectmaster.cpp
-
--kmix_panelapplet_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
-+kmix_panelapplet_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -I/usr/include/glib-2.0 -module
- kmix_panelapplet_la_LIBADD = $(LIB_KDEUI) $(LIB_KUTILS) $(LIBALIB) $(LIBOSSAUDIO) $(LIBASOUND)
-
- xdg_apps_DATA = kmix.desktop
-diff -Nuar ./kmix-tde-ori/mixer_pulse.cpp ./kmix/mixer_pulse.cpp
---- ./kmix-tde-ori/mixer_pulse.cpp 1970-01-01 01:00:00.000000000 +0100
-+++ ./kmix/mixer_pulse.cpp 2013-05-21 23:37:43.565178347 +0200
-@@ -0,0 +1,1368 @@
-+/*
-+ * KMix -- KDE's full featured mini mixer
-+ *
-+ *
-+ * Copyright (C) 2008 Helio Chissini de Castro <helio@kde.org>
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Library General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2 of the License, or (at your option) any later version.
-+ *
-+ * 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
-+ * Library General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Library 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 "mixer_pulse.h"
-+
-+#include <cstdlib>
-+//#include <QtCore/QAbstractEventDispatcher>
-+#include <tqtimer.h>
-+
-+#include <klocale.h>
-+
-+#include "mixer.h"
-+//#include "core/ControlManager.h"
-+//#include "core/GlobalConfig.h"
-+
-+#include <pulse/glib-mainloop.h>
-+#include <pulse/ext-stream-restore.h>
-+#if defined(HAVE_CANBERRA)
-+# include <canberra.h>
-+#endif
-+
-+// PA_VOLUME_UI_MAX landed in pulseaudio-0.9.23, so this can be removed when/if
-+// minimum requirement is ever bumped up (from 0.9.12 currently)
-+#ifndef PA_VOLUME_UI_MAX
-+#define PA_VOLUME_UI_MAX (pa_sw_volume_from_dB(+11.0))
-+#endif
-+
-+#define HAVE_SOURCE_OUTPUT_VOLUMES PA_CHECK_VERSION(1,0,0)
-+
-+#define KMIXPA_PLAYBACK 0
-+#define KMIXPA_CAPTURE 1
-+#define KMIXPA_APP_PLAYBACK 2
-+#define KMIXPA_APP_CAPTURE 3
-+#define KMIXPA_WIDGET_MAX KMIXPA_APP_CAPTURE
-+
-+#define KMIXPA_EVENT_KEY "sink-input-by-media-role:event"
-+
-+static unsigned int refcount = 0;
-+static pa_glib_mainloop *s_mainloop = NULL;
-+static pa_context *s_context = NULL;
-+static enum { UNKNOWN, ACTIVE, INACTIVE } s_pulseActive = UNKNOWN;
-+static int s_outstandingRequests = 0;
-+
-+#if defined(HAVE_CANBERRA)
-+static ca_context *s_ccontext = NULL;
-+#endif
-+
-+TQMap<int,Mixer_PULSE*> s_mixers;
-+
-+typedef TQMap<int,devinfo> devmap;
-+static devmap outputDevices;
-+static devmap captureDevices;
-+static TQMap<int,TQString> clients;
-+static devmap outputStreams;
-+static devmap captureStreams;
-+static devmap outputRoles;
-+
-+typedef struct {
-+ pa_channel_map channel_map;
-+ pa_cvolume volume;
-+ bool mute;
-+ TQString device;
-+} restoreRule;
-+static TQMap<TQString,restoreRule> s_RestoreRules;
-+
-+static void dec_outstanding(pa_context *c) {
-+ if (s_outstandingRequests <= 0)
-+ return;
-+
-+ if (--s_outstandingRequests == 0)
-+ {
-+ s_pulseActive = ACTIVE;
-+
-+ // If this is our probe phase, exit our context immediately
-+ if (s_context != c) {
-+ pa_context_disconnect(c);
-+ } else
-+ kDebug(67100) << "Reconnected to PulseAudio";
-+ }
-+}
-+
-+static void translateMasksAndMaps(devinfo& dev)
-+{
-+ dev.chanMask = Volume::MNONE;
-+ dev.chanIDs.clear();
-+
-+ if (dev.channel_map.channels != dev.volume.channels) {
-+ kError() << "Hiddeous Channel mixup map says " << dev.channel_map.channels << ", volume says: " << dev.volume.channels;
-+ return;
-+ }
-+ if (1 == dev.channel_map.channels && PA_CHANNEL_POSITION_MONO == dev.channel_map.map[0]) {
-+ // We just use the left channel to represent this.
-+ dev.chanMask = (Volume::ChannelMask)( dev.chanMask | Volume::MLEFT);
-+ dev.chanIDs[0] = Volume::LEFT;
-+ } else {
-+ for (uint8_t i = 0; i < dev.channel_map.channels; ++i) {
-+ switch (dev.channel_map.map[i]) {
-+ case PA_CHANNEL_POSITION_MONO:
-+ kWarning(67100) << "Channel Map contains a MONO element but has >1 channel - we can't handle this.";
-+ return;
-+
-+ case PA_CHANNEL_POSITION_FRONT_LEFT:
-+ dev.chanMask = (Volume::ChannelMask)( dev.chanMask | Volume::MLEFT);
-+ dev.chanIDs[i] = Volume::LEFT;
-+ break;
-+ case PA_CHANNEL_POSITION_FRONT_RIGHT:
-+ dev.chanMask = (Volume::ChannelMask)( dev.chanMask | Volume::MRIGHT);
-+ dev.chanIDs[i] = Volume::RIGHT;
-+ break;
-+ case PA_CHANNEL_POSITION_FRONT_CENTER:
-+ dev.chanMask = (Volume::ChannelMask)( dev.chanMask | Volume::MCENTER);
-+ dev.chanIDs[i] = Volume::CENTER;
-+ break;
-+ case PA_CHANNEL_POSITION_REAR_CENTER:
-+ dev.chanMask = (Volume::ChannelMask)( dev.chanMask | Volume::MREARCENTER);
-+ dev.chanIDs[i] = Volume::REARCENTER;
-+ break;
-+ case PA_CHANNEL_POSITION_REAR_LEFT:
-+ dev.chanMask = (Volume::ChannelMask)( dev.chanMask | Volume::MSURROUNDLEFT);
-+ dev.chanIDs[i] = Volume::SURROUNDLEFT;
-+ break;
-+ case PA_CHANNEL_POSITION_REAR_RIGHT:
-+ dev.chanMask = (Volume::ChannelMask)( dev.chanMask | Volume::MSURROUNDRIGHT);
-+ dev.chanIDs[i] = Volume::SURROUNDRIGHT;
-+ break;
-+ case PA_CHANNEL_POSITION_LFE:
-+ dev.chanMask = (Volume::ChannelMask)( dev.chanMask | Volume::MWOOFER);
-+ dev.chanIDs[i] = Volume::WOOFER;
-+ break;
-+ case PA_CHANNEL_POSITION_SIDE_LEFT:
-+ dev.chanMask = (Volume::ChannelMask)( dev.chanMask | Volume::MREARSIDELEFT);
-+ dev.chanIDs[i] = Volume::REARSIDELEFT;
-+ break;
-+ case PA_CHANNEL_POSITION_SIDE_RIGHT:
-+ dev.chanMask = (Volume::ChannelMask)( dev.chanMask | Volume::MREARSIDERIGHT);
-+ dev.chanIDs[i] = Volume::REARSIDERIGHT;
-+ break;
-+ default:
-+ kWarning(67100) << "Channel Map contains a pa_channel_position we cannot handle " << dev.channel_map.map[i];
-+ break;
-+ }
-+ }
-+ }
-+}
-+
-+static TQString getIconNameFromProplist(pa_proplist *l) {
-+ const char *t;
-+
-+ if ((t = pa_proplist_gets(l, PA_PROP_MEDIA_ICON_NAME)))
-+ return TQString::fromUtf8(t);
-+
-+ if ((t = pa_proplist_gets(l, PA_PROP_WINDOW_ICON_NAME)))
-+ return TQString::fromUtf8(t);
-+
-+ if ((t = pa_proplist_gets(l, PA_PROP_APPLICATION_ICON_NAME)))
-+ return TQString::fromUtf8(t);
-+
-+ if ((t = pa_proplist_gets(l, PA_PROP_MEDIA_ROLE))) {
-+
-+ if (strcmp(t, "video") == 0 || strcmp(t, "phone") == 0)
-+ return TQString::fromUtf8(t);
-+
-+ if (strcmp(t, "music") == 0)
-+ return "audio";
-+
-+ if (strcmp(t, "game") == 0)
-+ return "applications-games";
-+
-+ if (strcmp(t, "event") == 0)
-+ return "dialog-information";
-+ }
-+
-+ return "";
-+}
-+
-+static void sink_cb(pa_context *c, const pa_sink_info *i, int eol, void *) {
-+
-+ if (eol < 0) {
-+ if (pa_context_errno(c) == PA_ERR_NOENTITY)
-+ return;
-+
-+ kWarning(67100) << "Sink callback failure";
-+ return;
-+ }
-+
-+ if (eol > 0) {
-+ dec_outstanding(c);
-+ if (s_mixers.contains(KMIXPA_PLAYBACK))
-+ s_mixers[KMIXPA_PLAYBACK]->triggerUpdate();
-+ return;
-+ }
-+
-+ devinfo s;
-+ s.index = s.device_index = i->index;
-+ s.name = TQString::fromUtf8(i->name).replace(' ', '_');
-+ s.description = TQString::fromUtf8(i->description);
-+ s.icon_name = TQString::fromUtf8(pa_proplist_gets(i->proplist, PA_PROP_DEVICE_ICON_NAME));
-+ s.volume = i->volume;
-+ s.channel_map = i->channel_map;
-+ s.mute = !!i->mute;
-+ s.stream_restore_rule = "";
-+
-+ translateMasksAndMaps(s);
-+
-+ bool is_new = !outputDevices.contains(s.index);
-+ outputDevices[s.index] = s;
-+// kDebug(67100) << "Got some info about sink: " << s.description;
-+
-+ if (s_mixers.contains(KMIXPA_PLAYBACK)) {
-+ if (is_new)
-+ s_mixers[KMIXPA_PLAYBACK]->addWidget(s.index);
-+ else {
-+ int mid = s_mixers[KMIXPA_PLAYBACK]->id2num(s.name);
-+ if (mid >= 0) {
-+ MixSet *ms = s_mixers[KMIXPA_PLAYBACK]->getMixSet();
-+ (*ms)[mid]->setReadableName(s.description);
-+ }
-+ }
-+ }
-+}
-+
-+static void source_cb(pa_context *c, const pa_source_info *i, int eol, void *) {
-+
-+ if (eol < 0) {
-+ if (pa_context_errno(c) == PA_ERR_NOENTITY)
-+ return;
-+
-+ kWarning(67100) << "Source callback failure";
-+ return;
-+ }
-+
-+ if (eol > 0) {
-+ dec_outstanding(c);
-+ if (s_mixers.contains(KMIXPA_CAPTURE))
-+ s_mixers[KMIXPA_CAPTURE]->triggerUpdate();
-+ return;
-+ }
-+
-+ // Do something....
-+ if (PA_INVALID_INDEX != i->monitor_of_sink)
-+ {
-+ kDebug(67100) << "Ignoring Monitor Source: " << i->description;
-+ return;
-+ }
-+
-+ devinfo s;
-+ s.index = s.device_index = i->index;
-+ s.name = TQString::fromUtf8(i->name).replace(' ', '_');
-+ s.description = TQString::fromUtf8(i->description);
-+ s.icon_name = TQString::fromUtf8(pa_proplist_gets(i->proplist, PA_PROP_DEVICE_ICON_NAME));
-+ s.volume = i->volume;
-+ s.channel_map = i->channel_map;
-+ s.mute = !!i->mute;
-+ s.stream_restore_rule = "";
-+
-+ translateMasksAndMaps(s);
-+
-+ bool is_new = !captureDevices.contains(s.index);
-+ captureDevices[s.index] = s;
-+// kDebug(67100) << "Got some info about source: " << s.description;
-+
-+ if (s_mixers.contains(KMIXPA_CAPTURE)) {
-+ if (is_new)
-+ s_mixers[KMIXPA_CAPTURE]->addWidget(s.index);
-+ else {
-+ int mid = s_mixers[KMIXPA_CAPTURE]->id2num(s.name);
-+ if (mid >= 0) {
-+ MixSet *ms = s_mixers[KMIXPA_CAPTURE]->getMixSet();
-+ (*ms)[mid]->setReadableName(s.description);
-+ }
-+ }
-+ }
-+}
-+
-+static void client_cb(pa_context *c, const pa_client_info *i, int eol, void *) {
-+
-+ if (eol < 0) {
-+ if (pa_context_errno(c) == PA_ERR_NOENTITY)
-+ return;
-+
-+ kWarning(67100) << "Client callback failure";
-+ return;
-+ }
-+
-+ if (eol > 0) {
-+ dec_outstanding(c);
-+ return;
-+ }
-+
-+ clients[i->index] = TQString::fromUtf8(i->name);
-+ //kDebug(67100) << "Got some info about client: " << clients[i->index];
-+}
-+
-+static void sink_input_cb(pa_context *c, const pa_sink_input_info *i, int eol, void *) {
-+
-+ if (eol < 0) {
-+ if (pa_context_errno(c) == PA_ERR_NOENTITY)
-+ return;
-+
-+ kWarning(67100) << "Sink Input callback failure";
-+ return;
-+ }
-+
-+ if (eol > 0) {
-+ dec_outstanding(c);
-+ if (s_mixers.contains(KMIXPA_APP_PLAYBACK))
-+ s_mixers[KMIXPA_APP_PLAYBACK]->triggerUpdate();
-+ return;
-+ }
-+
-+ const char *t;
-+ if ((t = pa_proplist_gets(i->proplist, "module-stream-restore.id"))) {
-+ if (strcmp(t, KMIXPA_EVENT_KEY) == 0) {
-+ kWarning(67100) << "Ignoring sink-input due to it being designated as an event and thus handled by the Event slider";
-+ return;
-+ }
-+ }
-+
-+ TQString appname = i18n("Unknown Application");
-+ if (clients.contains(i->client))
-+ appname = clients[i->client];
-+
-+ TQString prefix = TQString("%1: ").arg(appname);
-+
-+ devinfo s;
-+ s.index = i->index;
-+ s.device_index = i->sink;
-+ s.description = prefix + TQString::fromUtf8(i->name);
-+ s.name = TQString("stream:") + TQString::number(i->index); //appname.replace(' ', '_').toLower();
-+ s.icon_name = getIconNameFromProplist(i->proplist);
-+ s.channel_map = i->channel_map;
-+ s.volume = i->volume;
-+ s.mute = !!i->mute;
-+ s.stream_restore_rule = TQString::fromUtf8(t);
-+
-+ translateMasksAndMaps(s);
-+
-+ bool is_new = !outputStreams.contains(s.index);
-+ outputStreams[s.index] = s;
-+// kDebug(67100) << "Got some info about sink input (playback stream): " << s.description;
-+
-+ if (s_mixers.contains(KMIXPA_APP_PLAYBACK)) {
-+ if (is_new)
-+ s_mixers[KMIXPA_APP_PLAYBACK]->addWidget(s.index, true);
-+ else {
-+ int mid = s_mixers[KMIXPA_APP_PLAYBACK]->id2num(s.name);
-+ if (mid >= 0) {
-+ MixSet *ms = s_mixers[KMIXPA_APP_PLAYBACK]->getMixSet();
-+ (*ms)[mid]->setReadableName(s.description);
-+ }
-+ }
-+ }
-+}
-+
-+static void source_output_cb(pa_context *c, const pa_source_output_info *i, int eol, void *) {
-+
-+ if (eol < 0) {
-+ if (pa_context_errno(c) == PA_ERR_NOENTITY)
-+ return;
-+
-+ kWarning(67100) << "Source Output callback failure";
-+ return;
-+ }
-+
-+ if (eol > 0) {
-+ dec_outstanding(c);
-+ if (s_mixers.contains(KMIXPA_APP_CAPTURE))
-+ s_mixers[KMIXPA_APP_CAPTURE]->triggerUpdate();
-+ return;
-+ }
-+
-+ /* NB Until Source Outputs support volumes, we just use the volume of the source itself */
-+ if (!captureDevices.contains(i->source)) {
-+ kDebug(67100) << "Source Output refers to a Source we don't have any info for (probably just a peak meter or similar)";
-+ return;
-+ }
-+
-+ TQString appname = i18n("Unknown Application");
-+ if (clients.contains(i->client))
-+ appname = clients[i->client];
-+
-+ TQString prefix = TQString("%1: ").arg(appname);
-+
-+ devinfo s;
-+ s.index = i->index;
-+ s.device_index = i->source;
-+ s.description = prefix + TQString::fromUtf8(i->name);
-+ s.name = TQString("stream:") + TQString::number(i->index); //appname.replace(' ', '_').toLower();
-+ s.icon_name = getIconNameFromProplist(i->proplist);
-+ s.channel_map = i->channel_map;
-+#if HAVE_SOURCE_OUTPUT_VOLUMES
-+ s.volume = i->volume;
-+ s.mute = !!i->mute;
-+#else
-+ s.volume = captureDevices[i->source].volume;
-+ s.mute = captureDevices[i->source].mute;
-+#endif
-+ s.stream_restore_rule = TQString::fromUtf8(pa_proplist_gets(i->proplist, "module-stream-restore.id"));
-+
-+ translateMasksAndMaps(s);
-+
-+ bool is_new = !captureStreams.contains(s.index);
-+ captureStreams[s.index] = s;
-+// kDebug(67100) << "Got some info about source output (capture stream): " << s.description;
-+
-+ if (s_mixers.contains(KMIXPA_APP_CAPTURE)) {
-+ if (is_new)
-+ s_mixers[KMIXPA_APP_CAPTURE]->addWidget(s.index, true);
-+ else {
-+ int mid = s_mixers[KMIXPA_APP_CAPTURE]->id2num(s.name);
-+ if (mid >= 0) {
-+ MixSet *ms = s_mixers[KMIXPA_APP_CAPTURE]->getMixSet();
-+ (*ms)[mid]->setReadableName(s.description);
-+ }
-+ }
-+ }
-+}
-+
-+
-+static devinfo create_role_devinfo(TQString name) {
-+
-+ TQ_ASSERT(s_RestoreRules.contains(name));
-+
-+ devinfo s;
-+ s.index = s.device_index = PA_INVALID_INDEX;
-+ s.description = i18n("Event Sounds");
-+ s.name = TQString("restore:") + name;
-+ s.icon_name = "dialog-information";
-+ s.channel_map = s_RestoreRules[name].channel_map;
-+ s.volume = s_RestoreRules[name].volume;
-+ s.mute = s_RestoreRules[name].mute;
-+ s.stream_restore_rule = name;
-+
-+ translateMasksAndMaps(s);
-+ return s;
-+}
-+
-+
-+void ext_stream_restore_read_cb(pa_context *c, const pa_ext_stream_restore_info *i, int eol, void *) {
-+
-+ if (eol < 0) {
-+ dec_outstanding(c);
-+ kWarning(67100) << "Failed to initialize stream_restore extension: " << pa_strerror(pa_context_errno(s_context));
-+ return;
-+ }
-+
-+ if (eol > 0) {
-+ dec_outstanding(c);
-+
-+ // Special case: ensure that our media events exists.
-+ // On first login by a new users, this wont be in our database so we should create it.
-+ if (!s_RestoreRules.contains(KMIXPA_EVENT_KEY)) {
-+ // Create a fake rule
-+ restoreRule rule;
-+ rule.channel_map.channels = 1;
-+ rule.channel_map.map[0] = PA_CHANNEL_POSITION_MONO;
-+ rule.volume.channels = 1;
-+ rule.volume.values[0] = PA_VOLUME_NORM;
-+ rule.mute = false;
-+ rule.device = "";
-+ s_RestoreRules[KMIXPA_EVENT_KEY] = rule;
-+ kDebug(67100) << "Initialising restore rule for new user: " << i18n("Event Sounds");
-+ }
-+
-+ if (s_mixers.contains(KMIXPA_APP_PLAYBACK)) {
-+ // If we have rules, it will be created below... but if no rules
-+ // then we add it here.
-+ if (!outputRoles.contains(PA_INVALID_INDEX)) {
-+ devinfo s = create_role_devinfo(KMIXPA_EVENT_KEY);
-+ outputRoles[s.index] = s;
-+
-+ s_mixers[KMIXPA_APP_PLAYBACK]->addWidget(s.index);
-+ }
-+
-+ s_mixers[KMIXPA_APP_PLAYBACK]->triggerUpdate();
-+ }
-+
-+ return;
-+ }
-+
-+
-+ TQString name = TQString::fromUtf8(i->name);
-+// kDebug(67100) << TQString("Got some info about restore rule: '%1' (Device: %2)").arg(name).arg(i->device ? i->device : "None");
-+ restoreRule rule;
-+ rule.channel_map = i->channel_map;
-+ rule.volume = i->volume;
-+ rule.mute = !!i->mute;
-+ rule.device = i->device;
-+
-+ if (rule.channel_map.channels < 1 && name == KMIXPA_EVENT_KEY) {
-+ // Stream restore rules may not have valid volumes/channel maps (as these are optional)
-+ // but we need a valid volume+channelmap for our events sounds so fix it up.
-+ rule.channel_map.channels = 1;
-+ rule.channel_map.map[0] = PA_CHANNEL_POSITION_MONO;
-+ rule.volume.channels = 1;
-+ rule.volume.values[0] = PA_VOLUME_NORM;
-+ }
-+
-+ s_RestoreRules[name] = rule;
-+
-+ if (s_mixers.contains(KMIXPA_APP_PLAYBACK)) {
-+ // We only want to know about Sound Events for now...
-+ if (name == KMIXPA_EVENT_KEY) {
-+ devinfo s = create_role_devinfo(name);
-+ bool is_new = !outputRoles.contains(s.index);
-+ outputRoles[s.index] = s;
-+
-+ if (is_new)
-+ s_mixers[KMIXPA_APP_PLAYBACK]->addWidget(s.index, true);
-+ }
-+ }
-+}
-+
-+static void ext_stream_restore_subscribe_cb(pa_context *c, void *) {
-+
-+ TQ_ASSERT(c == s_context);
-+
-+ pa_operation *o;
-+ if (!(o = pa_ext_stream_restore_read(c, ext_stream_restore_read_cb, NULL))) {
-+ kWarning(67100) << "pa_ext_stream_restore_read() failed";
-+ return;
-+ }
-+
-+ pa_operation_unref(o);
-+}
-+
-+
-+static void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *) {
-+
-+ TQ_ASSERT(c == s_context);
-+
-+ switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
-+ case PA_SUBSCRIPTION_EVENT_SINK:
-+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-+ if (s_mixers.contains(KMIXPA_PLAYBACK))
-+ s_mixers[KMIXPA_PLAYBACK]->removeWidget(index);
-+ } else {
-+ pa_operation *o;
-+ if (!(o = pa_context_get_sink_info_by_index(c, index, sink_cb, NULL))) {
-+ kWarning(67100) << "pa_context_get_sink_info_by_index() failed";
-+ return;
-+ }
-+ pa_operation_unref(o);
-+ }
-+ break;
-+
-+ case PA_SUBSCRIPTION_EVENT_SOURCE:
-+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-+ if (s_mixers.contains(KMIXPA_CAPTURE))
-+ s_mixers[KMIXPA_CAPTURE]->removeWidget(index);
-+ } else {
-+ pa_operation *o;
-+ if (!(o = pa_context_get_source_info_by_index(c, index, source_cb, NULL))) {
-+ kWarning(67100) << "pa_context_get_source_info_by_index() failed";
-+ return;
-+ }
-+ pa_operation_unref(o);
-+ }
-+ break;
-+
-+ case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
-+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-+ if (s_mixers.contains(KMIXPA_APP_PLAYBACK))
-+ s_mixers[KMIXPA_APP_PLAYBACK]->removeWidget(index);
-+ } else {
-+ pa_operation *o;
-+ if (!(o = pa_context_get_sink_input_info(c, index, sink_input_cb, NULL))) {
-+ kWarning(67100) << "pa_context_get_sink_input_info() failed";
-+ return;
-+ }
-+ pa_operation_unref(o);
-+ }
-+ break;
-+
-+ case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
-+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-+ if (s_mixers.contains(KMIXPA_APP_CAPTURE))
-+ s_mixers[KMIXPA_APP_CAPTURE]->removeWidget(index);
-+ } else {
-+ pa_operation *o;
-+ if (!(o = pa_context_get_source_output_info(c, index, source_output_cb, NULL))) {
-+ kWarning(67100) << "pa_context_get_sink_input_info() failed";
-+ return;
-+ }
-+ pa_operation_unref(o);
-+ }
-+ break;
-+
-+ case PA_SUBSCRIPTION_EVENT_CLIENT:
-+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-+ clients.remove(index);
-+ } else {
-+ pa_operation *o;
-+ if (!(o = pa_context_get_client_info(c, index, client_cb, NULL))) {
-+ kWarning(67100) << "pa_context_get_client_info() failed";
-+ return;
-+ }
-+ pa_operation_unref(o);
-+ }
-+ break;
-+
-+ }
-+}
-+
-+
-+static void context_state_callback(pa_context *c, void *)
-+{
-+ pa_context_state_t state = pa_context_get_state(c);
-+ if (state == PA_CONTEXT_READY) {
-+ // Attempt to load things up
-+ pa_operation *o;
-+
-+ // 1. Register for the stream changes (except during probe)
-+ if (s_context == c) {
-+ pa_context_set_subscribe_callback(c, subscribe_cb, NULL);
-+
-+ if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t)
-+ (PA_SUBSCRIPTION_MASK_SINK|
-+ PA_SUBSCRIPTION_MASK_SOURCE|
-+ PA_SUBSCRIPTION_MASK_CLIENT|
-+ PA_SUBSCRIPTION_MASK_SINK_INPUT|
-+ PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT), NULL, NULL))) {
-+ kWarning(67100) << "pa_context_subscribe() failed";
-+ return;
-+ }
-+ pa_operation_unref(o);
-+ }
-+
-+ if (!(o = pa_context_get_sink_info_list(c, sink_cb, NULL))) {
-+ kWarning(67100) << "pa_context_get_sink_info_list() failed";
-+ return;
-+ }
-+ pa_operation_unref(o);
-+ s_outstandingRequests++;
-+
-+ if (!(o = pa_context_get_source_info_list(c, source_cb, NULL))) {
-+ kWarning(67100) << "pa_context_get_source_info_list() failed";
-+ return;
-+ }
-+ pa_operation_unref(o);
-+ s_outstandingRequests++;
-+
-+
-+ if (!(o = pa_context_get_client_info_list(c, client_cb, NULL))) {
-+ kWarning(67100) << "pa_context_client_info_list() failed";
-+ return;
-+ }
-+ pa_operation_unref(o);
-+ s_outstandingRequests++;
-+
-+ if (!(o = pa_context_get_sink_input_info_list(c, sink_input_cb, NULL))) {
-+ kWarning(67100) << "pa_context_get_sink_input_info_list() failed";
-+ return;
-+ }
-+ pa_operation_unref(o);
-+ s_outstandingRequests++;
-+
-+ if (!(o = pa_context_get_source_output_info_list(c, source_output_cb, NULL))) {
-+ kWarning(67100) << "pa_context_get_source_output_info_list() failed";
-+ return;
-+ }
-+ pa_operation_unref(o);
-+ s_outstandingRequests++;
-+
-+ /* These calls are not always supported */
-+ if ((o = pa_ext_stream_restore_read(c, ext_stream_restore_read_cb, NULL))) {
-+ pa_operation_unref(o);
-+ s_outstandingRequests++;
-+
-+ pa_ext_stream_restore_set_subscribe_cb(c, ext_stream_restore_subscribe_cb, NULL);
-+
-+ if ((o = pa_ext_stream_restore_subscribe(c, 1, NULL, NULL)))
-+ pa_operation_unref(o);
-+ } else {
-+ kWarning(67100) << "Failed to initialize stream_restore extension: " << pa_strerror(pa_context_errno(s_context));
-+ }
-+ } 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 {
-+ // If we're not probing, it means we've been disconnected from our
-+ // glib context
-+ pa_context_unref(s_context);
-+ s_context = NULL;
-+
-+ // Remove all GUI elements
-+ TQMap<int,Mixer_PULSE*>::iterator it;
-+ for (it = s_mixers.begin(); it != s_mixers.end(); ++it) {
-+ (*it)->removeAllWidgets();
-+ }
-+ // This one is not handled above.
-+ clients.clear();
-+
-+ if (s_mixers.contains(KMIXPA_PLAYBACK)) {
-+ kWarning(67100) << "Connection to PulseAudio daemon closed. Attempting reconnection.";
-+ s_pulseActive = UNKNOWN;
-+ TQTimer::singleShot(50, s_mixers[KMIXPA_PLAYBACK], SLOT(reinit()));
-+ }
-+ }
-+ }
-+}
-+
-+static void setVolumeFromPulse(Volume& volume, const devinfo& dev)
-+{
-+ chanIDMap::const_iterator iter;
-+ for (iter = dev.chanIDs.begin(); iter != dev.chanIDs.end(); ++iter)
-+ {
-+ //kDebug(67100) << "Setting volume for channel " << iter.value() << " to " << (long)dev.volume.values[iter.key()] << " (" << ((100*(long)dev.volume.values[iter.key()]) / PA_VOLUME_NORM) << "%)";
-+ volume.setVolume(iter.value(), (long)dev.volume.values[iter.key()]);
-+ }
-+}
-+
-+static pa_cvolume genVolumeForPulse(const devinfo& dev, Volume& volume)
-+{
-+ pa_cvolume cvol = dev.volume;
-+
-+ chanIDMap::const_iterator iter;
-+ for (iter = dev.chanIDs.begin(); iter != dev.chanIDs.end(); ++iter)
-+ {
-+ cvol.values[iter.key()] = (uint32_t)volume.getVolume(iter.value());
-+ //kDebug(67100) << "Setting volume for channel " << iter.value() << " to " << cvol.values[iter.key()] << " (" << ((100*cvol.values[iter.key()]) / PA_VOLUME_NORM) << "%)";
-+ }
-+ return cvol;
-+}
-+
-+static devmap* get_widget_map(int type, TQString id = "")
-+{
-+ TQ_ASSERT(type >= 0 && type <= KMIXPA_WIDGET_MAX);
-+
-+ if (KMIXPA_PLAYBACK == type)
-+ return &outputDevices;
-+ else if (KMIXPA_CAPTURE == type)
-+ return &captureDevices;
-+ else if (KMIXPA_APP_PLAYBACK == type) {
-+ if (id.startsWith("restore:"))
-+ return &outputRoles;
-+ return &outputStreams;
-+ } else if (KMIXPA_APP_CAPTURE == type)
-+ return &captureStreams;
-+
-+ TQ_ASSERT(0);
-+ return NULL;
-+}
-+static devmap* get_widget_map(int type, int index)
-+{
-+ if (PA_INVALID_INDEX == (uint32_t)index)
-+ return get_widget_map(type, "restore:");
-+ return get_widget_map(type);
-+}
-+
-+void Mixer_PULSE::emitControlsReconfigured()
-+{
-+ ControlManager::instance().announce(_mixer->id(), ControlChangeType::ControlList, getDriverName());
-+}
-+
-+void Mixer_PULSE::addWidget(int index, bool isAppStream)
-+{
-+ devmap* map = get_widget_map(m_devnum, index);
-+
-+ if (!map->contains(index)) {
-+ kWarning(67100) << "New " << m_devnum << " widget notified for index " << index << " but I cannot find it in my list :s";
-+ return;
-+ }
-+ addDevice((*map)[index], isAppStream);
-+ emitControlsReconfigured();
-+}
-+
-+void Mixer_PULSE::removeWidget(int index)
-+{
-+ devmap* map = get_widget_map(m_devnum);
-+
-+ if (!map->contains(index)) {
-+ //kWarning(67100) << "Removing " << m_devnum << " widget notified for index " << index << " but I cannot find it in my list :s";
-+ // Sometimes we ignore things (e.g. event sounds) so don't be too noisy here.
-+ return;
-+ }
-+
-+ TQString id = (*map)[index].name;
-+ map->remove(index);
-+
-+ // We need to find the MixDevice that goes with this widget and remove it.
-+ MixSet::iterator iter;
-+ for (iter = m_mixDevices.begin(); iter != m_mixDevices.end(); ++iter)
-+ {
-+ if ((*iter)->id() == id)
-+ {
-+ shared_ptr<MixDevice> md = m_mixDevices.get(id);
-+ kDebug() << "MixDevice 1 useCount=" << md.use_count();
-+ md->close();
-+ kDebug() << "MixDevice 2 useCount=" << md.use_count();
-+
-+ m_mixDevices.erase(iter);
-+ kDebug() << "MixDevice 3 useCount=" << md.use_count();
-+ emitControlsReconfigured();
-+ kDebug() << "MixDevice 4 useCount=" << md.use_count();
-+ return;
-+ }
-+ }
-+}
-+
-+void Mixer_PULSE::removeAllWidgets()
-+{
-+ devmap* map = get_widget_map(m_devnum);
-+ map->clear();
-+
-+ // Special case
-+ if (KMIXPA_APP_PLAYBACK == m_devnum)
-+ outputRoles.clear();
-+
-+ freeMixDevices();
-+ emitControlsReconfigured();
-+}
-+
-+void Mixer_PULSE::addDevice(devinfo& dev, bool isAppStream)
-+{
-+ if (dev.chanMask != Volume::MNONE) {
-+ MixSet *ms = 0;
-+ if (m_devnum == KMIXPA_APP_PLAYBACK && s_mixers.contains(KMIXPA_PLAYBACK))
-+ ms = s_mixers[KMIXPA_PLAYBACK]->getMixSet();
-+ else if (m_devnum == KMIXPA_APP_CAPTURE && s_mixers.contains(KMIXPA_CAPTURE))
-+ ms = s_mixers[KMIXPA_CAPTURE]->getMixSet();
-+
-+ int maxVol = GlobalConfig::instance().volumeOverdrive ? PA_VOLUME_UI_MAX : PA_VOLUME_NORM;
-+ Volume v(maxVol, PA_VOLUME_MUTED, true, false);
-+ v.addVolumeChannels(dev.chanMask);
-+ setVolumeFromPulse(v, dev);
-+ MixDevice* md = new MixDevice( _mixer, dev.name, dev.description, dev.icon_name, ms);
-+ if (isAppStream)
-+ md->setApplicationStream(true);
-+
-+ kDebug() << "Adding Pulse volume " << dev.name << ", isCapture= " << (m_devnum == KMIXPA_CAPTURE || m_devnum == KMIXPA_APP_CAPTURE) << ", isAppStream= " << isAppStream << "=" << md->isApplicationStream() << ", devnum=" << m_devnum;
-+ md->addPlaybackVolume(v);
-+ md->setMuted(dev.mute);
-+ m_mixDevices.append(md->addToPool());
-+ }
-+}
-+
-+Mixer_Backend* PULSE_getMixer( Mixer *mixer, int devnum )
-+{
-+ Mixer_Backend *l_mixer;
-+ l_mixer = new Mixer_PULSE( mixer, devnum );
-+ return l_mixer;
-+}
-+
-+bool Mixer_PULSE::connectToDaemon()
-+{
-+ TQ_ASSERT(NULL == s_context);
-+
-+ kDebug(67100) << "Attempting connection to PulseAudio sound daemon";
-+ pa_mainloop_api *api = pa_glib_mainloop_get_api(s_mainloop);
-+ TQ_ASSERT(api);
-+
-+ s_context = pa_context_new(api, "KMix");
-+ TQ_ASSERT(s_context);
-+
-+ if (pa_context_connect(s_context, NULL, PA_CONTEXT_NOFAIL, 0) < 0) {
-+ pa_context_unref(s_context);
-+ s_context = NULL;
-+ return false;
-+ }
-+ pa_context_set_state_callback(s_context, &context_state_callback, NULL);
-+ return true;
-+}
-+
-+
-+Mixer_PULSE::Mixer_PULSE(Mixer *mixer, int devnum) : Mixer_Backend(mixer, devnum)
-+{
-+ if ( devnum == -1 )
-+ m_devnum = 0;
-+
-+ TQString pulseenv = qgetenv("KMIX_PULSEAUDIO_DISABLE");
-+ if (pulseenv.toInt())
-+ s_pulseActive = INACTIVE;
-+
-+ // We require a glib event loop
-+ if (!QByteArray(QAbstractEventDispatcher::instance()->metaObject()->className()).contains("EventDispatcherGlib")) {
-+ kDebug(67100) << "Disabling PulseAudio integration for lack of GLib event loop";
-+ s_pulseActive = INACTIVE;
-+ }
-+
-+
-+ ++refcount;
-+ if (INACTIVE != s_pulseActive && 1 == refcount)
-+ {
-+ // First of all conenct to PA via simple/blocking means and if that succeeds,
-+ // use a fully async integrated mainloop method to connect and get proper support.
-+ pa_mainloop *p_test_mainloop;
-+ if (!(p_test_mainloop = pa_mainloop_new())) {
-+ kDebug(67100) << "PulseAudio support disabled: Unable to create mainloop";
-+ s_pulseActive = INACTIVE;
-+ goto endconstruct;
-+ }
-+
-+ pa_context *p_test_context;
-+ if (!(p_test_context = pa_context_new(pa_mainloop_get_api(p_test_mainloop), "kmix-probe"))) {
-+ kDebug(67100) << "PulseAudio support disabled: Unable to create context";
-+ pa_mainloop_free(p_test_mainloop);
-+ s_pulseActive = INACTIVE;
-+ goto endconstruct;
-+ }
-+
-+ kDebug(67100) << "Probing for PulseAudio...";
-+ // (cg) Convert to PA_CONTEXT_NOFLAGS when PulseAudio 0.9.19 is required
-+ if (pa_context_connect(p_test_context, NULL, static_cast<pa_context_flags_t>(0), NULL) < 0) {
-+ kDebug(67100) << TQString("PulseAudio support disabled: %1").arg(pa_strerror(pa_context_errno(p_test_context)));
-+ pa_context_disconnect(p_test_context);
-+ pa_context_unref(p_test_context);
-+ pa_mainloop_free(p_test_mainloop);
-+ s_pulseActive = INACTIVE;
-+ goto endconstruct;
-+ }
-+
-+ // Assume we are inactive, it will be set to active if appropriate
-+ s_pulseActive = INACTIVE;
-+ pa_context_set_state_callback(p_test_context, &context_state_callback, NULL);
-+ for (;;) {
-+ pa_mainloop_iterate(p_test_mainloop, 1, NULL);
-+
-+ if (!PA_CONTEXT_IS_GOOD(pa_context_get_state(p_test_context))) {
-+ kDebug(67100) << "PulseAudio probe complete.";
-+ break;
-+ }
-+ }
-+ pa_context_disconnect(p_test_context);
-+ pa_context_unref(p_test_context);
-+ pa_mainloop_free(p_test_mainloop);
-+
-+
-+ if (INACTIVE != s_pulseActive)
-+ {
-+ // Reconnect via integrated mainloop
-+ s_mainloop = pa_glib_mainloop_new(NULL);
-+ TQ_ASSERT(s_mainloop);
-+
-+ connectToDaemon();
-+
-+#if defined(HAVE_CANBERRA)
-+ int ret = ca_context_create(&s_ccontext);
-+ if (ret < 0) {
-+ kDebug(67100) << "Disabling Sound Feedback. Canberra context failed.";
-+ s_ccontext = NULL;
-+ } else
-+ ca_context_set_driver(s_ccontext, "pulse");
-+#endif
-+ }
-+
-+ kDebug(67100) << "PulseAudio status: " << (s_pulseActive==UNKNOWN ? "Unknown (bug)" : (s_pulseActive==ACTIVE ? "Active" : "Inactive"));
-+ }
-+
-+endconstruct:
-+ s_mixers[m_devnum] = this;
-+}
-+
-+Mixer_PULSE::~Mixer_PULSE()
-+{
-+ s_mixers.remove(m_devnum);
-+
-+ if (refcount > 0)
-+ {
-+ --refcount;
-+ if (0 == refcount)
-+ {
-+#if defined(HAVE_CANBERRA)
-+ if (s_ccontext) {
-+ ca_context_destroy(s_ccontext);
-+ s_ccontext = NULL;
-+ }
-+#endif
-+
-+ if (s_context) {
-+ pa_context_unref(s_context);
-+ s_context = NULL;
-+ }
-+
-+ if (s_mainloop) {
-+ pa_glib_mainloop_free(s_mainloop);
-+ s_mainloop = NULL;
-+ }
-+ }
-+ }
-+
-+ closeCommon();
-+}
-+
-+int Mixer_PULSE::open()
-+{
-+ //kDebug(67100) << "Trying Pulse sink";
-+
-+ if (ACTIVE == s_pulseActive && m_devnum <= KMIXPA_APP_CAPTURE)
-+ {
-+ // Make sure the GUI layers know we are dynamic so as to always paint us
-+ _mixer->setDynamic();
-+
-+ devmap::iterator iter;
-+ if (KMIXPA_PLAYBACK == m_devnum)
-+ {
-+ _id = "Playback Devices";
-+ m_mixerName = i18n("Playback Devices");
-+ for (iter = outputDevices.begin(); iter != outputDevices.end(); ++iter)
-+ addDevice(*iter);
-+ }
-+ else if (KMIXPA_CAPTURE == m_devnum)
-+ {
-+ _id = "Capture Devices";
-+ m_mixerName = i18n("Capture Devices");
-+ for (iter = captureDevices.begin(); iter != captureDevices.end(); ++iter)
-+ addDevice(*iter);
-+ }
-+ else if (KMIXPA_APP_PLAYBACK == m_devnum)
-+ {
-+ _id = "Playback Streams";
-+ m_mixerName = i18n("Playback Streams");
-+ for (iter = outputRoles.begin(); iter != outputRoles.end(); ++iter)
-+ addDevice(*iter, true);
-+ for (iter = outputStreams.begin(); iter != outputStreams.end(); ++iter)
-+ addDevice(*iter, true);
-+ }
-+ else if (KMIXPA_APP_CAPTURE == m_devnum)
-+ {
-+ _id = "Capture Streams";
-+ m_mixerName = i18n("Capture Streams");
-+ for (iter = captureStreams.begin(); iter != captureStreams.end(); ++iter)
-+ addDevice(*iter);
-+ }
-+
-+ kDebug(67100) << "Using PulseAudio for mixer: " << m_mixerName;
-+ m_isOpen = true;
-+ }
-+
-+ return 0;
-+}
-+
-+int Mixer_PULSE::close()
-+{
-+ closeCommon();
-+ return 1;
-+}
-+
-+int Mixer_PULSE::id2num(const TQString& id) {
-+ //kDebug(67100) << "id2num() id=" << id;
-+ int num = -1;
-+ // todo: Store this in a hash or similar
-+ int i;
-+ for (i = 0; i < m_mixDevices.size(); ++i) {
-+ if (m_mixDevices[i]->id() == id) {
-+ num = i;
-+ break;
-+ }
-+ }
-+ //kDebug(67100) << "id2num() num=" << num;
-+ return num;
-+}
-+
-+int Mixer_PULSE::readVolumeFromHW( const TQString& id, shared_ptr<MixDevice> md )
-+{
-+ devmap *map = get_widget_map(m_devnum, id);
-+
-+ devmap::iterator iter;
-+ for (iter = map->begin(); iter != map->end(); ++iter)
-+ {
-+ if (iter->name == id)
-+ {
-+ setVolumeFromPulse(md->playbackVolume(), *iter);
-+ md->setMuted(iter->mute);
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+int Mixer_PULSE::writeVolumeToHW( const TQString& id, shared_ptr<MixDevice> md )
-+{
-+ devmap::iterator iter;
-+ if (KMIXPA_PLAYBACK == m_devnum)
-+ {
-+ for (iter = outputDevices.begin(); iter != outputDevices.end(); ++iter)
-+ {
-+ if (iter->name == id)
-+ {
-+ pa_operation *o;
-+
-+ pa_cvolume volume = genVolumeForPulse(*iter, md->playbackVolume());
-+ if (!(o = pa_context_set_sink_volume_by_index(s_context, iter->index, &volume, NULL, NULL))) {
-+ kWarning(67100) << "pa_context_set_sink_volume_by_index() failed";
-+ return Mixer::ERR_READ;
-+ }
-+ pa_operation_unref(o);
-+
-+ if (!(o = pa_context_set_sink_mute_by_index(s_context, iter->index, (md->isMuted() ? 1 : 0), NULL, NULL))) {
-+ kWarning(67100) << "pa_context_set_sink_mute_by_index() failed";
-+ return Mixer::ERR_READ;
-+ }
-+ pa_operation_unref(o);
-+
-+#if defined(HAVE_CANBERRA)
-+ if (s_ccontext && Mixer::getBeepOnVolumeChange() ) {
-+ int playing = 0;
-+ int cindex = 2; // Note "2" is simply the index we've picked. It's somewhat irrelevant.
-+
-+
-+ ca_context_playing(s_ccontext, cindex, &playing);
-+
-+ // NB Depending on how this is desired to work, we may want to simply
-+ // skip playing, or cancel the currently playing sound and play our
-+ // new one... for now, let's do the latter.
-+ if (playing) {
-+ ca_context_cancel(s_ccontext, cindex);
-+ playing = 0;
-+ }
-+
-+ if (!playing) {
-+ char dev[64];
-+
-+ snprintf(dev, sizeof(dev), "%lu", (unsigned long) iter->index);
-+ ca_context_change_device(s_ccontext, dev);
-+
-+ // Ideally we'd use something like ca_gtk_play_for_widget()...
-+ ca_context_play(
-+ s_ccontext,
-+ cindex,
-+ CA_PROP_EVENT_DESCRIPTION, i18n("Volume Control Feedback Sound").toUtf8().constData(),
-+ CA_PROP_EVENT_ID, "audio-volume-change",
-+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
-+ CA_PROP_CANBERRA_ENABLE, "1",
-+ NULL
-+ );
-+
-+ ca_context_change_device(s_ccontext, NULL);
-+ }
-+ }
-+#endif
-+
-+ return 0;
-+ }
-+ }
-+ }
-+ else if (KMIXPA_CAPTURE == m_devnum)
-+ {
-+ for (iter = captureDevices.begin(); iter != captureDevices.end(); ++iter)
-+ {
-+ if (iter->name == id)
-+ {
-+ pa_operation *o;
-+
-+ pa_cvolume volume = genVolumeForPulse(*iter, md->playbackVolume());
-+ if (!(o = pa_context_set_source_volume_by_index(s_context, iter->index, &volume, NULL, NULL))) {
-+ kWarning(67100) << "pa_context_set_source_volume_by_index() failed";
-+ return Mixer::ERR_READ;
-+ }
-+ pa_operation_unref(o);
-+
-+ if (!(o = pa_context_set_source_mute_by_index(s_context, iter->index, (md->isMuted() ? 1 : 0), NULL, NULL))) {
-+ kWarning(67100) << "pa_context_set_source_mute_by_index() failed";
-+ return Mixer::ERR_READ;
-+ }
-+ pa_operation_unref(o);
-+
-+ return 0;
-+ }
-+ }
-+ }
-+ else if (KMIXPA_APP_PLAYBACK == m_devnum)
-+ {
-+ if (id.startsWith("stream:"))
-+ {
-+ for (iter = outputStreams.begin(); iter != outputStreams.end(); ++iter)
-+ {
-+ if (iter->name == id)
-+ {
-+ pa_operation *o;
-+
-+ pa_cvolume volume = genVolumeForPulse(*iter, md->playbackVolume());
-+ if (!(o = pa_context_set_sink_input_volume(s_context, iter->index, &volume, NULL, NULL))) {
-+ kWarning(67100) << "pa_context_set_sink_input_volume() failed";
-+ return Mixer::ERR_READ;
-+ }
-+ pa_operation_unref(o);
-+
-+ if (!(o = pa_context_set_sink_input_mute(s_context, iter->index, (md->isMuted() ? 1 : 0), NULL, NULL))) {
-+ kWarning(67100) << "pa_context_set_sink_input_mute() failed";
-+ return Mixer::ERR_READ;
-+ }
-+ pa_operation_unref(o);
-+
-+ return 0;
-+ }
-+ }
-+ }
-+ else if (id.startsWith("restore:"))
-+ {
-+ for (iter = outputRoles.begin(); iter != outputRoles.end(); ++iter)
-+ {
-+ if (iter->name == id)
-+ {
-+ restoreRule &rule = s_RestoreRules[iter->stream_restore_rule];
-+ pa_ext_stream_restore_info info;
-+ info.name = iter->stream_restore_rule.toUtf8().constData();
-+ info.channel_map = rule.channel_map;
-+ info.volume = genVolumeForPulse(*iter, md->playbackVolume());
-+ info.device = rule.device.isEmpty() ? NULL : rule.device.toUtf8().constData();
-+ info.mute = (md->isMuted() ? 1 : 0);
-+
-+ pa_operation* o;
-+ if (!(o = pa_ext_stream_restore_write(s_context, PA_UPDATE_REPLACE, &info, 1, true, NULL, NULL))) {
-+ kWarning(67100) << "pa_ext_stream_restore_write() failed" << info.channel_map.channels << info.volume.channels << info.name;
-+ return Mixer::ERR_READ;
-+ }
-+ pa_operation_unref(o);
-+
-+ return 0;
-+ }
-+ }
-+ }
-+ }
-+ else if (KMIXPA_APP_CAPTURE == m_devnum)
-+ {
-+ for (iter = captureStreams.begin(); iter != captureStreams.end(); ++iter)
-+ {
-+ if (iter->name == id)
-+ {
-+ pa_operation *o;
-+
-+#if HAVE_SOURCE_OUTPUT_VOLUMES
-+ pa_cvolume volume = genVolumeForPulse(*iter, md->playbackVolume());
-+ if (!(o = pa_context_set_source_output_volume(s_context, iter->index, &volume, NULL, NULL))) {
-+ kWarning(67100) << "pa_context_set_source_output_volume_by_index() failed";
-+ return Mixer::ERR_READ;
-+ }
-+ pa_operation_unref(o);
-+
-+ if (!(o = pa_context_set_source_output_mute(s_context, iter->index, (md->isMuted() ? 1 : 0), NULL, NULL))) {
-+ kWarning(67100) << "pa_context_set_source_output_mute_by_index() failed";
-+ return Mixer::ERR_READ;
-+ }
-+ pa_operation_unref(o);
-+#else
-+ // NB Note that this is different from APP_PLAYBACK in that we set the volume on the source itself.
-+ pa_cvolume volume = genVolumeForPulse(*iter, md->playbackVolume());
-+ if (!(o = pa_context_set_source_volume_by_index(s_context, iter->device_index, &volume, NULL, NULL))) {
-+ kWarning(67100) << "pa_context_set_source_volume_by_index() failed";
-+ return Mixer::ERR_READ;
-+ }
-+ pa_operation_unref(o);
-+
-+ if (!(o = pa_context_set_source_mute_by_index(s_context, iter->device_index, (md->isMuted() ? 1 : 0), NULL, NULL))) {
-+ kWarning(67100) << "pa_context_set_source_mute_by_index() failed";
-+ return Mixer::ERR_READ;
-+ }
-+ pa_operation_unref(o);
-+#endif
-+
-+ return 0;
-+ }
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+* Move the stream to a new destination
-+*/
-+bool Mixer_PULSE::moveStream( const TQString& id, const TQString& destId ) {
-+ TQ_ASSERT(KMIXPA_APP_PLAYBACK == m_devnum || KMIXPA_APP_CAPTURE == m_devnum);
-+
-+ kDebug(67100) << "Mixer_PULSE::moveStream(): Move Stream Requested - Stream: " << id << ", Destination: " << destId;
-+
-+ // Lookup the stream index.
-+ uint32_t stream_index = PA_INVALID_INDEX;
-+ TQString stream_restore_rule = "";
-+ devmap::iterator iter;
-+ devmap *map = get_widget_map(m_devnum);
-+ for (iter = map->begin(); iter != map->end(); ++iter) {
-+ if (iter->name == id) {
-+ stream_index = iter->index;
-+ stream_restore_rule = iter->stream_restore_rule;
-+ break;
-+ }
-+ }
-+
-+ if (PA_INVALID_INDEX == stream_index) {
-+ kError(67100) << "Mixer_PULSE::moveStream(): Cannot find stream index";
-+ return false;
-+ }
-+
-+ if (destId.isEmpty()) {
-+ // We want to remove any specific device in the stream restore rule.
-+ if (stream_restore_rule.isEmpty() || !s_RestoreRules.contains(stream_restore_rule)) {
-+ kWarning(67100) << "Mixer_PULSE::moveStream(): Trying to set Automatic on a stream with no rule";
-+ } else {
-+ restoreRule &rule = s_RestoreRules[stream_restore_rule];
-+ pa_ext_stream_restore_info info;
-+ info.name = stream_restore_rule.toUtf8().constData();
-+ info.channel_map = rule.channel_map;
-+ info.volume = rule.volume;
-+ info.device = NULL;
-+ info.mute = rule.mute ? 1 : 0;
-+
-+ pa_operation* o;
-+ if (!(o = pa_ext_stream_restore_write(s_context, PA_UPDATE_REPLACE, &info, 1, true, NULL, NULL))) {
-+ kWarning(67100) << "pa_ext_stream_restore_write() failed" << info.channel_map.channels << info.volume.channels << info.name;
-+ return Mixer::ERR_READ;
-+ }
-+ pa_operation_unref(o);
-+ }
-+ } else {
-+ pa_operation* o;
-+ if (KMIXPA_APP_PLAYBACK == m_devnum) {
-+ if (!(o = pa_context_move_sink_input_by_name(s_context, stream_index, destId.toUtf8().constData(), NULL, NULL))) {
-+ kWarning(67100) << "pa_context_move_sink_input_by_name() failed";
-+ return false;
-+ }
-+ } else {
-+ if (!(o = pa_context_move_source_output_by_name(s_context, stream_index, destId.toUtf8().constData(), NULL, NULL))) {
-+ kWarning(67100) << "pa_context_move_source_output_by_name() failed";
-+ return false;
-+ }
-+ }
-+ pa_operation_unref(o);
-+ }
-+
-+ return true;
-+}
-+
-+void Mixer_PULSE::reinit()
-+{
-+ // We only support reinit on our primary mixer.
-+ TQ_ASSERT(KMIXPA_PLAYBACK == m_devnum);
-+ connectToDaemon();
-+}
-+
-+void Mixer_PULSE::triggerUpdate()
-+{
-+ readSetFromHWforceUpdate();
-+ readSetFromHW();
-+}
-+
-+// Please see KMixWindow::initActionsAfterInitMixer(), it uses the driverName
-+
-+TQString PULSE_getDriverName() {
-+ return "PulseAudio";
-+}
-+
-+TQString Mixer_PULSE::getDriverName()
-+{
-+ return "PulseAudio";
-+}
-+
-diff -Nuar ./kmix-tde-ori/mixer_pulse.h ./kmix/mixer_pulse.h
---- ./kmix-tde-ori/mixer_pulse.h 1970-01-01 01:00:00.000000000 +0100
-+++ ./kmix/mixer_pulse.h 2013-05-21 23:27:28.960083350 +0200
-@@ -0,0 +1,85 @@
-+/*
-+ * KMix -- KDE's full featured mini mixer
-+ *
-+ *
-+ * Copyright (C) 2008 Helio Chissini de Castro <helio@kde.org>
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Library General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2 of the License, or (at your option) any later version.
-+ *
-+ * 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
-+ * Library General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Library 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.
-+ */
-+
-+#ifndef MIXER_PULSE_H
-+#define MIXER_PULSE_H
-+
-+#include <tqstring.h>
-+
-+#include "mixer_backend.h"
-+#include <pulse/pulseaudio.h>
-+
-+typedef TQMap<uint8_t,Volume::ChannelID> chanIDMap;
-+typedef struct {
-+ int index;
-+ int device_index;
-+ TQString name;
-+ TQString description;
-+ TQString icon_name;
-+ pa_cvolume volume;
-+ pa_channel_map channel_map;
-+ bool mute;
-+ TQString stream_restore_rule;
-+
-+ Volume::ChannelMask chanMask;
-+ chanIDMap chanIDs;
-+} devinfo;
-+
-+class Mixer_PULSE : public Mixer_Backend
-+{
-+ public:
-+ Mixer_PULSE(Mixer *mixer, int devnum);
-+ virtual ~Mixer_PULSE();
-+
-+ virtual int readVolumeFromHW( const TQString& id, shared_ptr<MixDevice> );
-+ virtual int writeVolumeToHW ( const TQString& id, shared_ptr<MixDevice> );
-+
-+ virtual bool moveStream( const TQString& id, const TQString& destId );
-+
-+ virtual TQString getDriverName();
-+ virtual TQString getId() const { return _id; };
-+
-+ virtual bool needsPolling() { return false; }
-+
-+ void triggerUpdate();
-+ void addWidget(int index, bool = false);
-+ void removeWidget(int index);
-+ void removeAllWidgets();
-+ MixSet *getMixSet() { return &m_mixDevices; }
-+ int id2num(const TQString& id);
-+
-+ protected:
-+ virtual int open();
-+ virtual int close();
-+
-+ int fd;
-+ TQString _id;
-+
-+ private:
-+ void addDevice(devinfo& dev, bool = false);
-+ bool connectToDaemon();
-+ void emitControlsReconfigured();
-+public:
-+ void reinit();
-+
-+};
-+
-+#endif