[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