Add QAudioOutput volume API and pulseaudio backend implementation.
authorhawcroft <derick.hawcroft@nokia.com>
Wed, 28 Sep 2011 03:20:26 +0000 (13:20 +1000)
committerQt by Nokia <qt-info@nokia.com>
Wed, 28 Sep 2011 03:33:38 +0000 (05:33 +0200)
Change-Id: I70784e8d17522a23f6467713d58384b30557694b
Reviewed-on: http://codereview.qt-project.org/5663
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: derick hawcroft <derick.hawcroft@nokia.com>
src/multimediakit/audio/qaudiooutput.cpp
src/multimediakit/audio/qaudiooutput.h
src/multimediakit/audio/qaudiosystem.cpp
src/multimediakit/audio/qaudiosystem.h
src/plugins/pulseaudio/qaudiooutput_pulse.cpp
src/plugins/pulseaudio/qaudiooutput_pulse.h

index ea9dcb1..d4a2d7f 100644 (file)
@@ -366,6 +366,25 @@ QAudio::State QAudioOutput::state() const
 }
 
 /*!
+    Sets the volume.
+    Where \a volume is between 0.0 and 1.0 inclusive.
+    \since 5.0
+*/
+void QAudioOutput::setVolume(qreal volume)
+{
+    d->setVolume(volume);
+}
+
+/*!
+    Returns the volume between 0.0 and 1.0 inclusive.
+    \since 5.0
+*/
+qreal QAudioOutput::volume() const
+{
+    return d->volume();
+}
+
+/*!
     \fn QAudioOutput::stateChanged(QAudio::State state)
     This signal is emitted when the device \a state has changed.
     This is the current state of the audio output.
index b61c4d9..f146c80 100644 (file)
@@ -97,6 +97,9 @@ public:
     QAudio::Error error() const;
     QAudio::State state() const;
 
+    void setVolume(qreal);
+    qreal volume() const;
+
 Q_SIGNALS:
     void stateChanged(QAudio::State);
     void notify();
index 4555be9..0c0475e 100644 (file)
@@ -248,6 +248,19 @@ QT_BEGIN_NAMESPACE
 */
 
 /*!
+    \fn virtual void QAbstractAudioOutput::setVolume(qreal volume)
+    Sets the volume.
+    Where \a volume is between 0.0 and 1.0.
+    \since 5.0
+*/
+
+/*!
+    \fn virtual qreal QAbstractAudioOutput::volume() const
+    Returns the volume in the range 0.0 and 1.0.
+    \since 5.0
+*/
+
+/*!
     \fn QAbstractAudioOutput::errorChanged(QAudio::Error error)
     This signal is emitted when the \a error state has changed.
     \since 1.0
index 7430528..72dbffa 100644 (file)
@@ -95,6 +95,8 @@ public:
     virtual QAudio::State state() const = 0;
     virtual void setFormat(const QAudioFormat& fmt) = 0;
     virtual QAudioFormat format() const = 0;
+    virtual void setVolume(qreal) {}
+    virtual qreal volume() const { return 1.0; }
 
 Q_SIGNALS:
     void errorChanged(QAudio::Error);
index 927cbc7..b638d07 100644 (file)
@@ -41,6 +41,7 @@
 
 #include <QtCore/qcoreapplication.h>
 #include <QtCore/qdebug.h>
+#include <QtCore/qmath.h>
 
 #include "qaudiooutput_pulse.h"
 #include "qaudiodeviceinfo_pulse.h"
@@ -150,6 +151,7 @@ QPulseAudioOutput::QPulseAudioOutput(const QByteArray &device)
     , m_tickTimer(new QTimer(this))
     , m_audioBuffer(0)
     , m_resuming(false)
+    , m_volume(1.0)
 {
     connect(m_tickTimer, SIGNAL(timeout()), SLOT(userFeed()));
 }
@@ -247,6 +249,7 @@ bool QPulseAudioOutput::open()
         return false;
     }
 
+    m_spec = spec;
     m_totalTimeValue = 0;
     m_elapsedTimeOffset = 0;
     m_timeStamp.restart();
@@ -272,7 +275,16 @@ bool QPulseAudioOutput::open()
     pa_stream_set_overflow_callback(m_stream, outputStreamOverflowCallback, this);
     pa_stream_set_latency_update_callback(m_stream, outputStreamLatencyCallback, this);
 
-    if (pa_stream_connect_playback(m_stream, m_device.data(), NULL, (pa_stream_flags_t)0, NULL, NULL) < 0) {
+    pa_volume_t paVolume;
+    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 (pa_stream_connect_playback(m_stream, m_device.data(), NULL, (pa_stream_flags_t)0, &m_chVolume, NULL) < 0) {
         qWarning() << "pa_stream_connect_playback() failed!";
         return false;
     }
@@ -568,6 +580,42 @@ qint64 OutputPrivate::writeData(const char *data, qint64 len)
     return written;
 }
 
+void QPulseAudioOutput::setVolume(qreal vol)
+{
+    if (vol >= 0.0 && vol <= 1.0) {
+        if (!qFuzzyCompare(m_volume, vol)) {
+            m_volume = vol;
+            if (m_opened) {
+                QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+                pa_threaded_mainloop_lock(pulseEngine->mainloop());
+                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);
+                pa_threaded_mainloop_unlock(pulseEngine->mainloop());
+            }
+        }
+    }
+}
+
+qreal QPulseAudioOutput::volume() const
+{
+    return m_volume;
+}
+
 QT_END_NAMESPACE
 
 #include "moc_qaudiooutput_pulse.cpp"
index f6f6282..884164e 100644 (file)
@@ -95,6 +95,9 @@ public:
     void setFormat(const QAudioFormat &format);
     QAudioFormat format() const;
 
+    void setVolume(qreal volume);
+    qreal volume() const;
+
 public:
     void streamUnderflowCallback();
 
@@ -129,6 +132,10 @@ private:
     QTime m_timeStamp;
     qint64 m_elapsedTimeOffset;
     bool m_resuming;
+
+    qreal m_volume;
+    pa_cvolume m_chVolume;
+    pa_sample_spec m_spec;
 };
 
 class OutputPrivate : public QIODevice