[SCM] qtmultimedia packaging branch, ubuntu, updated. ubuntu/5.5.1-4ubuntu2-2-g9da7ff1

Timo Jyrinki timo at moszumanska.debian.org
Wed Apr 13 10:43:15 UTC 2016


Gitweb-URL: http://git.debian.org/?p=pkg-kde/qt/qtmultimedia.git;a=commitdiff;h=9da7ff1

The following commit has been merged in the ubuntu branch:
commit 9da7ff1b043c54b634cc9b4289f4a8a5f9a31ff1
Author: Timo Jyrinki <timo.jyrinki at canonical.com>
Date:   Wed Apr 13 10:42:42 2016 +0000

    debian/patches/PulseAudio-change-the-way-volume-is-applied.patch:
    
    * debian/patches/PulseAudio-change-the-way-volume-is-applied.patch:
      - Backport from 5.6, change Pulseaudio volume control (LP: #1485522)
---
 debian/changelog                                   |   7 +-
 ...lseAudio-change-the-way-volume-is-applied.patch | 783 +++++++++++++++++++++
 debian/patches/series                              |   1 +
 3 files changed, 788 insertions(+), 3 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index 462f162..55f9179 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,9 @@
-qtmultimedia-opensource-src (5.5.1-4ubuntu3) UNRELEASED; urgency=medium
+qtmultimedia-opensource-src (5.5.1-4ubuntu3) xenial; urgency=medium
 
-  * 
+  * debian/patches/PulseAudio-change-the-way-volume-is-applied.patch:
+    - Backport from 5.6, change Pulseaudio volume control (LP: #1485522)
 
- -- Timo Jyrinki <timo-jyrinki at ubuntu.com>  Tue, 12 Apr 2016 09:29:26 +0000
+ -- Timo Jyrinki <timo-jyrinki at ubuntu.com>  Wed, 13 Apr 2016 10:41:46 +0000
 
 qtmultimedia-opensource-src (5.5.1-4ubuntu2) xenial; urgency=medium
 
diff --git a/debian/patches/PulseAudio-change-the-way-volume-is-applied.patch b/debian/patches/PulseAudio-change-the-way-volume-is-applied.patch
new file mode 100644
index 0000000..bcd078e
--- /dev/null
+++ b/debian/patches/PulseAudio-change-the-way-volume-is-applied.patch
@@ -0,0 +1,783 @@
+From b17e0cd5dd28b93b1ea567c676f0e183acb6dd7c Mon Sep 17 00:00:00 2001
+From: Yoann Lopes <yoann.lopes at theqtcompany.com>
+Date: Fri, 5 Feb 2016 14:07:20 +0100
+Subject: [PATCH] PulseAudio: change the way volume is applied.
+
+We used to change the PulseAudio sink input volume. Doing so had
+some potential unwanted side effects depending on the PulseAudio server
+configuration. When flat volumes were enabled, it would affect the
+global system volume. It could also affect the volume of other streams
+having the same audio role.
+Volumes in Qt Multimedia are supposed to be relative to the application
+volume and should not affect anything else than the object on which it
+was changed. To guarantee that, PulseAudio volume APIs are not used
+anymore. Instead, software-based volume attenuation is applied on the
+audio samples before being passed to PulseAudio.
+
+Applies to QSoundEffect, QAudioOutput and QAudioInput.
+
+Task-number: QTBUG-40823
+Task-number: QTBUG-49461
+Change-Id: I690716976bda8fe666969ca2cbdf6d8d0b419733
+Reviewed-by: Christian Stromme <christian.stromme at theqtcompany.com>
+---
+ src/multimedia/audio/qsoundeffect_pulse_p.cpp | 214 +++++++-------------------
+ src/multimedia/audio/qsoundeffect_pulse_p.h   |  13 +-
+ src/plugins/pulseaudio/qaudioinput_pulse.cpp  |  99 +++---------
+ src/plugins/pulseaudio/qaudioinput_pulse.h    |   8 +-
+ src/plugins/pulseaudio/qaudiooutput_pulse.cpp |  84 ++++------
+ src/plugins/pulseaudio/qaudiooutput_pulse.h   |   2 -
+ 6 files changed, 113 insertions(+), 307 deletions(-)
+
+diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.cpp b/src/multimedia/audio/qsoundeffect_pulse_p.cpp
+index ecc42ca..43d4a6c 100644
+--- a/src/multimedia/audio/qsoundeffect_pulse_p.cpp
++++ b/src/multimedia/audio/qsoundeffect_pulse_p.cpp
+@@ -49,10 +49,7 @@
+ 
+ #include "qsoundeffect_pulse_p.h"
+ 
+-#if defined(Q_WS_MAEMO_6) || defined(NEMO_AUDIO)
+-#include <pulse/ext-stream-restore.h>
+-#endif
+-
++#include <private/qaudiohelpers_p.h>
+ #include <private/qmediaresourcepolicy_p.h>
+ #include <private/qmediaresourceset_p.h>
+ 
+@@ -124,26 +121,9 @@ public:
+         return m_context;
+     }
+ 
+-    inline pa_cvolume * calcVolume(pa_cvolume *dest, int soundEffectVolume)
+-    {
+-        pa_volume_t v = m_vol * soundEffectVolume / 100;
+-        for (int i = 0; i < dest->channels; ++i)
+-            dest->values[i] = v;
+-        return dest;
+-    }
+-
+-    void updateStatus(const pa_cvolume& volume)
+-    {
+-        if (m_vol != pa_cvolume_max(&volume)) {
+-            m_vol = pa_cvolume_max(&volume);
+-            emit volumeChanged();
+-        }
+-    }
+-
+ Q_SIGNALS:
+     void contextReady();
+     void contextFailed();
+-    void volumeChanged();
+ 
+ private Q_SLOTS:
+     void onContextFailed()
+@@ -158,8 +138,6 @@ private Q_SLOTS:
+ 
+     void prepare()
+     {
+-        m_vol = PA_VOLUME_NORM;
+-
+         m_context = 0;
+         m_mainLoop = pa_threaded_mainloop_new();
+         if (m_mainLoop == 0) {
+@@ -232,11 +210,6 @@ private:
+             case PA_CONTEXT_SETTING_NAME:
+                 break;
+             case PA_CONTEXT_READY:
+-    #if defined(Q_WS_MAEMO_6) || defined(NEMO_AUDIO)
+-                pa_ext_stream_restore_read(c, &stream_restore_info_callback, self);
+-                pa_ext_stream_restore_set_subscribe_cb(c, &stream_restore_monitor_callback, self);
+-                pa_ext_stream_restore_subscribe(c, 1, 0, self);
+-    #endif
+                 QMetaObject::invokeMethod(self, "contextReady", Qt::QueuedConnection);
+                 break;
+             case PA_CONTEXT_FAILED:
+@@ -247,37 +220,6 @@ private:
+         }
+     }
+ 
+-#if defined(Q_WS_MAEMO_6) || defined(NEMO_AUDIO)
+-
+-    static void stream_restore_monitor_callback(pa_context *c, void *userdata)
+-    {
+-        PulseDaemon *self = reinterpret_cast<PulseDaemon*>(userdata);
+-        pa_ext_stream_restore_read(c, &stream_restore_info_callback, self);
+-    }
+-
+-    static void stream_restore_info_callback(pa_context *c,
+-            const pa_ext_stream_restore_info *info,
+-            int eol, void *userdata)
+-    {
+-        Q_UNUSED(c)
+-
+-        PulseDaemon *self = reinterpret_cast<PulseDaemon*>(userdata);
+-
+-        if (!eol) {
+-            if (QString(info->name).startsWith(QLatin1String("sink-input-by-media-role:x-maemo"))) {
+-#ifdef QT_PA_DEBUG
+-                qDebug() << "x-maemo volume =(" << info->volume.values[0] * 100 / PA_VOLUME_NORM << ","
+-                         << info->volume.values[1] * 100 / PA_VOLUME_NORM << "), "
+-                         << "mute = " << info->mute;
+-#endif
+-                self->updateStatus(info->volume);
+-            }
+-        }
+-    }
+-#endif
+-
+-    pa_volume_t m_vol;
+-
+     bool m_prepared;
+     pa_context *m_context;
+     pa_threaded_mainloop *m_mainLoop;
+@@ -385,9 +327,6 @@ QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent):
+     m_sample(0),
+     m_position(0),
+     m_resourcesAvailable(false)
+-#if defined(Q_WS_MAEMO_6) || defined(NEMO_AUDIO)
+-    , m_customVolume(false)
+-#endif
+ {
+     m_ref = new QSoundEffectRef(this);
+     pa_sample_spec_init(&m_pulseSpec);
+@@ -538,60 +477,32 @@ void QSoundEffectPrivate::setLoopCount(int loopCount)
+ 
+ qreal QSoundEffectPrivate::volume() const
+ {
++    QReadLocker locker(&m_volumeLock);
+     return m_volume;
+ }
+ 
+ void QSoundEffectPrivate::setVolume(qreal volume)
+ {
+-#if defined(Q_WS_MAEMO_6) || defined(NEMO_AUDIO)
+-    m_customVolume = true;
+-#endif
+-    m_volume = volume;
+-    emit volumeChanged();
+-    updateVolume();
+-}
++    QWriteLocker locker(&m_volumeLock);
+ 
+-void QSoundEffectPrivate::updateVolume()
+-{
+-    if (m_sinkInputId < 0)
++    if (qFuzzyCompare(m_volume, volume))
+         return;
+-#if defined(Q_WS_MAEMO_6) || defined(NEMO_AUDIO)
+-    if (!m_customVolume)
+-        return;
+-#endif
+-    PulseDaemonLocker locker;
+-    pa_cvolume volume;
+-    volume.channels = m_pulseSpec.channels;
+-    if (pulseDaemon()->context())
+-        pa_operation_unref(pa_context_set_sink_input_volume(pulseDaemon()->context(), m_sinkInputId, pulseDaemon()->calcVolume(&volume, qRound(m_volume * 100)), setvolume_callback, m_ref->getRef()));
+-    Q_ASSERT(pa_cvolume_valid(&volume));
+-#ifdef QT_PA_DEBUG
+-    qDebug() << this << "updateVolume =" << pa_cvolume_max(&volume);
+-#endif
++
++    m_volume = qBound(qreal(0), volume, qreal(1));
++    emit volumeChanged();
+ }
+ 
+ bool QSoundEffectPrivate::isMuted() const
+ {
++    QReadLocker locker(&m_volumeLock);
+     return m_muted;
+ }
+ 
+ void QSoundEffectPrivate::setMuted(bool muted)
+ {
++    QWriteLocker locker(&m_volumeLock);
+     m_muted = muted;
+     emit mutedChanged();
+-    updateMuted();
+-}
+-
+-void QSoundEffectPrivate::updateMuted()
+-{
+-    if (m_sinkInputId < 0)
+-        return;
+-    PulseDaemonLocker locker;
+-    if (pulseDaemon()->context())
+-        pa_operation_unref(pa_context_set_sink_input_mute(pulseDaemon()->context(), m_sinkInputId, m_muted, setmuted_callback, m_ref->getRef()));
+-#ifdef QT_PA_DEBUG
+-    qDebug() << this << "updateMuted = " << m_muted;
+-#endif
+ }
+ 
+ bool QSoundEffectPrivate::isLoaded() const
+@@ -801,7 +712,6 @@ void QSoundEffectPrivate::unloadPulseStream()
+         pa_stream_set_underflow_callback(m_pulseStream, 0, 0);
+         pa_stream_disconnect(m_pulseStream);
+         pa_stream_unref(m_pulseStream);
+-        disconnect(pulseDaemon(), SIGNAL(volumeChanged()), this, SLOT(updateVolume()));
+         disconnect(pulseDaemon(), SIGNAL(contextFailed()), this, SLOT(contextFailed()));
+         m_pulseStream = 0;
+         m_reloadCategory = false; // category will be reloaded when we connect anyway
+@@ -822,11 +732,8 @@ void QSoundEffectPrivate::prepare()
+              << "actual writeBytes =" << writeBytes
+              << "m_playQueued =" << m_playQueued;
+ #endif
+-    m_position = int(writeBytes);
+-    if (pa_stream_write(m_pulseStream, reinterpret_cast<void *>(const_cast<char*>(m_sample->data().data())), writeBytes,
+-                        stream_write_done_callback, 0, PA_SEEK_RELATIVE) != 0) {
+-        qWarning("QSoundEffect(pulseaudio): pa_stream_write, error = %s", pa_strerror(pa_context_errno(pulseDaemon()->context())));
+-    }
++    m_position = writeToStream(m_sample->data().data(), writeBytes);
++
+     if (m_playQueued) {
+         m_playQueued = false;
+         setLoopsRemaining(m_loopCount);
+@@ -854,15 +761,13 @@ void QSoundEffectPrivate::uploadSample()
+         }
+     }
+ 
+-    int writtenBytes = 0;
+     int writableSize = int(pa_stream_writable_size(m_pulseStream));
+     int firstPartLength = qMin(m_sample->data().size() - m_position, writableSize);
+-    if (pa_stream_write(m_pulseStream, reinterpret_cast<void *>(const_cast<char*>(m_sample->data().data()) + m_position),
+-                        firstPartLength, stream_write_done_callback, 0, PA_SEEK_RELATIVE) != 0) {
+-        qWarning("QSoundEffect(pulseaudio): pa_stream_write, error = %s", pa_strerror(pa_context_errno(pulseDaemon()->context())));
+-    }
+-    writtenBytes = firstPartLength;
+-    m_position += firstPartLength;
++
++    int writtenBytes = writeToStream(m_sample->data().data() + m_position,
++                                     firstPartLength);
++
++    m_position += writtenBytes;
+     if (m_position == m_sample->data().size()) {
+         m_position = 0;
+         if (m_runningCount > 0)
+@@ -871,11 +776,8 @@ void QSoundEffectPrivate::uploadSample()
+         {
+             while (writtenBytes < writableSize) {
+                 int writeSize = qMin(writableSize - writtenBytes, m_sample->data().size());
+-                if (pa_stream_write(m_pulseStream, reinterpret_cast<void *>(const_cast<char*>(m_sample->data().data())),
+-                                    writeSize, stream_write_done_callback, 0, PA_SEEK_RELATIVE) != 0) {
+-                    qWarning("QSoundEffect(pulseaudio): pa_stream_write, error = %s", pa_strerror(pa_context_errno(pulseDaemon()->context())));
+-                }
+-                writtenBytes += writeSize;
++                writtenBytes += writeToStream(m_sample->data().data(), writeSize);
++
+                 if (writeSize < m_sample->data().size()) {
+                     m_position = writeSize;
+                     break;
+@@ -893,6 +795,39 @@ void QSoundEffectPrivate::uploadSample()
+ #endif
+ }
+ 
++int QSoundEffectPrivate::writeToStream(const void *data, int size)
++{
++    m_volumeLock.lockForRead();
++    qreal volume = m_muted ? 0 : m_volume;
++    m_volumeLock.unlock();
++    pa_free_cb_t writeDoneCb = stream_write_done_callback;
++
++    if (volume < 1.0f) {
++        // Don't use PulseAudio volume, as it might affect all other streams of the same category
++        // or even affect the system volume if flat volumes are enabled
++        void *dest = NULL;
++        size_t nbytes = size;
++        if (pa_stream_begin_write(m_pulseStream, &dest, &nbytes) < 0) {
++            qWarning("QSoundEffect(pulseaudio): pa_stream_begin_write, error = %s",
++                     pa_strerror(pa_context_errno(pulseDaemon()->context())));
++            return 0;
++        }
++
++        size = int(nbytes);
++        QAudioHelperInternal::qMultiplySamples(volume, m_sample->format(), data, dest, size);
++        data = dest;
++        writeDoneCb = NULL;
++    }
++
++    if (pa_stream_write(m_pulseStream, data, size, writeDoneCb, 0, PA_SEEK_RELATIVE) < 0) {
++        qWarning("QSoundEffect(pulseaudio): pa_stream_write, error = %s",
++                 pa_strerror(pa_context_errno(pulseDaemon()->context())));
++        return 0;
++    }
++
++    return size;
++}
++
+ void QSoundEffectPrivate::playSample()
+ {
+ #ifdef QT_PA_DEBUG
+@@ -939,8 +874,6 @@ void QSoundEffectPrivate::streamReady()
+ #endif
+     PulseDaemonLocker locker;
+     m_sinkInputId =  pa_stream_get_index(m_pulseStream);
+-    updateMuted();
+-    updateVolume();
+ #ifdef QT_PA_DEBUG
+     const pa_buffer_attr *realBufAttr = pa_stream_get_buffer_attr(m_pulseStream);
+     qDebug() << this << "m_sinkInputId =" << m_sinkInputId
+@@ -966,7 +899,6 @@ void QSoundEffectPrivate::createPulseStream()
+     pa_stream *stream = pa_stream_new_with_proplist(pulseDaemon()->context(), m_name.constData(), &m_pulseSpec, 0, propList);
+     pa_proplist_free(propList);
+ 
+-    connect(pulseDaemon(), SIGNAL(volumeChanged()), this, SLOT(updateVolume()));
+     connect(pulseDaemon(), SIGNAL(contextFailed()), this, SLOT(contextFailed()));
+ 
+     if (stream == 0) {
+@@ -994,9 +926,7 @@ void QSoundEffectPrivate::createPulseStream()
+ #else
+     if (pa_stream_connect_playback(m_pulseStream, 0, 0,
+ #endif
+-                                   m_muted ? pa_stream_flags_t(PA_STREAM_START_MUTED | PA_STREAM_START_CORKED)
+-                                           : pa_stream_flags_t(PA_STREAM_START_UNMUTED | PA_STREAM_START_CORKED),
+-                                   0, 0) < 0) {
++                                   PA_STREAM_START_CORKED, 0, 0) < 0) {
+         qWarning("QSoundEffect(pulseaudio): Failed to connect stream, error = %s",
+                  pa_strerror(pa_context_errno(pulseDaemon()->context())));
+     }
+@@ -1115,46 +1045,6 @@ void QSoundEffectPrivate::stream_adjust_prebuffer_callback(pa_stream *s, int suc
+     QMetaObject::invokeMethod(self, "streamReady", Qt::QueuedConnection);
+ }
+ 
+-void QSoundEffectPrivate::setvolume_callback(pa_context *c, int success, void *userdata)
+-{
+-#ifdef QT_PA_DEBUG
+-    qDebug() << "setvolume_callback";
+-#endif
+-    Q_UNUSED(c);
+-    Q_UNUSED(userdata);
+-    QSoundEffectRef *ref = reinterpret_cast<QSoundEffectRef*>(userdata);
+-    QSoundEffectPrivate *self = ref->soundEffect();
+-    ref->release();
+-    if (!self)
+-        return;
+-#ifdef QT_PA_DEBUG
+-    qDebug() << self << "setvolume_callback";
+-#endif
+-    if (!success) {
+-        qWarning("QSoundEffect(pulseaudio): faild to set volume");
+-    }
+-}
+-
+-void QSoundEffectPrivate::setmuted_callback(pa_context *c, int success, void *userdata)
+-{
+-#ifdef QT_PA_DEBUG
+-    qDebug() << "setmuted_callback";
+-#endif
+-    Q_UNUSED(c);
+-    Q_UNUSED(userdata);
+-    QSoundEffectRef *ref = reinterpret_cast<QSoundEffectRef*>(userdata);
+-    QSoundEffectPrivate *self = ref->soundEffect();
+-    ref->release();
+-    if (!self)
+-        return;
+-#ifdef QT_PA_DEBUG
+-    qDebug() << self << "setmuted_callback";
+-#endif
+-    if (!success) {
+-        qWarning("QSoundEffect(pulseaudio): faild to set muted");
+-    }
+-}
+-
+ void QSoundEffectPrivate::stream_underrun_callback(pa_stream *s, void *userdata)
+ {
+     Q_UNUSED(s);
+diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.h b/src/multimedia/audio/qsoundeffect_pulse_p.h
+index 9b3564c..0f16b98 100644
+--- a/src/multimedia/audio/qsoundeffect_pulse_p.h
++++ b/src/multimedia/audio/qsoundeffect_pulse_p.h
+@@ -50,6 +50,7 @@
+ 
+ #include <QtCore/qobject.h>
+ #include <QtCore/qdatetime.h>
++#include <QtCore/qreadwritelock.h>
+ #include <qmediaplayer.h>
+ #include <pulse/pulseaudio.h>
+ #include "qsamplecache_p.h"
+@@ -111,8 +112,6 @@ private Q_SLOTS:
+     void prepare();
+     void streamReady();
+     void emptyComplete(void *stream);
+-    void updateVolume();
+-    void updateMuted();
+ 
+     void handleAvailabilityChanged(bool available);
+ 
+@@ -124,6 +123,8 @@ private:
+     void createPulseStream();
+     void unloadPulseStream();
+ 
++    int writeToStream(const void *data, int size);
++
+     void setPlaying(bool playing);
+     void setStatus(QSoundEffect::Status status);
+     void setLoopsRemaining(int loopsRemaining);
+@@ -136,8 +137,6 @@ private:
+     static void stream_write_done_callback(void *p);
+     static void stream_adjust_prebuffer_callback(pa_stream *s, int success, void *userdata);
+     static void stream_reset_buffer_callback(pa_stream *s, int success, void *userdata);
+-    static void setvolume_callback(pa_context *c, int success, void *userdata);
+-    static void setmuted_callback(pa_context *c, int success, void *userdata);
+ 
+     pa_stream *m_pulseStream;
+     int        m_sinkInputId;
+@@ -165,11 +164,9 @@ private:
+ 
+     bool m_resourcesAvailable;
+ 
+-    QMediaPlayerResourceSetInterface *m_resources;
++    mutable QReadWriteLock m_volumeLock;
+ 
+-#if defined(Q_WS_MAEMO_6) || defined(NEMO_AUDIO)
+-    bool m_customVolume;
+-#endif
++    QMediaPlayerResourceSetInterface *m_resources;
+ };
+ 
+ QT_END_NAMESPACE
+diff --git a/src/plugins/pulseaudio/qaudioinput_pulse.cpp b/src/plugins/pulseaudio/qaudioinput_pulse.cpp
+index 77b438f..93d4105 100644
+--- a/src/plugins/pulseaudio/qaudioinput_pulse.cpp
++++ b/src/plugins/pulseaudio/qaudioinput_pulse.cpp
+@@ -34,6 +34,7 @@
+ #include <QtCore/qcoreapplication.h>
+ #include <QtCore/qdebug.h>
+ #include <QtCore/qmath.h>
++#include <private/qaudiohelpers_p.h>
+ 
+ #include "qaudioinput_pulse.h"
+ #include "qaudiodeviceinfo_pulse.h"
+@@ -118,32 +119,6 @@ static void inputStreamSuccessCallback(pa_stream *stream, int success, void *use
+     pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
+ }
+ 
+-void QPulseAudioInput::sourceInfoCallback(pa_context *context, const pa_source_info *i, int eol, void *userdata)
+-{
+-    Q_UNUSED(context);
+-    Q_UNUSED(eol);
+-
+-    Q_ASSERT(userdata);
+-    if (i) {
+-        QPulseAudioInput *that = reinterpret_cast<QPulseAudioInput*>(userdata);
+-        that->m_volume = pa_sw_volume_to_linear(pa_cvolume_avg(&i->volume));
+-    }
+-}
+-
+-void QPulseAudioInput::inputVolumeCallback(pa_context *context, int success, void *userdata)
+-{
+-    Q_UNUSED(success);
+-
+-    if (!success)
+-        qWarning() << "QAudioInput: failed to set input volume";
+-
+-    QPulseAudioInput *that = reinterpret_cast<QPulseAudioInput*>(userdata);
+-
+-    // Regardless of success or failure, we update the volume property
+-    if (that->m_stream)
+-        pa_context_get_source_info_by_index(context, pa_stream_get_device_index(that->m_stream), sourceInfoCallback, userdata);
+-}
+-
+ QPulseAudioInput::QPulseAudioInput(const QByteArray &device)
+     : m_totalTimeValue(0)
+     , m_audioSource(0)
+@@ -356,8 +330,6 @@ bool QPulseAudioInput::open()
+     if (actualBufferAttr->tlength != (uint32_t)-1)
+         m_bufferSize = actualBufferAttr->tlength;
+ 
+-    setPulseVolume();
+-
+     pulseEngine->unlock();
+ 
+     connect(pulseEngine, &QPulseAudioEngine::contextFailed, this, &QPulseAudioInput::onPulseContextFailed);
+@@ -407,32 +378,6 @@ void QPulseAudioInput::close()
+     m_opened = false;
+ }
+ 
+-/* Call this with the stream opened and the mainloop locked */
+-void QPulseAudioInput::setPulseVolume()
+-{
+-    QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+-    Q_ASSERT(pulseEngine->context() != 0);
+-
+-    pa_cvolume cvolume;
+-
+-    if (qFuzzyCompare(m_volume, 0.0)) {
+-        pa_cvolume_mute(&cvolume, m_spec.channels);
+-    } else {
+-        pa_cvolume_set(&cvolume, m_spec.channels, pa_sw_volume_from_linear(m_volume));
+-    }
+-
+-    pa_operation *op = pa_context_set_source_volume_by_index(pulseEngine->context(),
+-            pa_stream_get_device_index(m_stream),
+-            &cvolume,
+-            inputVolumeCallback,
+-            this);
+-
+-    if (op == NULL)
+-        qWarning() << "QAudioInput: Failed to set volume";
+-    else
+-        pa_operation_unref(op);
+-}
+-
+ int QPulseAudioInput::checkBytesReady()
+ {
+     if (m_deviceState != QAudio::ActiveState && m_deviceState != QAudio::IdleState) {
+@@ -494,7 +439,9 @@ qint64 QPulseAudioInput::read(char *data, qint64 len)
+ 
+         qint64 actualLength = 0;
+         if (m_pullMode) {
+-            actualLength = m_audioSource->write(static_cast<const char *>(audioBuffer), readLength);
++            QByteArray adjusted(readLength, Qt::Uninitialized);
++            applyVolume(audioBuffer, adjusted.data(), readLength);
++            actualLength = m_audioSource->write(adjusted);
+ 
+             if (actualLength < qint64(readLength)) {
+                 pulseEngine->unlock();
+@@ -506,7 +453,7 @@ qint64 QPulseAudioInput::read(char *data, qint64 len)
+             }
+         } else {
+             actualLength = qMin(static_cast<int>(len - readBytes), static_cast<int>(readLength));
+-            memcpy(data + readBytes, audioBuffer, actualLength);
++            applyVolume(audioBuffer, data + readBytes, actualLength);
+         }
+ 
+ #ifdef DEBUG_PULSE
+@@ -517,7 +464,10 @@ qint64 QPulseAudioInput::read(char *data, qint64 len)
+ #ifdef DEBUG_PULSE
+             qDebug() << "QPulseAudioInput::read -- appending " << readLength - actualLength << " bytes of data to temp buffer";
+ #endif
+-            m_tempBuffer.append(static_cast<const char *>(audioBuffer) + actualLength, readLength - actualLength);
++            int diff = readLength - actualLength;
++            int oldSize = m_tempBuffer.size();
++            m_tempBuffer.resize(m_tempBuffer.size() + diff);
++            applyVolume(static_cast<const char *>(audioBuffer) + actualLength, m_tempBuffer.data() + oldSize, diff);
+             QMetaObject::invokeMethod(this, "userFeed", Qt::QueuedConnection);
+         }
+ 
+@@ -544,6 +494,14 @@ qint64 QPulseAudioInput::read(char *data, qint64 len)
+     return readBytes;
+ }
+ 
++void QPulseAudioInput::applyVolume(const void *src, void *dest, int len)
++{
++    if (m_volume < 1.f)
++        QAudioHelperInternal::qMultiplySamples(m_volume, m_format, src, dest, len);
++    else
++        memcpy(dest, src, len);
++}
++
+ void QPulseAudioInput::resume()
+ {
+     if (m_deviceState == QAudio::SuspendedState || m_deviceState == QAudio::IdleState) {
+@@ -567,29 +525,17 @@ void QPulseAudioInput::resume()
+ 
+ void QPulseAudioInput::setVolume(qreal vol)
+ {
+-    if (vol >= 0.0 && vol <= 1.0) {
+-        QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+-        pulseEngine->lock();
+-        if (!qFuzzyCompare(m_volume, vol)) {
+-            m_volume = vol;
+-            if (m_opened) {
+-                setPulseVolume();
+-            }
+-        }
+-        pulseEngine->unlock();
+-    }
++    if (qFuzzyCompare(m_volume, vol))
++        return;
++
++    m_volume = qBound(qreal(0), vol, qreal(1));
+ }
+ 
+ qreal QPulseAudioInput::volume() const
+ {
+-    QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+-    pulseEngine->lock();
+-    qreal vol = m_volume;
+-    pulseEngine->unlock();
+-    return vol;
++    return m_volume;
+ }
+ 
+-
+ void QPulseAudioInput::setBufferSize(int value)
+ {
+     m_bufferSize = value;
+diff --git a/src/plugins/pulseaudio/qaudioinput_pulse.h b/src/plugins/pulseaudio/qaudioinput_pulse.h
+index 7b898c4..c130f8c 100644
+--- a/src/plugins/pulseaudio/qaudioinput_pulse.h
++++ b/src/plugins/pulseaudio/qaudioinput_pulse.h
+@@ -100,7 +100,6 @@ public:
+     QAudio::Error m_errorState;
+     QAudio::State m_deviceState;
+     qreal m_volume;
+-    pa_cvolume m_chVolume;
+ 
+ private slots:
+     void userFeed();
+@@ -112,15 +110,14 @@ private:
+     void setState(QAudio::State state);
+     void setError(QAudio::Error error);
+ 
++    void applyVolume(const void *src, void *dest, int len);
++
+     int checkBytesReady();
+     bool open();
+     void close();
+-    void setPulseVolume();
+ 
+     static QMap<void *, QPulseAudioInput*> s_inputsMap;
+ 
+-    static void sourceInfoCallback(pa_context *c, const pa_source_info *i, int eol, void *userdata);
+-    static void inputVolumeCallback(pa_context *context, int success, void *userdata);
+ 
+     bool m_pullMode;
+     bool m_opened;
+diff --git a/src/plugins/pulseaudio/qaudiooutput_pulse.cpp b/src/plugins/pulseaudio/qaudiooutput_pulse.cpp
+index c1d46fa..a850c9b 100644
+--- a/src/plugins/pulseaudio/qaudiooutput_pulse.cpp
++++ b/src/plugins/pulseaudio/qaudiooutput_pulse.cpp
+@@ -34,6 +34,7 @@
+ #include <QtCore/qcoreapplication.h>
+ #include <QtCore/qdebug.h>
+ #include <QtCore/qmath.h>
++#include <private/qaudiohelpers_p.h>
+ 
+ #include "qaudiooutput_pulse.h"
+ #include "qaudiodeviceinfo_pulse.h"
+@@ -162,7 +163,6 @@ QPulseAudioOutput::QPulseAudioOutput(const QByteArray &device)
+     , m_audioBuffer(0)
+     , m_resuming(false)
+     , m_volume(1.0)
+-    , m_customVolumeRequired(false)
+ {
+     connect(m_tickTimer, SIGNAL(timeout()), SLOT(userFeed()));
+ }
+@@ -312,27 +312,6 @@ bool QPulseAudioOutput::open()
+     pa_stream_set_overflow_callback(m_stream, outputStreamOverflowCallback, this);
+     pa_stream_set_latency_update_callback(m_stream, outputStreamLatencyCallback, this);
+ 
+-    pa_volume_t paVolume;
+-
+-    /* streams without a custom volume set are expected to already have a
+-     * sensible volume set by Pulse, so we don't set it explicitly.
+-     *
+-     * explicit setting also breaks volume handling on sailfish, where each
+-     * stream's volume is set separately inside pulseaudio, with the
+-     * exception of streams that already have a volume set (i.e. if we set
+-     * it here, we'd ignore system volume).
+-     */
+-    if (m_customVolumeRequired) {
+-        if (qFuzzyCompare(m_volume, 0.0)) {
+-            paVolume = PA_VOLUME_MUTED;
+-            m_volume = 0.0;
+-        } else {
+-            paVolume = qFloor(m_volume * PA_VOLUME_NORM + 0.5);
+-        }
+-
+-        pa_cvolume_set(&m_chVolume, m_spec.channels, paVolume);
+-    }
+-
+     if (m_bufferSize <= 0 && m_category == LOW_LATENCY_CATEGORY_NAME) {
+         m_bufferSize = bytesPerSecond * LowLatencyBufferSizeMs / qint64(1000);
+     }
+@@ -344,7 +323,7 @@ bool QPulseAudioOutput::open()
+     requestedBuffer.prebuf = (uint32_t)-1;
+     requestedBuffer.tlength = m_bufferSize;
+ 
+-    if (pa_stream_connect_playback(m_stream, m_device.data(), (m_bufferSize > 0) ? &requestedBuffer : NULL, (pa_stream_flags_t)0, m_customVolumeRequired ? &m_chVolume : NULL, NULL) < 0) {
++    if (pa_stream_connect_playback(m_stream, m_device.data(), (m_bufferSize > 0) ? &requestedBuffer : NULL, (pa_stream_flags_t)0, NULL, NULL) < 0) {
+         qWarning() << "pa_stream_connect_playback() failed!";
+         pa_stream_unref(m_stream);
+         m_stream = 0;
+@@ -491,8 +470,33 @@ qint64 QPulseAudioOutput::write(const char *data, qint64 len)
+     QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+ 
+     pulseEngine->lock();
++
+     len = qMin(len, static_cast<qint64>(pa_stream_writable_size(m_stream)));
+-    pa_stream_write(m_stream, data, len, 0, 0, PA_SEEK_RELATIVE);
++
++    if (m_volume < 1.0f) {
++        // Don't use PulseAudio volume, as it might affect all other streams of the same category
++        // or even affect the system volume if flat volumes are enabled
++        void *dest = NULL;
++        size_t nbytes = len;
++        if (pa_stream_begin_write(m_stream, &dest, &nbytes) < 0) {
++            qWarning("QAudioOutput(pulseaudio): pa_stream_begin_write, error = %s",
++                     pa_strerror(pa_context_errno(pulseEngine->context())));
++            setError(QAudio::IOError);
++            return 0;
++        }
++
++        len = int(nbytes);
++        QAudioHelperInternal::qMultiplySamples(m_volume, m_format, data, dest, len);
++        data = reinterpret_cast<char *>(dest);
++    }
++
++    if (pa_stream_write(m_stream, data, len, NULL, 0, PA_SEEK_RELATIVE) < 0) {
++        qWarning("QAudioOutput(pulseaudio): pa_stream_write, error = %s",
++                 pa_strerror(pa_context_errno(pulseEngine->context())));
++        setError(QAudio::IOError);
++        return 0;
++    }
++
+     pulseEngine->unlock();
+     m_totalTimeValue += len;
+ 
+@@ -664,34 +668,10 @@ qint64 PulseOutputPrivate::writeData(const char *data, qint64 len)
+ 
+ void QPulseAudioOutput::setVolume(qreal vol)
+ {
+-    if (vol >= 0.0 && vol <= 1.0) {
+-        if (!qFuzzyCompare(m_volume, vol)) {
+-            m_customVolumeRequired = true;
+-            m_volume = vol;
+-            if (m_opened) {
+-                QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+-                pulseEngine->lock();
+-                pa_volume_t paVolume;
+-                if (qFuzzyCompare(vol, 0.0)) {
+-                    pa_cvolume_mute(&m_chVolume, m_spec.channels);
+-                    m_volume = 0.0;
+-                } else {
+-                    paVolume = qFloor(m_volume * PA_VOLUME_NORM + 0.5);
+-                    pa_cvolume_set(&m_chVolume, m_spec.channels, paVolume);
+-                }
+-                pa_operation *op = pa_context_set_sink_input_volume(pulseEngine->context(),
+-                        pa_stream_get_index(m_stream),
+-                        &m_chVolume,
+-                        NULL,
+-                        NULL);
+-                if (op == NULL)
+-                    qWarning()<<"QAudioOutput: Failed to set volume";
+-                else
+-                    pa_operation_unref(op);
+-                pulseEngine->unlock();
+-            }
+-        }
+-    }
++    if (qFuzzyCompare(m_volume, vol))
++        return;
++
++    m_volume = qBound(qreal(0), vol, qreal(1));
+ }
+ 
+ qreal QPulseAudioOutput::volume() const
+diff --git a/src/plugins/pulseaudio/qaudiooutput_pulse.h b/src/plugins/pulseaudio/qaudiooutput_pulse.h
+index e24fd51..a165da8 100644
+--- a/src/plugins/pulseaudio/qaudiooutput_pulse.h
++++ b/src/plugins/pulseaudio/qaudiooutput_pulse.h
+@@ -135,8 +135,6 @@ private:
+     QString m_category;
+ 
+     qreal m_volume;
+-    bool m_customVolumeRequired;
+-    pa_cvolume m_chVolume;
+     pa_sample_spec m_spec;
+ };
+ 
+-- 
+2.7.4
+
diff --git a/debian/patches/series b/debian/patches/series
index 7d3214d..9f231d4 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -9,6 +9,7 @@ Change-the-way-a-playlist-is-bound-to-a-media-object.patch
 Added-addItems-to-QML-Playlist-for-batch-adding-of-t.patch
 Added-insertItems-and-removeItems-to-QML-Playlist.patch
 Add-moveItem-from-to-to-QMediaPlaylist.patch
+PulseAudio-change-the-way-volume-is-applied.patch
 
 # Ubuntu patches
 backport_adjustments.patch

-- 
qtmultimedia packaging



More information about the pkg-kde-commits mailing list