#include <QJsonArray>
#include <QJsonObject>
+#include <QTimer>
#include <QtDebug>
-#include "mixer.h"
+#include "mixer.hpp"
+
Mixer::Mixer(QObject* parent)
- : 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
{
- connect(&m_client, SIGNAL(connected()), this, SLOT(onClientConnected()));
+ return m_roles;
}
-QStringList Mixer::roles() const
+void Mixer::setRoleVolume(AudioRole* role)
{
- return m_roles;
+ if (role == nullptr) return;
+
+ QJsonObject arg;
+ arg.insert("control", role->Name().toLocal8Bit().data());
+ arg.insert("value", QJsonValue(role->Value() / 100.0));
+
+ m_client.call("audiomixer", "volume", arg);
}
-void Mixer::open(const QUrl &url)
+void Mixer::parseControls(const QJsonValue & v)
{
- m_client.open(url);
+ 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 = static_cast<int>(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()
{
- // 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();
- }
- });
+ 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::setVolume(const QString& name, int value)
+void Mixer::onClientEventReceived(QString eventName, const QJsonValue& data)
{
- QJsonObject arg;
- arg.insert("action", "volume");
- arg.insert("value", QJsonValue(value));
- m_client.call("ahl-4a", name, arg, [name](bool r, const QJsonValue& v) {
- if (r && v.isObject())
- {
- // TODO: Success, update the slider
- }
- else
- {
- // TODO: Failed, reset the slider to previous value
- }
- });
+ 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 = static_cast<int>(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::getVolume(const QString& name)
+void Mixer::TryOpen()
{
- 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
- int newVolume = v.toObject()["response"].toObject()["volnew"].toInt();
- auto currentVolume = volumes_.find(name);
- if (currentVolume != volumes_.end() && *currentVolume == newVolume)
- return;
-
- volumes_[name] = newVolume;
- emit volumeChanged(name, newVolume);
- }
- else
- {
- // TODO: Failed, what to do ?
- }
- });
+ qDebug() << "Mixer::TryOpen: " << m_url;
+ m_client.open(m_url);
}