summaryrefslogtreecommitdiffstats
path: root/src/plugins/pulseaudio/qaudiooutput_pulse.cpp
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@theqtcompany.com>2016-02-05 14:07:20 +0100
committerYoann Lopes <yoann.lopes@theqtcompany.com>2016-03-16 12:04:33 +0000
commitb17e0cd5dd28b93b1ea567c676f0e183acb6dd7c (patch)
tree4ad693212afdc479429eb5d609af9d078cc6baae /src/plugins/pulseaudio/qaudiooutput_pulse.cpp
parent399ec97f101f8bc4917139bf658bb08fd5316811 (diff)
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@theqtcompany.com>
Diffstat (limited to 'src/plugins/pulseaudio/qaudiooutput_pulse.cpp')
-rw-r--r--src/plugins/pulseaudio/qaudiooutput_pulse.cpp84
1 files changed, 32 insertions, 52 deletions
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