[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kmix/kmix-improvements] src/daemon: Implement sink controls
From:       Trever Fischer <tdfischer () fedoraproject ! org>
Date:       2013-02-19 19:56:03
Message-ID: 20130219195603.3D26AA60DF () git ! kde ! org
[Download RAW message or body]

Git commit 6fb982842e18eb4af5bebcabc3d9bc7771ad00ea by Trever Fischer.
Committed on 27/09/2012 at 19:30.
Pushed by tdfischer into branch 'kmix-improvements'.

Implement sink controls

M  +1    -0    src/daemon/CMakeLists.txt
M  +46   -0    src/daemon/backends/PulseAudio.cpp
M  +5    -0    src/daemon/backends/PulseAudio.h
A  +128  -0    src/daemon/backends/PulseSourceControl.cpp     [License: LGPL (v2+)]
A  +45   -0    src/daemon/backends/PulseSourceControl.h     [License: LGPL (v2+)]

http://commits.kde.org/kmix/6fb982842e18eb4af5bebcabc3d9bc7771ad00ea

diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt
index b090c8d..4976a9b 100644
--- a/src/daemon/CMakeLists.txt
+++ b/src/daemon/CMakeLists.txt
@@ -21,6 +21,7 @@ if (PULSEAUDIO_FOUND)
         backends/PulseSourceOutputControl.cpp
         backends/PulseSinkInputControl.cpp
         backends/PulseSinkControl.cpp
+        backends/PulseSourceControl.cpp
     )
 endif()
 
diff --git a/src/daemon/backends/PulseAudio.cpp b/src/daemon/backends/PulseAudio.cpp
index d9c05d3..c4868c7 100644
--- a/src/daemon/backends/PulseAudio.cpp
+++ b/src/daemon/backends/PulseAudio.cpp
@@ -23,6 +23,7 @@
 #include "PulseSourceOutputControl.h"
 #include "PulseSinkInputControl.h"
 #include "PulseSinkControl.h"
+#include "PulseSourceControl.h"
 #include <QtCore/QDebug>
 
 namespace Backends {
@@ -74,6 +75,28 @@ void PulseAudio::sink_input_cb(pa_context *cxt, const \
pa_sink_input_info *info,  }
 }
 
+void PulseAudio::source_cb(pa_context *cxt, const pa_source_info *info, int eol, \
gpointer user_data) +{
+    PulseAudio *that = static_cast<PulseAudio*>(user_data);
+    if (eol < 0) {
+        if (pa_context_errno(cxt) == PA_ERR_NOENTITY)
+            return;
+    }
+    if (eol > 0) {
+        return;
+    }
+    PulseSourceControl *control;
+    if (!that->m_sources.contains(info->index)) {
+        control = new PulseSourceControl(cxt, info, that);
+        QObject::connect(control, SIGNAL(scheduleRefresh(int)), that, \
SLOT(refreshSource(int))); +        that->m_sources[info->index] = control;
+        that->registerControl(control);
+    } else {
+        control = that->m_sources[info->index];
+        control->update(info);
+    }
+}
+
 PulseSinkControl *PulseAudio::sink(int idx)
 {
     if (m_sinks.contains(idx))
@@ -145,6 +168,11 @@ void PulseAudio::refreshSinkInput(int idx)
     pa_context_get_sink_input_info(m_context, idx, sink_input_cb, this);
 }
 
+void PulseAudio::refreshSource(int idx)
+{
+    pa_context_get_source_info_by_index(m_context, idx, source_cb, this);
+}
+
 void PulseAudio::refreshSourceOutput(int idx)
 {
     pa_context_get_source_output_info(m_context, idx, source_output_cb, this);
@@ -172,6 +200,7 @@ void PulseAudio::subscribe_cb(pa_context *cxt, \
                pa_subscription_event_type t, uin
             if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == \
                PA_SUBSCRIPTION_EVENT_REMOVE) {
                 PulseControl *control = that->m_sourceOutputs.take(index);
                 that->deregisterControl(control);
+                that->m_excludedSourceOutputs.removeOne(control->pulseIndex());
                 control->deleteLater();
             } else {
                 pa_operation *op;
@@ -182,6 +211,19 @@ void PulseAudio::subscribe_cb(pa_context *cxt, \
pa_subscription_event_type t, uin  pa_operation_unref(op);
             }
             break;
+        case PA_SUBSCRIPTION_EVENT_SOURCE:
+            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == \
PA_SUBSCRIPTION_EVENT_REMOVE) { +                PulseControl *control = \
that->m_sources.take(index); +                that->deregisterControl(control);
+                control->deleteLater();
+            } else {
+                pa_operation *op;
+                if (!(op = pa_context_get_source_info_by_index(cxt, index, \
source_cb, user_data))) { +                    qWarning() << \
"pa_context_get_source_info_by_index failed"; +                    return;
+                }
+                pa_operation_unref(op);
+            }
         case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
             if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == \
PA_SUBSCRIPTION_EVENT_REMOVE) {  PulseControl *control = \
that->m_sinkInputs.take(index); @@ -221,6 +263,10 @@ void \
PulseAudio::context_state_callback(pa_context *cxt, gpointer user_data)  return;
         }
         pa_operation_unref(op);
+        if (!(op = pa_context_get_source_info_list(cxt, source_cb, that))) {
+            return;
+        }
+        pa_operation_unref(op);
         if (!(op = pa_context_get_source_output_info_list(cxt, source_output_cb, \
that))) {  return;
         }
diff --git a/src/daemon/backends/PulseAudio.h b/src/daemon/backends/PulseAudio.h
index 5ddad40..ec80729 100644
--- a/src/daemon/backends/PulseAudio.h
+++ b/src/daemon/backends/PulseAudio.h
@@ -31,6 +31,7 @@ class PulseControl;
 class PulseSinkControl;
 class PulseSourceOutputControl;
 class PulseSinkInputControl;
+class PulseSourceControl;
 
 class PulseAudio : public Backend {
     Q_OBJECT
@@ -44,11 +45,13 @@ private slots:
     void refreshSink(int idx);
     void refreshSourceOutput(int idx);
     void refreshSinkInput(int idx);
+    void refreshSource(int idx);
 private:
     static void context_state_callback(pa_context *cxt, gpointer user_data);
     static void sink_cb(pa_context *cxt, const pa_sink_info *info, int eol, gpointer \
                user_data);
     static void source_output_cb(pa_context *cxt, const pa_source_output_info *info, \
                int eol, gpointer user_data);
     static void sink_input_cb(pa_context *cxt, const pa_sink_input_info *info, int \
eol, gpointer user_data); +    static void source_cb(pa_context *cxt, const \
                pa_source_info *info, int eol, gpointer user_data);
     static void subscribe_cb(pa_context *cxt, pa_subscription_event_type t, uint32_t \
index, gpointer user_data);  pa_glib_mainloop *m_loop;
     pa_mainloop_api *m_loopAPI;
@@ -56,6 +59,8 @@ private:
     QMap<int, PulseSinkControl*> m_sinks;
     QMap<int, PulseSourceOutputControl*> m_sourceOutputs;
     QMap<int, PulseSinkInputControl*> m_sinkInputs;
+    QMap<int, PulseSourceControl*> m_sources;
+    QList<int> m_excludedSourceOutputs;
 };
 
 } //namespace Backends
diff --git a/src/daemon/backends/PulseSourceControl.cpp \
b/src/daemon/backends/PulseSourceControl.cpp new file mode 100644
index 0000000..1ab1017
--- /dev/null
+++ b/src/daemon/backends/PulseSourceControl.cpp
@@ -0,0 +1,128 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ * Copyright (C) Trever Fischer <tdfischer@fedoraproject.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  \
02110-1301, USA. + */
+
+#include "PulseSourceControl.h"
+#include <QtCore/QDebug>
+#include "PulseAudio.h"
+
+namespace Backends {
+
+PulseSourceControl::PulseSourceControl(pa_context *cxt, const pa_source_info *info, \
PulseAudio *parent) +    : PulseControl(Control::HardwareInput, cxt, parent)
+    , m_monitor(0)
+{
+    update(info);
+    qDebug() << displayName();
+}
+
+void PulseSourceControl::setVolume(Channel c, int v)
+{
+    m_volumes.values[(int)c] = v;
+    if (!pa_context_set_source_volume_by_index(m_context, m_idx, &m_volumes, NULL, \
NULL)) { +        qWarning() << "pa_context_set_source_volume_by_index() failed";
+    }
+}
+
+void PulseSourceControl::setMute(bool yes)
+{
+    pa_context_set_sink_mute_by_index(m_context, m_idx, yes, cb_refresh, this);
+}
+
+void PulseSourceControl::update(const pa_source_info *info)
+{
+    m_idx = info->index;
+    m_displayName = QString::fromUtf8(info->description);
+    m_iconName = QString::fromUtf8(pa_proplist_gets(info->proplist, \
PA_PROP_DEVICE_ICON_NAME)); +    updateVolumes(info->volume);
+    if (m_muted != info->mute) {
+        emit muteChanged(info->mute);
+    }
+    m_muted = info->mute;
+}
+
+bool PulseSourceControl::canMonitor() const
+{
+    return pa_context_get_server_protocol_version(m_context) >= 13;
+}
+
+void PulseSourceControl::startMonitor()
+{
+    qDebug() << "Starting monitor?";
+    if (m_monitor)
+        return;
+    qDebug() << "k.";
+    pa_stream *s;
+    pa_buffer_attr attr;
+    pa_sample_spec spec;
+
+    spec.channels = 1;
+    spec.format = PA_SAMPLE_FLOAT32;
+    spec.rate = 2;
+
+    memset(&attr, 0, sizeof(attr));
+    attr.fragsize = sizeof(float);
+    attr.maxlength = (uint32_t) - 1;
+
+    if (!(s = pa_stream_new(m_context, "Peak Detect", &spec, NULL))) {
+        qWarning() << "Couldn't create peak detect stream?!";
+        return;
+    }
+
+    pa_stream_set_read_callback(s, monitor_cb, this);
+    if (pa_stream_connect_record(s, NULL, &attr, (pa_stream_flags_t) \
(PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND|PA_STREAM_DONT_MOVE|PA_STREAM_PEAK_DETECT|PA_STREAM_ADJUST_LATENCY)) \
< 0) { +        qWarning() << "Couldn't connect monitor stream?!";
+        pa_stream_unref(s);
+        return;
+    }
+
+    m_monitor = s;
+}
+
+void PulseSourceControl::monitor_cb(pa_stream *s, size_t length, void *user_data)
+{
+    PulseSourceControl *that = static_cast<PulseSourceControl*>(user_data);
+    const void *data;
+    double v;
+    if (pa_stream_peek(s, &data, &length) < 0) {
+        qWarning() << "Couldn't read monitor stream?!";
+        return;
+    }
+
+    assert(length > 0);
+    assert(length % sizeof(float) == 0);
+
+    v = ((const float*) data)[length / sizeof(float) - 1];
+    pa_stream_drop(s);
+
+    v = qMax(0.0, qMin(v, 1.0));
+
+    that->levelUpdate(v*65536);
+}
+
+void PulseSourceControl::stopMonitor()
+{
+    qDebug() << "Stopping monitor";
+    if (m_monitor)
+        pa_stream_unref(m_monitor);
+}
+
+}
+
+#include "PulseSourceControl.moc"
diff --git a/src/daemon/backends/PulseSourceControl.h \
b/src/daemon/backends/PulseSourceControl.h new file mode 100644
index 0000000..3c079bc
--- /dev/null
+++ b/src/daemon/backends/PulseSourceControl.h
@@ -0,0 +1,45 @@
+/*
+ * KMix -- KDE's full featured mini mixer
+ *
+ * Copyright (C) Trever Fischer <tdfischer@fedoraproject.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  \
02110-1301, USA. + */
+
+#ifndef PULSESOURCECONTROL_H
+#define PULSESOURCECONTROL_H
+
+#include "PulseControl.h"
+
+namespace Backends {
+
+class PulseSourceControl : public PulseControl {
+    Q_OBJECT
+public:
+    PulseSourceControl(pa_context *cxt, const pa_source_info *info, PulseAudio \
*parent = 0); +    void setVolume(Channel c, int v);
+    void setMute(bool yes);
+    void update(const pa_source_info *info);
+    bool canMonitor() const;
+    void startMonitor();
+    void stopMonitor();
+private:
+    static void monitor_cb(pa_stream *s, size_t length, void *data);
+    pa_stream *m_monitor;
+};
+
+}
+
+#endif // PULSESOURCECONTROL_H


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic