873f1bea849a03f82a63d7affd326d7d414538f3
[apps/mixer.git] / app / mixer.cpp
1 /*
2  * Copyright (C) 2016 The Qt Company Ltd.
3  * Copyright (C) 2016,2017 Konsulko Group
4  * Copyright (C) 2018 IoT.bzh
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <QJsonArray>
20 #include <QJsonObject>
21 #include <QTimer>
22 #include <QtDebug>
23 #include "mixer.hpp"
24
25
26 Mixer::Mixer(QObject* parent)
27         : QObject(parent)
28 {
29         connect(&m_client, SIGNAL(connected()), this, SLOT(onClientConnected()));
30         connect(&m_client, SIGNAL(disconnected()), this, SLOT(onClientDisconnected()));
31         connect(&m_client, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onClientError(QAbstractSocket::SocketError)));
32         connect(&m_client, SIGNAL(eventReceived(QString, const QJsonValue&)), this, SLOT(onClientEventReceived(QString, const QJsonValue&)));
33 }
34
35 void Mixer::open(const QUrl& url)
36 {
37         m_url = url;
38         TryOpen();
39 }
40
41 QList<QObject*> Mixer::roles() const
42 {
43         return m_roles;
44 }
45
46 void Mixer::setRoleVolume(AudioRole* role)
47 {
48         if (role == nullptr) return;
49
50         QJsonObject arg;
51         arg.insert("control", role->Name().toLocal8Bit().data());
52         arg.insert("value", QJsonValue(role->Value()));
53
54         m_client.call("audiomixer", "volume", arg);
55 }
56
57 void Mixer::parseControls(const QJsonValue & v)
58 {
59         qDebug() << "got controls: " << v;
60
61         for(QObject* role : m_roles) delete role;
62         m_roles.clear();
63
64         for (const QJsonValue & av : v.toArray()) {
65                 QString name = av.toObject()["control"].toString();
66                 int value = av.toObject()["volume"].toDouble() * 100;
67                 value = qBound(0, value, 100);
68
69                 AudioRole *ar = new AudioRole(name, value);
70                 connect(ar, SIGNAL(ValueChanged()), this, SLOT(onRoleValueChanged()));
71                 m_roles.append(ar);
72
73                 qDebug() << "added role: " << ar->Name()
74                         << " value: " << ar->Value();
75         }
76
77         emit rolesChanged();
78 }
79
80 void Mixer::onClientConnected()
81 {
82         m_client.call("audiomixer", "list_controls", QJsonObject(), [this](bool r, const QJsonValue& v) {
83                 if (r && v.isObject()) {
84                         parseControls(v.toObject()["response"]);
85                 }
86
87                 QJsonObject arg;
88                 arg.insert("event", "controls_changed");
89                 m_client.call("audiomixer", "subscribe", arg);
90
91                 arg.insert("event", "volume_changed");
92                 m_client.call("audiomixer", "subscribe", arg);
93         });
94 }
95
96 void Mixer::onClientDisconnected()
97 {
98         qDebug() << "Mixer::onClientDisconnected!";
99         QTimer::singleShot(1000, this, SLOT(TryOpen()));
100 }
101
102 void Mixer::onClientError(QAbstractSocket::SocketError se)
103 {
104         qDebug() << "Mixer::onClientError: " << se;
105 }
106
107 void Mixer::onClientEventReceived(QString eventName, const QJsonValue& data)
108 {
109         qDebug() << "Mixer::onClientEventReceived[" << eventName << "]: " << data;
110
111         if (eventName == "audiomixer/controls_changed") {
112                 m_client.call("audiomixer", "list_controls", QJsonObject(), [this](bool r, const QJsonValue& v) {
113                         if (r && v.isObject()) {
114                                 parseControls(v.toObject()["response"]);
115                         }
116                 });
117         }
118         else if (eventName == "audiomixer/volume_changed") {
119                 QString name = data.toObject()["control"].toString();
120                 int value = data.toObject()["value"].toDouble() * 100;
121                 value = qBound(0, value, 100);
122
123                 for (AudioRole *ar : m_roles) {
124                         if (ar->Name() == name) {
125                                 ar->BeginUpdate();
126                                 ar->setValue(value);
127                                 break;
128                         }
129                 }
130         }
131 }
132
133 void Mixer::onRoleValueChanged()
134 {
135         AudioRole* role = qobject_cast<AudioRole*>(QObject::sender());
136         if (role == nullptr) return;
137
138         /* if the role was not being updated by us, it was modified from the UI,
139            in which case we have to set it to the backend */
140         if (!role->EndUpdate())
141                 setRoleVolume(role);
142 }
143
144 void Mixer::TryOpen()
145 {
146         qDebug() << "Mixer::TryOpen: " << m_url;
147         m_client.open(m_url);
148 }