summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/multimedia/audio/qsoundeffect_pulse_p.cpp214
-rw-r--r--src/multimedia/audio/qsoundeffect_pulse_p.h13
-rw-r--r--src/plugins/pulseaudio/qaudioinput_pulse.cpp99
-rw-r--r--src/plugins/pulseaudio/qaudioinput_pulse.h8
-rw-r--r--src/plugins/pulseaudio/qaudiooutput_pulse.cpp84
-rw-r--r--src/plugins/pulseaudio/qaudiooutput_pulse.h2
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 ecc42cac5..43d4a6cb0 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 9b3564cc9..0f16b98a2 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 77b438ff9..93d410598 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 7b898c480..c130f8cac 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 c1d46fac4..a850c9b0e 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 e24fd514b..a165da86a 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;
};