[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