summaryrefslogtreecommitdiff
path: root/debian/patches
diff options
context:
space:
mode:
authorFathi Boudra <fabo@debian.org>2010-01-31 11:04:40 +0100
committerFathi Boudra <fabo@debian.org>2010-01-31 11:04:40 +0100
commita1896bbe8fa68dac87fa2bb78dd7f83d93b2b552 (patch)
tree841889ecbedb1aab55f5b3e131f344ac572faa09 /debian/patches
parentac34295f68690de3783233e9d291ab941feb75f3 (diff)
downloadqt4-x11-a1896bbe8fa68dac87fa2bb78dd7f83d93b2b552.tar.gz
Add patch to update Qt Phonon from kdesupport Phonon 4.3.80.
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/97_update_phonon_4.3.80.diff5608
-rw-r--r--debian/patches/series1
2 files changed, 5609 insertions, 0 deletions
diff --git a/debian/patches/97_update_phonon_4.3.80.diff b/debian/patches/97_update_phonon_4.3.80.diff
new file mode 100644
index 0000000..8b943df
--- /dev/null
+++ b/debian/patches/97_update_phonon_4.3.80.diff
@@ -0,0 +1,5608 @@
+Description: update Qt Phonon from kdesupport Phonon 4.3.80.
+To create the following patch, use the following command excluding some patterns
+(DESIGN cmake ds9 experimental mmf qt7 tests xine)
+$ diff -Nur -X phonon.exclude qt4-x11-4.6.1/src/3rdparty/phonon phonon-4.3.80
+Forwarded: not-needed
+Author: Fathi Boudra <fabo@debian.org>
+
+--- a/src/3rdparty/phonon/CMakeLists.txt
++++ b/src/3rdparty/phonon/CMakeLists.txt
+@@ -149,7 +149,7 @@ set(CMAKE_COLOR_MAKEFILE ON)
+
+ set(PHONON_LIB_MAJOR_VERSION "4")
+ set(PHONON_LIB_MINOR_VERSION "3")
+-set(PHONON_LIB_PATCH_VERSION "50")
++set(PHONON_LIB_PATCH_VERSION "80")
+ set(PHONON_LIB_VERSION "${PHONON_LIB_MAJOR_VERSION}.4.0")
+ set(PHONON_LIB_SOVERSION ${PHONON_LIB_MAJOR_VERSION})
+
+--- a/src/3rdparty/phonon/gstreamer/abstractrenderer.cpp
++++ b/src/3rdparty/phonon/gstreamer/abstractrenderer.cpp
+@@ -17,7 +17,6 @@
+
+ #include "abstractrenderer.h"
+
+-#ifndef QT_NO_PHONON_VIDEO
+ QT_BEGIN_NAMESPACE
+
+ namespace Phonon
+@@ -53,5 +52,5 @@ void AbstractRenderer::movieSizeChanged(
+ } //namespace Phonon::Gstreamer
+
+ QT_END_NAMESPACE
+-#endif //QT_NO_PHONON_VIDEO
++
+
+--- a/src/3rdparty/phonon/gstreamer/abstractrenderer.h
++++ b/src/3rdparty/phonon/gstreamer/abstractrenderer.h
+@@ -23,7 +23,6 @@
+ #include "medianode.h"
+ #include <phonon/videowidget.h>
+
+-#ifndef QT_NO_PHONON_VIDEO
+ QT_BEGIN_NAMESPACE
+
+ class QString;
+@@ -59,5 +58,5 @@ protected:
+ } //namespace Phonon::Gstreamer
+
+ QT_END_NAMESPACE
+-#endif //QT_NO_PHONON_VIDEO
++
+ #endif // Phonon_GSTREAMER_ABSTRACTRENDERER_H
+--- a/src/3rdparty/phonon/gstreamer/artssink.cpp
++++ b/src/3rdparty/phonon/gstreamer/artssink.cpp
+@@ -233,7 +233,7 @@ static void arts_sink_init (ArtsSink * s
+ Q_UNUSED(g_class);
+ GST_DEBUG_OBJECT (src, "initializing artssink");
+ src->stream = 0;
+-#ifndef QT_NO_LIBRARY
++
+ p_arts_init = (Ptr_arts_init)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_init");
+ p_arts_play_stream = (Ptr_arts_play_stream)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_play_stream");
+ p_arts_close_stream = (Ptr_arts_close_stream)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_close_stream");
+@@ -250,7 +250,6 @@ static void arts_sink_init (ArtsSink * s
+ }
+ }
+ sinkCount ++;
+-#endif //QT_NO_LIBRARY
+ }
+
+ static void arts_sink_dispose (GObject * object)
+--- /dev/null
++++ b/gstreamer/audiodataoutput.cpp
+@@ -0,0 +1,143 @@
++/* This file is part of the KDE project
++ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
++ Copyright (C) 2009 Martin Sandsmark <sandsmark@samfundet.no>
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) version 3, or any
++ later version accepted by the membership of KDE e.V. (or its
++ successor approved by the membership of KDE e.V.), Nokia Corporation
++ (or its successors, if any) and the KDE Free Qt Foundation, which shall
++ act as a proxy defined in Section 6 of version 3 of the license.
++
++ This library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with this library. If not, see <http://www.gnu.org/licenses/>.
++
++*/
++
++#include "audiodataoutput.h"
++#include "gsthelper.h"
++#include "medianode.h"
++#include "mediaobject.h"
++#include <QtCore/QVector>
++#include <QtCore/QMap>
++#include <phonon/audiooutput.h>
++
++namespace Phonon
++{
++namespace Gstreamer
++{
++AudioDataOutput::AudioDataOutput(Backend *backend, QObject *parent)
++ : QObject(parent),
++ MediaNode(backend, AudioSink | AudioSource)
++{
++ static int count = 0;
++ m_name = "AudioDataOutput" + QString::number(count++);
++
++ m_queue = gst_element_factory_make ("identity", NULL);
++ gst_object_ref(m_queue);
++ m_isValid = true;
++}
++
++AudioDataOutput::~AudioDataOutput()
++{
++ gst_element_set_state(m_queue, GST_STATE_NULL);
++ gst_object_unref(m_queue);
++}
++
++int AudioDataOutput::dataSize() const
++{
++ return m_dataSize;
++}
++
++int AudioDataOutput::sampleRate() const
++{
++ return 44100;
++}
++
++void AudioDataOutput::setDataSize(int size)
++{
++ m_dataSize = size;
++}
++
++typedef QMap<Phonon::AudioDataOutput::Channel, QVector<float> > FloatMap;
++typedef QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > IntMap;
++
++inline void AudioDataOutput::convertAndEmit(const QVector<qint16> &leftBuffer, const QVector<qint16> &rightBuffer)
++{
++ //TODO: Floats
++ IntMap map;
++ map.insert(Phonon::AudioDataOutput::LeftChannel, leftBuffer);
++ map.insert(Phonon::AudioDataOutput::RightChannel, rightBuffer);
++ emit dataReady(map);
++}
++
++void AudioDataOutput::processBuffer(GstPad*, GstBuffer* buffer, gpointer gThat)
++{
++ // TODO emit endOfMedia
++ AudioDataOutput *that = reinterpret_cast<AudioDataOutput*>(gThat);
++
++ // determine the number of channels
++ GstStructure* structure = gst_caps_get_structure (GST_BUFFER_CAPS(buffer), 0);
++ gst_structure_get_int (structure, "channels", &that->m_channels);
++
++ if (that->m_channels > 2 || that->m_channels < 0) {
++ qWarning() << Q_FUNC_INFO << ": Number of channels not supported: " << that->m_channels;
++ return;
++ }
++
++ gint16 *data = reinterpret_cast<gint16*>(GST_BUFFER_DATA(buffer));
++ guint size = GST_BUFFER_SIZE(buffer) / sizeof(gint16);
++
++ that->m_pendingData.reserve(that->m_pendingData.size() + size);
++
++ for (uint i=0; i<size; i++) {
++ // 8 bit? interleaved? yay for lacking documentation!
++ that->m_pendingData.append(data[i]);
++ }
++
++ while (that->m_pendingData.size() > that->m_dataSize * that->m_channels) {
++ if (that->m_channels == 1) {
++ QVector<qint16> intBuffer(that->m_dataSize);
++ memcpy(intBuffer.data(), that->m_pendingData.constData(), that->m_dataSize * sizeof(qint16));
++
++ that->convertAndEmit(intBuffer, intBuffer);
++ int newSize = that->m_pendingData.size() - that->m_dataSize;
++ memmove(that->m_pendingData.data(), that->m_pendingData.constData() + that->m_dataSize, newSize * sizeof(qint16));
++ that->m_pendingData.resize(newSize);
++ } else {
++ QVector<qint16> left(that->m_dataSize), right(that->m_dataSize);
++ for (int i=0; i<that->m_dataSize; i++) {
++ left[i] = that->m_pendingData[i*2];
++ right[i] = that->m_pendingData[i*2+1];
++ }
++ that->m_pendingData.resize(that->m_pendingData.size() - that->m_dataSize*2);
++ that->convertAndEmit(left, right);
++ }
++ }
++}
++
++void AudioDataOutput::mediaNodeEvent(const MediaNodeEvent *event)
++{
++ if (event->type() == MediaNodeEvent::MediaObjectConnected && root()) {
++ g_object_set(G_OBJECT(audioElement()), "sync", true, (const char*)NULL);
++ GstPad *audiopad = gst_element_get_pad (audioElement(), "src");
++ gst_pad_add_buffer_probe (audiopad, G_CALLBACK(processBuffer), this);
++ gst_object_unref (audiopad);
++ return;
++ }
++
++ MediaNode::mediaNodeEvent(event);
++}
++
++}} //namespace Phonon::Gstreamer
++
++#include "moc_audiodataoutput.cpp"
++// vim: sw=4 ts=4
++
+--- /dev/null
++++ b/gstreamer/audiodataoutput.h
+@@ -0,0 +1,84 @@
++/* This file is part of the KDE project
++ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
++ Copyright (C) 2009 Martin Sandsmark <sandsmark@samfundet.no>
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) version 3, or any
++ later version accepted by the membership of KDE e.V. (or its
++ successor approved by the membership of KDE e.V.), Nokia Corporation
++ (or its successors, if any) and the KDE Free Qt Foundation, which shall
++ act as a proxy defined in Section 6 of version 3 of the license.
++
++ This library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with this library. If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#ifndef Phonon_GSTREAMER_AUDIODATAOUTPUT_H
++#define Phonon_GSTREAMER_AUDIODATAOUTPUT_H
++
++#include "abstractaudiooutput.h"
++#include "backend.h"
++#include "medianode.h"
++#include <phonon/audiodataoutput.h>
++#include <phonon/audiodataoutputinterface.h>
++
++namespace Phonon
++{
++namespace Gstreamer
++{
++ /**
++ * \author Martin Sandsmark <sandsmark@samfundet.no>
++ */
++ class AudioDataOutput : public QObject,
++ public AudioDataOutputInterface,
++ public MediaNode
++ {
++ Q_OBJECT
++ Q_INTERFACES(Phonon::AudioDataOutputInterface Phonon::Gstreamer::MediaNode)
++
++ public:
++ AudioDataOutput(Backend *, QObject *);
++ ~AudioDataOutput();
++
++ public Q_SLOTS:
++ int dataSize() const;
++ int sampleRate() const;
++ void setDataSize(int size);
++
++ public:
++ /// callback function for handling new audio data
++ static void processBuffer(GstPad*, GstBuffer*, gpointer);
++
++ Phonon::AudioDataOutput* frontendObject() const { return m_frontend; }
++ void setFrontendObject(Phonon::AudioDataOutput *frontend) { m_frontend = frontend; }
++
++ GstElement *audioElement() { return m_queue; }
++
++ void mediaNodeEvent(const MediaNodeEvent *event);
++
++
++ signals:
++ void dataReady(const QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > &data);
++ void dataReady(const QMap<Phonon::AudioDataOutput::Channel, QVector<float> > &data);
++ void endOfMedia(int remainingSamples);
++
++ private:
++ void convertAndEmit(const QVector<qint16>&, const QVector<qint16>&);
++
++ GstElement *m_queue;
++ int m_dataSize;
++ QVector<qint16> m_pendingData;
++ Phonon::AudioDataOutput *m_frontend;
++ int m_channels;
++ };
++}} //namespace Phonon::Gstreamer
++
++// vim: sw=4 ts=4 tw=80
++#endif // Phonon_FAKE_AUDIODATAOUTPUT_H
+--- a/src/3rdparty/phonon/gstreamer/audioeffect.cpp
++++ b/src/3rdparty/phonon/gstreamer/audioeffect.cpp
+@@ -23,7 +23,7 @@
+ #include "gsthelper.h"
+
+ #include <gst/gst.h>
+-#ifndef QT_NO_PHONON_EFFECT
++
+ QT_BEGIN_NAMESPACE
+
+ namespace Phonon
+@@ -75,5 +75,4 @@ GstElement* AudioEffect::createEffectBin
+ } //namespace Phonon::Gstreamer
+
+ QT_END_NAMESPACE
+-#endif //QT_NO_PHONON_EFFECT
+ #include "moc_audioeffect.cpp"
+--- a/src/3rdparty/phonon/gstreamer/audioeffect.h
++++ b/src/3rdparty/phonon/gstreamer/audioeffect.h
+@@ -29,8 +29,8 @@
+
+ #include <gst/gst.h>
+
+-#ifndef QT_NO_PHONON_EFFECT
+ QT_BEGIN_NAMESPACE
++
+ namespace Phonon
+ {
+ namespace Gstreamer
+@@ -49,7 +49,7 @@ namespace Gstreamer
+ QString m_effectName;
+ };
+ }} //namespace Phonon::Gstreamer
++
+ QT_END_NAMESPACE
+-#endif //QT_NO_PHONON_EFFECT
+
+ #endif // Phonon_GSTREAMER_AUDIOEFFECT_H
+--- a/src/3rdparty/phonon/gstreamer/audiooutput.cpp
++++ b/src/3rdparty/phonon/gstreamer/audiooutput.cpp
+@@ -125,6 +125,7 @@ void AudioOutput::setVolume(qreal newVol
+ bool AudioOutput::setOutputDevice(int newDevice)
+ {
+ m_backend->logMessage(Q_FUNC_INFO + QString::number(newDevice), Backend::Info, this);
++
+ if (newDevice == m_device)
+ return true;
+
+@@ -135,20 +136,11 @@ bool AudioOutput::setOutputDevice(int ne
+ }
+
+ bool success = false;
+- const QList<AudioDevice> deviceList = m_backend->deviceManager()->audioOutputDevices();
+- int deviceIdx = -1;
+- for (int i=0; i<deviceList.size(); i++) {
+- if (deviceList.at(i).id == newDevice) {
+- deviceIdx = i;
+- break;
+- }
+- }
+-
+- if (m_audioSink && deviceIdx >= 0) {
++ if (m_audioSink && newDevice >= 0) {
+ // Save previous state
+ GstState oldState = GST_STATE(m_audioSink);
+ const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device");
+- const QByteArray deviceId = deviceList.at(deviceIdx).gstId;
++ const QByteArray deviceId = m_backend->deviceManager()->gstId(newDevice);
+ m_device = newDevice;
+
+ // We test if the device can be opened by checking if it can go from NULL to READY state
+--- a/src/3rdparty/phonon/gstreamer/backend.cpp
++++ b/src/3rdparty/phonon/gstreamer/backend.cpp
+@@ -18,6 +18,7 @@
+ #include "common.h"
+ #include "backend.h"
+ #include "audiooutput.h"
++#include "audiodataoutput.h"
+ #include "audioeffect.h"
+ #include "mediaobject.h"
+ #include "videowidget.h"
+@@ -26,6 +27,7 @@
+ #include "message.h"
+ #include "volumefadereffect.h"
+ #include <gst/interfaces/propertyprobe.h>
++#include <phonon/pulsesupport_p.h>
+
+ #include <QtCore/QSet>
+ #include <QtCore/QVariant>
+@@ -49,26 +51,28 @@ Backend::Backend(QObject *parent, const
+ , m_debugLevel(Warning)
+ , m_isValid(false)
+ {
++ // Initialise PulseAudio support
++ PulseSupport *pulse = PulseSupport::getInstance();
++ connect(pulse, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)), SIGNAL(objectDescriptionChanged(ObjectDescriptionType)));
++
+ // In order to support reloading, we only set the app name once...
+ static bool first = true;
+ if (first) {
+ first = false;
+ g_set_application_name(qApp->applicationName().toUtf8());
+ }
+-
+ GError *err = 0;
+ bool wasInit = gst_init_check(0, 0, &err); //init gstreamer: must be called before any gst-related functions
+ if (err)
+ g_error_free(err);
+
+ qRegisterMetaType<Message>("Message");
+-#ifndef QT_NO_PROPERTIES
++
+ setProperty("identifier", QLatin1String("phonon_gstreamer"));
+ setProperty("backendName", QLatin1String("Gstreamer"));
+ setProperty("backendComment", QLatin1String("Gstreamer plugin for Phonon"));
+ setProperty("backendVersion", QLatin1String("0.2"));
+- setProperty("backendWebsite", QLatin1String("http://qt.nokia.com/"));
+-#endif //QT_NO_PROPERTIES
++ setProperty("backendWebsite", QLatin1String("http://qtsoftware.com/"));
+
+ //check if we should enable debug output
+ QString debugLevelString = qgetenv("PHONON_GST_DEBUG");
+@@ -92,6 +96,9 @@ Backend::Backend(QObject *parent, const
+
+ Backend::~Backend()
+ {
++ delete m_effectManager;
++ delete m_deviceManager;
++ PulseSupport::shutdown();
+ }
+
+ gboolean Backend::busCall(GstBus *bus, GstMessage *msg, gpointer data)
+@@ -119,20 +126,15 @@ QObject *Backend::createObject(BackendIn
+ case MediaObjectClass:
+ return new MediaObject(this, parent);
+
+- case AudioOutputClass: {
+- AudioOutput *ao = new AudioOutput(this, parent);
+- m_audioOutputs.append(ao);
+- return ao;
+- }
+-#ifndef QT_NO_PHONON_EFFECT
++ case AudioOutputClass:
++ return new AudioOutput(this, parent);
++
+ case EffectClass:
+ return new AudioEffect(this, args[0].toInt(), parent);
+-#endif //QT_NO_PHONON_EFFECT
++
+ case AudioDataOutputClass:
+- logMessage("createObject() : AudioDataOutput not implemented");
+- break;
++ return new AudioDataOutput(this, parent);
+
+-#ifndef QT_NO_PHONON_VIDEO
+ case VideoDataOutputClass:
+ logMessage("createObject() : VideoDataOutput not implemented");
+ break;
+@@ -141,11 +143,9 @@ QObject *Backend::createObject(BackendIn
+ QWidget *widget = qobject_cast<QWidget*>(parent);
+ return new VideoWidget(this, widget);
+ }
+-#endif //QT_NO_PHONON_VIDEO
+-#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
++
+ case VolumeFaderEffectClass:
+ return new VolumeFaderEffect(this, parent);
+-#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
+
+ case VisualizationClass: //Fall through
+ default:
+@@ -214,14 +214,14 @@ QStringList Backend::availableMimeTypes(
+ GstPluginFeature *feature = GST_PLUGIN_FEATURE(iter->data);
+ QString klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature));
+
+- if (klass == QLatin1String("Codec/Decoder") ||
+- klass == QLatin1String("Codec/Decoder/Audio") ||
+- klass == QLatin1String("Codec/Decoder/Video") ||
+- klass == QLatin1String("Codec/Demuxer") ||
+- klass == QLatin1String("Codec/Demuxer/Audio") ||
+- klass == QLatin1String("Codec/Demuxer/Video") ||
+- klass == QLatin1String("Codec/Parser") ||
+- klass == QLatin1String("Codec/Parser/Audio") ||
++ if (klass == QLatin1String("Codec/Decoder") ||
++ klass == QLatin1String("Codec/Decoder/Audio") ||
++ klass == QLatin1String("Codec/Decoder/Video") ||
++ klass == QLatin1String("Codec/Demuxer") ||
++ klass == QLatin1String("Codec/Demuxer/Audio") ||
++ klass == QLatin1String("Codec/Demuxer/Video") ||
++ klass == QLatin1String("Codec/Parser") ||
++ klass == QLatin1String("Codec/Parser/Audio") ||
+ klass == QLatin1String("Codec/Parser/Video")) {
+
+ const GList *static_templates;
+@@ -258,6 +258,10 @@ QList<int> Backend::objectDescriptionInd
+ if (!isValid())
+ return list;
+
++ PulseSupport *pulse = PulseSupport::getInstance();
++ if (pulse->isActive() && (Phonon::AudioOutputDeviceType == type || Phonon::AudioCaptureDeviceType == type))
++ return pulse->objectDescriptionIndexes(type);
++
+ switch (type) {
+ case Phonon::AudioOutputDeviceType: {
+ QList<AudioDevice> deviceList = deviceManager()->audioOutputDevices();
+@@ -291,16 +295,17 @@ QHash<QByteArray, QVariant> Backend::obj
+ if (!isValid())
+ return ret;
+
++ PulseSupport *pulse = PulseSupport::getInstance();
++ if (pulse->isActive() && (Phonon::AudioOutputDeviceType == type || Phonon::AudioCaptureDeviceType == type))
++ return pulse->objectDescriptionProperties(type, index);
++
+ switch (type) {
+ case Phonon::AudioOutputDeviceType: {
+- QList<AudioDevice> audioDevices = deviceManager()->audioOutputDevices();
+- foreach(const AudioDevice &device, audioDevices) {
+- if (device.id == index) {
+- ret.insert("name", device.gstId);
+- ret.insert("description", device.description);
+- ret.insert("icon", QLatin1String("audio-card"));
+- break;
+- }
++ AudioDevice* ad;
++ if ((ad = deviceManager()->audioDevice(index))) {
++ ret.insert("name", ad->gstId);
++ ret.insert("description", ad->description);
++ ret.insert("icon", ad->icon);
+ }
+ }
+ break;
+@@ -429,7 +434,7 @@ EffectManager* Backend::effectManager()
+
+ /**
+ * Returns a debuglevel that is determined by the
+- * PHONON_GSTREAMER_DEBUG environment variable.
++ * PHONON_GST_DEBUG environment variable.
+ *
+ * Warning - important warnings
+ * Info - general info
+--- a/src/3rdparty/phonon/gstreamer/backend.h
++++ b/src/3rdparty/phonon/gstreamer/backend.h
+@@ -86,7 +86,6 @@ private Q_SLOTS:
+
+ private:
+ static gboolean busCall(GstBus *bus, GstMessage *msg, gpointer data);
+- QList<QPointer<AudioOutput> > m_audioOutputs;
+
+ DeviceManager *m_deviceManager;
+ EffectManager *m_effectManager;
+--- a/src/3rdparty/phonon/gstreamer/CMakeLists.txt
++++ b/src/3rdparty/phonon/gstreamer/CMakeLists.txt
+@@ -1,4 +1,4 @@
+-# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
++# Copyright (C) 2009 Nokia Corporation. All rights reserved.
+ # Copyright (C) 2008 Matthias Kretz <kretz@kde.org>
+ #
+ # This library is free software: you can redistribute it and/or modify
+@@ -19,7 +19,7 @@ include(ConfigureChecks.cmake)
+ if (BUILD_PHONON_GSTREAMER)
+ include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+- ${GSTREAMER_INCLUDE_DIR}
++ ${GSTREAMER_INCLUDE_DIR}
+ ${GLIB2_INCLUDE_DIR}
+ ${LIBXML2_INCLUDE_DIR}
+ ${X11_X11_INCLUDE_PATH})
+@@ -34,7 +34,6 @@ if (BUILD_PHONON_GSTREAMER)
+
+ set(phonon_gstreamer_SRCS
+ audiooutput.cpp
+- artssink.cpp
+ backend.cpp
+ devicemanager.cpp
+ effectmanager.cpp
+@@ -50,14 +49,20 @@ if (BUILD_PHONON_GSTREAMER)
+ message.cpp
+ audioeffect.cpp
+ abstractrenderer.cpp
+- x11renderer.cpp
+ widgetrenderer.cpp
+ glrenderer.cpp
+ volumefadereffect.cpp
++ audiodataoutput.cpp
+ )
+
+- find_package(Alsa)
+- macro_ensure_version("0.10.22" ${GSTREAMER_VERSION} GSTREAMER_HAS_NONBLOCKING_ALSASINK)
++ if(NOT WIN32)
++ set(phonon_gstreamer_SRCS
++ ${phonon_gstreamer_SRCS}
++ artssink.cpp
++ x11renderer.cpp)
++ macro_optional_find_package(Alsa)
++ macro_ensure_version("0.10.22" ${GSTREAMER_VERSION} GSTREAMER_HAS_NONBLOCKING_ALSASINK)
++ endif(NOT WIN32)
+ if(ALSA_FOUND AND NOT GSTREAMER_HAS_NONBLOCKING_ALSASINK)
+ add_definitions(-DUSE_ALSASINK2)
+ include_directories(${ALSA_INCLUDES})
+@@ -78,6 +83,9 @@ if (BUILD_PHONON_GSTREAMER)
+ if(ALSA_FOUND)
+ target_link_libraries(phonon_gstreamer ${ASOUND_LIBRARY})
+ endif(ALSA_FOUND)
++ if(USE_INSTALL_PLUGIN)
++ target_link_libraries(phonon_gstreamer ${GSTREAMER_PLUGIN_PBUTILS_LIBRARIES})
++ endif(USE_INSTALL_PLUGIN)
+
+ install(TARGETS phonon_gstreamer DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/phonon_backend)
+ install(FILES gstreamer.desktop DESTINATION ${SERVICES_INSTALL_DIR}/phononbackends)
+--- a/src/3rdparty/phonon/gstreamer/ConfigureChecks.cmake
++++ b/src/3rdparty/phonon/gstreamer/ConfigureChecks.cmake
+@@ -1,4 +1,4 @@
+-# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
++# Copyright (C) 2009 Nokia Corporation. All rights reserved.
+ #
+ # This library is free software: you can redistribute it and/or modify
+ # it under the terms of the GNU Lesser General Public License as published by
+@@ -17,6 +17,7 @@ macro_log_feature(GSTREAMER_FOUND "GStre
+
+ macro_optional_find_package(GStreamerPlugins)
+ macro_log_feature(GSTREAMER_PLUGIN_VIDEO_LIBRARIES "GStreamer video plugin" "The gstreamer video plugin (part of gstreamer-plugins-base 0.10) is required for the multimedia gstreamer backend" "http://gstreamer.freedesktop.org/modules/" FALSE "0.10")
++macro_log_feature(GSTREAMER_PLUGIN_AUDIO_LIBRARIES "GStreamer audio plugin" "The gstreamer audio plugin (part of gstreamer-plugins-base 0.10) is required for the multimedia gstreamer backend" "http://gstreamer.freedesktop.org/modules/" FALSE "0.10")
+
+ macro_optional_find_package(GLIB2)
+ macro_log_feature(GLIB2_FOUND "GLib2" "GLib 2 is required to compile the gstreamer backend for Phonon" "http://www.gtk.org/download/" FALSE)
+@@ -30,8 +31,8 @@ macro_log_feature(LIBXML2_FOUND "LibXml2
+ macro_optional_find_package(OpenGL)
+ macro_log_feature(OPENGL_FOUND "OpenGL" "OpenGL support is required to compile the gstreamer backend for Phonon" "" FALSE)
+
+-if (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND)
++if (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GSTREAMER_PLUGIN_AUDIO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND)
+ set(BUILD_PHONON_GSTREAMER TRUE)
+-else (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND)
++else (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GSTREAMER_PLUGIN_AUDIO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND)
+ set(BUILD_PHONON_GSTREAMER FALSE)
+-endif (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND)
++endif (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GSTREAMER_PLUGIN_AUDIO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND)
+--- a/src/3rdparty/phonon/gstreamer/devicemanager.cpp
++++ b/src/3rdparty/phonon/gstreamer/devicemanager.cpp
+@@ -24,6 +24,7 @@
+ #include "widgetrenderer.h"
+ #include "x11renderer.h"
+ #include "artssink.h"
++#include "pulsesupport_p.h"
+
+ #ifdef USE_ALSASINK2
+ #include "alsasink2.h"
+@@ -44,9 +45,12 @@ namespace Gstreamer
+ AudioDevice::AudioDevice(DeviceManager *manager, const QByteArray &gstId)
+ : gstId(gstId)
+ {
+- //get an id
+- static int counter = 0;
+- id = counter++;
++ // This should never be called when PulseAudio is active.
++ Q_ASSERT(!PulseSupport::getInstance()->isActive());
++
++ id = manager->allocateDeviceId();
++ icon = "audio-card";
++
+ //get name from device
+ if (gstId == "default") {
+ description = "Default audio device";
+@@ -71,22 +75,25 @@ AudioDevice::AudioDevice(DeviceManager *
+ DeviceManager::DeviceManager(Backend *backend)
+ : QObject(backend)
+ , m_backend(backend)
++ , m_audioDeviceCounter(0)
+ {
+- m_audioSink = qgetenv("PHONON_GST_AUDIOSINK");
+- m_videoSinkWidget = qgetenv("PHONON_GST_VIDEOMODE");
+-
+-#ifndef QT_NO_SETTINGS
+ QSettings settings(QLatin1String("Trolltech"));
+ settings.beginGroup(QLatin1String("Qt"));
+
++ PulseSupport *pulse = PulseSupport::getInstance();
++ m_audioSink = qgetenv("PHONON_GST_AUDIOSINK");
+ if (m_audioSink.isEmpty()) {
+ m_audioSink = settings.value(QLatin1String("audiosink"), "Auto").toByteArray().toLower();
++ if (m_audioSink == "auto" && pulse->isActive())
++ m_audioSink = "pulsesink";
+ }
++ if ("pulsesink" != m_audioSink)
++ pulse->disable();
+
++ m_videoSinkWidget = qgetenv("PHONON_GST_VIDEOMODE");
+ if (m_videoSinkWidget.isEmpty()) {
+ m_videoSinkWidget = settings.value(QLatin1String("videomode"), "Auto").toByteArray().toLower();
+ }
+-#endif //QT_NO_SETTINGS
+
+ if (m_backend->isValid())
+ updateDeviceList();
+@@ -246,7 +253,6 @@ GstElement *DeviceManager::createAudioSi
+ return sink;
+ }
+
+-#ifndef QT_NO_PHONON_VIDEO
+ AbstractRenderer *DeviceManager::createVideoRenderer(VideoWidget *parent)
+ {
+ #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES)
+@@ -269,11 +275,18 @@ AbstractRenderer *DeviceManager::createV
+ #endif
+ return new WidgetRenderer(parent);
+ }
+-#endif //QT_NO_PHONON_VIDEO
+
+-/*
+- * Returns a positive device id or -1 if device
+- * does not exist
++/**
++ * Allocate a device id for a new audio device
++ */
++int DeviceManager::allocateDeviceId()
++{
++ return m_audioDeviceCounter++;
++}
++
++
++/**
++ * Returns a positive device id or -1 if device does not exist
+ *
+ * The gstId is typically in the format hw:1,0
+ */
+@@ -288,16 +301,30 @@ int DeviceManager::deviceId(const QByteA
+ }
+
+ /**
+- * Get a human-readable description from a device id
++ * Returns a gstId or "default" if device does not exist
++ *
++ * The gstId is typically in the format hw:1,0
+ */
+-QByteArray DeviceManager::deviceDescription(int id) const
++const QByteArray DeviceManager::gstId(int deviceId)
++{
++ if (!PulseSupport::getInstance()->isActive()) {
++ AudioDevice *ad = audioDevice(deviceId);
++ if (ad)
++ return QByteArray(ad->gstId);
++ }
++ return QByteArray("default");
++}
++
++/**
++* Get the AudioDevice for a given device id
++*/
++AudioDevice* DeviceManager::audioDevice(int id)
+ {
+ for (int i = 0 ; i < m_audioDeviceList.size() ; ++i) {
+- if (m_audioDeviceList[i].id == id) {
+- return m_audioDeviceList[i].description;
+- }
++ if (m_audioDeviceList[i].id == id)
++ return &m_audioDeviceList[i];
+ }
+- return QByteArray();
++ return NULL;
+ }
+
+ /**
+@@ -311,8 +338,11 @@ void DeviceManager::updateDeviceList()
+ QList<QByteArray> list;
+
+ if (audioSink) {
+- list = GstHelper::extractProperties(audioSink, "device");
+- list.prepend("default");
++ if (!PulseSupport::getInstance()->isActive()) {
++ // If we're using pulse, the PulseSupport class takes care of things for us.
++ list = GstHelper::extractProperties(audioSink, "device");
++ list.prepend("default");
++ }
+
+ for (int i = 0 ; i < list.size() ; ++i) {
+ QByteArray gstId = list.at(i);
+--- a/src/3rdparty/phonon/gstreamer/devicemanager.h
++++ b/src/3rdparty/phonon/gstreamer/devicemanager.h
+@@ -42,6 +42,7 @@ public :
+ int id;
+ QByteArray gstId;
+ QByteArray description;
++ QString icon;
+ };
+
+ class DeviceManager : public QObject {
+@@ -51,8 +52,10 @@ public:
+ virtual ~DeviceManager();
+ const QList<AudioDevice> audioOutputDevices() const;
+ GstPad *requestPad(int device) const;
++ int allocateDeviceId();
+ int deviceId(const QByteArray &gstId) const;
+- QByteArray deviceDescription(int id) const;
++ const QByteArray gstId(int id);
++ AudioDevice* audioDevice(int id);
+ GstElement *createGNOMEAudioSink(Category category);
+ GstElement *createAudioSink(Category category = NoCategory);
+ AbstractRenderer *createVideoRenderer(VideoWidget *parent);
+@@ -68,6 +71,7 @@ private:
+ bool canOpenDevice(GstElement *element) const;
+ Backend *m_backend;
+ QList <AudioDevice> m_audioDeviceList;
++ int m_audioDeviceCounter;
+ QTimer m_devicePollTimer;
+ QByteArray m_audioSink;
+ QByteArray m_videoSinkWidget;
+--- a/src/3rdparty/phonon/gstreamer/effect.cpp
++++ b/src/3rdparty/phonon/gstreamer/effect.cpp
+@@ -25,8 +25,8 @@
+
+ #include <gst/gst.h>
+
+-#ifndef QT_NO_PHONON_EFFECT
+ QT_BEGIN_NAMESPACE
++
+ namespace Phonon
+ {
+ namespace Gstreamer
+@@ -241,6 +241,6 @@ void Effect::setParameterValue(const Eff
+
+ }
+ } //namespace Phonon::Gstreamer
++
+ QT_END_NAMESPACE
+-#endif //QT_NO_PHONON_EFFECT
+ #include "moc_effect.cpp"
+--- a/src/3rdparty/phonon/gstreamer/effect.h
++++ b/src/3rdparty/phonon/gstreamer/effect.h
+@@ -28,8 +28,8 @@
+
+ #include <gst/gst.h>
+
+-#ifndef QT_NO_PHONON_EFFECT
+ QT_BEGIN_NAMESPACE
++
+ namespace Phonon
+ {
+ namespace Gstreamer
+@@ -58,7 +58,7 @@ namespace Gstreamer
+ QList<Phonon::EffectParameter> m_parameterList;
+ };
+ }} //namespace Phonon::Gstreamer
++
+ QT_END_NAMESPACE
+-#endif //QT_NO_PHONON_EFFECT
+
+ #endif // Phonon_GSTREAMER_EFFECT_H
+--- a/src/3rdparty/phonon/gstreamer/gstreamer.desktop
++++ b/src/3rdparty/phonon/gstreamer/gstreamer.desktop
+@@ -10,27 +10,69 @@ Icon=phonon-gstreamer
+ InitialPreference=10
+
+ Name=GStreamer
++Name[bg]=GStreamer
++Name[ca]=GStreamer
++Name[cs]=GStreamer
++Name[da]=GStreamer
++Name[de]=GStreamer
++Name[el]=GStreamer
++Name[en_GB]=GStreamer
++Name[es]=GStreamer
++Name[et]=GStreamer
++Name[eu]=GStreamer
++Name[fr]=GStreamer
++Name[ga]=GStreamer
++Name[gl]=GStreamer
++Name[hsb]=GStreamer
++Name[hu]=GStreamer
++Name[is]=GStreamer
++Name[it]=GStreamer
++Name[ja]=GStreamer
++Name[ko]=GStreamer
++Name[ku]=GStreamer
++Name[lt]=GStreamer
++Name[lv]=GStreamer
++Name[nds]=GStreamer
++Name[nl]=GStreamer
++Name[nn]=GStreamer
+ Name[pa]=ਜੀਸਟੀਰਮਰ
++Name[pl]=GStreamer
++Name[pt]=GStreamer
++Name[pt_BR]=GStreamer
++Name[se]=GStreamer
++Name[sk]=GStreamer
++Name[sl]=GStreamer
+ Name[sr]=Гстример
++Name[sr@latin]=GStreamer
+ Name[sv]=Gstreamer
++Name[tr]=GStreamer
++Name[uk]=GStreamer
+ Name[x-test]=xxGStreamerxx
++Name[zh_CN]=GStreamer
++Name[zh_TW]=GStreamer
+
+ Comment=Phonon GStreamer backend
+ Comment[bg]=Phonon GStreamer
+ Comment[ca]=Dorsal GStreamer del Phonon
++Comment[cs]=Phonon GStreamer backend
+ Comment[da]=GStreamer-backend til Phonon
+ Comment[de]=Phonon-Treiber für GStreamer
+ Comment[el]=Σύστημα υποστήριξης GStreamer του Phonon
++Comment[en_GB]=Phonon GStreamer backend
+ Comment[es]=Motor GStreamer para Phonon
+ Comment[et]=Phononi GStreameri taustaprogramm
++Comment[eu]=Phonon GStreamer backend
+ Comment[fr]=Système de gestion GStreamer pour Phonon
+ Comment[ga]=Inneall GStreamer le haghaidh Phonon
+ Comment[gl]=Infraestrutura de GStreamer para Phonon
++Comment[hsb]=Phonon GStreamer backend
++Comment[hu]=Phonon GStreamer modul
+ Comment[is]=Phonon GStreamer bakendi
+ Comment[it]=Motore Gstreamer di Phonon
+ Comment[ja]=Phonon GStreamer バックエンド
+ Comment[ko]=Phonon GStreamer 백엔드
+ Comment[ku]=Binesaza Phonon GStreamer
++Comment[lt]=Phonon GStreamer galinė sąsaja
+ Comment[lv]=Phonon GStreamer aizmugure
+ Comment[nds]=Phonon-Hülpprogramm GStreamer
+ Comment[nl]=GStreamer-backend (Phonon)
+@@ -39,6 +81,7 @@ Comment[pa]=ਫੋਨੋਨ ਜਸਟੀ
+ Comment[pl]=Obsługa GStreamera przez Phonon
+ Comment[pt]=Infra-estrutura do GStreamer para o Phonon
+ Comment[pt_BR]=Infraestrutura Phonon GStreamer
++Comment[se]=Phonon GStreamer duogášmohtor
+ Comment[sk]=GStreamer podsystém
+ Comment[sl]=Phononova hrbtenica GStreamer
+ Comment[sr]=Гстример као позадина Фонона
+--- a/src/3rdparty/phonon/gstreamer/mediaobject.cpp
++++ b/src/3rdparty/phonon/gstreamer/mediaobject.cpp
+@@ -16,6 +16,7 @@
+ */
+ #include <cmath>
+ #include <gst/interfaces/propertyprobe.h>
++#include <gst/pbutils/install-plugins.h>
+ #include "common.h"
+ #include "mediaobject.h"
+ #include "videowidget.h"
+@@ -23,6 +24,7 @@
+ #include "backend.h"
+ #include "streamreader.h"
+ #include "phononsrc.h"
++#include "phonon-config-gstreamer.h"
+ #include <QtCore>
+ #include <QtCore/QTimer>
+ #include <QtCore/QVector>
+@@ -53,6 +55,7 @@ MediaObject::MediaObject(Backend *backen
+ , m_tickTimer(new QTimer(this))
+ , m_prefinishMark(0)
+ , m_transitionTime(0)
++ , m_isStream(false)
+ , m_posAtSeek(-1)
+ , m_prefinishMarkReachedNotEmitted(true)
+ , m_aboutToFinishEmitted(false)
+@@ -79,6 +82,7 @@ MediaObject::MediaObject(Backend *backen
+ , m_autoplayTitles(true)
+ , m_availableTitles(0)
+ , m_currentTitle(1)
++ , m_pendingTitle(1)
+ {
+ qRegisterMetaType<GstCaps*>("GstCaps*");
+ qRegisterMetaType<State>("State");
+@@ -87,7 +91,7 @@ MediaObject::MediaObject(Backend *backen
+ m_name = "MediaObject" + QString::number(count++);
+
+ if (!m_backend->isValid()) {
+- setError(tr("Cannot start playback. \n\nCheck your GStreamer installation and make sure you "
++ setError(tr("Cannot start playback. \n\nCheck your Gstreamer installation and make sure you "
+ "\nhave libgstreamer-plugins-base installed."), Phonon::FatalError);
+ } else {
+ m_root = this;
+@@ -95,8 +99,8 @@ MediaObject::MediaObject(Backend *backen
+ m_backend->addBusWatcher(this);
+ connect(m_tickTimer, SIGNAL(timeout()), SLOT(emitTick()));
+ }
+- connect(this, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
+- this, SLOT(notifyStateChange(Phonon::State,Phonon::State)));
++ connect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
++ this, SLOT(notifyStateChange(Phonon::State, Phonon::State)));
+
+ }
+
+@@ -136,6 +140,14 @@ QString stateString(const Phonon::State
+ return QString();
+ }
+
++void
++pluginInstallationDone( GstInstallPluginsReturn res, gpointer userData )
++{
++ // Nothing inside yet
++ Q_UNUSED(res);
++ Q_UNUSED(userData);
++}
++
+ void MediaObject::saveState()
+ {
+ //Only first resumeState is respected
+@@ -195,13 +207,35 @@ void MediaObject::noMorePadsAvailable ()
+ if (m_missingCodecs.size() > 0) {
+ bool canPlay = (m_hasAudio || m_videoStreamFound);
+ Phonon::ErrorType error = canPlay ? Phonon::NormalError : Phonon::FatalError;
++#ifdef PLUGIN_INSTALL_API
++ GstInstallPluginsContext *ctx = gst_install_plugins_context_new ();
++ gchar *details[2];
++ details[0] = m_missingCodecs[0].toLocal8Bit().data();
++ details[1] = NULL;
++ GstInstallPluginsReturn status;
++
++ status = gst_install_plugins_async( details, ctx, pluginInstallationDone, NULL );
++ gst_install_plugins_context_free ( ctx );
++
++ if ( status != GST_INSTALL_PLUGINS_STARTED_OK )
++ {
++ if( status == GST_INSTALL_PLUGINS_HELPER_MISSING )
++ setError(QString(tr("Missing codec helper script assistant.")), Phonon::FatalError );
++ else
++ setError(QString(tr("Plugin codec installation failed for codec: %0"))
++ .arg(m_missingCodecs[0].split("|")[3]), error);
++ }
++ m_missingCodecs.clear();
++#else
++ QString codecs = m_missingCodecs.join(", ");
++
+ if (error == Phonon::NormalError && m_hasVideo && !m_videoStreamFound) {
+ m_hasVideo = false;
+ emit hasVideoChanged(false);
+ }
+- QString codecs = m_missingCodecs.join(", ");
+ setError(QString(tr("A required codec is missing. You need to install the following codec(s) to play this content: %0")).arg(codecs), error);
+ m_missingCodecs.clear();
++#endif
+ }
+ }
+
+@@ -226,7 +260,6 @@ void MediaObject::cb_unknown_type (GstEl
+ QString value = "unknown codec";
+
+ // These functions require GStreamer > 0.10.12
+-#ifndef QT_NO_LIBRARY
+ static Ptr_gst_pb_utils_init p_gst_pb_utils_init = 0;
+ static Ptr_gst_pb_utils_get_codec_description p_gst_pb_utils_get_codec_description = 0;
+ if (!p_gst_pb_utils_init) {
+@@ -240,15 +273,21 @@ void MediaObject::cb_unknown_type (GstEl
+ codecName = p_gst_pb_utils_get_codec_description (caps);
+ value = QString::fromUtf8(codecName);
+ g_free (codecName);
+- } else
+-#endif //QT_NO_LIBRARY
+- {
++ } else {
+ // For GStreamer versions < 0.10.12
+ GstStructure *str = gst_caps_get_structure (caps, 0);
+ value = QString::fromUtf8(gst_structure_get_name (str));
+-
+ }
+- media->addMissingCodecName(value);
++
++#ifdef PLUGIN_INSTALL_API
++ QString plugins = QString("gstreamer|0.10|%0|%1|decoder-%2")
++ .arg( qApp->applicationName() )
++ .arg( value )
++ .arg( QString::fromUtf8(gst_caps_to_string (caps) ) );
++ media->addMissingCodecName( plugins );
++#else
++ media->addMissingCodecName( value );
++#endif
+ }
+
+ static void notifyVideoCaps(GObject *obj, GParamSpec *, gpointer data)
+@@ -309,7 +348,7 @@ void MediaObject::connectVideo(GstPad *p
+ m_backend->logMessage("Video track connected", Backend::Info, this);
+ // Note that the notify::caps _must_ be installed after linking to work with Dapper
+ m_capsHandler = g_signal_connect(pad, "notify::caps", G_CALLBACK(notifyVideoCaps), this);
+-
++
+ if (!m_loading && !m_hasVideo) {
+ m_hasVideo = m_videoStreamFound;
+ emit hasVideoChanged(m_hasVideo);
+@@ -368,7 +407,10 @@ bool MediaObject::createPipefromURL(cons
+ }
+
+ // Create a new datasource based on the input URL
+- QByteArray encoded_cstr_url = url.toEncoded();
++ // add the 'file' scheme if it's missing; the double '/' is needed!
++ QByteArray encoded_cstr_url = (url.scheme() == QLatin1String("") ?
++ "file://" + url.toEncoded() :
++ url.toEncoded());
+ m_datasource = gst_element_make_from_uri(GST_URI_SRC, encoded_cstr_url.constData(), (const char*)NULL);
+ if (!m_datasource)
+ return false;
+@@ -388,6 +430,14 @@ bool MediaObject::createPipefromURL(cons
+ g_object_set (G_OBJECT (m_datasource), "read-speed", 2, (const char*)NULL);
+ m_backend->logMessage(QString("new device speed : 2X"), Backend::Info, this);
+ }
++ }
++
++ /* make HTTP sources send extra headers so we get icecast
++ * metadata in case the stream is an icecast stream */
++ if (encoded_cstr_url.startsWith("http://")
++ && g_object_class_find_property (G_OBJECT_GET_CLASS (m_datasource), "iradio-mode")) {
++ g_object_set (m_datasource, "iradio-mode", TRUE, NULL);
++ m_isStream = true;
+ }
+
+ // Link data source into pipeline
+@@ -408,7 +458,6 @@ bool MediaObject::createPipefromURL(cons
+ */
+ bool MediaObject::createPipefromStream(const MediaSource &source)
+ {
+-#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ // Remove any existing data source
+ if (m_datasource) {
+ gst_bin_remove(GST_BIN(m_pipeline), m_datasource);
+@@ -430,10 +479,6 @@ bool MediaObject::createPipefromStream(c
+ return false;
+ }
+ return true;
+-#else //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+- Q_UNUSED(source);
+- return false;
+-#endif
+ }
+
+ void MediaObject::createPipeline()
+@@ -676,7 +721,7 @@ void MediaObject::changeState(State news
+ return;
+
+ Phonon::State oldState = m_state;
+- m_state = newstate; // m_state must be set before emitting, since
++ m_state = newstate; // m_state must be set before emitting, since
+ // Error state requires that state() will return the new value
+ m_pendingState = newstate;
+ emit stateChanged(newstate, oldState);
+@@ -861,7 +906,7 @@ void MediaObject::setSource(const MediaS
+ // such as failing duration queries etc
+ GstState state;
+ gst_element_set_state(m_pipeline, GST_STATE_NULL);
+- gst_element_get_state (m_pipeline, &state, NULL, 2000);
++ gst_element_get_state(m_pipeline, &state, NULL, 2000);
+
+ m_source = source;
+ emit currentSourceChanged(m_source);
+@@ -885,7 +930,7 @@ void MediaObject::setSource(const MediaS
+ m_aboutToFinishEmitted = false;
+ m_error = NoError;
+ m_errorString = QString();
+-
++
+ m_bufferPercent = 0;
+ m_prefinishMarkReachedNotEmitted = true;
+ m_aboutToFinishEmitted = false;
+@@ -894,11 +939,16 @@ void MediaObject::setSource(const MediaS
+ setTotalTime(-1);
+ m_atEndOfStream = false;
+
+- // Clear exising meta tags
++ m_availableTitles = 0;
++ m_pendingTitle = 1;
++ m_currentTitle = 1;
++
++ // Clear existing meta tags
+ m_metaData.clear();
++ m_isStream = false;
+
+ switch (source.type()) {
+- case MediaSource::Url: {
++ case MediaSource::Url: {
+ if (createPipefromURL(source.url()))
+ m_loading = true;
+ else
+@@ -930,9 +980,9 @@ void MediaObject::setSource(const MediaS
+
+ case MediaSource::Disc:
+ {
+- QString mediaUrl;
+- switch (source.discType()) {
+- case Phonon::NoDisc:
++ QString mediaUrl;
++ switch (source.discType()) {
++ case Phonon::NoDisc:
+ qWarning() << "I should never get to see a MediaSource that is a disc but doesn't specify which one";
+ return;
+ case Phonon::Cd: // CD tracks can be specified by setting the url in the following way uri=cdda:4
+@@ -1004,13 +1054,10 @@ void MediaObject::getStreamInfo()
+ emit hasVideoChanged(m_hasVideo);
+ }
+
+- m_availableTitles = 1;
+- gint64 titleCount;
+- GstFormat format = gst_format_get_by_nick("track");
+- if (gst_element_query_duration (m_pipeline, &format, &titleCount)) {
+- //check if returned format is still "track",
+- //gstreamer sometimes returns the total time, if tracks information is not available.
+- if (qstrcmp(gst_format_get_name(format), "track") == 0) {
++ if (m_source.discType() == Phonon::Cd) {
++ gint64 titleCount;
++ GstFormat format = gst_format_get_by_nick("track");
++ if (gst_element_query_duration (m_pipeline, &format, &titleCount)) {
+ int oldAvailableTitles = m_availableTitles;
+ m_availableTitles = (int)titleCount;
+ if (m_availableTitles != oldAvailableTitles) {
+@@ -1077,7 +1124,7 @@ void MediaObject::seek(qint64 time)
+ }
+
+ quint64 current = currentTime();
+- quint64 total = totalTime();
++ quint64 total = totalTime();
+
+ if (current < total - m_prefinishMark)
+ m_prefinishMarkReachedNotEmitted = true;
+@@ -1098,7 +1145,7 @@ void MediaObject::emitTick()
+
+ if (m_tickInterval > 0 && currentTime != m_previousTickTime) {
+ emit tick(currentTime);
+- m_previousTickTime = currentTime;
++ m_previousTickTime = currentTime;
+ }
+ if (m_state == Phonon::PlayingState) {
+ if (currentTime >= totalTime - m_prefinishMark) {
+@@ -1109,7 +1156,12 @@ void MediaObject::emitTick()
+ }
+ // Prepare load of next source
+ if (currentTime >= totalTime - ABOUT_TO_FINNISH_TIME) {
+- if (!m_aboutToFinishEmitted) {
++ if (m_source.type() == MediaSource::Disc &&
++ m_autoplayTitles &&
++ m_availableTitles > 1 &&
++ m_currentTitle < m_availableTitles) {
++ m_aboutToFinishEmitted = false;
++ } else if (!m_aboutToFinishEmitted) {
+ m_aboutToFinishEmitted = true; // track is about to finish
+ emit aboutToFinish();
+ }
+@@ -1213,7 +1265,7 @@ void MediaObject::handleBusMessage(const
+
+ switch (GST_MESSAGE_TYPE (gstMessage)) {
+
+- case GST_MESSAGE_EOS:
++ case GST_MESSAGE_EOS:
+ m_backend->logMessage("EOS recieved", Backend::Info, this);
+ handleEndOfStream();
+ break;
+@@ -1222,14 +1274,98 @@ void MediaObject::handleBusMessage(const
+ GstTagList* tag_list = 0;
+ gst_message_parse_tag(gstMessage, &tag_list);
+ if (tag_list) {
++ TagMap newTags;
++ gst_tag_list_foreach (tag_list, &foreach_tag_function, &newTags);
++ gst_tag_list_free(tag_list);
++
++ // Determine if we should no fake the album/artist tags.
++ // This is a little confusing as we want to fake it on initial
++ // connection where title, album and artist are all missing.
++ // There are however times when we get just other information,
++ // e.g. codec, and so we want to only do clever stuff if we
++ // have a commonly available tag (ORGANIZATION) or we have a
++ // change in title
++ bool fake_it =
++ (m_isStream
++ && ((!newTags.contains("TITLE")
++ && newTags.contains("ORGANIZATION"))
++ || (newTags.contains("TITLE")
++ && m_metaData.value("TITLE") != newTags.value("TITLE")))
++ && !newTags.contains("ALBUM")
++ && !newTags.contains("ARTIST"));
++
+ TagMap oldMap = m_metaData; // Keep a copy of the old one for reference
+- // Append any new meta tags to the existing tag list
+- gst_tag_list_foreach (tag_list, &foreach_tag_function, &m_metaData);
++
++ // Now we've checked the new data, append any new meta tags to the existing tag list
++ // We cannot use TagMap::iterator as this is a multimap and when streaming data
++ // could in theory be lost.
++ QList<QString> keys = newTags.keys();
++ for (QList<QString>::iterator i = keys.begin(); i != keys.end(); ++i) {
++ QString key = *i;
++ if (m_isStream) {
++ // If we're streaming, we need to remove data in m_metaData
++ // in order to stop it filling up indefinitely (as it's a multimap)
++ m_metaData.remove(key);
++ }
++ QList<QString> values = newTags.values(key);
++ for (QList<QString>::iterator j = values.begin(); j != values.end(); ++j) {
++ QString value = *j;
++ QString currVal = m_metaData.value(key);
++ if (!m_metaData.contains(key) || currVal != value) {
++ m_metaData.insert(key, value);
++ }
++ }
++ }
++
+ m_backend->logMessage("Meta tags found", Backend::Info, this);
+- if (oldMap != m_metaData && !m_loading)
+- emit metaDataChanged(m_metaData);
+- gst_tag_list_free(tag_list);
+- }
++ if (oldMap != m_metaData) {
++ // This is a bit of a hack to ensure that stream metadata is
++ // returned. We get as much as we can from the Shoutcast server's
++ // StreamTitle= header. If further info is decoded from the stream
++ // itself later, then it will overwrite this info.
++ if (m_isStream && fake_it) {
++ m_metaData.remove("ALBUM");
++ m_metaData.remove("ARTIST");
++
++ // Detect whether we want to "fill in the blanks"
++ QString str;
++ if (m_metaData.contains("TITLE"))
++ {
++ str = m_metaData.value("TITLE");
++ int splitpoint;
++ // Check to see if our title matches "%s - %s"
++ // Where neither %s are empty...
++ if ((splitpoint = str.indexOf(" - ")) > 0
++ && str.size() > (splitpoint+3)) {
++ m_metaData.insert("ARTIST", str.left(splitpoint));
++ m_metaData.replace("TITLE", str.mid(splitpoint+3));
++ }
++ } else {
++ str = m_metaData.value("GENRE");
++ if (!str.isEmpty())
++ m_metaData.insert("TITLE", str);
++ else
++ m_metaData.insert("TITLE", "Streaming Data");
++ }
++ if (!m_metaData.contains("ARTIST")) {
++ str = m_metaData.value("LOCATION");
++ if (!str.isEmpty())
++ m_metaData.insert("ARTIST", str);
++ else
++ m_metaData.insert("ARTIST", "Streaming Data");
++ }
++ str = m_metaData.value("ORGANIZATION");
++ if (!str.isEmpty())
++ m_metaData.insert("ALBUM", str);
++ else
++ m_metaData.insert("ALBUM", "Streaming Data");
++ }
++ // As we manipulate the title, we need to recompare
++ // oldMap and m_metaData here...
++ if (oldMap != m_metaData && !m_loading)
++ emit metaDataChanged(m_metaData);
++ }
++ }
+ }
+ break;
+
+@@ -1255,6 +1391,9 @@ void MediaObject::handleBusMessage(const
+ m_backend->logMessage("gstreamer: pipeline state set to playing", Backend::Info, this);
+ m_tickTimer->start();
+ changeState(Phonon::PlayingState);
++ if ((m_source.type() == MediaSource::Disc) && (m_currentTitle != m_pendingTitle)) {
++ setTrack(m_pendingTitle);
++ }
+ if (m_resumeState && m_oldState == Phonon::PlayingState) {
+ seek(m_oldPos);
+ m_resumeState = false;
+@@ -1290,6 +1429,9 @@ void MediaObject::handleBusMessage(const
+ changeState(Phonon::StoppedState);
+ m_backend->logMessage("gstreamer: pipeline state set to ready", Backend::Debug, this);
+ m_tickTimer->stop();
++ if ((m_source.type() == MediaSource::Disc) && (m_currentTitle != m_pendingTitle)) {
++ setTrack(m_pendingTitle);
++ }
+ break;
+
+ case GST_STATE_VOID_PENDING :
+@@ -1328,7 +1470,7 @@ void MediaObject::handleBusMessage(const
+ setError(err->message, Phonon::FatalError);
+ gst_caps_unref (caps);
+ gst_object_unref (sinkPad);
+- }
++ }
+ } else {
+ setError(QString(err->message), Phonon::FatalError);
+ }
+@@ -1400,8 +1542,8 @@ void MediaObject::handleBusMessage(const
+ //case GST_MESSAGE_STEP_DONE:
+ //case GST_MESSAGE_LATENCY: only from 0.10.12
+ //case GST_MESSAGE_ASYNC_DONE: only from 0.10.13
+- default:
+- break;
++ default:
++ break;
+ }
+ }
+
+@@ -1417,7 +1559,8 @@ void MediaObject::handleEndOfStream()
+ if (!m_seekable)
+ m_atEndOfStream = true;
+
+- if (m_autoplayTitles &&
++ if (m_source.type() == MediaSource::Disc &&
++ m_autoplayTitles &&
+ m_availableTitles > 1 &&
+ m_currentTitle < m_availableTitles) {
+ _iface_setCurrentTitle(m_currentTitle + 1);
+@@ -1502,15 +1645,30 @@ int MediaObject::_iface_currentTitle() c
+
+ void MediaObject::_iface_setCurrentTitle(int title)
+ {
+- GstFormat trackFormat = gst_format_get_by_nick("track");
+ m_backend->logMessage(QString("setCurrentTitle %0").arg(title), Backend::Info, this);
+- if ((title == m_currentTitle) || (title < 1) || (title > m_availableTitles))
++ if ((title == m_currentTitle) || (title == m_pendingTitle))
++ return;
++
++ m_pendingTitle = title;
++
++ if (m_state == Phonon::PlayingState || m_state == Phonon::StoppedState) {
++ setTrack(m_pendingTitle);
++ } else {
++ setState(Phonon::StoppedState);
++ }
++}
++
++void MediaObject::setTrack(int title)
++{
++ if (((m_state != Phonon::PlayingState) && (m_state != Phonon::StoppedState)) || (title < 1) || (title > m_availableTitles))
+ return;
+
+- m_currentTitle = title;
+
+ //let's seek to the beginning of the song
+- if (gst_element_seek_simple(m_pipeline, trackFormat, GST_SEEK_FLAG_FLUSH, m_currentTitle - 1)) {
++ GstFormat trackFormat = gst_format_get_by_nick("track");
++ m_backend->logMessage(QString("setTrack %0").arg(title), Backend::Info, this);
++ if (gst_element_seek_simple(m_pipeline, trackFormat, GST_SEEK_FLAG_FLUSH, title - 1)) {
++ m_currentTitle = title;
+ updateTotalTime();
+ m_atEndOfStream = false;
+ emit titleChanged(title);
+--- a/src/3rdparty/phonon/gstreamer/mediaobject.h
++++ b/src/3rdparty/phonon/gstreamer/mediaobject.h
+@@ -55,6 +55,7 @@ class MediaObject : public QObject, publ
+ , public MediaNode
+ {
+ friend class Stream;
++ friend class AudioDataOutput;
+ Q_OBJECT
+ Q_INTERFACES(Phonon::MediaObjectInterface
+ #ifndef QT_NO_PHONON_MEDIACONTROLLER
+@@ -236,6 +237,7 @@ private:
+ int _iface_availableTitles() const;
+ int _iface_currentTitle() const;
+ void _iface_setCurrentTitle(int title);
++ void setTrack(int title);
+
+ bool m_resumeState;
+ State m_oldState;
+@@ -250,6 +252,7 @@ private:
+ MediaSource m_nextSource;
+ qint32 m_prefinishMark;
+ qint32 m_transitionTime;
++ bool m_isStream;
+
+ qint64 m_posAtSeek;
+
+@@ -285,6 +288,7 @@ private:
+ bool m_autoplayTitles;
+ int m_availableTitles;
+ int m_currentTitle;
++ int m_pendingTitle;
+ };
+ }
+ } //namespace Phonon::Gstreamer
+--- /dev/null
++++ b/gstreamer/phonon-config-gstreamer.h.cmake
+@@ -0,0 +1,5 @@
++/* GStreamer install plugin definitions */
++
++/* If api-plugin is defined */
++#cmakedefine PLUGIN_INSTALL_API 1
++
+--- a/src/3rdparty/phonon/gstreamer/phononsrc.cpp
++++ b/src/3rdparty/phonon/gstreamer/phononsrc.cpp
+@@ -109,25 +109,18 @@ static void phonon_src_class_init (Phono
+ static void phonon_src_init (PhononSrc * src, PhononSrcClass * g_class)
+ {
+ Q_UNUSED(g_class);
+-#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ src->device = 0;
+-#else
+- Q_UNUSED(src);
+-#endif
+ }
+
+ static void phonon_src_finalize (GObject * object)
+ {
+-#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ PhononSrc *src;
+ src = GST_PHONON_SRC (object);
+ delete src->device;
+ src->device = 0;
+-#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+ }
+
+-#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ static gboolean phonon_src_set_device(PhononSrc * src, StreamReader* device)
+ {
+ GstState state;
+@@ -152,7 +145,6 @@ wrong_state:
+ return FALSE;
+ }
+ }
+-#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+ static void phonon_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
+ {
+@@ -161,7 +153,6 @@ static void phonon_src_set_property (GOb
+ src = GST_PHONON_SRC (object);
+
+ switch (prop_id) {
+-#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ case ARG_PHONONSRC:
+ {
+ StreamReader *dev = (StreamReader*)(g_value_get_pointer(value));
+@@ -169,9 +160,6 @@ static void phonon_src_set_property (GOb
+ phonon_src_set_device(src, dev);
+ break;
+ }
+-#else
+- Q_UNUSED(value);
+-#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+@@ -186,13 +174,9 @@ static void phonon_src_get_property (GOb
+ src = GST_PHONON_SRC (object);
+
+ switch (prop_id) {
+-#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ case ARG_PHONONSRC:
+ g_value_set_pointer(value, src->device);
+ break;
+-#else //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+- Q_UNUSED(value);
+-#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+@@ -201,7 +185,6 @@ static void phonon_src_get_property (GOb
+
+ static GstFlowReturn phonon_src_create_read (PhononSrc * src, guint64 offset, guint length, GstBuffer ** buffer)
+ {
+-#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ Q_ASSERT(src->device);
+ if (!src->device)
+ return GST_FLOW_ERROR;
+@@ -221,13 +204,6 @@ static GstFlowReturn phonon_src_create_r
+
+ gst_mini_object_unref(GST_MINI_OBJECT(buf));
+ return GST_FLOW_ERROR;
+-#else //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+- Q_UNUSED(src);
+- Q_UNUSED(offset);
+- Q_UNUSED(length);
+- Q_UNUSED(buffer);
+- return GST_FLOW_ERROR;
+-#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ }
+
+ static GstFlowReturn phonon_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer)
+@@ -242,23 +218,19 @@ static GstFlowReturn phonon_src_create (
+ static gboolean phonon_src_is_seekable (GstBaseSrc * basesrc)
+ {
+ PhononSrc *src = GST_PHONON_SRC (basesrc);
+-#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ if (src->device)
+ return src->device->streamSeekable();
+-#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ return false;
+ }
+
+ static gboolean phonon_src_get_size (GstBaseSrc * basesrc, guint64 * size)
+ {
+-#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ PhononSrc *src;
+ src = GST_PHONON_SRC (basesrc);
+ if (src->device && src->device->streamSeekable()) {
+ *size = src->device->streamSize();
+ return TRUE;
+ }
+-#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ *size = 0;
+ return FALSE;
+ }
+--- a/src/3rdparty/phonon/gstreamer/phononsrc.h
++++ b/src/3rdparty/phonon/gstreamer/phononsrc.h
+@@ -49,9 +49,7 @@ typedef struct _PhononSrcClass PhononSrc
+ // PhononSrc:
+ struct _PhononSrc {
+ GstBaseSrc element;
+-#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ StreamReader *device;
+-#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ };
+
+ struct _PhononSrcClass {
+--- a/src/3rdparty/phonon/gstreamer/qwidgetvideosink.h
++++ b/src/3rdparty/phonon/gstreamer/qwidgetvideosink.h
+@@ -19,6 +19,7 @@
+ #define Phonon_GSTREAMER_VIDEOSINK_H
+
+ #include "common.h"
++#include "qwidgetvideosink.h"
+
+ #include <QtCore/QByteArray>
+ #include <QtCore/QEvent>
+--- a/src/3rdparty/phonon/gstreamer/streamreader.cpp
++++ b/src/3rdparty/phonon/gstreamer/streamreader.cpp
+@@ -20,7 +20,7 @@ along with this library. If not, see <h
+ #include <phonon/streaminterface.h>
+
+ QT_BEGIN_NAMESPACE
+-#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
++
+ namespace Phonon
+ {
+ namespace Gstreamer
+@@ -49,6 +49,5 @@ bool StreamReader::read(quint64 pos, int
+
+ }
+ }
+-#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+ QT_END_NAMESPACE
+--- a/src/3rdparty/phonon/gstreamer/streamreader.h
++++ b/src/3rdparty/phonon/gstreamer/streamreader.h
+@@ -23,8 +23,6 @@ along with this library. If not, see <h
+
+ QT_BEGIN_NAMESPACE
+
+-#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+-
+ namespace Phonon
+ {
+ class MediaSource;
+@@ -93,8 +91,6 @@ private:
+ }
+ }
+
+-#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+-
+ QT_END_NAMESPACE
+
+ #endif
+--- a/src/3rdparty/phonon/gstreamer/videowidget.cpp
++++ b/src/3rdparty/phonon/gstreamer/videowidget.cpp
+@@ -33,7 +33,6 @@
+ #include "widgetrenderer.h"
+ #include "x11renderer.h"
+
+-#ifndef QT_NO_PHONON_VIDEO
+ QT_BEGIN_NAMESPACE
+
+ namespace Phonon
+@@ -384,6 +383,5 @@ void VideoWidget::mediaNodeEvent(const M
+ } //namespace Phonon::Gstreamer
+
+ QT_END_NAMESPACE
+-#endif //QT_NO_PHONON_VIDEO
+
+ #include "moc_videowidget.cpp"
+--- a/src/3rdparty/phonon/gstreamer/videowidget.h
++++ b/src/3rdparty/phonon/gstreamer/videowidget.h
+@@ -25,10 +25,10 @@
+ #include "common.h"
+ #include "medianode.h"
+ #include "abstractrenderer.h"
++#include "videowidget.h"
+
+ #include <gst/gst.h>
+
+-#ifndef QT_NO_PHONON_VIDEO
+ QT_BEGIN_NAMESPACE
+
+ class QString;
+@@ -103,5 +103,5 @@ private:
+ } //namespace Phonon::Gstreamer
+
+ QT_END_NAMESPACE
+-#endif //QT_NO_PHONON_VIDEO
++
+ #endif // Phonon_GSTREAMER_VIDEOWIDGET_H
+--- a/src/3rdparty/phonon/gstreamer/volumefadereffect.cpp
++++ b/src/3rdparty/phonon/gstreamer/volumefadereffect.cpp
+@@ -21,11 +21,11 @@
+
+ QT_BEGIN_NAMESPACE
+
+-#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
+ namespace Phonon
+ {
+ namespace Gstreamer
+ {
++
+ VolumeFaderEffect::VolumeFaderEffect(Backend *backend, QObject *parent)
+ : Effect(backend, parent, AudioSource | AudioSink)
+ , m_fadeCurve(Phonon::VolumeFaderEffect::Fade3Decibel)
+@@ -156,7 +156,7 @@ bool VolumeFaderEffect::event(QEvent *ev
+ }
+
+ }} //namespace Phonon::Gstreamer
+-#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
++
+ QT_END_NAMESPACE
+
+ #include "moc_volumefadereffect.cpp"
+--- a/src/3rdparty/phonon/gstreamer/volumefadereffect.h
++++ b/src/3rdparty/phonon/gstreamer/volumefadereffect.h
+@@ -30,7 +30,7 @@
+ #include <gst/gst.h>
+
+ QT_BEGIN_NAMESPACE
+-#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
++
+ namespace Phonon
+ {
+ namespace Gstreamer
+@@ -64,7 +64,7 @@ namespace Gstreamer
+ QTime m_fadeStartTime;
+ };
+ }} //namespace Phonon::Gstreamer
+-#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
++
+ QT_END_NAMESPACE
+
+ #endif // Phonon_GSTREAMER_VOLUMEFADEREFFECT_H
+--- a/src/3rdparty/phonon/gstreamer/widgetrenderer.cpp
++++ b/src/3rdparty/phonon/gstreamer/widgetrenderer.cpp
+@@ -32,7 +32,6 @@
+ # define GL_TEXTURE2 0x84C2
+ #endif
+
+-#ifndef QT_NO_PHONON_VIDEO
+ QT_BEGIN_NAMESPACE
+
+ static void frameRendered()
+@@ -149,4 +148,3 @@ bool WidgetRenderer::eventFilter(QEvent
+ } //namespace Phonon::Gstreamer
+
+ QT_END_NAMESPACE
+-#endif //QT_NO_PHONON_VIDEO
+--- a/src/3rdparty/phonon/gstreamer/widgetrenderer.h
++++ b/src/3rdparty/phonon/gstreamer/widgetrenderer.h
+@@ -26,7 +26,6 @@
+ #include <QtOpenGL/QGLWidget>
+ #endif
+
+-#ifndef QT_NO_PHONON_VIDEO
+ QT_BEGIN_NAMESPACE
+
+ class QString;
+@@ -60,5 +59,5 @@ private:
+ } //namespace Phonon::Gstreamer
+
+ QT_END_NAMESPACE
+-#endif //QT_NO_PHONON_VIDEO
++
+ #endif // Phonon_GSTREAMER_WIDGETRENDERER_H
+--- a/src/3rdparty/phonon/gstreamer/x11renderer.cpp
++++ b/src/3rdparty/phonon/gstreamer/x11renderer.cpp
+@@ -138,6 +138,7 @@ void X11Renderer::scaleModeChanged(Phono
+ void X11Renderer::movieSizeChanged(const QSize &movieSize)
+ {
+ Q_UNUSED(movieSize);
++
+ if (m_renderWidget) {
+ m_renderWidget->setGeometry(m_videoWidget->calculateDrawFrameRect());
+ }
+--- /dev/null
++++ b/Mainpage.dox
+@@ -0,0 +1,64 @@
++/** @mainpage The Phonon Library API Reference
++
++<p><b>
++Overview |
++@ref development
++</b></p>
++
++<a href="http://phonon.kde.org/">Phonon</a> provides a Qt-style interface for audio
++and video. It is aimed at the average desktop application, whether that is a game
++that needs sound effects or a full-blown multimedia playback application like
++<a href="http://amarok.kde.org/">Amarok</a> or
++<a href="http://www.dragonplayer.org/">Dragon Player</a>.
++
++If you writing a Qt program and want audio or video playback, then Phonon is almost
++certainly the right choice for you. It provides an API that any Qt developer will
++be comfortable with, and uses the native sound systems on Windows and MacOS. On
++UNIX systems, where there is no one standard multimedia system, it offers
++<a href="http://www.gstreamer.net/">GStreamer</a> and <a href="http://xinehq.de/">Xine</a>
++backends, and more (such as <a href="http://www.videolan.org/">VLC</a>) are available
++from third parties.
++
++However, Phonon is not aimed at professional audio applications (in the style of
++<a href="http://audacity.sourceforge.net/">Audacity</a>, say). For these applications,
++you will probably want more control over the audio layer than Phonon will give you,
++and you should probably be using something like <a href="http://jackaudio.org/">JACK</a>.
++
++@authors
++Matthias Kretz \<kretz@kde.org\><br>
++Ricardo Villalba \<rvm@escomposlinux.org\><br>
++Ian Monroe \<ian@monroe.nu\><br>
++Nokia Corporation and/or its subsidiary(-ies)
++
++@maintainers
++Matthias Kretz \<kretz@kde.org\>
++
++@licenses
++Libraries: @lgpl<br>
++Examples: @mit<br>
++Backends: @lgpl or @gpl
++
++*/
++
++/** @page development Development
++
++<p><b>
++@ref index "Overview" |
++Development
++</b></p>
++
++If you want to get involved with Phonon backend development please subscribe to <a href="https://mail.kde.org/mailman/listinfo/phonon-backends">phonon-backends@kde.org</a>.
++
++If you want to contribute, make comments or useful suggestions you can also write to the <a href="mailto:kde-multimedia@kde.org">KDE Multimedia mailinglist</a> or <a href="mailto:kretz@kde.org">Matthias Kretz</a>. You can join the mailinglist using the <a href="https://mail.kde.org/mailman/listinfo/kde-multimedia">webinterface</a> or take a look at the <a href="http://lists.kde.org/?l=kde-multimedia">archives</a>
++
++*/
++
++// DOXYGEN_VERSION=4.3
++// DOXYGEN_NAME=Phonon
++// DOXYGEN_ENABLE=YES
++// DOXYGEN_SET_INPUT = @topdir@/phonon/phonon @topdir@/phonon/Mainpage.dox
++// DOXYGEN_SET_FILE_PATTERNS = *.h *.dox */phononnamespace.h.in
++// ignore backend docs
++// DOXYGEN_SET_EXCLUDE_PATTERNS = *interface.h */phonon/examples/* */tests/* *_p.h */experimental/videocapturedevice/* */phonon/backend*
++
++// vim:ts=4:sw=4:expandtab:filetype=doxygen
+--- a/src/3rdparty/phonon/phonon/abstractmediastream.cpp
++++ b/src/3rdparty/phonon/phonon/abstractmediastream.cpp
+@@ -49,6 +49,7 @@ AbstractMediaStream::AbstractMediaStream
+
+ AbstractMediaStream::~AbstractMediaStream()
+ {
++ delete d_ptr;
+ }
+
+ qint64 AbstractMediaStream::streamSize() const
+--- a/src/3rdparty/phonon/phonon/abstractmediastream.h
++++ b/src/3rdparty/phonon/phonon/abstractmediastream.h
+@@ -214,7 +214,7 @@ class PHONON_EXPORT AbstractMediaStream
+ virtual void seekStream(qint64 offset);
+
+ AbstractMediaStream(AbstractMediaStreamPrivate &dd, QObject *parent);
+- QScopedPointer<AbstractMediaStreamPrivate> d_ptr;
++ AbstractMediaStreamPrivate *d_ptr;
+ };
+
+ } // namespace Phonon
+--- a/src/3rdparty/phonon/phonon/abstractmediastream_p.h
++++ b/src/3rdparty/phonon/phonon/abstractmediastream_p.h
+@@ -45,7 +45,6 @@ class PHONON_EXPORT AbstractMediaStreamP
+ public:
+ void setStreamInterface(StreamInterface *);
+ void setMediaObjectPrivate(MediaObjectPrivate *);
+- ~AbstractMediaStreamPrivate();
+
+ protected:
+ AbstractMediaStreamPrivate()
+@@ -57,6 +56,7 @@ class PHONON_EXPORT AbstractMediaStreamP
+ errorType(NoError)
+ {
+ }
++ ~AbstractMediaStreamPrivate();
+
+ virtual void setStreamSize(qint64 newSize);
+ virtual void setStreamSeekable(bool s);
+--- /dev/null
++++ b/phonon/audiodataoutput.cpp
+@@ -0,0 +1,68 @@
++/* This file is part of the KDE project
++ Copyright (C) 2005 Matthias Kretz <kretz@kde.org>
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) version 3, or any
++ later version accepted by the membership of KDE e.V. (or its
++ successor approved by the membership of KDE e.V.), Nokia Corporation
++ (or its successors, if any) and the KDE Free Qt Foundation, which shall
++ act as a proxy defined in Section 6 of version 3 of the license.
++
++ This library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with this library. If not, see <http://www.gnu.org/licenses/>.
++
++*/
++
++#include "audiodataoutput.h"
++#include "audiodataoutput_p.h"
++#include "factory_p.h"
++
++#define PHONON_CLASSNAME AudioDataOutput
++
++namespace Phonon
++{
++
++PHONON_HEIR_IMPL(AbstractAudioOutput)
++
++PHONON_GETTER(int, dataSize, d->dataSize)
++PHONON_GETTER(int, sampleRate, -1)
++PHONON_SETTER(setDataSize, dataSize, int)
++
++bool AudioDataOutputPrivate::aboutToDeleteBackendObject()
++{
++ Q_ASSERT(m_backendObject);
++ pBACKEND_GET(int, dataSize, "dataSize");
++
++ return AbstractAudioOutputPrivate::aboutToDeleteBackendObject();
++}
++
++void AudioDataOutputPrivate::setupBackendObject()
++{
++ Q_Q(AudioDataOutput);
++ Q_ASSERT(m_backendObject);
++ AbstractAudioOutputPrivate::setupBackendObject();
++
++ // set up attributes
++ pBACKEND_CALL1("setDataSize", int, dataSize);
++
++ qRegisterMetaType<QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > >("QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> >");
++
++ QObject::connect(m_backendObject,
++ SIGNAL(dataReady(const QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > &)),
++ q, SIGNAL(dataReady(const QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > &)));
++ QObject::connect(m_backendObject, SIGNAL(endOfMedia(int)), q, SIGNAL(endOfMedia(int)));
++}
++
++} // namespace Phonon
++
++#include "audiodataoutput.moc"
++
++#undef PHONON_CLASSNAME
++// vim: sw=4 ts=4 tw=80
+--- /dev/null
++++ b/phonon/audiodataoutput.h
+@@ -0,0 +1,129 @@
++/* This file is part of the KDE project
++ Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) version 3, or any
++ later version accepted by the membership of KDE e.V. (or its
++ successor approved by the membership of KDE e.V.), Nokia Corporation
++ (or its successors, if any) and the KDE Free Qt Foundation, which shall
++ act as a proxy defined in Section 6 of version 3 of the license.
++
++ This library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with this library. If not, see <http://www.gnu.org/licenses/>.
++
++*/
++#ifndef Phonon_AUDIODATAOUTPUT_H
++#define Phonon_AUDIODATAOUTPUT_H
++
++#include "phonon_export.h"
++#include "abstractaudiooutput.h"
++#include "phonondefs.h"
++
++#ifndef DOXYGEN_SHOULD_SKIP_THIS
++template<typename T> class QVector;
++template<typename Key, typename T> class QMap;
++#endif
++
++namespace Phonon
++{
++ class AudioDataOutputPrivate;
++
++ /**
++ * \short This class gives you the audio data (for visualizations).
++ *
++ * This class implements a special AbstractAudioOutput that gives your
++ * application the audio data. Don't expect realtime performance. But
++ * the latencies should be low enough to use the audio data for
++ * visualizations. You can also use the audio data for further processing
++ * (e.g. encoding and saving to a file).
++ *
++ * \author Matthias Kretz <kretz@kde.org>
++ */
++ class PHONON_EXPORT AudioDataOutput : public AbstractAudioOutput
++ {
++ Q_OBJECT
++ K_DECLARE_PRIVATE(AudioDataOutput)
++ Q_ENUMS(Channel)
++ Q_PROPERTY(int dataSize READ dataSize WRITE setDataSize)
++ PHONON_HEIR(AudioDataOutput)
++ public:
++ /**
++ * Specifies the channel the audio data belongs to.
++ */
++ enum Channel
++ {
++ LeftChannel,
++ RightChannel,
++ CenterChannel,
++ LeftSurroundChannel,
++ RightSurroundChannel,
++ SubwooferChannel
++ };
++
++ /**
++ * Returns the currently used number of samples passed through
++ * the signal.
++ *
++ * \see setDataSize
++ */
++ int dataSize() const;
++
++ /**
++ * Returns the sample rate in Hz. Common sample rates are 44100 Hz
++ * and 48000 Hz. AudioDataOutput will not do any sample rate
++ * conversion for you. If you need to convert the sample rate you
++ * might want to take a look at libsamplerate. For visualizations it
++ * is often enough to do simple interpolation or even drop/duplicate
++ * samples.
++ *
++ * \return The sample rate as reported by the backend. If the
++ * backend is unavailable -1 is returned.
++ */
++ int sampleRate() const;
++
++ public Q_SLOTS:
++ /**
++ * Sets the number of samples to be passed in one signal emission.
++ *
++ * Defaults to 512 samples per emitted signal.
++ *
++ * \param size the number of samples
++ */
++ void setDataSize(int size);
++
++ Q_SIGNALS:
++ /**
++ * Emitted whenever another dataSize number of samples are ready.
++ *
++ * \param data A mapping of Channel to a vector holding the audio data.
++ */
++ void dataReady(const QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > &data);
++
++
++ /**
++ * This signal is emitted before the last dataReady signal of a
++ * media is emitted.
++ *
++ * If, for example, the playback of a media file has finished and the
++ * last audio data of that file is going to be passed with the next
++ * dataReady signal, and only the 28 first samples of the data
++ * vector are from that media file endOfMedia will be emitted right
++ * before dataReady with \p remainingSamples = 28.
++ *
++ * \param remainingSamples The number of samples in the next
++ * dataReady vector that belong to the media that was playing to
++ * this point.
++ */
++ void endOfMedia(int remainingSamples);
++ };
++} // namespace Phonon
++
++// vim: sw=4 ts=4 tw=80
++#endif // Phonon_AUDIODATAOUTPUT_H
+--- /dev/null
++++ b/phonon/audiodataoutputinterface.h
+@@ -0,0 +1,44 @@
++/* This file is part of the KDE project
++ Copyright (C) 2008 Matthias Kretz <kretz@kde.org>
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) version 3, or any
++ later version accepted by the membership of KDE e.V. (or its
++ successor approved by the membership of KDE e.V.), Nokia Corporation
++ (or its successors, if any) and the KDE Free Qt Foundation, which shall
++ act as a proxy defined in Section 6 of version 3 of the license.
++
++ This library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with this library. If not, see <http://www.gnu.org/licenses/>.
++
++*/
++
++#ifndef PHONON_AUDIODATAOUTPUTINTERFACE_H
++#define PHONON_AUDIODATAOUTPUTINTERFACE_H
++
++namespace Phonon
++{
++
++class AudioDataOutput;
++
++class AudioDataOutputInterface
++{
++ public:
++ virtual ~AudioDataOutputInterface() {}
++
++ virtual AudioDataOutput *frontendObject() const = 0;
++ virtual void setFrontendObject(AudioDataOutput *) = 0;
++};
++
++} // namespace Phonon
++
++Q_DECLARE_INTERFACE(Phonon::AudioDataOutputInterface, "0AudioDataOutputInterface.phonon.kde.org")
++
++#endif // PHONON_AUDIODATAOUTPUTINTERFACE_H
+--- /dev/null
++++ b/phonon/audiodataoutput_p.h
+@@ -0,0 +1,48 @@
++/* This file is part of the KDE project
++ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) version 3, or any
++ later version accepted by the membership of KDE e.V. (or its
++ successor approved by the membership of KDE e.V.), Nokia Corporation
++ (or its successors, if any) and the KDE Free Qt Foundation, which shall
++ act as a proxy defined in Section 6 of version 3 of the license.
++
++ This library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with this library. If not, see <http://www.gnu.org/licenses/>.
++
++*/
++
++#ifndef AUDIODATAOUTPUT_P_H
++#define AUDIODATAOUTPUT_P_H
++
++#include "audiodataoutput.h"
++#include "abstractaudiooutput_p.h"
++
++namespace Phonon
++{
++
++class AudioDataOutputPrivate : public AbstractAudioOutputPrivate
++{
++ Q_DECLARE_PUBLIC(AudioDataOutput)
++ PHONON_PRIVATECLASS
++ protected:
++ AudioDataOutputPrivate()
++ : dataSize(512)
++ {
++ }
++
++ int dataSize;
++};
++
++} // namespace Phonon
++
++#endif // AUDIODATAOUTPUT_P_H
++// vim: sw=4 ts=4 tw=80
+--- a/src/3rdparty/phonon/phonon/audiooutput.cpp
++++ b/src/3rdparty/phonon/phonon/audiooutput.cpp
+@@ -24,10 +24,11 @@
+ #include "factory_p.h"
+ #include "objectdescription.h"
+ #include "audiooutputadaptor_p.h"
+-#include "globalconfig_p.h"
++#include "globalconfig.h"
+ #include "audiooutputinterface.h"
+ #include "phononnamespace_p.h"
+ #include "platform_p.h"
++#include "pulsesupport_p.h"
+
+ #include <QtCore/qmath.h>
+
+@@ -42,8 +43,12 @@ QT_BEGIN_NAMESPACE
+ namespace Phonon
+ {
+
+-static inline bool callSetOutputDevice(MediaNodePrivate *const d, int index)
++static inline bool callSetOutputDevice(AudioOutputPrivate *const d, int index)
+ {
++ PulseSupport *pulse = PulseSupport::getInstance();
++ if (pulse->isActive())
++ return pulse->setOutputDevice(d->getStreamUuid(), index);
++
+ Iface<IFACES2> iface(d);
+ if (iface) {
+ return iface->setOutputDevice(AudioOutputDevice::fromIndex(index));
+@@ -51,8 +56,12 @@ static inline bool callSetOutputDevice(M
+ return Iface<IFACES0>::cast(d)->setOutputDevice(index);
+ }
+
+-static inline bool callSetOutputDevice(MediaNodePrivate *const d, const AudioOutputDevice &dev)
++static inline bool callSetOutputDevice(AudioOutputPrivate *const d, const AudioOutputDevice &dev)
+ {
++ PulseSupport *pulse = PulseSupport::getInstance();
++ if (pulse->isActive())
++ return pulse->setOutputDevice(d->getStreamUuid(), dev.index());
++
+ Iface<IFACES2> iface(d);
+ if (iface) {
+ return iface->setOutputDevice(dev);
+@@ -89,6 +98,8 @@ void AudioOutputPrivate::init(Phonon::Ca
+ #endif
+
+ category = c;
++ streamUuid = QUuid::createUuid().toString();
++ PulseSupport::getInstance()->setStreamPropList(category, streamUuid);
+
+ // select hardware device according to the category
+ device = AudioOutputDevice::fromIndex(GlobalConfig().audioOutputDeviceFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices));
+@@ -98,7 +109,10 @@ void AudioOutputPrivate::init(Phonon::Ca
+ q->connect(Factory::sender(), SIGNAL(availableAudioOutputDevicesChanged()), SLOT(_k_deviceListChanged()));
+ }
+
+-
++QString AudioOutputPrivate::getStreamUuid()
++{
++ return streamUuid;
++}
+
+ void AudioOutputPrivate::createBackendObject()
+ {
+@@ -234,7 +248,7 @@ bool AudioOutput::setOutputDevice(const
+ d->device = newAudioOutputDevice;
+ }
+ if (k_ptr->backendObject()) {
+- return callSetOutputDevice(k_ptr, d->device.index());
++ return callSetOutputDevice(d, d->device.index());
+ }
+ return true;
+ }
+@@ -259,7 +273,6 @@ void AudioOutputPrivate::setupBackendObj
+ // set up attributes
+ pINTERFACE_CALL(setVolume(pow(volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));
+
+-#ifndef QT_NO_PHONON_SETTINGSGROUP
+ // if the output device is not available and the device was not explicitly set
+ if (!callSetOutputDevice(this, device) && !outputDeviceOverridden) {
+ // fall back in the preference list of output devices
+@@ -267,8 +280,8 @@ void AudioOutputPrivate::setupBackendObj
+ if (deviceList.isEmpty()) {
+ return;
+ }
+- for (int i = 0; i < deviceList.count(); ++i) {
+- const AudioOutputDevice &dev = AudioOutputDevice::fromIndex(deviceList.at(i));
++ foreach (int devIndex, deviceList) {
++ const AudioOutputDevice &dev = AudioOutputDevice::fromIndex(devIndex);
+ if (callSetOutputDevice(this, dev)) {
+ handleAutomaticDeviceChange(dev, AudioOutputPrivate::FallbackChange);
+ return; // found one that works
+@@ -279,7 +292,6 @@ void AudioOutputPrivate::setupBackendObj
+ callSetOutputDevice(this, none);
+ handleAutomaticDeviceChange(none, FallbackChange);
+ }
+-#endif //QT_NO_PHONON_SETTINGSGROUP
+ }
+
+ void AudioOutputPrivate::_k_volumeChanged(qreal newVolume)
+@@ -309,10 +321,8 @@ void AudioOutputPrivate::_k_audioDeviceF
+ pDebug() << Q_FUNC_INFO;
+ // outputDeviceIndex identifies a failing device
+ // fall back in the preference list of output devices
+-#ifndef QT_NO_PHONON_SETTINGSGROUP
+- const QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices);
+- for (int i = 0; i < deviceList.count(); ++i) {
+- const int devIndex = deviceList.at(i);
++ QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices);
++ foreach (int devIndex, deviceList) {
+ // if it's the same device as the one that failed, ignore it
+ if (device.index() != devIndex) {
+ const AudioOutputDevice &info = AudioOutputDevice::fromIndex(devIndex);
+@@ -322,7 +332,6 @@ void AudioOutputPrivate::_k_audioDeviceF
+ }
+ }
+ }
+-#endif //QT_NO_PHONON_SETTINGSGROUP
+ // if we get here there is no working output device. Tell the backend.
+ const AudioOutputDevice none;
+ callSetOutputDevice(this, none);
+@@ -332,12 +341,10 @@ void AudioOutputPrivate::_k_audioDeviceF
+ void AudioOutputPrivate::_k_deviceListChanged()
+ {
+ pDebug() << Q_FUNC_INFO;
+-#ifndef QT_NO_PHONON_SETTINGSGROUP
+ // let's see if there's a usable device higher in the preference list
+- const QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings);
++ QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings);
+ DeviceChangeType changeType = HigherPreferenceChange;
+- for (int i = 0; i < deviceList.count(); ++i) {
+- const int devIndex = deviceList.at(i);
++ foreach (int devIndex, deviceList) {
+ const AudioOutputDevice &info = AudioOutputDevice::fromIndex(devIndex);
+ if (!info.property("available").toBool()) {
+ if (device.index() == devIndex) {
+@@ -358,7 +365,6 @@ void AudioOutputPrivate::_k_deviceListCh
+ break; // found one with higher preference that works
+ }
+ }
+-#endif //QT_NO_PHONON_SETTINGSGROUP
+ }
+
+ static struct
+@@ -410,6 +416,7 @@ void AudioOutputPrivate::handleAutomatic
+
+ AudioOutputPrivate::~AudioOutputPrivate()
+ {
++ PulseSupport::getInstance()->clearStreamCache(streamUuid);
+ #ifndef QT_NO_DBUS
+ if (adaptor) {
+ emit adaptor->outputDestroyed();
+--- a/src/3rdparty/phonon/phonon/audiooutput_p.h
++++ b/src/3rdparty/phonon/phonon/audiooutput_p.h
+@@ -46,6 +46,7 @@ class AudioOutputPrivate : public Abstra
+ return 0;
+ }
+ void init(Phonon::Category c);
++ QString getStreamUuid();
+
+
+ protected:
+@@ -79,6 +80,7 @@ class AudioOutputPrivate : public Abstra
+ QString name;
+ Phonon::AudioOutputDevice device;
+ qreal volume;
++ QString streamUuid;
+ #ifndef QT_NO_DBUS
+ Phonon::AudioOutputAdaptor *adaptor;
+ #endif
+--- /dev/null
++++ b/phonon/backend/Mainpage.dox
+@@ -0,0 +1,109 @@
++/** \mainpage Phonon Backend Interface
++
++
++\section phonon_backend_development Backend Development
++If you want to write a new backend for %Phonon this is for you:
++\li \ref phonon_backend_development_page "Phonon Backend Development"
++\li \ref Backend
++
++\authors
++Matthias Kretz \<kretz@kde.org\>
++
++\maintainers
++Matthias Kretz \<kretz@kde.org\>
++
++\licenses
++\lgpl
++
++
++
++
++
++
++
++
++\page phonon_tut1 Phonon Tutorial Part 1: a simple audio player
++
++<p><b>
++\ref index "Overview" |
++Application Example |
++\ref phonon_backend_development_page "Backend Development"
++</b></p>
++
++\includelineno tutorial2.cpp
++
++
++
++
++
++
++
++
++\page phonon_backend_development_page Phonon Backend Development
++
++<p><b>
++\ref index "Overview" |
++\ref phonon_tut1 "Application Example" |
++Backend Development
++</b></p>
++
++The backend is the most important part in %Phonon to provide functionality. This
++document will get you started how backends work, how to start development of a
++new backend and how to understand existing backend code.
++
++\section phonon_backend_introduction Introduction
++
++The first step is to understand how the %Phonon frontend calls the backend: In
++the frontend objects all backend objects are "only" QObjects. But QObject has
++powerful introspection capabilities that %Phonon uses to call methods in the
++backend. If you're interested look at \ref QMetaObject::invokeMethod. In order
++to make sure that a backend is fully operational (there are no abstract classes
++that tell the backend developer what method signatures are wrong or what
++methods are missing) there are two test programs compiled with kdelibs (if
++KDE4_BUILD_TESTS is set in cmake) that inspects the backend.
++
++In short that requires the backend classes to inherit from QObject and to make
++all methods that are to be called from the frontend slots or prefixed with
++Q_INVOKABLE (the latter doesn't work reliable with Qt 4.1.3 at least, so you
++should simply make those methods slots).
++
++\section phonon_backend_classes The Backend Classes
++
++The central class that needs to be implemented is the backend factory class,
++throughout this documentation simply called Backend:
++
++\li \ref phonon_Backend "Backend"
++
++\subsection phonon_mediaproducingclasses The classes producing media data (sources)
++
++\li \ref Phonon::MediaObjectInterface "common methods/signals for media producing classes"
++\li \ref phonon_MediaObject "MediaObject"
++
++\subsection phonon_pathclass The path class
++
++\li \ref phonon_Path "Path"
++
++\subsection phonon_outputclasses The output classes
++\li \ref phonon_AudioDataOutput "AudioDataOutput"
++\li \ref phonon_AudioOutput "AudioOutput"
++\li \ref phonon_VideoDataOutput "VideoDataOutput"
++\li \ref phonon_VideoWidget "VideoWidget"
++
++\subsection phonon_EffectClasses The effect classes
++
++\li \ref phonon_Effect "Effect"
++\li \ref phonon_Visualization "Visualization"
++\li \ref phonon_VolumeFaderEffect "VolumeFaderEffect"
++
++*/
++// DOXYGEN_REFERENCES = phonon
++// DOXYGEN_SET_EXPAND_AS_DEFINED = PHONON_OBJECT PHONON_HEIR PHONON_INTERFACE_GETTER
++// DOXYGEN_SET_HIDE_SCOPE_NAMES = YES
++// DOXYGEN_SET_HIDE_FRIEND_COMPOUNDS = YES
++// DOXYGEN_SET_PROJECT_NAME = Backend
++// DOXYGEN_SET_EXTRACT_ALL = NO
++// DOXYGEN_SET_HIDE_UNDOC_MEMBERS = YES
++// DOXYGEN_SET_SOURCE_BROWSER = NO
++// DOXYGEN_SET_INPUT = @topdir@/phonon/phonon
++// DOXYGEN_SET_FILE_PATTERNS = *interface.h */phonon/backend/Mainpage.dox */backend.dox
++// vim: tw=100 ts=4 sw=4 expandtab filetype=doxygen
+--- a/src/3rdparty/phonon/phonon/backendcapabilities.cpp
++++ b/src/3rdparty/phonon/phonon/backendcapabilities.cpp
+@@ -26,7 +26,7 @@
+ #include "phonondefs_p.h"
+ #include "backendinterface.h"
+ #include "factory_p.h"
+-#include "globalconfig_p.h"
++#include "globalconfig.h"
+ #include "globalstatic_p.h"
+ #include "objectdescription.h"
+
+@@ -75,12 +75,10 @@ bool BackendCapabilities::isMimeTypeAvai
+ QList<AudioOutputDevice> BackendCapabilities::availableAudioOutputDevices()
+ {
+ QList<AudioOutputDevice> ret;
+-#ifndef QT_NO_PHONON_SETTINGSGROUP
+ const QList<int> deviceIndexes = GlobalConfig().audioOutputDeviceListFor(Phonon::NoCategory);
+- for (int i = 0; i < deviceIndexes.count(); ++i) {
+- ret.append(AudioOutputDevice::fromIndex(deviceIndexes.at(i)));
++ foreach (int i, deviceIndexes) {
++ ret.append(AudioOutputDevice::fromIndex(i));
+ }
+-#endif //QT_NO_PHONON_SETTINGSGROUP
+ return ret;
+ }
+
+@@ -90,8 +88,8 @@ QList<AudioCaptureDevice> BackendCapabil
+ {
+ QList<AudioCaptureDevice> ret;
+ const QList<int> deviceIndexes = GlobalConfig().audioCaptureDeviceListFor(Phonon::NoCategory);
+- for (int i = 0; i < deviceIndexes.count(); ++i) {
+- ret.append(AudioCaptureDevice::fromIndex(deviceIndexes.at(i)));
++ foreach (int i, deviceIndexes) {
++ ret.append(AudioCaptureDevice::fromIndex(i));
+ }
+ return ret;
+ }
+@@ -103,9 +101,9 @@ QList<EffectDescription> BackendCapabili
+ BackendInterface *backendIface = qobject_cast<BackendInterface *>(Factory::backend());
+ QList<EffectDescription> ret;
+ if (backendIface) {
+- const QList<int> deviceIndexes = backendIface->objectDescriptionIndexes(Phonon::EffectType);
+- for (int i = 0; i < deviceIndexes.count(); ++i) {
+- ret.append(EffectDescription::fromIndex(deviceIndexes.at(i)));
++ QList<int> deviceIndexes = backendIface->objectDescriptionIndexes(Phonon::EffectType);
++ foreach (int i, deviceIndexes) {
++ ret.append(EffectDescription::fromIndex(i));
+ }
+ }
+ return ret;
+--- a/src/3rdparty/phonon/phonon/backendcapabilities.h
++++ b/src/3rdparty/phonon/phonon/backendcapabilities.h
+@@ -15,7 +15,7 @@
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+- You should have received a copy of the GNU Lesser General Public
++ You should have received a copy of the GNU Lesser General Public
+ License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ */
+@@ -88,18 +88,19 @@ namespace BackendCapabilities
+ };
+
+ /**
+- * Use this function to get a QObject pointer to connect to one of the Notifier signals.
++ * Use this function to get a QObject pointer to connect to the capabilitiesChanged signal.
+ *
+ * \return a pointer to a QObject.
+ *
+- * To connect to the signal do the following:
++ * The capabilitiesChanged signal is emitted if the capabilities have changed. This can
++ * happen if the user has requested a backend change.
++ *
++ * To connect to this signal do the following:
+ * \code
+ * QObject::connect(BackendCapabilities::notifier(), SIGNAL(capabilitiesChanged()), ...
+ * \endcode
+ *
+ * \see Notifier::capabilitiesChanged()
+- * \see Notifier::availableAudioOutputDevicesChanged()
+- * \see Notifier::availableAudioCaptureDevicesChanged()
+ */
+ PHONON_EXPORT Notifier *notifier();
+
+--- a/src/3rdparty/phonon/phonon/CMakeLists.txt
++++ b/src/3rdparty/phonon/phonon/CMakeLists.txt
+@@ -8,6 +8,22 @@ endif (PHONON_BUILD_EXAMPLES)
+
+ add_subdirectory(experimental)
+
++set(PULSEAUDIO_MINIMUM_VERSION "0.9.21")
++macro_optional_find_package(PulseAudio)
++macro_log_feature(PULSEAUDIO_FOUND "PulseAudio" "A cross-platform, networked sound server." "http://www.pulseaudio.org" FALSE "" "Allows audio playback via the PulseAudio soundserver when it is running")
++macro_optional_find_package(GLIB2)
++macro_log_feature(GLIB2_FOUND "GLib2" "GLib 2 is required to compile the pulseaudio for Phonon" "http://www.gtk.org/download/" FALSE)
++
++if (GLIB2_FOUND AND PULSEAUDIO_FOUND)
++ add_definitions(-DHAVE_PULSEAUDIO)
++ include_directories(${GLIB2_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIR})
++else(GLIB2_FOUND AND PULSEAUDIO_FOUND)
++ set(PULSEAUDIO_INCLUDE_DIR "")
++ set(PULSEAUDIO_LIBRARY "")
++ set(PULSEAUDIO_MAINLOOP_LIBRARY "")
++endif(GLIB2_FOUND AND PULSEAUDIO_FOUND)
++
++
+ set(phonon_LIB_SRCS
+ objectdescription.cpp
+ objectdescriptionmodel.cpp
+@@ -35,9 +51,12 @@ set(phonon_LIB_SRCS
+ videowidget.cpp
+ videoplayer.cpp
+ seekslider.cpp
++ swiftslider.cpp
+ volumeslider.cpp
+ effectwidget.cpp
+ iodevicestream.cpp
++ audiodataoutput.cpp
++ pulsesupport.cpp
+ )
+
+ if (QT_QTDBUS_FOUND)
+@@ -50,6 +69,10 @@ endif (QT_QTDBUS_FOUND)
+ add_definitions(-DPHONON_LIBRARY_PATH="${PLUGIN_INSTALL_DIR}/plugins")
+ automoc4_add_library(phonon SHARED ${phonon_LIB_SRCS})
+ target_link_libraries(phonon ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
++if (GLIB2_FOUND AND PULSEAUDIO_FOUND)
++target_link_libraries(phonon ${GLIB2_LIBRARIES} ${GOBJECT_LIBRARIES} ${PULSEAUDIO_LIBRARY} ${PULSEAUDIO_MAINLOOP_LIBRARY})
++endif (GLIB2_FOUND AND PULSEAUDIO_FOUND)
++
+ if (QT_QTDBUS_FOUND)
+ target_link_libraries(phonon ${QT_QTDBUS_LIBRARY})
+ endif (QT_QTDBUS_FOUND)
+@@ -99,6 +122,9 @@ install(FILES
+ volumeslider.h
+ effectwidget.h
+ platformplugin.h
++ audiodataoutput.h
++ audiodataoutputinterface.h
++ globalconfig.h
+ DESTINATION ${INCLUDE_INSTALL_DIR}/phonon COMPONENT Devel)
+
+ install(FILES org.kde.Phonon.AudioOutput.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR})
+--- a/src/3rdparty/phonon/phonon/effect.cpp
++++ b/src/3rdparty/phonon/phonon/effect.cpp
+@@ -107,8 +107,7 @@ bool EffectPrivate::aboutToDeleteBackend
+ {
+ if (m_backendObject) {
+ const QList<EffectParameter> parameters = pINTERFACE_CALL(parameters());
+- for (int i = 0; i < parameters.count(); ++i) {
+- const EffectParameter &p = parameters.at(i);
++ foreach (const EffectParameter &p, parameters) {
+ parameterValues[p] = pINTERFACE_CALL(parameterValue(p));
+ }
+ }
+@@ -121,8 +120,7 @@ void EffectPrivate::setupBackendObject()
+
+ // set up attributes
+ const QList<EffectParameter> parameters = pINTERFACE_CALL(parameters());
+- for (int i = 0; i < parameters.count(); ++i) {
+- const EffectParameter &p = parameters.at(i);
++ foreach (const EffectParameter &p, parameters) {
+ pINTERFACE_CALL(setParameterValue(p, parameterValues[p]));
+ }
+ }
+--- a/src/3rdparty/phonon/phonon/effectwidget.cpp
++++ b/src/3rdparty/phonon/phonon/effectwidget.cpp
+@@ -97,9 +97,7 @@ void EffectWidgetPrivate::autogenerateUi
+ Q_Q(EffectWidget);
+ QVBoxLayout *mainLayout = new QVBoxLayout(q);
+ mainLayout->setMargin(0);
+- const QList<Phonon::EffectParameter> parameters = effect->parameters();
+- for (int i = 0; i < parameters.count(); ++i) {
+- const EffectParameter &para = parameters.at(i);
++ foreach (const EffectParameter &para, effect->parameters()) {
+ QVariant value = effect->parameterValue(para);
+ QHBoxLayout *pLayout = new QHBoxLayout;
+ mainLayout->addLayout(pLayout);
+@@ -119,14 +117,13 @@ void EffectWidgetPrivate::autogenerateUi
+ control = cb;
+ if (value.type() == QVariant::Int) {
+ //value just defines the item index
+- for (int i = 0; i < para.possibleValues().count(); ++i) {
+- cb->addItem(para.possibleValues().at(i).toString());
++ foreach (const QVariant &item, para.possibleValues()) {
++ cb->addItem(item.toString());
+ }
+ cb->setCurrentIndex(value.toInt());
+ QObject::connect(cb, SIGNAL(currentIndexChanged(int)), q, SLOT(_k_setIntParameter(int)));
+ } else {
+- for (int i = 0; i < para.possibleValues().count(); ++i) {
+- const QVariant &item = para.possibleValues().at(i);
++ foreach (const QVariant &item, para.possibleValues()) {
+ cb->addItem(item.toString());
+ if (item == value) {
+ cb->setCurrentIndex(cb->count() - 1);
+@@ -158,20 +155,18 @@ void EffectWidgetPrivate::autogenerateUi
+ QObject::connect(sb, SIGNAL(valueChanged(int)), q, SLOT(_k_setIntParameter(int)));
+ }
+ break;
+- case QMetaType::Float:
+ case QVariant::Double:
+ {
+- const qreal minValue = para.minimumValue().canConvert(QVariant::Double) ?
+- para.minimumValue().toReal() : DEFAULT_MIN;
+- const qreal maxValue = para.maximumValue().canConvert(QVariant::Double) ?
+- para.maximumValue().toReal() : DEFAULT_MAX;
++ const double minValue = (para.minimumValue().type() == QVariant::Double ?
++ para.minimumValue().toDouble() : DEFAULT_MIN);
++ const double maxValue = (para.maximumValue().type() == QVariant::Double ?
++ para.maximumValue().toDouble() : DEFAULT_MAX);
+
+ if (minValue == -1. && maxValue == 1.) {
+ //Special case values between -1 and 1.0 to use a slider for improved usability
+ QSlider *slider = new QSlider(Qt::Horizontal, q);
+- control = slider;
+ slider->setRange(-SLIDER_RANGE, +SLIDER_RANGE);
+- slider->setValue(int(SLIDER_RANGE * value.toReal()));
++ slider->setValue(int(SLIDER_RANGE * value.toDouble()));
+ slider->setTickPosition(QSlider::TicksBelow);
+ slider->setTickInterval(TICKINTERVAL);
+ QObject::connect(slider, SIGNAL(valueChanged(int)), q, SLOT(_k_setSliderParameter(int)));
+@@ -193,10 +188,10 @@ void EffectWidgetPrivate::autogenerateUi
+ break;
+ }
+
+- if (control) {
+ #ifndef QT_NO_TOOLTIP
+ control->setToolTip(para.description());
+ #endif
++ if (control) {
+ #ifndef QT_NO_SHORTCUT
+ label->setBuddy(control);
+ #endif
+--- a/src/3rdparty/phonon/phonon/factory.cpp
++++ b/src/3rdparty/phonon/phonon/factory.cpp
+@@ -111,7 +111,6 @@ void Factory::setBackend(QObject *b)
+
+ bool FactoryPrivate::createBackend()
+ {
+-#ifndef QT_NO_LIBRARY
+ Q_ASSERT(m_backendObject == 0);
+ #ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ PlatformPlugin *f = globalFactory->platformPlugin();
+@@ -125,39 +124,15 @@ bool FactoryPrivate::createBackend()
+ // could not load a backend through the platform plugin. Falling back to the default
+ // (finding the first loadable backend).
+ const QLatin1String suffix("/phonon_backend/");
+- const QStringList paths = QCoreApplication::libraryPaths();
+- for (int i = 0; i < paths.count(); ++i) {
+- const QString libPath = paths.at(i) + suffix;
++ foreach (QString libPath, QCoreApplication::libraryPaths()) {
++ libPath += suffix;
+ const QDir dir(libPath);
+ if (!dir.exists()) {
+ pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
+ continue;
+ }
+-
+- QStringList plugins(dir.entryList(QDir::Files));
+-
+-#ifdef Q_OS_SYMBIAN
+- /* On Symbian OS we might have two plugins, one which uses Symbian
+- * MMF framework("phonon_mmf"), and one which uses Real Networks's
+- * Helix("hxphonon"). We prefer the latter because it's more
+- * sophisticated, so we make sure the Helix backend is attempted
+- * to be loaded first, and the MMF backend is used for backup. */
+- {
+-
+- const int hxphonon = plugins.indexOf(QLatin1String("hxphonon"));
+- if (hxphonon != -1)
+- plugins.move(hxphonon, 0);
+-
+- // Code for debugging the MMF backend.
+- if(hxphonon != -1) {
+- qDebug() << "Found hxphonon backend and removed it from the lookup list.";
+- plugins.removeAll(QLatin1String("hxphonon"));
+- }
+- }
+-#endif
+-
+- for (int i = 0; i < plugins.count(); ++i) {
+- QPluginLoader pluginLoader(libPath + plugins.at(i));
++ foreach (const QString &pluginName, dir.entryList(QDir::Files)) {
++ QPluginLoader pluginLoader(libPath + pluginName);
+ if (!pluginLoader.load()) {
+ pDebug() << Q_FUNC_INFO << " load failed:"
+ << pluginLoader.errorString();
+@@ -187,20 +162,14 @@ bool FactoryPrivate::createBackend()
+ SLOT(objectDescriptionChanged(ObjectDescriptionType)));
+
+ return true;
+-#else //QT_NO_LIBRARY
+- pWarning() << Q_FUNC_INFO << "Trying to use Phonon with QT_NO_LIBRARY defined. "
+- "That is currently not supported";
+- return false;
+-#endif
+ }
+
+ FactoryPrivate::FactoryPrivate()
+- :
+ #ifndef QT_NO_PHONON_PLATFORMPLUGIN
+- m_platformPlugin(0),
+- m_noPlatformPlugin(false),
++ : m_platformPlugin(0),
++ m_noPlatformPlugin(false)
+ #endif //QT_NO_PHONON_PLATFORMPLUGIN
+- m_backendObject(0)
++ , m_backendObject(0)
+ {
+ // Add the post routine to make sure that all other global statics (especially the ones from Qt)
+ // are still available. If the FactoryPrivate dtor is called too late many bad things can happen
+@@ -214,8 +183,14 @@ FactoryPrivate::FactoryPrivate()
+
+ FactoryPrivate::~FactoryPrivate()
+ {
+- for (int i = 0; i < mediaNodePrivateList.count(); ++i) {
+- mediaNodePrivateList.at(i)->deleteBackendObject();
++ foreach (QObject *o, objects) {
++ MediaObject *m = qobject_cast<MediaObject *>(o);
++ if (m) {
++ m->stop();
++ }
++ }
++ foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
++ bp->deleteBackendObject();
+ }
+ if (objects.size() > 0) {
+ pError() << "The backend objects are not deleted as was requested.";
+@@ -283,8 +258,8 @@ void Factory::deregisterFrontendObject(M
+ void FactoryPrivate::phononBackendChanged()
+ {
+ if (m_backendObject) {
+- for (int i = 0; i < mediaNodePrivateList.count(); ++i) {
+- mediaNodePrivateList.at(i)->deleteBackendObject();
++ foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
++ bp->deleteBackendObject();
+ }
+ if (objects.size() > 0) {
+ pDebug() << "WARNING: we were asked to change the backend but the application did\n"
+@@ -293,8 +268,8 @@ void FactoryPrivate::phononBackendChange
+ "backendswitching possible.";
+ // in case there were objects deleted give 'em a chance to recreate
+ // them now
+- for (int i = 0; i < mediaNodePrivateList.count(); ++i) {
+- mediaNodePrivateList.at(i)->createBackendObject();
++ foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
++ bp->createBackendObject();
+ }
+ return;
+ }
+@@ -302,8 +277,8 @@ void FactoryPrivate::phononBackendChange
+ m_backendObject = 0;
+ }
+ createBackend();
+- for (int i = 0; i < mediaNodePrivateList.count(); ++i) {
+- mediaNodePrivateList.at(i)->createBackendObject();
++ foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
++ bp->createBackendObject();
+ }
+ emit backendChanged();
+ }
+@@ -350,6 +325,7 @@ FACTORY_IMPL(AudioOutput)
+ #ifndef QT_NO_PHONON_VIDEO
+ FACTORY_IMPL(VideoWidget)
+ #endif //QT_NO_PHONON_VIDEO
++FACTORY_IMPL(AudioDataOutput)
+
+ #undef FACTORY_IMPL
+
+@@ -387,17 +363,15 @@ PlatformPlugin *FactoryPrivate::platform
+ QStringList())
+ );
+ dir.setFilter(QDir::Files);
+- const QStringList libPaths = QCoreApplication::libraryPaths();
+ forever {
+- for (int i = 0; i < libPaths.count(); ++i) {
+- const QString libPath = libPaths.at(i) + suffix;
++ foreach (QString libPath, QCoreApplication::libraryPaths()) {
++ libPath += suffix;
+ dir.setPath(libPath);
+ if (!dir.exists()) {
+ continue;
+ }
+- const QStringList files = dir.entryList(QDir::Files);
+- for (int i = 0; i < files.count(); ++i) {
+- QPluginLoader pluginLoader(libPath + files.at(i));
++ foreach (const QString &pluginName, dir.entryList()) {
++ QPluginLoader pluginLoader(libPath + pluginName);
+ if (!pluginLoader.load()) {
+ pDebug() << Q_FUNC_INFO << " platform plugin load failed:"
+ << pluginLoader.errorString();
+@@ -449,7 +423,6 @@ QObject *Factory::backend(bool createWhe
+ return globalFactory->m_backendObject;
+ }
+
+-#ifndef QT_NO_PROPERTIES
+ #define GET_STRING_PROPERTY(name) \
+ QString Factory::name() \
+ { \
+@@ -465,11 +438,11 @@ GET_STRING_PROPERTY(backendComment)
+ GET_STRING_PROPERTY(backendVersion)
+ GET_STRING_PROPERTY(backendIcon)
+ GET_STRING_PROPERTY(backendWebsite)
+-#endif //QT_NO_PROPERTIES
++
+ QObject *Factory::registerQObject(QObject *o)
+ {
+ if (o) {
+- QObject::connect(o, SIGNAL(destroyed(QObject*)), globalFactory, SLOT(objectDestroyed(QObject*)), Qt::DirectConnection);
++ QObject::connect(o, SIGNAL(destroyed(QObject *)), globalFactory, SLOT(objectDestroyed(QObject *)), Qt::DirectConnection);
+ globalFactory->objects.append(o);
+ }
+ return o;
+--- a/src/3rdparty/phonon/phonon/factory_p.h
++++ b/src/3rdparty/phonon/phonon/factory_p.h
+@@ -122,6 +122,13 @@ namespace Factory
+ #endif //QT_NO_PHONON_VIDEO
+
+ /**
++ * Create a new backend object for a AudioDataOutput.
++ *
++ * \return a pointer to the AudioDataOutput the backend provides.
++ */
++ PHONON_EXPORT QObject *createAudioDataOutput(QObject *parent = 0);
++
++ /**
+ * \return a pointer to the backend interface.
+ */
+ PHONON_EXPORT QObject *backend(bool createWhenNull = true);
+--- a/src/3rdparty/phonon/phonon/globalconfig.cpp
++++ b/src/3rdparty/phonon/phonon/globalconfig.cpp
+@@ -20,6 +20,7 @@
+
+ */
+
++#include "globalconfig.h"
+ #include "globalconfig_p.h"
+
+ #include "factory_p.h"
+@@ -29,6 +30,7 @@
+ #include "backendinterface.h"
+ #include "qsettingsgroup_p.h"
+ #include "phononnamespace_p.h"
++#include "pulsesupport_p.h"
+
+ #include <QtCore/QList>
+ #include <QtCore/QVariant>
+@@ -38,15 +40,18 @@ QT_BEGIN_NAMESPACE
+ namespace Phonon
+ {
+
++GlobalConfigPrivate::GlobalConfigPrivate() : config(QLatin1String("kde.org"), QLatin1String("libphonon"))
++{
++}
++
+ GlobalConfig::GlobalConfig()
+-#ifndef QT_NO_SETTINGS
+- : m_config(QLatin1String("kde.org"), QLatin1String("libphonon"))
+-#endif //QT_NO_SETTINGS
++ : k_ptr(new GlobalConfigPrivate)
+ {
+ }
+
+ GlobalConfig::~GlobalConfig()
+ {
++ delete k_ptr;
+ }
+
+ enum WhatToFilter {
+@@ -85,9 +90,12 @@ static void filter(ObjectDescriptionType
+ }
+ }
+
+-#ifndef QT_NO_PHONON_SETTINGSGROUP
+-static QList<int> listSortedByConfig(const QSettingsGroup &backendConfig, Phonon::Category category, QList<int> &defaultList)
++static QList<int> sortDevicesByCategoryPriority(const GlobalConfig *config, const QSettingsGroup *backendConfig, ObjectDescriptionType type, Phonon::Category category, QList<int> &defaultList)
+ {
++ Q_ASSERT(config);
++ Q_ASSERT(backendConfig);
++ Q_ASSERT(type == AudioOutputDeviceType || type == AudioCaptureDeviceType);
++
+ if (defaultList.size() <= 1) {
+ // nothing to sort
+ return defaultList;
+@@ -104,20 +112,26 @@ static QList<int> listSortedByConfig(con
+ }
+ }
+
+- QString categoryKey = QLatin1String("Category_") + QString::number(static_cast<int>(category));
+- if (!backendConfig.hasKey(categoryKey)) {
+- // no list in config for the given category
+- categoryKey = QLatin1String("Category_") + QString::number(static_cast<int>(Phonon::NoCategory));
+- if (!backendConfig.hasKey(categoryKey)) {
+- // no list in config for NoCategory
+- return defaultList;
++ QList<int> deviceList;
++ PulseSupport *pulse = PulseSupport::getInstance();
++ if (pulse->isActive()) {
++ deviceList = pulse->objectIndexesByCategory(type, category);
++ } else {
++ QString categoryKey = QLatin1String("Category_") + QString::number(static_cast<int>(category));
++ if (!backendConfig->hasKey(categoryKey)) {
++ // no list in config for the given category
++ categoryKey = QLatin1String("Category_") + QString::number(static_cast<int>(Phonon::NoCategory));
++ if (!backendConfig->hasKey(categoryKey)) {
++ // no list in config for NoCategory
++ return defaultList;
++ }
+ }
+- }
+
+- //Now the list from m_config
+- QList<int> deviceList = backendConfig.value(categoryKey, QList<int>());
++ //Now the list from d->config
++ deviceList = backendConfig->value(categoryKey, QList<int>());
++ }
+
+- //if there are devices in m_config that the backend doesn't report, remove them from the list
++ //if there are devices in d->config that the backend doesn't report, remove them from the list
+ QMutableListIterator<int> i(deviceList);
+ while (i.hasNext()) {
+ if (0 == defaultList.removeAll(i.next())) {
+@@ -125,49 +139,176 @@ static QList<int> listSortedByConfig(con
+ }
+ }
+
+- //if the backend reports more devices that are not in m_config append them to the list
++ //if the backend reports more devices that are not in d->config append them to the list
+ deviceList += defaultList;
+
+ return deviceList;
+ }
+-#endif //QT_NO_PHONON_SETTINGSGROUP
+
+-#ifndef QT_NO_PHONON_SETTINGSGROUP
+-QList<int> GlobalConfig::audioOutputDeviceListFor(Phonon::Category category, int override) const
++bool GlobalConfig::hideAdvancedDevices() const
+ {
++ K_D(const GlobalConfig);
+ //The devices need to be stored independently for every backend
+- const QSettingsGroup backendConfig(&m_config, QLatin1String("AudioOutputDevice")); // + Factory::identifier());
+- const QSettingsGroup generalGroup(&m_config, QLatin1String("General"));
+- const bool hideAdvancedDevices = ((override & AdvancedDevicesFromSettings)
+- ? generalGroup.value(QLatin1String("HideAdvancedDevices"), true)
++ const QSettingsGroup generalGroup(&d->config, QLatin1String("General"));
++ return generalGroup.value(QLatin1String("HideAdvancedDevices"), true);
++}
++
++void GlobalConfig::setHideAdvancedDevices(bool hide)
++{
++ K_D(GlobalConfig);
++ QSettingsGroup generalGroup(&d->config, QLatin1String("General"));
++ generalGroup.setValue(QLatin1String("HideAdvancedDevices"), hide);
++}
++
++static bool isHiddenAudioOutputDevice(const GlobalConfig *config, int i)
++{
++ Q_ASSERT(config);
++
++ if (!config->hideAdvancedDevices())
++ return false;
++
++ AudioOutputDevice ad = AudioOutputDevice::fromIndex(i);
++ const QVariant var = ad.property("isAdvanced");
++ return (var.isValid() && var.toBool());
++}
++
++#ifndef QT_NO_PHONON_AUDIOCAPTURE
++static bool isHiddenAudioCaptureDevice(const GlobalConfig *config, int i)
++{
++ Q_ASSERT(config);
++
++ if (!config->hideAdvancedDevices())
++ return false;
++
++ AudioCaptureDevice ad = AudioCaptureDevice::fromIndex(i);
++ const QVariant var = ad.property("isAdvanced");
++ return (var.isValid() && var.toBool());
++}
++#endif
++
++static QList<int> reindexList(const GlobalConfig *config, Phonon::Category category, QList<int>newOrder, bool output)
++{
++ Q_ASSERT(config);
++#ifdef QT_NO_PHONON_AUDIOCAPTURE
++ Q_ASSERT(output);
++#endif
++
++ /*QString sb;
++ sb = QString("(Size %1)").arg(currentList.size());
++ foreach (int i, currentList)
++ sb += QString("%1, ").arg(i);
++ fprintf(stderr, "=== Reindex Current: %s\n", sb.toUtf8().constData());
++ sb = QString("(Size %1)").arg(newOrder.size());
++ foreach (int i, newOrder)
++ sb += QString("%1, ").arg(i);
++ fprintf(stderr, "=== Reindex Before : %s\n", sb.toUtf8().constData());*/
++
++ QList<int> currentList;
++ if (output)
++ currentList = config->audioOutputDeviceListFor(category, GlobalConfig::ShowUnavailableDevices|GlobalConfig::ShowAdvancedDevices);
++#ifndef QT_NO_PHONON_AUDIOCAPTURE
++ else
++ currentList = config->audioCaptureDeviceListFor(category, GlobalConfig::ShowUnavailableDevices|GlobalConfig::ShowAdvancedDevices);
++#endif
++
++ QList<int> newList;
++
++ foreach (int i, newOrder) {
++ int found = currentList.indexOf(i);
++ if (found < 0) {
++ // It's not in the list, so something is odd (e.g. client error). Ignore it.
++ continue;
++ }
++
++ // Iterate through the list from this point onward. If there are hidden devices
++ // immediately following, take them too.
++ newList.append(currentList.takeAt(found));
++ while (found < currentList.size()) {
++ bool hidden = true;
++ if (output)
++ hidden = isHiddenAudioOutputDevice(config, currentList.at(found));
++#ifndef QT_NO_PHONON_AUDIOCAPTURE
++ else
++ hidden = isHiddenAudioCaptureDevice(config, currentList.at(found));
++#endif
++
++ if (!hidden)
++ break;
++ newList.append(currentList.takeAt(found));
++ }
++ }
++
++ // If there are any devices left in.. just tack them on the end.
++ if (currentList.size() > 0)
++ newList += currentList;
++
++ /*sb = QString("(Size %1)").arg(newList.size());
++ foreach (int i, newList)
++ sb += QString("%1, ").arg(i);
++ fprintf(stderr, "=== Reindex After : %s\n", sb.toUtf8().constData());*/
++ return newList;
++}
++
++
++void GlobalConfig::setAudioOutputDeviceListFor(Phonon::Category category, QList<int> order)
++{
++ PulseSupport *pulse = PulseSupport::getInstance();
++ if (pulse->isActive()) {
++ pulse->setOutputDevicePriorityForCategory(category, order);
++ return;
++ }
++
++ K_D(GlobalConfig);
++ QSettingsGroup backendConfig(&d->config, QLatin1String("AudioOutputDevice")); // + Factory::identifier());
++
++ order = reindexList(this, category, order, true);
++
++ const QList<int> noCategoryOrder = audioOutputDeviceListFor(Phonon::NoCategory, ShowUnavailableDevices|ShowAdvancedDevices);
++ if (category != Phonon::NoCategory && order == noCategoryOrder) {
++ backendConfig.removeEntry(QLatin1String("Category_") + QString::number(category));
++ } else {
++ backendConfig.setValue(QLatin1String("Category_") + QString::number(category), order);
++ }
++}
++
++QList<int> GlobalConfig::audioOutputDeviceListFor(Phonon::Category category, int override) const
++{
++ K_D(const GlobalConfig);
++
++ const bool hide = ((override & AdvancedDevicesFromSettings)
++ ? hideAdvancedDevices()
+ : static_cast<bool>(override & HideAdvancedDevices));
+
+ QList<int> defaultList;
++ BackendInterface *backendIface = qobject_cast<BackendInterface *>(Factory::backend());
++
+ #ifndef QT_NO_PHONON_PLATFORMPLUGIN
+- if (PlatformPlugin *platformPlugin = Factory::platformPlugin()) {
+- // the platform plugin lists the audio devices for the platform
+- // this list already is in default order (as defined by the platform plugin)
+- defaultList = platformPlugin->objectDescriptionIndexes(Phonon::AudioOutputDeviceType);
+- if (hideAdvancedDevices) {
+- QMutableListIterator<int> it(defaultList);
+- while (it.hasNext()) {
+- AudioOutputDevice objDesc = AudioOutputDevice::fromIndex(it.next());
+- const QVariant var = objDesc.property("isAdvanced");
+- if (var.isValid() && var.toBool()) {
+- it.remove();
++ if (!backendIface || !PulseSupport::getInstance()->isActive()) {
++ if (PlatformPlugin *platformPlugin = Factory::platformPlugin()) {
++ // the platform plugin lists the audio devices for the platform
++ // this list already is in default order (as defined by the platform plugin)
++ defaultList = platformPlugin->objectDescriptionIndexes(Phonon::AudioOutputDeviceType);
++ if (hide) {
++ QMutableListIterator<int> it(defaultList);
++ while (it.hasNext()) {
++ AudioOutputDevice objDesc = AudioOutputDevice::fromIndex(it.next());
++ const QVariant var = objDesc.property("isAdvanced");
++ if (var.isValid() && var.toBool()) {
++ it.remove();
++ }
+ }
+ }
+ }
+ }
+ #endif //QT_NO_PHONON_PLATFORMPLUGIN
+
+- // lookup the available devices directly from the backend (mostly for virtual devices)
+- if (BackendInterface *backendIface = qobject_cast<BackendInterface *>(Factory::backend())) {
++ // lookup the available devices directly from the backend
++ if (backendIface) {
+ // this list already is in default order (as defined by the backend)
+ QList<int> list = backendIface->objectDescriptionIndexes(Phonon::AudioOutputDeviceType);
+- if (hideAdvancedDevices || !defaultList.isEmpty() || (override & HideUnavailableDevices)) {
++ if (hide || !defaultList.isEmpty() || (override & HideUnavailableDevices)) {
+ filter(AudioOutputDeviceType, backendIface, &list,
+- (hideAdvancedDevices ? FilterAdvancedDevices : 0)
++ (hide ? FilterAdvancedDevices : 0)
+ // the platform plugin already provided the hardware devices
+ | (defaultList.isEmpty() ? 0 : FilterHardwareDevices)
+ | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0)
+@@ -176,56 +317,78 @@ QList<int> GlobalConfig::audioOutputDevi
+ defaultList += list;
+ }
+
+- return listSortedByConfig(backendConfig, category, defaultList);
++ const QSettingsGroup backendConfig(&d->config, QLatin1String("AudioOutputDevice")); // + Factory::identifier());
++ return sortDevicesByCategoryPriority(this, &backendConfig, AudioOutputDeviceType, category, defaultList);
+ }
+-#endif //QT_NO_PHONON_SETTINGSGROUP
++
+ int GlobalConfig::audioOutputDeviceFor(Phonon::Category category, int override) const
+ {
+-#ifndef QT_NO_PHONON_SETTINGSGROUP
+ QList<int> ret = audioOutputDeviceListFor(category, override);
+- if (!ret.isEmpty())
+- return ret.first();
+-#endif //QT_NO_PHONON_SETTINGSGROUP
+- return -1;
++ if (ret.isEmpty())
++ return -1;
++ return ret.first();
+ }
+
+ #ifndef QT_NO_PHONON_AUDIOCAPTURE
++void GlobalConfig::setAudioCaptureDeviceListFor(Phonon::Category category, QList<int> order)
++{
++ PulseSupport *pulse = PulseSupport::getInstance();
++ if (pulse->isActive()) {
++ pulse->setCaptureDevicePriorityForCategory(category, order);
++ return;
++ }
++
++ K_D(GlobalConfig);
++ QSettingsGroup backendConfig(&d->config, QLatin1String("AudioCaptureDevice")); // + Factory::identifier());
++
++ order = reindexList(this, category, order, false);
++
++ const QList<int> noCategoryOrder = audioCaptureDeviceListFor(Phonon::NoCategory, ShowUnavailableDevices|ShowAdvancedDevices);
++ if (category != Phonon::NoCategory && order == noCategoryOrder) {
++ backendConfig.removeEntry(QLatin1String("Category_") + QString::number(category));
++ } else {
++ backendConfig.setValue(QLatin1String("Category_") + QString::number(category), order);
++ }
++}
++
+ QList<int> GlobalConfig::audioCaptureDeviceListFor(Phonon::Category category, int override) const
+ {
+-#ifndef QT_NO_PHONON_SETTINGSGROUP
+- //The devices need to be stored independently for every backend
+- const QSettingsGroup backendConfig(&m_config, QLatin1String("AudioCaptureDevice")); // + Factory::identifier());
+- const QSettingsGroup generalGroup(&m_config, QLatin1String("General"));
+- const bool hideAdvancedDevices = ((override & AdvancedDevicesFromSettings)
+- ? generalGroup.value(QLatin1String("HideAdvancedDevices"), true)
++ K_D(const GlobalConfig);
++
++ const bool hide = ((override & AdvancedDevicesFromSettings)
++ ? hideAdvancedDevices()
+ : static_cast<bool>(override & HideAdvancedDevices));
+
+ QList<int> defaultList;
++ BackendInterface *backendIface = qobject_cast<BackendInterface *>(Factory::backend());
++
+ #ifndef QT_NO_PHONON_PLATFORMPLUGIN
+- if (PlatformPlugin *platformPlugin = Factory::platformPlugin()) {
+- // the platform plugin lists the audio devices for the platform
+- // this list already is in default order (as defined by the platform plugin)
+- defaultList = platformPlugin->objectDescriptionIndexes(Phonon::AudioCaptureDeviceType);
+- if (hideAdvancedDevices) {
+- QMutableListIterator<int> it(defaultList);
+- while (it.hasNext()) {
+- AudioCaptureDevice objDesc = AudioCaptureDevice::fromIndex(it.next());
+- const QVariant var = objDesc.property("isAdvanced");
+- if (var.isValid() && var.toBool()) {
+- it.remove();
++ if (!backendIface || !PulseSupport::getInstance()->isActive()) {
++ if (PlatformPlugin *platformPlugin = Factory::platformPlugin()) {
++ // the platform plugin lists the audio devices for the platform
++ // this list already is in default order (as defined by the platform plugin)
++ defaultList = platformPlugin->objectDescriptionIndexes(Phonon::AudioCaptureDeviceType);
++ if (hide) {
++ QMutableListIterator<int> it(defaultList);
++ while (it.hasNext()) {
++ AudioCaptureDevice objDesc = AudioCaptureDevice::fromIndex(it.next());
++ const QVariant var = objDesc.property("isAdvanced");
++ if (var.isValid() && var.toBool()) {
++ it.remove();
++ }
+ }
+ }
+ }
+ }
+ #endif //QT_NO_PHONON_PLATFORMPLUGIN
+
+- // lookup the available devices directly from the backend (mostly for virtual devices)
+- if (BackendInterface *backendIface = qobject_cast<BackendInterface *>(Factory::backend())) {
++ // lookup the available devices directly from the backend
++ if (backendIface) {
+ // this list already is in default order (as defined by the backend)
+ QList<int> list = backendIface->objectDescriptionIndexes(Phonon::AudioCaptureDeviceType);
+- if (hideAdvancedDevices || !defaultList.isEmpty() || (override & HideUnavailableDevices)) {
++ if (hide || !defaultList.isEmpty() || (override & HideUnavailableDevices)) {
+ filter(AudioCaptureDeviceType, backendIface, &list,
+- (hideAdvancedDevices ? FilterAdvancedDevices : 0)
++ (hide ? FilterAdvancedDevices : 0)
+ // the platform plugin already provided the hardware devices
+ | (defaultList.isEmpty() ? 0 : FilterHardwareDevices)
+ | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0)
+@@ -234,10 +397,8 @@ QList<int> GlobalConfig::audioCaptureDev
+ defaultList += list;
+ }
+
+- return listSortedByConfig(backendConfig, category, defaultList);
+-#else //QT_NO_SETTINGSGROUP
+- return QList<int>();
+-#endif //QT_NO_SETTINGSGROUP
++ const QSettingsGroup backendConfig(&d->config, QLatin1String("AudioCaptureDevice")); // + Factory::identifier());
++ return sortDevicesByCategoryPriority(this, &backendConfig, AudioCaptureDeviceType, category, defaultList);
+ }
+
+ int GlobalConfig::audioCaptureDeviceFor(Phonon::Category category, int override) const
+--- /dev/null
++++ b/phonon/globalconfig.h
+@@ -0,0 +1,71 @@
++/* This file is part of the KDE project
++Copyright (C) 2006-2008 Matthias Kretz <kretz@kde.org>
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) version 3, or any
++ later version accepted by the membership of KDE e.V. (or its
++ successor approved by the membership of KDE e.V.), Nokia Corporation
++ (or its successors, if any) and the KDE Free Qt Foundation, which shall
++ act as a proxy defined in Section 6 of version 3 of the license.
++
++ This library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with this library. If not, see <http://www.gnu.org/licenses/>.
++
++*/
++
++#ifndef PHONON_GLOBALCONFIG_H
++#define PHONON_GLOBALCONFIG_H
++
++#include "phonon_export.h"
++#include "phononnamespace.h"
++#include "phonondefs.h"
++
++QT_BEGIN_HEADER
++QT_BEGIN_NAMESPACE
++
++namespace Phonon
++{
++ class GlobalConfigPrivate;
++
++ class PHONON_EXPORT GlobalConfig
++ {
++ K_DECLARE_PRIVATE(GlobalConfig)
++ public:
++ GlobalConfig();
++ virtual ~GlobalConfig();
++
++ enum DevicesToHideFlag {
++ ShowUnavailableDevices = 0,
++ ShowAdvancedDevices = 0,
++ HideAdvancedDevices = 1,
++ AdvancedDevicesFromSettings = 2,
++ HideUnavailableDevices = 4
++ };
++ bool hideAdvancedDevices() const;
++ void setHideAdvancedDevices(bool hide = true);
++ void setAudioOutputDeviceListFor(Phonon::Category category, QList<int> order);
++ QList<int> audioOutputDeviceListFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const;
++ int audioOutputDeviceFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const;
++
++#ifndef QT_NO_PHONON_AUDIOCAPTURE
++ void setAudioCaptureDeviceListFor(Phonon::Category category, QList<int> order);
++ QList<int> audioCaptureDeviceListFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const;
++ int audioCaptureDeviceFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const;
++#endif //QT_NO_PHONON_AUDIOCAPTURE
++
++ protected:
++ GlobalConfigPrivate *const k_ptr;
++ };
++} // namespace Phonon
++
++QT_END_NAMESPACE
++QT_END_HEADER
++
++#endif // PHONON_GLOBALCONFIG_H
+--- a/src/3rdparty/phonon/phonon/globalconfig_p.h
++++ b/src/3rdparty/phonon/phonon/globalconfig_p.h
+@@ -26,40 +26,19 @@ Copyright (C) 2006-2008 Matthias Kretz <
+ #include <QtCore/QSettings>
+
+ #include "phonon_export.h"
+-#include "phononnamespace.h"
+
+ QT_BEGIN_HEADER
+ QT_BEGIN_NAMESPACE
+
+ namespace Phonon
+ {
+- class PHONON_EXPORT GlobalConfig
++ class GlobalConfigPrivate
+ {
+- public:
+- GlobalConfig();
+- virtual ~GlobalConfig();
+-
+- enum DevicesToHideFlag {
+- ShowUnavailableDevices = 0,
+- ShowAdvancedDevices = 0,
+- HideAdvancedDevices = 1,
+- AdvancedDevicesFromSettings = 2,
+- HideUnavailableDevices = 4
+- };
+-#ifndef QT_NO_PHONON_SETTINGSGROUP
+- QList<int> audioOutputDeviceListFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const;
+-#endif //QT_NO_PHONON_SETTINGSGROUP
+- int audioOutputDeviceFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const;
+-
+-#ifndef QT_NO_PHONON_AUDIOCAPTURE
+- QList<int> audioCaptureDeviceListFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const;
+- int audioCaptureDeviceFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const;
+-#endif //QT_NO_PHONON_AUDIOCAPTURE
+-
+- protected:
+-#ifndef QT_NO_SETTINGS
+- QSettings m_config;
+-#endif //QT_NO_SETTINGS
++ public:
++ GlobalConfigPrivate();
++ virtual ~GlobalConfigPrivate() {}
++
++ QSettings config;
+ };
+ } // namespace Phonon
+
+--- a/src/3rdparty/phonon/phonon/medianode.cpp
++++ b/src/3rdparty/phonon/phonon/medianode.cpp
+@@ -67,8 +67,8 @@ bool MediaNode::isValid() const
+
+ MediaNodePrivate::~MediaNodePrivate()
+ {
+- for (int i = 0 ; i < handlers.count(); ++i) {
+- handlers.at(i)->phononObjectDestroyed(this);
++ foreach (MediaNodeDestructionHandler *handler, handlers) {
++ handler->phononObjectDestroyed(this);
+ }
+ Factory::deregisterFrontendObject(this);
+ delete m_backendObject;
+--- a/src/3rdparty/phonon/phonon/mediaobject.cpp
++++ b/src/3rdparty/phonon/phonon/mediaobject.cpp
+@@ -300,15 +300,15 @@ void MediaObject::enqueue(const MediaSou
+
+ void MediaObject::enqueue(const QList<MediaSource> &sources)
+ {
+- for (int i = 0; i < sources.count(); ++i) {
+- enqueue(sources.at(i));
++ foreach (const MediaSource &m, sources) {
++ enqueue(m);
+ }
+ }
+
+ void MediaObject::enqueue(const QList<QUrl> &urls)
+ {
+- for (int i = 0; i < urls.count(); ++i) {
+- enqueue(urls.at(i));
++ foreach (const QUrl &url, urls) {
++ enqueue(url);
+ }
+ }
+
+@@ -453,9 +453,9 @@ void MediaObjectPrivate::setupBackendObj
+ //pDebug() << Q_FUNC_INFO;
+
+ #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+- QObject::connect(m_backendObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)), q, SLOT(_k_stateChanged(Phonon::State,Phonon::State)));
++ QObject::connect(m_backendObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), q, SLOT(_k_stateChanged(Phonon::State, Phonon::State)));
+ #else
+- QObject::connect(m_backendObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)), q, SIGNAL(stateChanged(Phonon::State,Phonon::State)));
++ QObject::connect(m_backendObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), q, SIGNAL(stateChanged(Phonon::State, Phonon::State)));
+ #endif // QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ QObject::connect(m_backendObject, SIGNAL(tick(qint64)), q, SIGNAL(tick(qint64)));
+ QObject::connect(m_backendObject, SIGNAL(seekableChanged(bool)), q, SIGNAL(seekableChanged(bool)));
+@@ -467,10 +467,10 @@ void MediaObjectPrivate::setupBackendObj
+ QObject::connect(m_backendObject, SIGNAL(aboutToFinish()), q, SLOT(_k_aboutToFinish()));
+ QObject::connect(m_backendObject, SIGNAL(prefinishMarkReached(qint32)), q, SIGNAL(prefinishMarkReached(qint32)));
+ QObject::connect(m_backendObject, SIGNAL(totalTimeChanged(qint64)), q, SIGNAL(totalTimeChanged(qint64)));
+- QObject::connect(m_backendObject, SIGNAL(metaDataChanged(QMultiMap<QString,QString>)),
+- q, SLOT(_k_metaDataChanged(QMultiMap<QString,QString>)));
+- QObject::connect(m_backendObject, SIGNAL(currentSourceChanged(MediaSource)),
+- q, SLOT(_k_currentSourceChanged(MediaSource)));
++ QObject::connect(m_backendObject, SIGNAL(metaDataChanged(const QMultiMap<QString, QString> &)),
++ q, SLOT(_k_metaDataChanged(const QMultiMap<QString, QString> &)));
++ QObject::connect(m_backendObject, SIGNAL(currentSourceChanged(const MediaSource&)),
++ q, SLOT(_k_currentSourceChanged(const MediaSource&)));
+
+ // set up attributes
+ pINTERFACE_CALL(setTickInterval(tickInterval));
+@@ -502,8 +502,8 @@ void MediaObjectPrivate::setupBackendObj
+ }
+
+ #ifndef QT_NO_PHONON_MEDIACONTROLLER
+- for (int i = 0 ; i < interfaceList.count(); ++i) {
+- interfaceList.at(i)->_backendObjectChanged();
++ foreach (FrontendInterfacePrivate *f, interfaceList) {
++ f->_backendObjectChanged();
+ }
+ #endif //QT_NO_PHONON_MEDIACONTROLLER
+
+--- a/src/3rdparty/phonon/phonon/mediaobject.h
++++ b/src/3rdparty/phonon/phonon/mediaobject.h
+@@ -15,7 +15,7 @@
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+- You should have received a copy of the GNU Lesser General Public
++ You should have received a copy of the GNU Lesser General Public
+ License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ */
+@@ -198,18 +198,18 @@ namespace Phonon
+ * Check whether the current media may be seeked.
+ *
+ * \warning This information cannot be known immediately. It is best
+- * to also listen to the seekableChanged signal.
++ * to also listen to the hasVideoChanged signal.
+ *
+ * \code
+- * connect(media, SIGNAL(seekableChanged(bool)), seekableChanged(bool));
++ * connect(media, SIGNAL(hasVideoChanged(bool)), hasVideoChanged(bool));
+ * media->setCurrentSource("somevideo.avi");
+- * media->isSeekable(); // returns false;
++ * media->hasVideo(); // returns false;
+ * }
+ *
+- * void seekableChanged(bool b)
++ * void hasVideoChanged(bool b)
+ * {
+ * // b == true
+- * media->isSeekable(); // returns true;
++ * media->hasVideo(); // returns true;
+ * }
+ * \endcode
+ *
+@@ -301,7 +301,7 @@ namespace Phonon
+ void setCurrentSource(const MediaSource &source);
+
+ /**
+- * Returns the queued media sources. This list does not include
++ * Returns the queued media sources. This does list does not include
+ * the current source (returned by currentSource).
+ */
+ QList<MediaSource> queue() const;
+@@ -456,6 +456,8 @@ namespace Phonon
+ Q_SIGNALS:
+ /**
+ * Emitted when the state of the MediaObject has changed.
++ * In case you're not interested in the old state you can also
++ * connect to a slot that only has one State argument.
+ *
+ * @param newstate The state the Player is in now.
+ * @param oldstate The state the Player was in before.
+@@ -585,7 +587,7 @@ namespace Phonon
+ /**
+ * This signal is emitted as soon as the total time of the media file is
+ * known or has changed. For most non-local media data the total
+- * time of the media can only be known after some time. Initially the
++ * time of the media can only be known after some time. At that time the
+ * totalTime function can not return useful information. You have
+ * to wait for this signal to know the real total time.
+ *
+--- a/src/3rdparty/phonon/phonon/mediasource.cpp
++++ b/src/3rdparty/phonon/phonon/mediasource.cpp
+@@ -140,12 +140,8 @@ MediaSourcePrivate::~MediaSourcePrivate(
+ {
+ #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ if (autoDelete) {
+- //here we use deleteLater because this object
+- //might be destroyed from another thread
+- if (stream)
+- stream->deleteLater();
+- if (ioDevice)
+- ioDevice->deleteLater();
++ delete stream;
++ delete ioDevice;
+ }
+ #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ }
+--- a/src/3rdparty/phonon/phonon/objectdescription.cpp
++++ b/src/3rdparty/phonon/phonon/objectdescription.cpp
+@@ -29,6 +29,7 @@
+ #include <QtCore/QStringList>
+ #include "backendinterface.h"
+ #include "platformplugin.h"
++#include "pulsesupport_p.h"
+
+ QT_BEGIN_NAMESPACE
+
+@@ -108,22 +109,24 @@ bool ObjectDescriptionData::isValid() co
+
+ ObjectDescriptionData *ObjectDescriptionData::fromIndex(ObjectDescriptionType type, int index)
+ {
++ BackendInterface *iface = qobject_cast<BackendInterface *>(Factory::backend());
++
+ // prefer to get the ObjectDescriptionData from the platform plugin for audio devices
+ #ifndef QT_NO_PHONON_PLATFORMPLUGIN
+- if (type == AudioOutputDeviceType || type == AudioCaptureDeviceType) {
+- PlatformPlugin *platformPlugin = Factory::platformPlugin();
+- if (platformPlugin) {
+- QList<int> indexes = platformPlugin->objectDescriptionIndexes(type);
+- if (indexes.contains(index)) {
+- QHash<QByteArray, QVariant> properties = platformPlugin->objectDescriptionProperties(type, index);
+- return new ObjectDescriptionData(index, properties);
++ if (!iface || !PulseSupport::getInstance()->isActive()) {
++ if (type == AudioOutputDeviceType || type == AudioCaptureDeviceType) {
++ PlatformPlugin *platformPlugin = Factory::platformPlugin();
++ if (platformPlugin) {
++ QList<int> indexes = platformPlugin->objectDescriptionIndexes(type);
++ if (indexes.contains(index)) {
++ QHash<QByteArray, QVariant> properties = platformPlugin->objectDescriptionProperties(type, index);
++ return new ObjectDescriptionData(index, properties);
++ }
+ }
+ }
+ }
+ #endif //QT_NO_PHONON_PLATFORMPLUGIN
+
+- QObject *b = Factory::backend();
+- BackendInterface *iface = qobject_cast<BackendInterface *>(b);
+ if (iface) {
+ QList<int> indexes = iface->objectDescriptionIndexes(type);
+ if (indexes.contains(index)) {
+--- a/src/3rdparty/phonon/phonon/objectdescriptionmodel.cpp
++++ b/src/3rdparty/phonon/phonon/objectdescriptionmodel.cpp
+@@ -67,8 +67,6 @@ static const char qt_meta_stringdata_Pho
+ namespace Phonon
+ {
+
+-#if !defined(Q_CC_MINGW) || __MINGW32_MAJOR_VERSION >= 4
+-
+ template<> const QMetaObject ObjectDescriptionModel<AudioOutputDeviceType>::staticMetaObject = {
+ { &QAbstractListModel::staticMetaObject, qt_meta_stringdata_Phonon__ObjectDescriptionModel_AudioOutputDeviceType,
+ qt_meta_data_Phonon__ObjectDescriptionModel, 0 }
+@@ -139,7 +137,6 @@ int ObjectDescriptionModel<type>::qt_met
+ return QAbstractListModel::qt_metacall(_c, _id, _a);
+ }
+ */
+-#endif
+
+ int ObjectDescriptionModelData::rowCount(const QModelIndex &parent) const
+ {
+@@ -321,8 +318,8 @@ bool ObjectDescriptionModelData::dropMim
+ }
+ }
+ d->model->beginInsertRows(QModelIndex(), row, row + toInsert.size() - 1);
+- for (int i = 0 ; i < toInsert.count(); ++i) {
+- d->data.insert(row, toInsert.at(i));
++ foreach (const QExplicitlySharedDataPointer<ObjectDescriptionData> &obj, toInsert) {
++ d->data.insert(row, obj);
+ }
+ d->model->endInsertRows();
+ return true;
+@@ -365,8 +362,7 @@ QStringList ObjectDescriptionModelData::
+ return QStringList(QLatin1String("application/x-phonon-objectdescription") + QString::number(static_cast<int>(type)));
+ }
+
+-#if !defined(Q_CC_MINGW) || __MINGW32_MAJOR_VERSION >= 4
+-#if !defined(Q_CC_MSVC) || _MSC_VER > 1300 || defined(Q_CC_INTEL)
++#if !defined(Q_CC_MSVC) || _MSC_VER > 1300 || defined(Q_CC_INTEL) || defined(Q_CC_MINGW)
+ #define INSTANTIATE_META_FUNCTIONS(type) \
+ template const QMetaObject *ObjectDescriptionModel<type>::metaObject() const; \
+ template void *ObjectDescriptionModel<type>::qt_metacast(const char *)
+@@ -384,7 +380,6 @@ INSTANTIATE_META_FUNCTIONS(VideoCodecTyp
+ INSTANTIATE_META_FUNCTIONS(ContainerFormatType);
+ INSTANTIATE_META_FUNCTIONS(VisualizationType);
+ */
+-#endif //Q_CC_MINGW
+ } // namespace Phonon
+
+ #endif //QT_NO_PHONON_OBJECTDESCRIPTIONMODEL
+--- a/src/3rdparty/phonon/phonon/objectdescriptionmodel.h
++++ b/src/3rdparty/phonon/phonon/objectdescriptionmodel.h
+@@ -35,6 +35,18 @@ QT_BEGIN_NAMESPACE
+
+ #ifndef QT_NO_PHONON_OBJECTDESCRIPTIONMODEL
+
++/* MinGW 3.4.x gives an ICE when trying to instantiate one of the
++ ObjectDescriptionModel<foo> classes because it can't handle
++ half exported classes correct. gcc 4.3.x has a fix for this but
++ we currently there's no official gcc 4.3 on windows available.
++ Because of this we need this little hack
++ */
++#if defined(Q_CC_MINGW)
++#define PHONON_EXPORT_ODM
++#else
++#define PHONON_EXPORT_ODM PHONON_EXPORT
++#endif
++
+ namespace Phonon
+ {
+ class ObjectDescriptionModelDataPrivate;
+@@ -139,21 +151,6 @@ namespace Phonon
+ ObjectDescriptionModelDataPrivate *const d;
+ };
+
+-/* Required to ensure template class vtables are exported on both symbian
+-and existing builds. */
+-#if defined(Q_OS_SYMBIAN) && defined(Q_CC_RVCT)
+-// RVCT compiler (2.2.686) requires the export declaration to be on the class to export vtables
+-// MWC compiler works both ways
+-// GCCE compiler is unknown (it can't compile QtCore yet)
+-#define PHONON_TEMPLATE_CLASS_EXPORT PHONON_EXPORT
+-#define PHONON_TEMPLATE_CLASS_MEMBER_EXPORT
+-#else
+-// Windows builds (at least) do not support export declaration on templated class
+-// But if you export a member function, the vtable is implicitly exported
+-#define PHONON_TEMPLATE_CLASS_EXPORT
+-#define PHONON_TEMPLATE_CLASS_MEMBER_EXPORT PHONON_EXPORT
+-#endif
+-
+ /** \class ObjectDescriptionModel objectdescriptionmodel.h Phonon/ObjectDescriptionModel
+ * \short The ObjectDescriptionModel class provides a model from
+ * a list of ObjectDescription objects.
+@@ -190,26 +187,17 @@ and existing builds. */
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+ template<ObjectDescriptionType type>
+- class PHONON_TEMPLATE_CLASS_EXPORT ObjectDescriptionModel : public QAbstractListModel
++ class ObjectDescriptionModel : public QAbstractListModel
+ {
+ public:
+ Q_OBJECT_CHECK
+-
+-/* MinGW 3.4.x gives an ICE when trying to instantiate one of the
+- ObjectDescriptionModel<foo> classes because it can't handle
+- half exported classes correct. gcc 4.3.x has a fix for this but
+- we currently there's no official gcc 4.3 on windows available.
+- Because of this we need this little hack
+- */
+-#if !defined(Q_CC_MINGW) || __MINGW32_MAJOR_VERSION >= 4
+ /** \internal */
+- static PHONON_TEMPLATE_CLASS_MEMBER_EXPORT const QMetaObject staticMetaObject;
++ static PHONON_EXPORT const QMetaObject staticMetaObject;
+ /** \internal */
+- PHONON_TEMPLATE_CLASS_MEMBER_EXPORT const QMetaObject *metaObject() const;
++ PHONON_EXPORT_ODM const QMetaObject *metaObject() const;
+ /** \internal */
+- PHONON_TEMPLATE_CLASS_MEMBER_EXPORT void *qt_metacast(const char *_clname);
++ PHONON_EXPORT_ODM void *qt_metacast(const char *_clname);
+ //int qt_metacall(QMetaObject::Call _c, int _id, void **_a);
+-#endif
+
+ /**
+ * Returns the number of rows in the model. This value corresponds
+@@ -307,8 +295,8 @@ and existing builds. */
+ */
+ inline void setModelData(const QList<ObjectDescription<type> > &data) { //krazy:exclude=inline
+ QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > list;
+- for (int i = 0; i < data.count(); ++i) {
+- list += data.at(i).d;
++ Q_FOREACH (const ObjectDescription<type> &desc, data) {
++ list << desc.d;
+ }
+ d->setModelData(list);
+ }
+@@ -322,8 +310,8 @@ and existing builds. */
+ inline QList<ObjectDescription<type> > modelData() const { //krazy:exclude=inline
+ QList<ObjectDescription<type> > ret;
+ QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > list = d->modelData();
+- for (int i = 0; i < list.count(); ++i) {
+- ret << ObjectDescription<type>(list.at(i));
++ Q_FOREACH (const QExplicitlySharedDataPointer<ObjectDescriptionData> &data, list) {
++ ret << ObjectDescription<type>(data);
+ }
+ return ret;
+ }
+--- a/src/3rdparty/phonon/phonon/path.cpp
++++ b/src/3rdparty/phonon/phonon/path.cpp
+@@ -58,8 +58,8 @@ class ConnectionTransaction
+ PathPrivate::~PathPrivate()
+ {
+ #ifndef QT_NO_PHONON_EFFECT
+- for (int i = 0; i < effects.count(); ++i) {
+- effects.at(i)->k_ptr->removeDestructionHandler(this);
++ foreach (Effect *e, effects) {
++ e->k_ptr->removeDestructionHandler(this);
+ }
+ delete effectsParent;
+ #endif
+@@ -233,8 +233,8 @@ bool Path::disconnect()
+ if (d->sourceNode)
+ list << d->sourceNode->k_ptr->backendObject();
+ #ifndef QT_NO_PHONON_EFFECT
+- for (int i = 0; i < d->effects.count(); ++i) {
+- list << d->effects.at(i)->k_ptr->backendObject();
++ foreach(Effect *e, d->effects) {
++ list << e->k_ptr->backendObject();
+ }
+ #endif
+ if (d->sinkNode) {
+@@ -260,8 +260,8 @@ bool Path::disconnect()
+ d->sourceNode = 0;
+
+ #ifndef QT_NO_PHONON_EFFECT
+- for (int i = 0; i < d->effects.count(); ++i) {
+- d->effects.at(i)->k_ptr->removeDestructionHandler(d.data());
++ foreach(Effect *e, d->effects) {
++ e->k_ptr->removeDestructionHandler(d.data());
+ }
+ d->effects.clear();
+ #endif
+@@ -292,13 +292,11 @@ MediaNode *Path::sink() const
+ bool PathPrivate::executeTransaction( const QList<QObjectPair> &disconnections, const QList<QObjectPair> &connections)
+ {
+ QSet<QObject*> nodesForTransaction;
+- for (int i = 0; i < disconnections.count(); ++i) {
+- const QObjectPair &pair = disconnections.at(i);
++ foreach(const QObjectPair &pair, disconnections) {
+ nodesForTransaction << pair.first;
+ nodesForTransaction << pair.second;
+ }
+- for (int i = 0; i < connections.count(); ++i) {
+- const QObjectPair &pair = connections.at(i);
++ foreach(const QObjectPair &pair, connections) {
+ nodesForTransaction << pair.first;
+ nodesForTransaction << pair.second;
+ }
+@@ -310,8 +308,8 @@ bool PathPrivate::executeTransaction( co
+ if (!transaction)
+ return false;
+
+- QList<QObjectPair>::const_iterator it = disconnections.constBegin();
+- for(;it != disconnections.constEnd();++it) {
++ QList<QObjectPair>::const_iterator it = disconnections.begin();
++ for(;it != disconnections.end();++it) {
+ const QObjectPair &pair = *it;
+ if (!backend->disconnectNodes(pair.first, pair.second)) {
+
+@@ -327,8 +325,8 @@ bool PathPrivate::executeTransaction( co
+ }
+ }
+
+- for(it = connections.constBegin(); it != connections.constEnd(); ++it) {
+- const QObjectPair pair = *it;
++ for(it = connections.begin(); it != connections.end();++it) {
++ const QObjectPair &pair = *it;
+ if (!backend->connectNodes(pair.first, pair.second)) {
+ //Error: a connection failed
+ QList<QObjectPair>::const_iterator it2 = connections.begin();
+@@ -340,8 +338,7 @@ bool PathPrivate::executeTransaction( co
+ }
+
+ //and now let's reconnect the nodes that were disconnected: rollback
+- for (int i = 0; i < disconnections.count(); ++i) {
+- const QObjectPair &pair = disconnections.at(i);
++ foreach(const QObjectPair &pair, disconnections) {
+ bool success = backend->connectNodes(pair.first, pair.second);
+ Q_ASSERT(success); //a failure here means it is impossible to reestablish the connection
+ Q_UNUSED(success);
+@@ -420,8 +417,7 @@ void PathPrivate::phononObjectDestroyed(
+ sinkNode = 0;
+ } else {
+ #ifndef QT_NO_PHONON_EFFECT
+- for (int i = 0; i < effects.count(); ++i) {
+- Effect *e = effects.at(i);
++ foreach (Effect *e, effects) {
+ if (e->k_ptr == mediaNodePrivate) {
+ removeEffect(e);
+ }
+--- a/src/3rdparty/phonon/phonon/phonondefs.h
++++ b/src/3rdparty/phonon/phonon/phonondefs.h
+@@ -29,6 +29,11 @@
+ QT_BEGIN_HEADER
+ QT_BEGIN_NAMESPACE
+
++#ifdef PHONON_BACKEND_VERSION_4_4
++# ifndef PHONON_BACKEND_VERSION_4_3
++# define PHONON_BACKEND_VERSION_4_3
++# endif
++#endif
+ #ifdef PHONON_BACKEND_VERSION_4_3
+ # ifndef PHONON_BACKEND_VERSION_4_2
+ # define PHONON_BACKEND_VERSION_4_2
+--- a/src/3rdparty/phonon/phonon/phononnamespace.h
++++ /dev/null
+@@ -1,311 +0,0 @@
+-/* This file is part of the KDE project
+- Copyright (C) 2005-2008 Matthias Kretz <kretz@kde.org>
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Lesser General Public
+- License as published by the Free Software Foundation; either
+- version 2.1 of the License, or (at your option) version 3, or any
+- later version accepted by the membership of KDE e.V. (or its
+- successor approved by the membership of KDE e.V.), Nokia Corporation
+- (or its successors, if any) and the KDE Free Qt Foundation, which shall
+- act as a proxy defined in Section 6 of version 3 of the license.
+-
+- This library 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
+- Lesser General Public License for more details.
+-
+- You should have received a copy of the GNU Lesser General Public
+- License along with this library. If not, see <http://www.gnu.org/licenses/>.
+-
+-*/
+-
+-#ifndef PHONONNAMESPACE_H
+-#define PHONONNAMESPACE_H
+-
+-#include "phonon_export.h"
+-
+-#ifdef __QT_SYNCQT__
+-// Tell syncqt to create a "Global" header here
+-#pragma qt_class(Phonon::Global)
+-#endif
+-
+-/**
+- * Helper macro that can be used like
+- * \code
+- * #if (PHONON_VERSION >= PHONON_VERSION_CHECK(4, 4, 0))
+- * \endcode
+- */
+-#define PHONON_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch))
+-
+-/**
+- * PHONON_VERSION is (major << 16) + (minor << 8) + patch.
+- */
+-#define PHONON_VERSION PHONON_VERSION_CHECK(4, 3, 1)
+-
+-/**
+- * PHONON_VERSION_STR is "major.minor.patch". E.g. "4.2.1"
+- */
+-#define PHONON_VERSION_STR "4.3.1"
+-
+-QT_BEGIN_HEADER
+-QT_BEGIN_NAMESPACE
+-
+-class QString;
+-
+-/**
+- * \brief The %KDE Multimedia classes
+- *
+- * In this Namespace you find the classes to access Multimedia functions for
+- * audio and video playback. Those classes are not dependent
+- * on any specific framework (like they were in pre KDE4 times) but rather use
+- * exchangeable backends to do the work.
+- *
+- * If you want to write a new backend take a look at \ref phonon_backend_development_page.
+- *
+- * \author Matthias Kretz <kretz@kde.org>
+- */
+-namespace Phonon
+-{
+- PHONON_EXPORT const char *phononVersion();
+-
+- /**
+- * Enum to identify the media discs supported by MediaObject.
+- *
+- * \see MediaSource(Phonon::DiscType, const QString &deviceName)
+- */
+- enum DiscType {
+- /**
+- * No disc was selected. This is only useful as a return value from
+- * MediaSource::distType();
+- */
+- NoDisc = -1,
+- /**
+- * Identifies Audio CDs.
+- */
+- Cd = 0,
+- /**
+- * Identifies DVDs (not arbitrary data DVDs, only movie DVDs).
+- */
+- Dvd = 1,
+- /**
+- * Identifies Video CDs.
+- */
+- Vcd = 2
+- };
+-
+- /**
+- * Provided as keys for \ref MediaObject::metaData for convenience, in addition to the strings defined in
+- * the Ogg Vorbis specification.
+- */
+- enum MetaData {
+- /**
+- * The artist generally considered responsible for the work. In popular
+- * music this is usually the performing band or singer. For classical
+- * music it would be the composer. For an audio book it would be the
+- * author of the original text.
+- */
+- ArtistMetaData,
+- /**
+- * The collection name to which this track belongs.
+- */
+- AlbumMetaData,
+- /**
+- * Track/Work name
+- */
+- TitleMetaData,
+- /**
+- * Date the track was recorded
+- */
+- DateMetaData,
+- /**
+- * A short text indication of music genre
+- */
+- GenreMetaData,
+- /**
+- * The track number of this piece if part of a specific larger
+- * collection or album
+- */
+- TracknumberMetaData,
+- /**
+- * A short text description of the contents
+- */
+- DescriptionMetaData,
+- MusicBrainzDiscIdMetaData
+- };
+-
+- /**
+- * The state the media producing object is in at the moment.
+- *
+- * \see MediaObject
+- */
+- enum State
+- {
+- /**
+- * After construction it might take a while before the Player is
+- * ready to play(). Normally this doesn't happen for local
+- * files, but can happen for remote files where the asynchronous
+- * mimetype detection and prebuffering can take a while.
+- */
+- LoadingState,
+- /**
+- * The Player has a valid media file loaded and is ready for
+- * playing.
+- */
+- StoppedState,
+- /**
+- * The Player is playing a media file.
+- */
+- PlayingState,
+- /**
+- * The Player is waiting for data to be able to continue
+- * playing.
+- */
+- BufferingState,
+- /**
+- * The Player is currently paused.
+- */
+- PausedState,
+- /**
+- * An unrecoverable error occurred. The Object is unusable in this state.
+- */
+- ErrorState
+- };
+-
+- /**
+- * Set's the category your program should be listed in in the mixer.
+- *
+- * A Jukebox will set this to Music, a VoIP program to Communication, a
+- * DVD player to video, and so on.
+- *
+- * \note These categories can also become useful for an application that
+- * controls the volumes automatically, like turning down the music when a call
+- * comes in, or turning down the notifications when the media player knows
+- * it's playing classical music.
+- *
+- * \see AudioOutput::setCategory
+- */
+- enum Category
+- {
+- /**
+- * Will make use of the default device.
+- */
+- NoCategory = -1,
+- /**
+- * If the sounds produced are notifications (bing, beep and such) you
+- * should use this category.
+- */
+- NotificationCategory = 0,
+- /**
+- * If your application is a music player (like a jukebox or media player
+- * playing an audio file).
+- */
+- MusicCategory = 1,
+- /**
+- * If the sound is the audio channel of a video.
+- */
+- VideoCategory = 2,
+- /**
+- * If your applications produces sounds from communication with somebody
+- * else (VoIP, voice chat).
+- */
+- CommunicationCategory = 3,
+- /**
+- * Sound produced by a computer game should go into this category.
+- */
+- GameCategory = 4,
+- /**
+- * Sounds produced for accessibility (e.g. Text-To-Speech)
+- */
+- AccessibilityCategory = 5,
+- /**
+- * \internal
+- * Holds the largest value of categories.
+- */
+- LastCategory = AccessibilityCategory
+- };
+-
+- /**
+- * Tells your program how to recover from an error.
+- *
+- * \see MediaObject::errorType()
+- */
+- enum ErrorType {
+- /**
+- * No error. MediaObject::errorType() returns this if
+- * MediaObject::state() != Phonon::ErrorState.
+- */
+- NoError = 0,
+- /**
+- * Playback should work, and trying with another URL should work.
+- */
+- NormalError = 1,
+- /**
+- * Something important does not work. Your program cannot continue
+- * playback or capture or whatever it was trying to do
+- * without help from the user.
+- */
+- FatalError = 2
+- };
+-
+- /**
+- * Returns a (translated) string to show to the user identifying the given
+- * Category.
+- */
+- PHONON_EXPORT QString categoryToString(Category c);
+-
+- // TODO: naming
+- /*enum MediaStreamType {
+- Audio = 1,
+- Video = 2,
+- StillImage = 4,
+- Subtitle = 8,
+- AllMedia = 0xFFFFFFFF
+- };
+- Q_DECLARE_FLAGS(MediaStreamTypes, MediaStreamType)*/
+-} // namespace Phonon
+-//Q_DECLARE_OPERATORS_FOR_FLAGS(Phonon::MediaStreamTypes)
+-
+-QT_END_NAMESPACE
+-
+-//X class kdbgstream;
+-//X #include <kdebug.h>
+-//X /**
+-//X * Implements needed operator to use Phonon::State with kDebug
+-//X */
+-//X inline PHONON_EXPORT kdbgstream &operator<<(kdbgstream & stream, const Phonon::State state)
+-//X {
+-//X switch(state)
+-//X {
+-//X case Phonon::ErrorState:
+-//X stream << "ErrorState";
+-//X break;
+-//X case Phonon::LoadingState:
+-//X stream << "LoadingState";
+-//X break;
+-//X case Phonon::StoppedState:
+-//X stream << "StoppedState";
+-//X break;
+-//X case Phonon::PlayingState:
+-//X stream << "PlayingState";
+-//X break;
+-//X case Phonon::BufferingState:
+-//X stream << "BufferingState";
+-//X break;
+-//X case Phonon::PausedState:
+-//X stream << "PausedState";
+-//X break;
+-//X }
+-//X return stream;
+-//X }
+-
+-#include <QtCore/QMetaType>
+-
+-Q_DECLARE_METATYPE(Phonon::State)
+-Q_DECLARE_METATYPE(Phonon::ErrorType)
+-Q_DECLARE_METATYPE(Phonon::Category)
+-
+-QT_END_HEADER
+-
+-// vim: sw=4 ts=4 tw=80
+-#endif // PHONONNAMESPACE_H
+--- /dev/null
++++ b/phonon/pulsesupport.cpp
+@@ -0,0 +1,968 @@
++/* This file is part of the KDE project
++ Copyright (C) 2009 Colin Guthrie <cguthrie@mandriva.org>
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) version 3, or any
++ later version accepted by the membership of KDE e.V. (or its
++ successor approved by the membership of KDE e.V.), Nokia Corporation
++ (or its successors, if any) and the KDE Free Qt Foundation, which shall
++ act as a proxy defined in Section 6 of version 3 of the license.
++
++ This library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with this library. If not, see <http://www.gnu.org/licenses/>.
++
++*/
++
++#include <QtCore/QtGlobal>
++#include <QtCore/QEventLoop>
++#include <QtCore/QDebug>
++#include <QtCore/QStringList>
++
++#ifdef HAVE_PULSEAUDIO
++#include <glib.h>
++#include <pulse/pulseaudio.h>
++#include <pulse/xmalloc.h>
++#include <pulse/glib-mainloop.h>
++#include <pulse/ext-device-manager.h>
++#endif // HAVE_PULSEAUDIO
++
++#include "pulsesupport_p.h"
++
++QT_BEGIN_NAMESPACE
++
++namespace Phonon
++{
++
++static PulseSupport* s_instance = NULL;
++
++#ifdef HAVE_PULSEAUDIO
++/***
++* Prints a conditional debug message based on the current debug level
++* If obj is provided, classname and objectname will be printed as well
++*
++* see debugLevel()
++*/
++
++static int debugLevel() {
++ static int level = -1;
++ if (level < 1) {
++ level = 0;
++ QString pulseenv = qgetenv("PHONON_PULSEAUDIO_DEBUG");
++ int l = pulseenv.toInt();
++ if (l > 0)
++ level = (l > 2 ? 2 : l);
++ }
++ return level;
++}
++
++static void logMessage(const QString &message, int priority = 2, QObject *obj=0);
++static void logMessage(const QString &message, int priority, QObject *obj)
++{
++ if (debugLevel() > 0) {
++ QString output;
++ if (obj) {
++ // Strip away namespace from className
++ QString className(obj->metaObject()->className());
++ int nameLength = className.length() - className.lastIndexOf(':') - 1;
++ className = className.right(nameLength);
++ output.sprintf("%s %s (%s %p)", message.toLatin1().constData(),
++ obj->objectName().toLatin1().constData(),
++ className.toLatin1().constData(), obj);
++ }
++ else {
++ output = message;
++ }
++ if (priority <= debugLevel()) {
++ qDebug() << QString("PulseSupport(%1): %2").arg(priority).arg(output);
++ }
++ }
++}
++
++
++class AudioDevice
++{
++ public:
++ inline
++ AudioDevice(QString name, QString desc, QString icon, uint32_t index)
++ : pulseName(name), pulseIndex(index)
++ {
++ properties["name"] = desc;
++ properties["description"] = ""; // We don't have descriptions (well we do, but we use them as the name!)
++ properties["icon"] = icon;
++ properties["available"] = (index != PA_INVALID_INDEX);
++ properties["isAdvanced"] = false; // Nothing is advanced!
++ }
++
++ // Needed for QMap
++ inline AudioDevice() {}
++
++ QString pulseName;
++ uint32_t pulseIndex;
++ QHash<QByteArray, QVariant> properties;
++};
++bool operator!=(const AudioDevice &a, const AudioDevice &b)
++{
++ return !(a.pulseName == b.pulseName && a.properties == b.properties);
++}
++
++class PulseUserData
++{
++ public:
++ inline
++ PulseUserData()
++ {
++ }
++
++ QMap<QString, AudioDevice> newOutputDevices;
++ QMap<Phonon::Category, QMap<int, int> > newOutputDevicePriorities; // prio, device
++
++ QMap<QString, AudioDevice> newCaptureDevices;
++ QMap<Phonon::Category, QMap<int, int> > newCaptureDevicePriorities; // prio, device
++};
++
++static QMap<QString, Phonon::Category> s_roleCategoryMap;
++
++static bool s_pulseActive = false;
++
++static pa_glib_mainloop *s_mainloop = NULL;
++static pa_context *s_context = NULL;
++static QEventLoop *s_connectionEventloop = NULL;
++
++
++
++static int s_deviceIndexCounter = 0;
++
++static QMap<QString, int> s_outputDeviceIndexes;
++static QMap<int, AudioDevice> s_outputDevices;
++static QMap<Phonon::Category, QMap<int, int> > s_outputDevicePriorities; // prio, device
++static QMap<QString, uint32_t> s_outputStreamIndexMap;
++static QMap<QString, int> s_outputStreamMoveQueue;
++
++static QMap<QString, int> s_captureDeviceIndexes;
++static QMap<int, AudioDevice> s_captureDevices;
++static QMap<Phonon::Category, QMap<int, int> > s_captureDevicePriorities; // prio, device
++static QMap<QString, uint32_t> s_captureStreamIndexMap;
++static QMap<QString, int> s_captureStreamMoveQueue;
++
++
++static void ext_device_manager_subscribe_cb(pa_context *, void *);
++static void ext_device_manager_read_cb(pa_context *c, const pa_ext_device_manager_info *info, int eol, void *userdata) {
++ Q_ASSERT(c);
++ Q_ASSERT(userdata);
++
++ // If this is our first iteration, set things up properly
++ if (s_connectionEventloop) {
++ s_connectionEventloop->exit(0);
++ s_connectionEventloop = NULL;
++ s_pulseActive = true;
++
++ pa_operation *o;
++ pa_ext_device_manager_set_subscribe_cb(c, ext_device_manager_subscribe_cb, NULL);
++ if ((o = pa_ext_device_manager_subscribe(c, 1, NULL, NULL)))
++ pa_operation_unref(o);
++ }
++
++ if (eol < 0) {
++ logMessage(QString("Failed to initialize device manager extension: %1").arg(pa_strerror(pa_context_errno(c))));
++ // OK so we don't have the device manager extension, but we can show a single device and fake it.
++ int index;
++ s_outputDeviceIndexes.clear();
++ s_outputDevices.clear();
++ s_outputDevicePriorities.clear();
++ index = s_deviceIndexCounter++;
++ s_outputDeviceIndexes.insert("sink:default", index);
++ s_outputDevices.insert(index, AudioDevice("sink:default", QObject::tr("PulseAudio Sound Server").toUtf8(), "audio-backend-pulseaudio", 0));
++ for (int i = Phonon::NoCategory; i <= Phonon::LastCategory; ++i) {
++ Phonon::Category cat = static_cast<Phonon::Category>(i);
++ s_outputDevicePriorities[cat].insert(0, index);
++ }
++
++ s_captureDeviceIndexes.clear();
++ s_captureDevices.clear();
++ s_captureDevicePriorities.clear();
++ index = s_deviceIndexCounter++;
++ s_captureDeviceIndexes.insert("source:default", index);
++ s_captureDevices.insert(index, AudioDevice("source:default", QObject::tr("PulseAudio Sound Server").toUtf8(), "audio-backend-pulseaudio", 0));
++ for (int i = Phonon::NoCategory; i <= Phonon::LastCategory; ++i) {
++ Phonon::Category cat = static_cast<Phonon::Category>(i);
++ s_captureDevicePriorities[cat].insert(0, index);
++ }
++
++ return;
++ }
++
++ PulseUserData *u = reinterpret_cast<PulseUserData*>(userdata);
++ if (eol) {
++ // We're done reading the data, so order it by priority and copy it into the
++ // static variables where it can then be accessed by those classes that need it.
++
++ QMap<QString, AudioDevice>::iterator newdev_it;
++
++ // Check for new output devices or things changing about known output devices.
++ bool output_changed = false;
++ for (newdev_it = u->newOutputDevices.begin(); newdev_it != u->newOutputDevices.end(); ++newdev_it) {
++ QString name = newdev_it.key();
++
++ // The name + index map is always written when a new device is added.
++ Q_ASSERT(s_outputDeviceIndexes.contains(name));
++
++ int index = s_outputDeviceIndexes[name];
++ if (!s_outputDevices.contains(index)) {
++ // This is a totally new device
++ output_changed = true;
++ logMessage(QString("Brand New Output Device Found."));
++ s_outputDevices.insert(index, *newdev_it);
++ } else if (s_outputDevices[index] != *newdev_it) {
++ // We have this device already, but is it different?
++ output_changed = true;
++ logMessage(QString("Change to Existing Output Device (may be Added/Removed or something else)"));
++ s_outputDevices.remove(index);
++ s_outputDevices.insert(index, *newdev_it);
++ }
++ }
++ // Go through the output devices we know about and see if any are no longer mentioned in the list.
++ QMutableMapIterator<QString, int> output_existing_it(s_outputDeviceIndexes);
++ while (output_existing_it.hasNext()) {
++ output_existing_it.next();
++ if (!u->newOutputDevices.contains(output_existing_it.key())) {
++ output_changed = true;
++ logMessage(QString("Output Device Completely Removed"));
++ s_outputDevices.remove(output_existing_it.value());
++ output_existing_it.remove();
++ }
++ }
++
++ // Check for new capture devices or things changing about known capture devices.
++ bool capture_changed = false;
++ for (newdev_it = u->newCaptureDevices.begin(); newdev_it != u->newCaptureDevices.end(); ++newdev_it) {
++ QString name = newdev_it.key();
++
++ // The name + index map is always written when a new device is added.
++ Q_ASSERT(s_captureDeviceIndexes.contains(name));
++
++ int index = s_captureDeviceIndexes[name];
++ if (!s_captureDevices.contains(index)) {
++ // This is a totally new device
++ capture_changed = true;
++ logMessage(QString("Brand New Capture Device Found."));
++ s_captureDevices.insert(index, *newdev_it);
++ } else if (s_captureDevices[index] != *newdev_it) {
++ // We have this device already, but is it different?
++ capture_changed = true;
++ logMessage(QString("Change to Existing Capture Device (may be Added/Removed or something else)"));
++ s_captureDevices.remove(index);
++ s_captureDevices.insert(index, *newdev_it);
++ }
++ }
++ // Go through the capture devices we know about and see if any are no longer mentioned in the list.
++ QMutableMapIterator<QString, int> capture_existing_it(s_captureDeviceIndexes);
++ while (capture_existing_it.hasNext()) {
++ capture_existing_it.next();
++ if (!u->newCaptureDevices.contains(capture_existing_it.key())) {
++ capture_changed = true;
++ logMessage(QString("Capture Device Completely Removed"));
++ s_captureDevices.remove(capture_existing_it.value());
++ capture_existing_it.remove();
++ }
++ }
++
++ // Just copy accross the new priority lists as we know they are valid
++ if (s_outputDevicePriorities != u->newOutputDevicePriorities) {
++ output_changed = true;
++ s_outputDevicePriorities = u->newOutputDevicePriorities;
++ }
++ if (s_captureDevicePriorities != u->newCaptureDevicePriorities) {
++ capture_changed = true;
++ s_captureDevicePriorities = u->newCaptureDevicePriorities;
++ }
++
++ if (s_instance) {
++ if (output_changed)
++ s_instance->emitObjectDescriptionChanged(AudioOutputDeviceType);
++ if (capture_changed)
++ s_instance->emitObjectDescriptionChanged(AudioCaptureDeviceType);
++ }
++
++ // We can free the user data as we will not be called again.
++ delete u;
++
++ // Some debug
++ logMessage(QString("Output Device Priority List:"));
++ for (int i = Phonon::NoCategory; i <= Phonon::LastCategory; ++i) {
++ Phonon::Category cat = static_cast<Phonon::Category>(i);
++ if (s_outputDevicePriorities.contains(cat)) {
++ logMessage(QString(" Phonon Category %1").arg(cat));
++ int count = 0;
++ foreach (int j, s_outputDevicePriorities[cat]) {
++ QHash<QByteArray, QVariant> &props = s_outputDevices[j].properties;
++ logMessage(QString(" %1. %2 (Available: %3)").arg(++count).arg(props["name"].toString()).arg(props["available"].toBool()));
++ }
++ }
++ }
++ logMessage(QString("Capture Device Priority List:"));
++ for (int i = Phonon::NoCategory; i <= Phonon::LastCategory; ++i) {
++ Phonon::Category cat = static_cast<Phonon::Category>(i);
++ if (s_captureDevicePriorities.contains(cat)) {
++ logMessage(QString(" Phonon Category %1").arg(cat));
++ int count = 0;
++ foreach (int j, s_captureDevicePriorities[cat]) {
++ QHash<QByteArray, QVariant> &props = s_captureDevices[j].properties;
++ logMessage(QString(" %1. %2 (Available: %3)").arg(++count).arg(props["name"].toString()).arg(props["available"].toBool()));
++ }
++ }
++ }
++ }
++
++ if (!info)
++ return;
++
++ Q_ASSERT(info->name);
++ Q_ASSERT(info->description);
++ Q_ASSERT(info->icon);
++
++ // QString wrapper
++ QString name(info->name);
++ int index;
++ QMap<Phonon::Category, QMap<int, int> > *new_prio_map_cats; // prio, device
++ QMap<QString, AudioDevice> *new_devices;
++
++ if (name.startsWith("sink:")) {
++ new_devices = &u->newOutputDevices;
++ new_prio_map_cats = &u->newOutputDevicePriorities;
++
++ if (s_outputDeviceIndexes.contains(name))
++ index = s_outputDeviceIndexes[name];
++ else
++ index = s_outputDeviceIndexes[name] = s_deviceIndexCounter++;
++ } else if (name.startsWith("source:")) {
++ new_devices = &u->newCaptureDevices;
++ new_prio_map_cats = &u->newCaptureDevicePriorities;
++
++ if (s_captureDeviceIndexes.contains(name))
++ index = s_captureDeviceIndexes[name];
++ else
++ index = s_captureDeviceIndexes[name] = s_deviceIndexCounter++;
++ } else {
++ // This indicates a bug in pulseaudio.
++ return;
++ }
++
++ // Add the new device itself.
++ new_devices->insert(name, AudioDevice(name, info->description, info->icon, info->index));
++
++ // For each role in the priority, map it to a phonon category and store the order.
++ for (uint32_t i = 0; i < info->n_role_priorities; ++i) {
++ pa_ext_device_manager_role_priority_info* role_prio = &info->role_priorities[i];
++ Q_ASSERT(role_prio->role);
++
++ if (s_roleCategoryMap.contains(role_prio->role)) {
++ Phonon::Category cat = s_roleCategoryMap[role_prio->role];
++
++ (*new_prio_map_cats)[cat].insert(role_prio->priority, index);
++ }
++ }
++}
++
++static void set_output_device(QString streamUuid)
++{
++ // If we only have one device, bail. This will be true if we are not using module-device-manager
++ if (s_outputDevices.size() < 2)
++ return;
++
++ if (!s_outputStreamMoveQueue.contains(streamUuid))
++ return;
++
++ if (!s_outputStreamIndexMap.contains(streamUuid))
++ return;
++
++ if (s_outputStreamIndexMap[streamUuid] == PA_INVALID_INDEX)
++ return;
++
++ int device = s_outputStreamMoveQueue[streamUuid];
++ if (!s_outputDevices.contains(device))
++ return;
++
++ // We don't remove the uuid from the s_captureStreamMoveQueue
++ // as an application may reuse the phonon AudioOutput object
++
++ uint32_t pulse_device_index = s_outputDevices[device].pulseIndex;
++ uint32_t pulse_stream_index = s_outputStreamIndexMap[streamUuid];
++
++ const QVariant var = s_outputDevices[device].properties["name"];
++ logMessage(QString("Moving Pulse Sink Input %1 to '%2' (Pulse Sink %3)").arg(pulse_stream_index).arg(var.toString()).arg(pulse_device_index));
++
++ /// @todo Find a way to move the stream without saving it... We don't want to pollute the stream restore db.
++ pa_operation* o;
++ if (!(o = pa_context_move_sink_input_by_index(s_context, pulse_stream_index, pulse_device_index, NULL, NULL))) {
++ logMessage(QString("pa_context_move_sink_input_by_index() failed"));
++ return;
++ }
++ pa_operation_unref(o);
++}
++
++static void set_capture_device(QString streamUuid)
++{
++ // If we only have one device, bail. This will be true if we are not using module-device-manager
++ if (s_captureDevices.size() < 2)
++ return;
++
++ if (!s_captureStreamMoveQueue.contains(streamUuid))
++ return;
++
++ if (!s_captureStreamIndexMap.contains(streamUuid))
++ return;
++
++ if (s_captureStreamIndexMap[streamUuid] == PA_INVALID_INDEX)
++ return;
++
++ int device = s_captureStreamMoveQueue[streamUuid];
++ if (!s_captureDevices.contains(device))
++ return;
++
++ // We don't remove the uuid from the s_captureStreamMoveQueue
++ // as an application may reuse the phonon AudioCapture object (when it exists!)
++
++ uint32_t pulse_device_index = s_captureDevices[device].pulseIndex;
++ uint32_t pulse_stream_index = s_captureStreamIndexMap[streamUuid];
++
++ const QVariant var = s_captureDevices[device].properties["name"];
++ logMessage(QString("Moving Pulse Source Output %1 to '%2' (Pulse Sink %3)").arg(pulse_stream_index).arg(var.toString()).arg(pulse_device_index));
++
++ /// @todo Find a way to move the stream without saving it... We don't want to pollute the stream restore db.
++ pa_operation* o;
++ if (!(o = pa_context_move_source_output_by_index(s_context, pulse_stream_index, pulse_device_index, NULL, NULL))) {
++ logMessage(QString("pa_context_move_source_output_by_index() failed"));
++ return;
++ }
++ pa_operation_unref(o);
++}
++
++void sink_input_cb(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata) {
++ Q_UNUSED(userdata);
++ Q_ASSERT(c);
++
++ if (eol < 0) {
++ if (pa_context_errno(c) == PA_ERR_NOENTITY)
++ return;
++
++ logMessage(QString("Sink input callback failure"));
++ return;
++ }
++
++ if (eol > 0)
++ return;
++
++ Q_ASSERT(i);
++
++ // loop through (*i) and extract phonon->streamindex...
++ const char *t;
++ if ((t = pa_proplist_gets(i->proplist, "phonon.streamid"))) {
++ logMessage(QString("Found PulseAudio stream index %1 for Phonon Output Stream %2").arg(i->index).arg(t));
++ s_outputStreamIndexMap[QString(t)] = i->index;
++ // Process any pending moves...
++ set_output_device(QString(t));
++ }
++}
++
++void source_output_cb(pa_context *c, const pa_source_output_info *i, int eol, void *userdata) {
++ Q_UNUSED(userdata);
++ Q_ASSERT(c);
++
++ if (eol < 0) {
++ if (pa_context_errno(c) == PA_ERR_NOENTITY)
++ return;
++
++ logMessage(QString("Source output callback failure"));
++ return;
++ }
++
++ if (eol > 0)
++ return;
++
++ Q_ASSERT(i);
++
++ // loop through (*i) and extract phonon->streamindex...
++ const char *t;
++ if ((t = pa_proplist_gets(i->proplist, "phonon.streamid"))) {
++ logMessage(QString("Found PulseAudio stream index %1 for Phonon Capture Stream %2").arg(i->index).arg(t));
++ s_captureStreamIndexMap[QString(t)] = i->index;
++ // Process any pending moves...
++ set_capture_device(QString(t));
++ }
++}
++
++static void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata) {
++ Q_UNUSED(userdata);
++
++ switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
++ case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
++ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
++ QString phononid = s_outputStreamIndexMap.key(index);
++ if (!phononid.isEmpty()) {
++ if (s_outputStreamIndexMap.contains(phononid)) {
++ logMessage(QString("Phonon Output Stream %1 is gone at the PA end. Marking it as invalid in our cache as we may reuse it.").arg(phononid));
++ s_outputStreamIndexMap[phononid] = PA_INVALID_INDEX;
++ } else {
++ logMessage(QString("Removing Phonon Output Stream %1 (it's gone!)").arg(phononid));
++ s_outputStreamIndexMap.remove(phononid);
++ s_outputStreamMoveQueue.remove(phononid);
++ }
++ }
++ } else {
++ pa_operation *o;
++ if (!(o = pa_context_get_sink_input_info(c, index, sink_input_cb, NULL))) {
++ logMessage(QString("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) {
++ QString phononid = s_captureStreamIndexMap.key(index);
++ if (!phononid.isEmpty()) {
++ if (s_captureStreamIndexMap.contains(phononid)) {
++ logMessage(QString("Phonon Capture Stream %1 is gone at the PA end. Marking it as invalid in our cache as we may reuse it.").arg(phononid));
++ s_captureStreamIndexMap[phononid] = PA_INVALID_INDEX;
++ } else {
++ logMessage(QString("Removing Phonon Capture Stream %1 (it's gone!)").arg(phononid));
++ s_captureStreamIndexMap.remove(phononid);
++ s_captureStreamMoveQueue.remove(phononid);
++ }
++ }
++ } else {
++ pa_operation *o;
++ if (!(o = pa_context_get_source_output_info(c, index, source_output_cb, NULL))) {
++ logMessage(QString("pa_context_get_sink_input_info() failed"));
++ return;
++ }
++ pa_operation_unref(o);
++ }
++ break;
++ }
++}
++
++
++static void ext_device_manager_subscribe_cb(pa_context *c, void *) {
++ Q_ASSERT(c);
++
++ pa_operation *o;
++ PulseUserData *u = new PulseUserData; /** @todo Make some object to receive the info... */
++ if (!(o = pa_ext_device_manager_read(c, ext_device_manager_read_cb, u))) {
++ // We need to deal with failure on first iteration
++ if (s_connectionEventloop) {
++ s_connectionEventloop->exit(0);
++ s_connectionEventloop = NULL;
++ }
++ logMessage(QString("pa_ext_device_manager_read() failed"));
++ return;
++ }
++ pa_operation_unref(o);
++
++
++ // Register for the stream changes...
++ pa_context_set_subscribe_callback(c, subscribe_cb, NULL);
++
++ if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t)
++ (PA_SUBSCRIPTION_MASK_SINK_INPUT|
++ PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT), NULL, NULL))) {
++ logMessage(QString("pa_context_subscribe() failed"));
++ return;
++ }
++ pa_operation_unref(o);
++}
++
++static void context_state_callback(pa_context *c, void *)
++{
++ Q_ASSERT(c);
++
++ switch (pa_context_get_state(c)) {
++ case PA_CONTEXT_UNCONNECTED:
++ case PA_CONTEXT_CONNECTING:
++ case PA_CONTEXT_AUTHORIZING:
++ case PA_CONTEXT_SETTING_NAME:
++ break;
++
++ case PA_CONTEXT_READY:
++ // Attempt to load things up
++ ext_device_manager_subscribe_cb(c, NULL);
++ break;
++
++ case PA_CONTEXT_FAILED:
++ s_pulseActive = false;
++ if (s_connectionEventloop) {
++ s_connectionEventloop->exit(0);
++ s_connectionEventloop = NULL;
++ }
++ break;
++
++ case PA_CONTEXT_TERMINATED:
++ default:
++ s_pulseActive = false;
++ /// @todo Deal with reconnection...
++ break;
++ }
++}
++#endif // HAVE_PULSEAUDIO
++
++
++PulseSupport* PulseSupport::getInstance()
++{
++ if (NULL == s_instance) {
++ s_instance = new PulseSupport();
++ }
++ return s_instance;
++}
++
++void PulseSupport::shutdown()
++{
++ if (NULL != s_instance) {
++ delete s_instance;
++ s_instance = NULL;
++ }
++}
++
++PulseSupport::PulseSupport()
++ : QObject()
++{
++#ifdef HAVE_PULSEAUDIO
++ // Initialise our map (is there a better way to do this?)
++ s_roleCategoryMap["none"] = Phonon::NoCategory;
++ s_roleCategoryMap["video"] = Phonon::VideoCategory;
++ s_roleCategoryMap["music"] = Phonon::MusicCategory;
++ s_roleCategoryMap["game"] = Phonon::GameCategory;
++ s_roleCategoryMap["event"] = Phonon::NotificationCategory;
++ s_roleCategoryMap["phone"] = Phonon::CommunicationCategory;
++ //s_roleCategoryMap["animation"]; // No Mapping
++ //s_roleCategoryMap["production"]; // No Mapping
++ s_roleCategoryMap["a11y"] = Phonon::AccessibilityCategory;
++
++ // To allow for easy debugging, give an easy way to disable this pulseaudio check
++ QString pulseenv = qgetenv("PHONON_PULSEAUDIO_DISABLE");
++ if (pulseenv.toInt())
++ return;
++
++ s_mainloop = pa_glib_mainloop_new(NULL);
++ Q_ASSERT(s_mainloop);
++ pa_mainloop_api *api = pa_glib_mainloop_get_api(s_mainloop);
++
++ // We create a simple event loop to allow the glib loop
++ // to iterate until we've connected or not to the server.
++ s_connectionEventloop = new QEventLoop;
++
++ // XXX I don't want to show up in the client list. All I want to know is the list of sources
++ // and sinks...
++ s_context = pa_context_new(api, "libphonon");
++ // (cg) Convert to PA_CONTEXT_NOFLAGS when PulseAudio 0.9.19 is required
++ if (pa_context_connect(s_context, NULL, static_cast<pa_context_flags_t>(0), 0) >= 0) {
++ pa_context_set_state_callback(s_context, &context_state_callback, s_connectionEventloop);
++ // Now we block until we connect or otherwise...
++ s_connectionEventloop->exec();
++ }
++#endif
++}
++
++PulseSupport::~PulseSupport()
++{
++#ifdef HAVE_PULSEAUDIO
++ if (s_context) {
++ pa_context_disconnect(s_context);
++ s_context = NULL;
++ }
++
++ if (s_mainloop) {
++ pa_glib_mainloop_free(s_mainloop);
++ s_mainloop = NULL;
++ }
++
++ if (s_connectionEventloop) {
++ delete s_connectionEventloop;
++ s_connectionEventloop = NULL;
++ }
++#endif
++}
++
++bool PulseSupport::isActive()
++{
++#ifdef HAVE_PULSEAUDIO
++ return s_pulseActive;
++#else
++ return false;
++#endif
++}
++
++void PulseSupport::disable()
++{
++#ifdef HAVE_PULSEAUDIO
++ s_pulseActive = false;
++#endif
++}
++
++QList<int> PulseSupport::objectDescriptionIndexes(ObjectDescriptionType type) const
++{
++ QList<int> list;
++
++ if (type != AudioOutputDeviceType && type != AudioCaptureDeviceType)
++ return list;
++
++#ifdef HAVE_PULSEAUDIO
++ if (s_pulseActive) {
++ switch (type) {
++
++ case AudioOutputDeviceType: {
++ QMap<QString, int>::iterator it;
++ for (it = s_outputDeviceIndexes.begin(); it != s_outputDeviceIndexes.end(); ++it) {
++ list.append(*it);
++ }
++ break;
++ }
++ case AudioCaptureDeviceType: {
++ QMap<QString, int>::iterator it;
++ for (it = s_captureDeviceIndexes.begin(); it != s_captureDeviceIndexes.end(); ++it) {
++ list.append(*it);
++ }
++ break;
++ }
++ default:
++ break;
++ }
++ }
++#endif
++
++ return list;
++}
++
++QHash<QByteArray, QVariant> PulseSupport::objectDescriptionProperties(ObjectDescriptionType type, int index) const
++{
++ QHash<QByteArray, QVariant> ret;
++
++ if (type != AudioOutputDeviceType && type != AudioCaptureDeviceType)
++ return ret;
++
++#ifndef HAVE_PULSEAUDIO
++ Q_UNUSED(index);
++#else
++ if (s_pulseActive) {
++ switch (type) {
++
++ case AudioOutputDeviceType:
++ Q_ASSERT(s_outputDevices.contains(index));
++ ret = s_outputDevices[index].properties;
++ break;
++
++ case AudioCaptureDeviceType:
++ Q_ASSERT(s_captureDevices.contains(index));
++ ret = s_captureDevices[index].properties;
++ break;
++
++ default:
++ break;
++ }
++ }
++#endif
++
++ return ret;
++}
++
++QList<int> PulseSupport::objectIndexesByCategory(ObjectDescriptionType type, Category category) const
++{
++ QList<int> ret;
++
++ if (type != AudioOutputDeviceType && type != AudioCaptureDeviceType)
++ return ret;
++
++#ifndef HAVE_PULSEAUDIO
++ Q_UNUSED(category);
++#else
++ if (s_pulseActive) {
++ switch (type) {
++
++ case AudioOutputDeviceType:
++ if (s_outputDevicePriorities.contains(category))
++ ret = s_outputDevicePriorities[category].values();
++ break;
++
++ case AudioCaptureDeviceType:
++ if (s_captureDevicePriorities.contains(category))
++ ret = s_captureDevicePriorities[category].values();
++ break;
++
++ default:
++ break;
++ }
++ }
++#endif
++
++ return ret;
++}
++
++#ifdef HAVE_PULSEAUDIO
++static void setDevicePriority(Category category, QStringList list)
++{
++ QString role = s_roleCategoryMap.key(category);
++ if (role.isEmpty())
++ return;
++
++ logMessage(QString("Reindexing %1: %2").arg(role).arg(list.join(", ")));
++
++ char **devices;
++ devices = pa_xnew(char *, list.size()+1);
++ int i = 0;
++ foreach (QString str, list) {
++ devices[i++] = pa_xstrdup(str.toUtf8().constData());
++ }
++ devices[list.size()] = NULL;
++
++ pa_operation *o;
++ if (!(o = pa_ext_device_manager_reorder_devices_for_role(s_context, role.toUtf8().constData(), (const char**)devices, NULL, NULL)))
++ logMessage(QString("pa_ext_device_manager_reorder_devices_for_role() failed"));
++ else
++ pa_operation_unref(o);
++
++ for (i = 0; i < list.size(); ++i)
++ pa_xfree(devices[i]);
++ pa_xfree(devices);
++}
++#endif
++
++void PulseSupport::setOutputDevicePriorityForCategory(Category category, QList<int> order)
++{
++#ifndef HAVE_PULSEAUDIO
++ Q_UNUSED(category);
++ Q_UNUSED(order);
++#else
++ QStringList list;
++ QList<int>::iterator it;
++
++ for (it = order.begin(); it != order.end(); ++it) {
++ if (s_outputDevices.contains(*it)) {
++ list << s_outputDeviceIndexes.key(*it);
++ }
++ }
++ setDevicePriority(category, list);
++#endif
++}
++
++void PulseSupport::setCaptureDevicePriorityForCategory(Category category, QList<int> order)
++{
++#ifndef HAVE_PULSEAUDIO
++ Q_UNUSED(category);
++ Q_UNUSED(order);
++#else
++ QStringList list;
++ QList<int>::iterator it;
++
++ for (it = order.begin(); it != order.end(); ++it) {
++ if (s_captureDevices.contains(*it)) {
++ list << s_captureDeviceIndexes.key(*it);
++ }
++ }
++ setDevicePriority(category, list);
++#endif
++}
++
++void PulseSupport::setStreamPropList(Category category, QString streamUuid)
++{
++#ifndef HAVE_PULSEAUDIO
++ Q_UNUSED(category);
++ Q_UNUSED(streamUuid);
++#else
++ QString role = s_roleCategoryMap.key(category);
++ if (role.isEmpty())
++ return;
++
++ logMessage(QString("Setting role to %1 for streamindex %2").arg(role).arg(streamUuid));
++ setenv("PULSE_PROP_media.role", role.toLatin1().constData(), 1);
++ setenv("PULSE_PROP_phonon.streamid", streamUuid.toLatin1().constData(), 1);
++#endif
++}
++
++void PulseSupport::emitObjectDescriptionChanged(ObjectDescriptionType type)
++{
++ emit objectDescriptionChanged(type);
++}
++
++bool PulseSupport::setOutputDevice(QString streamUuid, int device) {
++#ifndef HAVE_PULSEAUDIO
++ Q_UNUSED(streamUuid);
++ Q_UNUSED(device);
++ return false;
++#else
++ if (s_outputDevices.size() < 2)
++ return true;
++
++ if (!s_outputDevices.contains(device)) {
++ logMessage(QString("Attempting to set Output Device for invalid device id %1.").arg(device));
++ return false;
++ }
++ const QVariant var = s_outputDevices[device].properties["name"];
++ logMessage(QString("Attempting to set Output Device to '%1' for Output Stream %2").arg(var.toString()).arg(streamUuid));
++
++ s_outputStreamMoveQueue[streamUuid] = device;
++ // Attempt to look up the pulse stream index.
++ if (s_outputStreamIndexMap.contains(streamUuid) && s_outputStreamIndexMap[streamUuid] != PA_INVALID_INDEX) {
++ logMessage(QString("... Found in map. Moving now"));
++ set_output_device(streamUuid);
++ } else {
++ logMessage(QString("... Not found in map. Saving move for when the stream appears"));
++ }
++ return true;
++#endif
++}
++
++bool PulseSupport::setCaptureDevice(QString streamUuid, int device) {
++#ifndef HAVE_PULSEAUDIO
++ Q_UNUSED(streamUuid);
++ Q_UNUSED(device);
++ return false;
++#else
++ if (s_captureDevices.size() < 2)
++ return true;
++
++ if (!s_captureDevices.contains(device)) {
++ logMessage(QString("Attempting to set Capture Device for invalid device id %1.").arg(device));
++ return false;
++ }
++ const QVariant var = s_captureDevices[device].properties["name"];
++ logMessage(QString("Attempting to set Capture Device to '%1' for Capture Stream %2").arg(var.toString()).arg(streamUuid));
++
++ s_captureStreamMoveQueue[streamUuid] = device;
++ // Attempt to look up the pulse stream index.
++ if (s_captureStreamIndexMap.contains(streamUuid) && s_captureStreamIndexMap[streamUuid] == PA_INVALID_INDEX) {
++ logMessage(QString("... Found in map. Moving now"));
++ set_capture_device(streamUuid);
++ } else {
++ logMessage(QString("... Not found in map. Saving move for when the stream appears"));
++ }
++ return true;
++#endif
++}
++
++void PulseSupport::clearStreamCache(QString streamUuid) {
++#ifndef HAVE_PULSEAUDIO
++ Q_UNUSED(streamUuid);
++ return;
++#else
++ logMessage(QString("Clearing stream cache for stream %1").arg(streamUuid));
++ s_outputStreamIndexMap.remove(streamUuid);
++ s_outputStreamMoveQueue.remove(streamUuid);
++ s_captureStreamIndexMap.remove(streamUuid);
++ s_captureStreamMoveQueue.remove(streamUuid);
++#endif
++}
++
++} // namespace Phonon
++
++QT_END_NAMESPACE
++
++#include "moc_pulsesupport_p.cpp"
++
++// vim: sw=4 ts=4
+--- /dev/null
++++ b/phonon/pulsesupport_p.h
+@@ -0,0 +1,74 @@
++/* This file is part of the KDE project
++ Copyright (C) 2009 Colin Guthrie <cguthrie@mandriva.org>
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) version 3, or any
++ later version accepted by the membership of KDE e.V. (or its
++ successor approved by the membership of KDE e.V.), Nokia Corporation
++ (or its successors, if any) and the KDE Free Qt Foundation, which shall
++ act as a proxy defined in Section 6 of version 3 of the license.
++
++ This library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with this library. If not, see <http://www.gnu.org/licenses/>.
++
++*/
++
++#ifndef PHONON_PULSESUPPORT_H
++#define PHONON_PULSESUPPORT_H
++
++#include "phonon_export.h"
++#include "phononnamespace.h"
++#include "objectdescription.h"
++
++#include <QtCore/QtGlobal>
++#include <QtCore/QSet>
++
++QT_BEGIN_HEADER
++QT_BEGIN_NAMESPACE
++
++namespace Phonon
++{
++ class PHONON_EXPORT PulseSupport : public QObject
++ {
++ Q_OBJECT
++ public:
++ static PulseSupport* getInstance();
++ static void shutdown();
++
++ bool isActive();
++ void disable();
++
++ QList<int> objectDescriptionIndexes(ObjectDescriptionType type) const;
++ QHash<QByteArray, QVariant> objectDescriptionProperties(ObjectDescriptionType type, int index) const;
++ QList<int> objectIndexesByCategory(ObjectDescriptionType type, Category category) const;
++
++ void setOutputDevicePriorityForCategory(Category category, QList<int> order);
++ void setCaptureDevicePriorityForCategory(Category category, QList<int> order);
++
++ void setStreamPropList(Category category, QString streamUuid);
++ void emitObjectDescriptionChanged(ObjectDescriptionType);
++
++ bool setOutputDevice(QString streamUuid, int device);
++ bool setCaptureDevice(QString streamUuid, int device);
++ void clearStreamCache(QString streamUuid);
++
++ signals:
++ void objectDescriptionChanged(ObjectDescriptionType);
++ private:
++ PulseSupport();
++ ~PulseSupport();
++ };
++} // namespace Phonon
++
++QT_END_NAMESPACE
++QT_END_HEADER
++
++#endif // PHONON_PULSESUPPORT_H
++
+\ No newline at end of file
+--- a/src/3rdparty/phonon/phonon/qsettingsgroup_p.h
++++ b/src/3rdparty/phonon/phonon/qsettingsgroup_p.h
+@@ -27,8 +27,6 @@
+ #include <QtCore/QString>
+ #include <QtCore/QVariant>
+
+-#ifndef QT_NO_PHONON_SETTINGSGROUP
+-
+ QT_BEGIN_HEADER
+ QT_BEGIN_NAMESPACE
+
+@@ -89,6 +87,5 @@ class QSettingsGroup
+
+ QT_END_NAMESPACE
+ QT_END_HEADER
+-#endif //QT_NO_PHONON_SETTINGSGROUP
+
+ #endif // PHONON_QSETTINGSGROUP_P_H
+--- a/src/3rdparty/phonon/phonon/seekslider.cpp
++++ b/src/3rdparty/phonon/phonon/seekslider.cpp
+@@ -72,12 +72,12 @@ void SeekSlider::setMediaObject(MediaObj
+ d->media = media;
+
+ if (media) {
+- connect(media, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
++ connect(media, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
+ SLOT(_k_stateChanged(Phonon::State)));
+ connect(media, SIGNAL(totalTimeChanged(qint64)), SLOT(_k_length(qint64)));
+ connect(media, SIGNAL(tick(qint64)), SLOT(_k_tick(qint64)));
+ connect(media, SIGNAL(seekableChanged(bool)), SLOT(_k_seekableChanged(bool)));
+- connect(media, SIGNAL(currentSourceChanged(Phonon::MediaSource)), SLOT(_k_currentSourceChanged()));
++ connect(media, SIGNAL(currentSourceChanged(const Phonon::MediaSource&)), SLOT(_k_currentSourceChanged()));
+ d->_k_stateChanged(media->state());
+ d->_k_seekableChanged(media->isSeekable());
+ d->_k_length(media->totalTime());
+--- a/src/3rdparty/phonon/phonon/seekslider_p.h
++++ b/src/3rdparty/phonon/phonon/seekslider_p.h
+@@ -24,8 +24,8 @@
+ #define SEEKSLIDER_P_H
+
+ #include "seekslider.h"
++#include "swiftslider_p.h"
+ #include <QtGui/QBoxLayout>
+-#include <QtGui/QSlider>
+ #include <QtGui/QLabel>
+ #include <QtGui/QPixmap>
+ #include <QtGui/QIcon>
+@@ -84,7 +84,7 @@ class SeekSliderPrivate
+ void _k_currentSourceChanged();
+
+ QBoxLayout layout;
+- QSlider slider;
++ SwiftSlider slider;
+ QLabel iconLabel;
+ QPointer<MediaObject> media;
+ bool ticking;
+--- /dev/null
++++ b/phonon/swiftslider.cpp
+@@ -0,0 +1,103 @@
++/* This file is part of the KDE project
++ Copyright (C) 2006-2008 Ricardo Villalba <rvm@escomposlinux.org>
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) version 3, or any
++ later version accepted by the membership of KDE e.V. (or its
++ successor approved by the membership of KDE e.V.), Nokia Corporation
++ (or its successors, if any) and the KDE Free Qt Foundation, which shall
++ act as a proxy defined in Section 6 of version 3 of the license.
++
++ This library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with this library. If not, see <http://www.gnu.org/licenses/>.
++
++*/
++
++#include "swiftslider_p.h"
++
++#include <QtGui/QMouseEvent>
++#include <QtGui/QStyle>
++#include <QtGui/QStyleOption>
++
++QT_BEGIN_NAMESPACE
++
++#if !defined(QT_NO_PHONON_SEEKSLIDER) && !defined(QT_NO_PHONON_VOLUMESLIDER)
++
++namespace Phonon
++{
++
++SwiftSlider::SwiftSlider(Qt::Orientation orientation, QWidget * parent)
++ : QSlider(orientation, parent)
++{
++}
++
++SwiftSlider::~SwiftSlider()
++{
++}
++
++// Function copied from qslider.cpp
++inline int SwiftSlider::pick(const QPoint &pt) const
++{
++ return orientation() == Qt::Horizontal ? pt.x() : pt.y();
++}
++
++// Function copied from qslider.cpp and modified to make it compile
++int SwiftSlider::pixelPosToRangeValue(int pos) const
++{
++ QStyleOptionSlider opt;
++ initStyleOption(&opt);
++ QRect gr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this);
++ QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
++ int sliderMin, sliderMax, sliderLength;
++
++ if (orientation() == Qt::Horizontal) {
++ sliderLength = sr.width();
++ sliderMin = gr.x();
++ sliderMax = gr.right() - sliderLength + 1;
++ } else {
++ sliderLength = sr.height();
++ sliderMin = gr.y();
++ sliderMax = gr.bottom() - sliderLength + 1;
++ }
++ return QStyle::sliderValueFromPosition(minimum(), maximum(), pos - sliderMin,
++ sliderMax - sliderMin, opt.upsideDown);
++}
++
++// Based on code from qslider.cpp
++void SwiftSlider::mousePressEvent(QMouseEvent *event)
++{
++ if (event->button() == Qt::LeftButton) {
++ QStyleOptionSlider opt;
++ initStyleOption(&opt);
++ const QRect sliderRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
++ const QPoint center = sliderRect.center() - sliderRect.topLeft();
++ // to take half of the slider off for the setSliderPosition call we use the center - topLeft
++
++ if (!sliderRect.contains(event->pos())) {
++ event->accept();
++
++ setSliderPosition(pixelPosToRangeValue(pick(event->pos() - center)));
++ triggerAction(SliderMove);
++ setRepeatAction(SliderNoAction);
++ } else {
++ QSlider::mousePressEvent(event);
++ }
++ } else {
++ QSlider::mousePressEvent(event);
++ }
++}
++
++} // namespace Phonon
++
++#endif //QT_NO_PHONON_VOLUMESLIDER && QT_NO_PHONON_VOLUMESLIDER
++
++QT_END_NAMESPACE
++
++#include "moc_swiftslider_p.cpp"
+--- /dev/null
++++ b/phonon/swiftslider_p.h
+@@ -0,0 +1,68 @@
++/* This file is part of the KDE project
++ Copyright (C) 2006-2008 Ricardo Villalba <rvm@escomposlinux.org>
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) version 3, or any
++ later version accepted by the membership of KDE e.V. (or its
++ successor approved by the membership of KDE e.V.), Nokia Corporation
++ (or its successors, if any) and the KDE Free Qt Foundation, which shall
++ act as a proxy defined in Section 6 of version 3 of the license.
++
++ This library 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
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with this library. If not, see <http://www.gnu.org/licenses/>.
++
++*/
++
++#ifndef SWIFTSLIDER_H
++#define SWIFTSLIDER_H
++
++#include <QtGui/QSlider>
++
++QT_BEGIN_NAMESPACE
++
++#if !defined(QT_NO_PHONON_SEEKSLIDER) && !defined(QT_NO_PHONON_VOLUMESLIDER)
++
++namespace Phonon
++{
++
++/** \class SwiftSlider swiftslider_p.h Phonon/SwiftSlider
++ * \short Modified QSlider that allows sudden/quick moves instead of stepped moves ("Click'n'Go" QSlider)
++ *
++ * This is an internal class used by SeekSlider and VolumeSlider.
++ *
++ * Ricardo Villalba, the original author of MySlider.cpp (from the SMPlayer project)
++ * gave his permission for the inclusion of this code inside Phonon by
++ * switching MySlider.cpp to the LGPLv2.1+ license.
++ * See http://smplayer.svn.sourceforge.net/viewvc/smplayer/smplayer/trunk/src/myslider.cpp?revision=2406&view=markup
++ *
++ * The original discussion about a "Click'n'Go QSlider": http://lists.trolltech.com/qt-interest/2006-11/msg00363.html
++ *
++ * \ingroup PhononWidgets
++ */
++class SwiftSlider : public QSlider
++{
++ Q_OBJECT
++public:
++ SwiftSlider(Qt::Orientation orientation, QWidget * parent);
++ ~SwiftSlider();
++
++private:
++ void mousePressEvent(QMouseEvent *event);
++ inline int pick(const QPoint &pt) const;
++ int pixelPosToRangeValue(int pos) const;
++};
++
++} // namespace Phonon
++
++#endif //QT_NO_PHONON_VOLUMESLIDER && QT_NO_PHONON_VOLUMESLIDER
++
++QT_END_NAMESPACE
++
++#endif //SWIFTSLIDER_H
+--- a/src/3rdparty/phonon/phonon/videowidget.cpp
++++ b/src/3rdparty/phonon/phonon/videowidget.cpp
+@@ -28,8 +28,9 @@
+ #include "phononnamespace_p.h"
+
+ #include <QtGui/QAction>
+-
+-#define PHONON_INTERFACENAME VideoWidgetInterface
++#define IFACES4 VideoWidgetInterface44
++#define IFACES0 VideoWidgetInterface, IFACES4
++#define PHONON_INTERFACENAME IFACES0
+
+ QT_BEGIN_NAMESPACE
+
+@@ -48,6 +49,8 @@ VideoWidget::VideoWidget(QWidget *parent
+ setMouseTracking(true);
+ }
+
++
++
+ VideoWidget::VideoWidget(VideoWidgetPrivate &dd, QWidget *parent)
+ : QWidget(parent),
+ Phonon::AbstractVideoOutput(dd)
+@@ -98,6 +101,15 @@ PHONON_INTERFACE_SETTER(setHue, hue, qre
+ PHONON_INTERFACE_GETTER(qreal, saturation, d->saturation)
+ PHONON_INTERFACE_SETTER(setSaturation, saturation, qreal)
+
++
++QImage VideoWidget::snapshot() const {
++ K_D(const VideoWidget);
++ ConstIface<IFACES4> iface(d);
++ if(iface) return iface->snapshot();
++ return QImage(); // TODO not implemented in VideoInterface
++}
++
++
+ void VideoWidget::setFullScreen(bool newFullScreen)
+ {
+ pDebug() << Q_FUNC_INFO << newFullScreen;
+--- a/src/3rdparty/phonon/phonon/videowidget.h
++++ b/src/3rdparty/phonon/phonon/videowidget.h
+@@ -172,6 +172,7 @@ class AbstractVideoOutput;
+ qreal contrast() const;
+ qreal hue() const;
+ qreal saturation() const;
++ QImage snapshot() const;
+
+ //TODO: bar colors property
+ public Q_SLOTS:
+--- a/src/3rdparty/phonon/phonon/videowidgetinterface.h
++++ b/src/3rdparty/phonon/phonon/videowidgetinterface.h
+@@ -53,8 +53,21 @@ class VideoWidgetInterface
+ //X virtual int overlayCapabilities() const = 0;
+ //X virtual bool createOverlay(QWidget *widget, int type) = 0;
+ };
++
++class VideoWidgetInterface44 : public VideoWidgetInterface
++{
++ public:
++ virtual QImage snapshot() const = 0;
++};
+ }
+
++#ifdef PHONON_BACKEND_VERSION_4_4
++namespace Phonon { typedef VideoWidgetInterface44 VideoWidgetInterfaceLatest; }
++#else
++namespace Phonon { typedef VideoWidgetInterface VideoWidgetInterfaceLatest; }
++#endif
++
++Q_DECLARE_INTERFACE(Phonon::VideoWidgetInterface44, "VideoWidgetInterface44.phonon.kde.org")
+ Q_DECLARE_INTERFACE(Phonon::VideoWidgetInterface, "VideoWidgetInterface3.phonon.kde.org")
+
+ #endif //QT_NO_PHONON_VIDEO
+--- a/src/3rdparty/phonon/phonon/volumeslider.cpp
++++ b/src/3rdparty/phonon/phonon/volumeslider.cpp
+@@ -85,7 +85,7 @@ VolumeSlider::~VolumeSlider()
+
+ bool VolumeSlider::isMuteVisible() const
+ {
+- return !k_ptr->muteButton.isHidden();
++ return k_ptr->muteButton.isVisible();
+ }
+
+ void VolumeSlider::setMuteVisible(bool visible)
+--- a/src/3rdparty/phonon/phonon/volumeslider_p.h
++++ b/src/3rdparty/phonon/phonon/volumeslider_p.h
+@@ -24,8 +24,8 @@
+ #define VOLUMESLIDER_P_H
+
+ #include "volumeslider.h"
++#include "swiftslider_p.h"
+ #include <QtGui/QBoxLayout>
+-#include <QtGui/QSlider>
+ #include <QtGui/QLabel>
+ #include <QtGui/QPixmap>
+ #include <QtGui/QToolButton>
+@@ -83,7 +83,7 @@ class VolumeSliderPrivate
+
+ private:
+ QBoxLayout layout;
+- QSlider slider;
++ SwiftSlider slider;
+ QToolButton muteButton;
+ QIcon volumeIcon;
+ QIcon mutedIcon;
+--- a/src/3rdparty/phonon/waveout/mediaobject.cpp
++++ b/src/3rdparty/phonon/waveout/mediaobject.cpp
+@@ -247,7 +247,7 @@ namespace Phonon
+ m_stopped(0)
+ {
+ m_thread = new WorkerThread();
+- connect(this, SIGNAL(outOfData(QIODevice*,QByteArray*,bool*)), m_thread, SLOT(stream(QIODevice*,QByteArray*,bool*)));
++ connect(this, SIGNAL(outOfData(QIODevice*, QByteArray*, bool*)), m_thread, SLOT(stream(QIODevice*, QByteArray*, bool*)));
+ m_thread->start();
+ m_soundBuffer1.waveHeader = new WAVEHDR;
+ m_soundBuffer2.waveHeader = new WAVEHDR;
+@@ -258,7 +258,7 @@ namespace Phonon
+ MediaObject::~MediaObject()
+ {
+ stop();
+- disconnect(this, SIGNAL(outOfData(QIODevice*,QByteArray*,bool*)), m_thread, SLOT(stream(QIODevice*,QByteArray*,bool*)));
++ disconnect(this, SIGNAL(outOfData(QIODevice*, QByteArray*, bool*)), m_thread, SLOT(stream(QIODevice*, QByteArray*, bool*)));
+ do { //The event loop of m_thread might not be started, yet
+ m_thread->quit(); //If the event loop is not started yet quit() does nothing
+ m_thread->wait(100);
+@@ -281,8 +281,6 @@ namespace Phonon
+
+ bool MediaObject::isSeekable() const
+ {
+- if (!m_stream)
+- return false;
+ return !m_stream->isSequential();
+ }
+
diff --git a/debian/patches/series b/debian/patches/series
index 2b09b66..1a3a4b7 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -38,3 +38,4 @@
92_armel_gcc43_valist_compat.diff
95_sparc_platform_definition.diff
96_powerpc_no_gc_sections.diff
+97_update_phonon_4.3.80 \ No newline at end of file