diff options
author | Yoann Lopes <yoann.lopes@theqtcompany.com> | 2016-02-05 14:07:20 +0100 |
---|---|---|
committer | Yoann Lopes <yoann.lopes@theqtcompany.com> | 2016-03-16 12:04:33 +0000 |
commit | b17e0cd5dd28b93b1ea567c676f0e183acb6dd7c (patch) | |
tree | 4ad693212afdc479429eb5d609af9d078cc6baae /src/plugins/pulseaudio/qaudiooutput_pulse.cpp | |
parent | 399ec97f101f8bc4917139bf658bb08fd5316811 (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.cpp | 84 |
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 |