aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorLoïc Collignon <loic.collignon@iot.bzh>2018-06-27 17:30:37 +0200
committerLoïc Collignon <loic.collignon@iot.bzh>2018-06-27 17:30:37 +0200
commit63dc51c35d26c837295ac0ef33c1b8e41353ea35 (patch)
tree24918fe062c14b29f1c69b2e024cb8d66d045c50 /app
parentd9bb450ee8898cb810027897a32afd3adcb05d9f (diff)
Merge 'eel' into 'master'
Replace content from 'master' by content from 'eel' as it's the new version based on 4a on which new development will be done. Change-Id: I2966af7dcee59701ff3a344487c008d7e65e68ed Signed-off-by: Loïc Collignon <loic.collignon@iot.bzh>
Diffstat (limited to 'app')
-rw-r--r--app/CMakeLists.txt57
-rw-r--r--app/Mixer.qml151
-rw-r--r--app/app.pri12
-rw-r--r--app/app.pro18
-rw-r--r--app/main.cpp27
-rw-r--r--app/mixer.cpp91
-rw-r--r--app/mixer.h54
-rw-r--r--app/paclient.cpp329
-rw-r--r--app/paclient.h97
-rw-r--r--app/pacontrolmodel.cpp208
-rw-r--r--app/pacontrolmodel.h92
11 files changed, 286 insertions, 850 deletions
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
new file mode 100644
index 0000000..8f8bd1e
--- /dev/null
+++ b/app/CMakeLists.txt
@@ -0,0 +1,57 @@
+###########################################################################
+# Copyright 2018 IoT.bzh
+#
+# author: Loïc Collignon <loic.collignon@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###########################################################################
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_CXX_STANDARD 14)
+
+find_package(Qt5 COMPONENTS Core Gui QuickControls2 WebSockets QuickWidgets REQUIRED)
+qt5_add_resources(RESOURCES Mixer.qrc)
+
+PROJECT_TARGET_ADD(mixer)
+
+add_executable(mixer
+ main.cpp
+ mixer.cpp
+ ${RESOURCES}
+)
+
+set_target_properties(mixer PROPERTIES
+ LABELS "EXECUTABLE"
+ PREFIX ""
+ COMPILE_FLAGS "${EXTRAS_CFLAGS} -DFOR_AFB_BINDING"
+ LINK_FLAGS "${BINDINGS_LINK_FLAG}"
+ LINK_LIBRARIES "${EXTRAS_LIBRARIES}"
+ OUTPUT_NAME "${TARGET_NAME}"
+)
+
+target_link_libraries(mixer
+ Qt5::QuickControls2
+ Qt5::WebSockets
+ homescreen
+ qtWindowmanagerWrapper
+ json-c
+ afb-helpers
+)
+
+#add_custom_command(TARGET ${TARGET_NAME}
+#PRE_BUILD
+#COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/../package/htdocs
+#COMMAND cp -rv ${CMAKE_CURRENT_SOURCE_DIR}/../htdocs ${CMAKE_CURRENT_BINARY_DIR}/../package/
+#COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/../package/etc
+#COMMAND cp -rv ${CMAKE_CURRENT_SOURCE_DIR}/../etc ${CMAKE_CURRENT_BINARY_DIR}/../package/)
diff --git a/app/Mixer.qml b/app/Mixer.qml
index 96875e0..8b1ba06 100644
--- a/app/Mixer.qml
+++ b/app/Mixer.qml
@@ -14,85 +14,94 @@
* limitations under the License.
*/
+// BUG: ValueChanged event is raised by sliders when you are moving the caret, should be raised only when you release it.
+// TODO: Call mixer.setVolume(sliderName, Value) on value change
+// TODO: Call mixer.getVolume(sliderName) on load
+
import QtQuick 2.6
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.0
import AGL.Demo.Controls 1.0
-import PaControlModel 1.0
+import Mixer 1.0
ApplicationWindow {
- id: root
+ id: root
+
+ Mixer {
+ id: mixer
+ Component.objectName: {
+ mixer.open(bindingAddress)
+ }
+ onRolesChanged: {
+ // Remove existing sliders
+ for(var i = sliders.children.length; i > 0 ; --i) {
+ console.log("destroying: " + i)
+ sliders.children[i-1].destroy()
+ }
+
+ // Add slider for each role
+ for(var j = 0; j < mixer.roles.length; ++j) {
+ addSlider(mixer.roles[j])
+ }
+ }
- Label {
- id: title
- font.pixelSize: 48
- text: "Mixer"
- anchors.horizontalCenter: parent.horizontalCenter
- }
+ function addSlider(name) {
+ Qt.createQmlObject("
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 2.0
+RowLayout {
+ property int value
+ id: slider_" + name + "
+ Layout.minimumHeight: 75
+ Label {
+ font.pixelSize: 24
+ text: \"" + name+ "\"
+ Layout.minimumWidth: 150
+ }
+ Label {
+ id: slider_" + name + "_textvalue
+ font.pixelSize: 24
+ text: \"0 %\"
+ }
+ Slider {
+ id: slider_" + name + "_slider
+ Layout.fillWidth: true
+ from: 0
+ to: 100
+ stepSize: 1
+ snapMode: Slider.SnapOnRelease
+ onValueChanged: {
+ slider_" + name + "_textvalue.text = value + \" %\"
+ mixer.setVolume(\"" + name + "\", value)
+ }
+ Component.objectName: {
+ mixer.getVolume(\"" + name + "\")
+ }
+ }
+ }", sliders, "volumeslider")
+ }
- Component {
- id: ctldesc
- Label {
- font.pixelSize: 32
- width: listView.width
- wrapMode: Text.WordWrap
- property var typeString: {modelType ? "Output" : "Input"}
- text: "[" + typeString + " #" + modelCIndex + "]: " + modelDesc
- }
- }
+ function deleteChilds(item) {
+ for(var i = item.children.length; i > 0 ; i--) {
+ deleteChilds(item.children[i-1])
+ }
+ item.destroy()
+ }
+ }
- Component {
- id: empty
- Item {
- }
- }
+ Label {
+ id: title
+ font.pixelSize: 48
+ text: "Mixer"
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
- ListView {
- id: listView
- anchors.left: parent.left
- anchors.top: title.bottom
- anchors.margins: 80
- anchors.fill: parent
- model: PaControlModel { objectName: "pacm" }
- delegate: ColumnLayout {
- width: parent.width
- spacing: 40
- Connections {
- target: listView.model
- onDataChanged: slider.value = volume
- }
- Loader {
- property int modelType: type
- property int modelCIndex: cindex
- property string modelDesc: name
- sourceComponent: (channel == 0) ? ctldesc : empty
- }
- RowLayout {
- Layout.minimumHeight: 75
- Label {
- font.pixelSize: 24
- text: cdesc
- Layout.minimumWidth: 150
- }
- Label {
- font.pixelSize: 24
- text: "0 %"
- }
- Slider {
- id: slider
- Layout.fillWidth: true
- from: 0
- to: 65536
- stepSize: 256
- snapMode: Slider.SnapOnRelease
- onValueChanged: volume = value
- Component.onCompleted: value = volume
- }
- Label {
- font.pixelSize: 24
- text: "100 %"
- }
- }
- }
- }
+ ColumnLayout {
+ id: sliders
+ anchors.margins: 80
+ anchors.top: title.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ }
}
+
diff --git a/app/app.pri b/app/app.pri
deleted file mode 100644
index 014646f..0000000
--- a/app/app.pri
+++ /dev/null
@@ -1,12 +0,0 @@
-TEMPLATE = app
-
-load(configure)
-qtCompileTest(libhomescreen)
-
-config_libhomescreen {
- CONFIG += link_pkgconfig
- PKGCONFIG += homescreen
- DEFINES += HAVE_LIBHOMESCREEN
-}
-
-DESTDIR = $${OUT_PWD}/../package/root/bin
diff --git a/app/app.pro b/app/app.pro
deleted file mode 100644
index a33fc0d..0000000
--- a/app/app.pro
+++ /dev/null
@@ -1,18 +0,0 @@
-TARGET = mixer
-QT = quickcontrols2
-
-HEADERS += \
- pacontrolmodel.h \
- paclient.h
-
-SOURCES = main.cpp \
- pacontrolmodel.cpp \
- paclient.cpp
-
-CONFIG += link_pkgconfig
-PKGCONFIG += libhomescreen qlibwindowmanager libpulse
-
-RESOURCES += \
- Mixer.qrc
-
-include(app.pri)
diff --git a/app/main.cpp b/app/main.cpp
index bfce498..9c6339f 100644
--- a/app/main.cpp
+++ b/app/main.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2016 The Qt Company Ltd.
* Copyright (C) 2016,2017 Konsulko Group
+ * Copyright (C) 2018 IoT.bzh
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,9 +16,6 @@
* limitations under the License.
*/
-#include "paclient.h"
-#include "pacontrolmodel.h"
-
#include <QtCore/QDebug>
#include <QtCore/QCommandLineParser>
#include <QtCore/QUrlQuery>
@@ -34,6 +32,7 @@
#include <QQuickWindow>
#include <libhomescreen.hpp>
#include <qlibwindowmanager.h>
+#include "mixer.h"
int main(int argc, char *argv[])
{
@@ -51,14 +50,7 @@ int main(int argc, char *argv[])
parser.process(app);
QStringList positionalArguments = parser.positionalArguments();
- // Fire up PA client QThread
- QThread* pat = new QThread;
- PaClient* client = new PaClient();
- client->moveToThread(pat);
- pat->start();
-
- // Register the PA Control Model
- qmlRegisterType<PaControlModel>("PaControlModel", 1, 0, "PaControlModel");
+ qmlRegisterType<Mixer>("Mixer", 1, 0, "Mixer");
QQmlApplicationEngine engine;
if (positionalArguments.length() == 2) {
@@ -88,7 +80,7 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
// Create an event callbnewack against an event type. Here a lambda is called when SyncDraw event occurs
- qwm->set_event_handler(QLibWindowmanager::Event_SyncDraw, [qwm, myname](json_object *object) {
+ qwm->set_event_handler(QLibWindowmanager::Event_SyncDraw, [qwm, myname](json_object*) {
fprintf(stderr, "Surface got syncDraw!\n");
qwm->endDraw(myname);
});
@@ -116,17 +108,6 @@ int main(int argc, char *argv[])
QQuickWindow *window = qobject_cast<QQuickWindow *>(mobjs.first());
QObject::connect(window, SIGNAL(frameSwapped()), qwm, SLOT(slotActivateSurface()));
-
- PaControlModel *pacm = mobjs.first()->findChild<PaControlModel *>("pacm");
- QObject::connect(client, SIGNAL(controlAdded(int, QString, QString, int, int, const char *, int)),
- pacm, SLOT(addOneControl(int, QString, QString, int, int, const char *, int)));
- QObject::connect(client, SIGNAL(volumeExternallyChanged(uint32_t, uint32_t, uint32_t, uint32_t)),
- pacm, SLOT(changeExternalVolume(uint32_t, uint32_t, uint32_t, uint32_t)));
- QObject::connect(pacm, SIGNAL(volumeChanged(uint32_t, uint32_t, uint32_t, uint32_t)),
- client, SLOT(setVolume(uint32_t, uint32_t, uint32_t, uint32_t)));
-
- // Initalize PA client
- client->init();
}
return app.exec();
}
diff --git a/app/mixer.cpp b/app/mixer.cpp
new file mode 100644
index 0000000..6614569
--- /dev/null
+++ b/app/mixer.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ * Copyright (C) 2016,2017 Konsulko Group
+ * Copyright (C) 2018 IoT.bzh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QJsonArray>
+#include <QJsonObject>
+#include <QtDebug>
+#include "mixer.h"
+
+Mixer::Mixer(QObject* parent)
+ : QObject(parent)
+{
+ connect(&m_client, SIGNAL(connected()), this, SLOT(onClientConnected()));
+}
+
+QStringList Mixer::roles() const
+{
+ return m_roles;
+}
+
+void Mixer::open(const QUrl &url)
+{
+ m_client.open(url);
+}
+
+void Mixer::onClientConnected()
+{
+ // Call HAL to populate list
+ m_client.call("ahl-4a", "get_roles", QJsonValue(), [this](bool r, const QJsonValue& val) {
+ if (r)
+ {
+ m_roles.clear();
+ //BUG: should be able to add this, but not handled right now: m_roles.append("playback");
+ QJsonArray cards = val.toObject()["response"].toArray();
+ foreach (const QJsonValue& card, cards)
+ {
+ m_roles.append(card.toString());
+ qDebug() << "Mixer::onClientConnected - added this HAL: " << card.toString();
+ }
+ emit rolesChanged();
+ }
+ });
+}
+
+void Mixer::setVolume(const QString& name, int value)
+{
+ QJsonObject arg;
+ arg.insert("action", "volume");
+ arg.insert("value", QJsonValue(value));
+ m_client.call("ahl-4a", name, arg, [this, name](bool r, const QJsonValue& v) {
+ if (r && v.isObject())
+ {
+ // TODO: Success, update the slider
+ }
+ else
+ {
+ // TODO: Failed, reset the slider to previous value
+ }
+ });
+}
+
+void Mixer::getVolume(const QString& name)
+{
+ QJsonObject arg;
+ arg.insert("action", "volume");
+ arg.insert("value", QJsonValue("+0")); // FIXME: Hack to get volume: ask for a relative change with a delta of zero
+ m_client.call("ahl-4a", name, arg, [this, name](bool r, const QJsonValue& v) {
+ if (r && v.isObject())
+ {
+ // TODO: Success, update the slider
+ }
+ else
+ {
+ // TODO: Failed, what to do ?
+ }
+ });
+}
diff --git a/app/mixer.h b/app/mixer.h
new file mode 100644
index 0000000..a46c8a1
--- /dev/null
+++ b/app/mixer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ * Copyright (C) 2016,2017 Konsulko Group
+ * Copyright (C) 2018 IoT.bzh
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <QObject>
+#include <QString>
+#include <QSharedPointer>
+#include <QStringList>
+#include "qafbwebsocketclient.h"
+//#include "volumeslider.h"
+
+class Mixer
+ : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QStringList roles READ roles NOTIFY rolesChanged)
+
+private:
+
+public:
+ explicit Mixer(QObject* parent = nullptr);
+ Mixer(const Mixer&) = delete;
+
+ Q_INVOKABLE void open(const QUrl& url);
+ Q_INVOKABLE QStringList roles() const;
+ Q_INVOKABLE void setVolume(const QString& name, int value);
+ Q_INVOKABLE void getVolume(const QString& name);
+
+signals:
+ void rolesChanged();
+ void volumeChanged(const QString& name, int value);
+
+private slots:
+ void onClientConnected();
+
+private:
+ QStringList m_roles;
+ QAfbWebsocketClient m_client;
+};
diff --git a/app/paclient.cpp b/app/paclient.cpp
deleted file mode 100644
index bd53cde..0000000
--- a/app/paclient.cpp
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2016,2017 Konsulko Group
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "paclient.h"
-
-#include <QtCore/QDebug>
-
-PaClient::PaClient()
- : m_init(false), m_ml(nullptr), m_mlapi(nullptr), m_ctx(nullptr)
-{
-}
-
-PaClient::~PaClient()
-{
- if (m_init)
- close();
-}
-
-void PaClient::close()
-{
- if (!m_init) return;
- pa_threaded_mainloop_stop(m_ml);
- pa_threaded_mainloop_free(m_ml);
- m_init = false;
-}
-
-static void set_sink_volume_cb(pa_context *c, int success, void *data)
-{
- Q_UNUSED(data);
-
- if (!success)
- qWarning() << "PaClient: set sink volume: " <<
- pa_strerror(pa_context_errno(c));
-}
-
-static void set_source_volume_cb(pa_context *c, int success, void *data)
-{
- Q_UNUSED(data);
-
- if (!success)
- qWarning() << "PaClient: set source volume: " <<
- pa_strerror(pa_context_errno(c));
-}
-
-void PaClient::setVolume(uint32_t type, uint32_t index, uint32_t channel, uint32_t volume)
-{
- pa_operation *o;
- pa_context *c = context();
- pa_cvolume *cvolume = NULL;
-
- if (type == C_SINK) {
- cvolume = m_sink_states.value(index);
- cvolume->values[channel] = volume;
- if (!(o = pa_context_set_sink_volume_by_index(c, index, cvolume, set_sink_volume_cb, NULL))) {
- qWarning() << "PaClient: set sink #" << index <<
- " channel #" << channel <<
- " volume: " << pa_strerror(pa_context_errno(c));
- return;
- }
- pa_operation_unref(o);
- } else if (type == C_SOURCE) {
- cvolume = m_source_states.value(index);
- cvolume->values[channel] = volume;
- if (!(o = pa_context_set_source_volume_by_index(c, index, cvolume, set_source_volume_cb, NULL))) {
- qWarning() << "PaClient: set source #" << index <<
- " channel #" << channel <<
- " volume: " << pa_strerror(pa_context_errno(c));
- return;
- }
- pa_operation_unref(o);
- }
-}
-
-void get_source_list_cb(pa_context *c,
- const pa_source_info *i,
- int eol,
- void *data)
-{
- int chan;
-
- PaClient *self = reinterpret_cast<PaClient*>(data);
-
- if (eol < 0) {
- qWarning() << "PaClient: get source list: " <<
- pa_strerror(pa_context_errno(c));
-
- self->close();
- return;
- }
-
- if (!eol) {
- self->addOneControlState(C_SOURCE, i->index, &i->volume);
- for (chan = 0; chan < i->channel_map.channels; chan++) {
- // NOTE: hide input control
- if (QString(i->name).endsWith("monitor"))
- continue;
-
- emit self->controlAdded(i->index, QString(i->name), QString(i->description),
- C_SOURCE, chan, channel_position_string[i->channel_map.map[chan]],
- i->volume.values[chan]);
- }
- }
-}
-
-void get_sink_list_cb(pa_context *c,
- const pa_sink_info *i,
- int eol,
- void *data)
-{
- PaClient *self = reinterpret_cast<PaClient*>(data);
- int chan;
-
- if(eol < 0) {
- qWarning() << "PaClient: get sink list: " <<
- pa_strerror(pa_context_errno(c));
- self->close();
- return;
- }
-
- if(!eol) {
- self->addOneControlState(C_SINK, i->index, &i->volume);
- for (chan = 0; chan < i->channel_map.channels; chan++) {
- emit self->controlAdded(i->index, QString(i->name), QString(i->description),
- C_SINK, chan, channel_position_string[i->channel_map.map[chan]],
- i->volume.values[chan]);
- }
- }
-}
-
-void get_sink_info_change_cb(pa_context *c,
- const pa_sink_info *i,
- int eol,
- void *data)
-{
- Q_UNUSED(c);
- Q_ASSERT(i);
- Q_ASSERT(data);
-
- if (eol) return;
-
- for (int chan = 0; chan < i->channel_map.channels; chan++) {
- PaClient *self = reinterpret_cast<PaClient*>(data);
- QHash<int, pa_cvolume *> states = self->sink_states();
- pa_cvolume *cvolume = states.value(i->index);
- // Check each channel for volume change
- if (cvolume->values[chan] != i->volume.values[chan]) {
- // On change, update cache and signal
- cvolume->values[chan] = i->volume.values[chan];
- emit self->volumeExternallyChanged(C_SINK, i->index, chan, i->volume.values[chan]);
- }
- }
-}
-
-void get_source_info_change_cb(pa_context *c,
- const pa_source_info *i,
- int eol,
- void *data)
-{
- Q_UNUSED(c);
- Q_ASSERT(i);
- Q_ASSERT(data);
-
- if (eol) return;
-
- for (int chan = 0; chan < i->channel_map.channels; chan++) {
- PaClient *self = reinterpret_cast<PaClient*>(data);
- QHash<int, pa_cvolume *> states = self->source_states();
- pa_cvolume *cvolume = states.value(i->index);
- // Check each channel for volume change
- if (cvolume->values[chan] != i->volume.values[chan]) {
- // On change, update cache and signal
- cvolume->values[chan] = i->volume.values[chan];
- emit self->volumeExternallyChanged(C_SOURCE, i->index, chan, i->volume.values[chan]);
- }
- }
-}
-
-
-void subscribe_cb(pa_context *c,
- pa_subscription_event_type_t type,
- uint32_t index,
- void *data)
-{
- pa_operation *o;
-
- if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE) {
- qWarning("PaClient: unhandled subscribe event operation");
- return;
- }
-
- switch (type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
- case PA_SUBSCRIPTION_EVENT_SINK:
- if (!(o = pa_context_get_sink_info_by_index(c, index, get_sink_info_change_cb, data))) {
- qWarning() << "PaClient: get sink info by index: " <<
- pa_strerror(pa_context_errno(c));
- return;
- }
- break;
- case PA_SUBSCRIPTION_EVENT_SOURCE:
- if (!(o = pa_context_get_source_info_by_index(c, index, get_source_info_change_cb, data))) {
- qWarning() << "PaClient: get source info by index: " <<
- pa_strerror(pa_context_errno(c));
- return;
- }
- break;
- default:
- qWarning("PaClient: unhandled subscribe event facility");
- }
-}
-
-void context_state_cb(pa_context *c, void *data)
-{
- pa_operation *o;
- PaClient *self = reinterpret_cast<PaClient*>(data);
-
- switch (pa_context_get_state(c)) {
- case PA_CONTEXT_CONNECTING:
- case PA_CONTEXT_AUTHORIZING:
- case PA_CONTEXT_SETTING_NAME:
- break;
- case PA_CONTEXT_READY:
- // Fetch the controls of interest
- if (!(o = pa_context_get_source_info_list(c, get_source_list_cb, data))) {
- qWarning() << "PaClient: get source info list: " <<
- pa_strerror(pa_context_errno(c));
- return;
- }
- pa_operation_unref(o);
- if (!(o = pa_context_get_sink_info_list(c, &get_sink_list_cb, data))) {
- qWarning() << "PaClient: get sink info list: " <<
- pa_strerror(pa_context_errno(c));
- return;
- }
- pa_operation_unref(o);
- pa_context_set_subscribe_callback(c, subscribe_cb, data);
- if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t)(PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE), NULL, NULL))) {
- qWarning() << "PaClient: subscribe: " <<
- pa_strerror(pa_context_errno(c));
- return;
- }
- break;
- case PA_CONTEXT_TERMINATED:
- self->close();
- break;
-
- case PA_CONTEXT_FAILED:
- default:
- qCritical() << "PaClient: connection failed: " <<
- pa_strerror(pa_context_errno(c));
- self->close();
- break;
- }
-}
-
-void PaClient::init()
-{
- m_ml = pa_threaded_mainloop_new();
- if (!m_ml) {
- qCritical("PaClient: failed to create mainloop");
- return;
- }
-
- pa_threaded_mainloop_set_name(m_ml, "PaClient mainloop");
-
- m_mlapi = pa_threaded_mainloop_get_api(m_ml);
-
- lock();
-
- m_ctx = pa_context_new(m_mlapi, "Mixer");
- if (!m_ctx) {
- qCritical("PaClient: failed to create context");
- pa_threaded_mainloop_free(m_ml);
- return;
- }
- pa_context_set_state_callback(m_ctx, context_state_cb, this);
-
- if (pa_context_connect(m_ctx, 0, (pa_context_flags_t)0, 0) < 0) {
- qCritical("PaClient: failed to connect");
- pa_context_unref(m_ctx);
- pa_threaded_mainloop_free(m_ml);
- return;
- }
-
- if (pa_threaded_mainloop_start(m_ml) != 0) {
- qCritical("PaClient: failed to start mainloop");
- pa_context_unref(m_ctx);
- pa_threaded_mainloop_free(m_ml);
- return;
- }
-
- unlock();
-
- m_init = true;
-}
-
-void PaClient::addOneControlState(int type, int index, const pa_cvolume *cvolume)
-{
- pa_cvolume *cvolume_new = new pa_cvolume;
- cvolume_new->channels = cvolume->channels;
- for (int i = 0; i < cvolume->channels; i++)
- cvolume_new->values[i] = cvolume->values[i];
- if (type == C_SINK)
- m_sink_states.insert(index, cvolume_new);
- else if (type == C_SOURCE)
- m_source_states.insert(index, cvolume_new);
-}
-
-QHash<int, pa_cvolume *> PaClient::sink_states(void)
-{
- return m_sink_states;
-}
-
-QHash<int, pa_cvolume *> PaClient::source_states(void)
-{
- return m_source_states;
-}
diff --git a/app/paclient.h b/app/paclient.h
deleted file mode 100644
index 73137f2..0000000
--- a/app/paclient.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2016,2017 Konsulko Group
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <pulse/pulseaudio.h>
-
-#include <QtCore/QHash>
-#include <QtCore/QObject>
-
-const char * const channel_position_string[] =
-{
- "Mono",
- "Front Left",
- "Front Right",
- "Center",
- "Rear Center",
- "Rear Left",
- "Rear Right",
- "LFE",
- "Left Center",
- "Right Center",
- "Side Left",
- "Side Right",
-};
-
-enum control_type
-{
- C_SOURCE,
- C_SINK
-};
-
-typedef struct
-{
- uint32_t type;
- uint32_t index;
- pa_cvolume cvolume;
-} CState;
-
-class PaClient : public QObject
-{
- Q_OBJECT
- public:
- PaClient();
- ~PaClient();
-
- void init();
- void close();
-
- inline pa_context *context() const
- {
- return m_ctx;
- }
-
- inline void lock()
- {
- pa_threaded_mainloop_lock(m_ml);
- }
-
- inline void unlock()
- {
- pa_threaded_mainloop_unlock(m_ml);
- }
-
- void addOneControlState(int type, int index, const pa_cvolume *cvolume);
-
- QHash<int, pa_cvolume *> sink_states();
- QHash<int, pa_cvolume *> source_states();
-
- public slots:
- void setVolume(uint32_t type, uint32_t index, uint32_t channel, uint32_t volume);
-
- signals:
- void controlAdded(int cindex, QString name, QString desc, int type, int channel, const char *cdesc, int volume);
- void volumeExternallyChanged(uint32_t type, uint32_t cindex, uint32_t channel, uint32_t volume);
-
- private:
- bool m_init;
- pa_threaded_mainloop *m_ml;
- pa_mainloop_api *m_mlapi;
- pa_context *m_ctx;
- QHash<int, pa_cvolume *> m_sink_states;
- QHash<int, pa_cvolume *> m_source_states;
-
- public slots:
-};
diff --git a/app/pacontrolmodel.cpp b/app/pacontrolmodel.cpp
deleted file mode 100644
index 9489052..0000000
--- a/app/pacontrolmodel.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2016,2017 Konsulko Group
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "pacontrolmodel.h"
-
-PaControl::PaControl(const quint32 &cindex, const QString &name, const QString &desc, const quint32 &type, const quint32 &channel, const QString &cdesc, const quint32 &volume)
- : m_cindex(cindex), m_name(name), m_desc(desc), m_type(type), m_channel(channel), m_cdesc(cdesc), m_volume(volume)
-{
-}
-
-quint32 PaControl::cindex() const
-{
- return m_cindex;
-}
-
-QString PaControl::name() const
-{
- QStringList list = m_name.split(".");
-
- return list.at(1);
-}
-
-QString PaControl::desc() const
-{
- return m_desc;
-}
-
-quint32 PaControl::type() const
-{
- return m_type;
-}
-
-quint32 PaControl::channel() const
-{
- return m_channel;
-}
-
-QString PaControl::cdesc() const
-{
- return m_cdesc;
-}
-
-
-quint32 PaControl::volume() const
-{
- return m_volume;
-}
-
-// FIXME: Not all of these should be editable roles
-void PaControl::setCIndex(const QVariant &cindex)
-{
- m_cindex = cindex.toUInt();
-}
-
-void PaControl::setName(const QVariant &name)
-{
- m_name = name.toString();
-}
-
-void PaControl::setDesc(const QVariant &desc)
-{
- m_desc = desc.toString();
-}
-
-void PaControl::setType(const QVariant &type)
-{
- m_type = type.toUInt();
-}
-
-void PaControl::setChannel(const QVariant &channel)
-{
- m_channel = channel.toUInt();
-}
-
-void PaControl::setCDesc(const QVariant &cdesc)
-{
- m_cdesc = cdesc.toString();
-}
-
-void PaControl::setVolume(PaControlModel *pacm, const QVariant &volume)
-{
- if (volume != m_volume) {
- m_volume = volume.toUInt();
- if (pacm)
- emit pacm->volumeChanged(type(), cindex(), channel(), m_volume);
- }
-}
-
-PaControlModel::PaControlModel(QObject *parent)
- : QAbstractListModel(parent)
-{
-}
-
-void PaControlModel::addControl(const PaControl &control)
-{
- beginInsertRows(QModelIndex(), rowCount(), rowCount());
- m_controls << control;
- endInsertRows();
-}
-
-void PaControlModel::addOneControl(int cindex, QString name, QString desc, int type, int channel, const char *cdesc, int volume)
-{
- addControl(PaControl(cindex, name, desc, type, channel, cdesc, volume));
-}
-
-void PaControlModel::changeExternalVolume(uint32_t type, uint32_t cindex, uint32_t channel, uint32_t volume)
-{
- QList<PaControl>::iterator i;
- int row;
-
- for (i = m_controls.begin(), row = 0; i < m_controls.end(); ++i, ++row) {
- if ((i->type() == type) &&
- (i->cindex() == cindex) &&
- (i->channel() == channel)) {
- break;
- }
- }
-
- i->setVolume(NULL, QVariant(volume));
- QModelIndex qmindex = index(row);
- QVector<int> roles;
- roles.push_back(VolumeRole);
- emit dataChanged(qmindex, qmindex, roles);
-}
-
-int PaControlModel::rowCount(const QModelIndex & parent) const {
- Q_UNUSED(parent);
- return m_controls.count();
-}
-
-bool PaControlModel::setData(const QModelIndex &index, const QVariant &value, int role) {
- if (index.row() < 0 || index.row() >= m_controls.count())
- return false;
- PaControl &control = m_controls[index.row()];
- if (role == CIndexRole)
- control.setCIndex(value);
- else if (role == NameRole)
- control.setName(value);
- else if (role == DescRole)
- control.setDesc(value);
- else if (role == TypeRole)
- control.setType(value);
- else if (role == ChannelRole)
- control.setChannel(value);
- else if (role == CDescRole)
- control.setCDesc(value);
- else if (role == VolumeRole)
- control.setVolume(this, value);
- QVector<int> roles;
- roles.push_back(role);
- emit dataChanged(index, index, roles);
- return true;
-}
-
-QVariant PaControlModel::data(const QModelIndex & index, int role) const {
- if (index.row() < 0 || index.row() >= m_controls.count())
- return QVariant();
-
- const PaControl &control = m_controls[index.row()];
- if (role == CIndexRole)
- return control.cindex();
- else if (role == NameRole)
- return control.name();
- else if (role == DescRole)
- return control.desc();
- else if (role == TypeRole)
- return control.type();
- else if (role == ChannelRole)
- return control.channel();
- else if (role == CDescRole)
- return control.cdesc();
- else if (role == VolumeRole)
- return control.volume();
- return QVariant();
-}
-
-Qt::ItemFlags PaControlModel::flags(const QModelIndex &index) const
-{
- if (!index.isValid())
- return Qt::ItemIsEnabled;
-
- return QAbstractListModel::flags(index) | Qt::ItemIsEditable;
-}
-
-QHash<int, QByteArray> PaControlModel::roleNames() const {
- QHash<int, QByteArray> roles;
- roles[CIndexRole] = "cindex";
- roles[NameRole] = "name";
- roles[DescRole] = "desc";
- roles[TypeRole] = "type";
- roles[ChannelRole] = "channel";
- roles[CDescRole] = "cdesc";
- roles[VolumeRole] = "volume";
- return roles;
-}
diff --git a/app/pacontrolmodel.h b/app/pacontrolmodel.h
deleted file mode 100644
index 81eb70b..0000000
--- a/app/pacontrolmodel.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2016,2017 Konsulko Group
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <pulse/pulseaudio.h>
-
-#include <QtCore/QAbstractListModel>
-#include <QtCore/QList>
-
-class PaControlModel;
-
-class PaControl
-{
- public:
- PaControl(const quint32 &index, const QString &name, const QString &desc, const quint32 &type, const quint32 &channel, const QString &cdesc, const quint32 &volume);
-
- quint32 cindex() const;
- QString name() const;
- QString desc() const;
- quint32 type() const;
- quint32 channel() const;
- QString cdesc() const;
- quint32 volume() const;
- void setCIndex(const QVariant&);
- void setName(const QVariant&);
- void setDesc(const QVariant&);
- void setType(const QVariant&);
- void setChannel(const QVariant&);
- void setCDesc(const QVariant&);
- void setVolume(PaControlModel *, const QVariant&);
-
- private:
- quint32 m_cindex;
- QString m_name;
- QString m_desc;
- quint32 m_type;
- quint32 m_channel;
- QString m_cdesc;
- quint32 m_volume;
-};
-
-class PaControlModel : public QAbstractListModel
-{
- Q_OBJECT
- public:
- enum PaControlRoles {
- CIndexRole = Qt::UserRole + 1,
- NameRole,
- DescRole,
- TypeRole,
- ChannelRole,
- CDescRole,
- VolumeRole
- };
-
- PaControlModel(QObject *parent = 0);
-
- void addControl(const PaControl &control);
-
- int rowCount(const QModelIndex &parent = QModelIndex()) const;
-
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
-
- bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
-
- Qt::ItemFlags flags(const QModelIndex &index) const;
-
- public slots:
- void addOneControl(int cindex, QString name, QString desc, int type, int channel, const char *cdesc, int volume);
- void changeExternalVolume(uint32_t type, uint32_t cindex, uint32_t chan, uint32_t volume);
-
- signals:
- void volumeChanged(uint32_t type, uint32_t index, uint32_t channel, uint32_t volume);
-
- protected:
- QHash<int, QByteArray> roleNames() const;
- private:
- QList<PaControl> m_controls;
- pa_context *pa_ctx;
-};