/*
* 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 <QTimer>
#include <QtDebug>
#include "mixer.hpp"
Mixer::Mixer(QObject* parent)
: QObject(parent)
{
connect(&m_client, SIGNAL(connected()), this, SLOT(onClientConnected()));
connect(&m_client, SIGNAL(disconnected()), this, SLOT(onClientDisconnected()));
connect(&m_client, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onClientError(QAbstractSocket::SocketError)));
connect(&m_client, SIGNAL(eventReceived(QString, const QJsonValue&)), this, SLOT(onClientEventReceived(QString, const QJsonValue&)));
}
void Mixer::open(const QUrl& url)
{
m_url = url;
TryOpen();
}
QList<QObject*> Mixer::roles() const
{
return m_roles;
}
void Mixer::setRoleVolume(AudioRole* role)
{
if (role == nullptr) return;
QJsonObject arg;
arg.insert("control", role->Name().toLocal8Bit().data());
arg.insert("value", QJsonValue(role->Value()));
m_client.call("audiomixer", "volume", arg);
}
void Mixer::parseControls(const QJsonValue & v)
{
qDebug() << "got controls: " << v;
for(QObject* role : m_roles) delete role;
m_roles.clear();
for (const QJsonValue & av : v.toArray()) {
QString name = av.toObject()["control"].toString();
int value = av.toObject()["volume"].toDouble() * 100;
value = qBound(0, value, 100);
AudioRole *ar = new AudioRole(name, value);
connect(ar, SIGNAL(ValueChanged()), this, SLOT(onRoleValueChanged()));
m_roles.append(ar);
qDebug() << "added role: " << ar->Name()
<< " value: " << ar->Value();
}
emit rolesChanged();
}
void Mixer::onClientConnected()
{
m_client.call("audiomixer", "list_controls", QJsonObject(), [this](bool r, const QJsonValue& v) {
if (r && v.isObject()) {
parseControls(v.toObject()["response"]);
}
QJsonObject arg;
arg.insert("event", "controls_changed");
m_client.call("audiomixer", "subscribe", arg);
arg.insert("event", "volume_changed");
m_client.call("audiomixer", "subscribe", arg);
});
}
void Mixer::onClientDisconnected()
{
qDebug() << "Mixer::onClientDisconnected!";
QTimer::singleShot(1000, this, SLOT(TryOpen()));
}
void Mixer::onClientError(QAbstractSocket::SocketError se)
{
qDebug() << "Mixer::onClientError: " << se;
}
void Mixer::onClientEventReceived(QString eventName, const QJsonValue& data)
{
qDebug() << "Mixer::onClientEventReceived[" << eventName << "]: " << data;
if (eventName == "audiomixer/controls_changed") {
m_client.call("audiomixer", "list_controls", QJsonObject(), [this](bool r, const QJsonValue& v) {
if (r && v.isObject()) {
parseControls(v.toObject()["response"]);
}
});
}
else if (eventName == "audiomixer/volume_changed") {
QString name = data.toObject()["control"].toString();
int value = data.toObject()["value"].toDouble() * 100;
value = qBound(0, value, 100);
for (QObject *o : m_roles) {
AudioRole *ar = static_cast<AudioRole*>(o);
if (ar->Name() == name) {
ar->BeginUpdate();
ar->setValue(value);
break;
}
}
}
}
void Mixer::onRoleValueChanged()
{
AudioRole* role = qobject_cast<AudioRole*>(QObject::sender());
if (role == nullptr) return;
/* if the role was not being updated by us, it was modified from the UI,
in which case we have to set it to the backend */
if (!role->EndUpdate())
setRoleVolume(role);
}
void Mixer::TryOpen()
{
qDebug() << "Mixer::TryOpen: " << m_url;
m_client.open(m_url);
}