diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.cpp b/src/multimedia/audio/qsoundeffect_pulse_p.cpp
index ecc42cac57258cd35e7b0f161b20e01ad9416faf..43d4a6cb0a062347a95fcab37c619b86bb7a2ea4 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 9b3564cc9d2df43087836c05ab30e62b1ce99db5..0f16b98a2f3a5ef096c936673c66c592290678b5 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 77b438ff9b0dafe8c39033d342bb2d9d0ae10575..93d4105980f02861d799f2d44446ed7fc85b13a2 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,39 +119,12 @@ 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)
     , m_errorState(QAudio::NoError)
     , m_deviceState(QAudio::StoppedState)
     , m_volume(qreal(1.0f))
-    , m_customVolumeRequired(false)
     , m_pullMode(true)
     , m_opened(false)
     , m_bytesAvailable(0)
@@ -356,9 +330,6 @@ bool QPulseAudioInput::open()
     if (actualBufferAttr->tlength != (uint32_t)-1)
         m_bufferSize = actualBufferAttr->tlength;
 
-    if (m_customVolumeRequired)
-        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,30 +525,17 @@ void QPulseAudioInput::resume()
 
 void QPulseAudioInput::setVolume(qreal vol)
 {
-    if (vol >= 0.0 && vol <= 1.0) {
-        QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
-        pulseEngine->lock();
-        m_customVolumeRequired = true;
-        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 7b898c480343ec62fe604c70d1a2099d22bcd678..c130f8cac25c2d1d8cfe0f2db7685e966fb3b38f 100644
--- a/src/plugins/pulseaudio/qaudioinput_pulse.h
+++ b/src/plugins/pulseaudio/qaudioinput_pulse.h
@@ -100,8 +100,6 @@ public:
     QAudio::Error m_errorState;
     QAudio::State m_deviceState;
     qreal m_volume;
-    bool m_customVolumeRequired;
-    pa_cvolume m_chVolume;
 
 private slots:
     void userFeed();
@@ -112,13 +110,11 @@ 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 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 c1d46fac4260bc4b1104ea00eec04942fbb759bf..a850c9b0e170a63bd56a28a8358f27d07642eb5c 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 e24fd514babccea6c6e57b76721d5c9928941f48..a165da86afe1a9f4d019d5b05cf5a7c6087b7028 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;
 };