playing favorites do work now

This commit is contained in:
Boernsman 2020-02-06 14:55:08 +05:00 committed by bernhard.trinnes
parent e572974418
commit 8fa10cc548
5 changed files with 315 additions and 42 deletions

View File

@ -35,6 +35,7 @@
#include <QJsonDocument> #include <QJsonDocument>
#include <QUrlQuery> #include <QUrlQuery>
#include <QTimer> #include <QTimer>
#include <QRandomGenerator>
Heos::Heos(const QHostAddress &hostAddress, QObject *parent) : Heos::Heos(const QHostAddress &hostAddress, QObject *parent) :
QObject(parent), QObject(parent),
@ -383,26 +384,36 @@ void Heos::groupVolumeDown(int groupId, int step)
/******************************** /********************************
* BROWSE COMMANDS * BROWSE COMMANDS
********************************/ ********************************/
void Heos::getMusicSources() quint32 Heos::getMusicSources()
{ {
QByteArray cmd = "heos://browse/get_music_sources\r\n"; quint32 sequence = QRandomGenerator::global()->generate();
QByteArray cmd = "heos://browse/get_music_sources?";
QUrlQuery queryParams;
queryParams.addQueryItem("SEQUENCE", QString::number(sequence));
cmd.append(queryParams.toString());
cmd.append("\r\n");
qCDebug(dcDenon) << "Get music sources:" << cmd; qCDebug(dcDenon) << "Get music sources:" << cmd;
m_socket->write(cmd); m_socket->write(cmd);
return sequence;
} }
void Heos::getSourceInfo(const QString &sourceId) quint32 Heos::getSourceInfo(const QString &sourceId)
{ {
quint32 sequence = QRandomGenerator::global()->generate();
QByteArray cmd = "heos://browse/get_source_info?"; QByteArray cmd = "heos://browse/get_source_info?";
QUrlQuery queryParams; QUrlQuery queryParams;
queryParams.addQueryItem("sid", sourceId); queryParams.addQueryItem("sid", sourceId);
queryParams.addQueryItem("SEQUENCE", QString::number(sequence));
cmd.append(queryParams.toString()); cmd.append(queryParams.toString());
cmd.append("\r\n"); cmd.append("\r\n");
qCDebug(dcDenon) << "Get source info:" << cmd; qCDebug(dcDenon) << "Get source info:" << cmd;
m_socket->write(cmd); m_socket->write(cmd);
return sequence;
} }
void Heos::getSearchCriteria(const QString &sourceId) quint32 Heos::getSearchCriteria(const QString &sourceId)
{ {
quint32 sequence = QRandomGenerator::global()->generate();
QByteArray cmd = "heos://browse/get_search_criteria?"; QByteArray cmd = "heos://browse/get_search_criteria?";
QUrlQuery queryParams; QUrlQuery queryParams;
queryParams.addQueryItem("sid", sourceId); queryParams.addQueryItem("sid", sourceId);
@ -410,94 +421,118 @@ void Heos::getSearchCriteria(const QString &sourceId)
cmd.append("\r\n"); cmd.append("\r\n");
qCDebug(dcDenon) << "Get search criteria:" << cmd; qCDebug(dcDenon) << "Get search criteria:" << cmd;
m_socket->write(cmd); m_socket->write(cmd);
return sequence;
} }
void Heos::browseSource(const QString &sourceId) quint32 Heos::browseSource(const QString &sourceId)
{ {
quint32 sequence = QRandomGenerator::global()->generate();
QByteArray cmd = "heos://browse/browse?"; QByteArray cmd = "heos://browse/browse?";
QUrlQuery queryParams; QUrlQuery queryParams;
queryParams.addQueryItem("sid", sourceId); queryParams.addQueryItem("sid", sourceId);
queryParams.addQueryItem("SEQUENCE", QString::number(sequence));
cmd.append(queryParams.toString()); cmd.append(queryParams.toString());
cmd.append("\r\n"); cmd.append("\r\n");
qCDebug(dcDenon) << "Browse source:" << cmd; qCDebug(dcDenon) << "Browse source:" << cmd;
m_socket->write(cmd); m_socket->write(cmd);
return sequence;
} }
void Heos::browseSourceContainers(const QString &sourceId, const QString &containerId) quint32 Heos::browseSourceContainers(const QString &sourceId, const QString &containerId)
{ {
quint32 sequence = QRandomGenerator::global()->generate();
QByteArray cmd = "heos://browse/browse?"; QByteArray cmd = "heos://browse/browse?";
QUrlQuery queryParams; QUrlQuery queryParams;
queryParams.addQueryItem("sid", sourceId); queryParams.addQueryItem("sid", sourceId);
queryParams.addQueryItem("cid", containerId); queryParams.addQueryItem("cid", containerId);
queryParams.addQueryItem("SEQUENCE", QString::number(sequence));
cmd.append(queryParams.toString()); cmd.append(queryParams.toString());
cmd.append("\r\n"); cmd.append("\r\n");
qCDebug(dcDenon) << "Browsing container:" << cmd; qCDebug(dcDenon) << "Browsing container:" << cmd;
m_socket->write(cmd); m_socket->write(cmd);
return sequence;
} }
void Heos::playStation(int playerId, const QString &sourceId, const QString &containerId, const QString &mediaId, const QString &stationName) quint32 Heos::playStation(int playerId, const QString &sourceId, const QString &containerId, const QString &mediaId, const QString &stationName)
{ {
quint32 sequence = QRandomGenerator::global()->generate();
QByteArray cmd("heos://browse/play_stream?"); QByteArray cmd("heos://browse/play_stream?");
QUrlQuery queryParams; QUrlQuery queryParams;
queryParams.addQueryItem("pid", QString::number(playerId)); queryParams.addQueryItem("pid", QString::number(playerId));
queryParams.addQueryItem("sid", sourceId); queryParams.addQueryItem("sid", sourceId);
queryParams.addQueryItem("cid", containerId); if (!containerId.isEmpty()) {
queryParams.addQueryItem("cid", containerId);
}
queryParams.addQueryItem("mid", mediaId); queryParams.addQueryItem("mid", mediaId);
queryParams.addQueryItem("name", stationName); queryParams.addQueryItem("name", stationName);
queryParams.addQueryItem("SEQUENCE", QString::number(sequence));
cmd.append(queryParams.toString()); cmd.append(queryParams.toString());
cmd.append("\r\n"); cmd.append("\r\n");
qCDebug(dcDenon) << "playing station:" << cmd; qCDebug(dcDenon) << "playing station:" << cmd;
m_socket->write(cmd); m_socket->write(cmd);
return sequence;
} }
void Heos::playPresetStation(int playerId, int presetNumber) quint32 Heos::playPresetStation(int playerId, int presetNumber)
{ {
quint32 sequence = QRandomGenerator::global()->generate();
QByteArray cmd("heos://browse/play_preset?"); QByteArray cmd("heos://browse/play_preset?");
QUrlQuery queryParams; QUrlQuery queryParams;
queryParams.addQueryItem("pid", QString::number(playerId)); queryParams.addQueryItem("pid", QString::number(playerId));
queryParams.addQueryItem("preset", QString::number(presetNumber)); queryParams.addQueryItem("preset", QString::number(presetNumber));
queryParams.addQueryItem("SEQUENCE", QString::number(sequence));
cmd.append(queryParams.toString()); cmd.append(queryParams.toString());
cmd.append("\r\n"); cmd.append("\r\n");
qCDebug(dcDenon) << "playing preset station:" << cmd; qCDebug(dcDenon) << "playing preset station:" << cmd;
m_socket->write(cmd); m_socket->write(cmd);
return sequence;
} }
void Heos::playInputSource(int playerId, const QString &inputName) quint32 Heos::playInputSource(int playerId, const QString &inputName)
{ {
quint32 sequence = QRandomGenerator::global()->generate();
QByteArray cmd("heos://browse/play_input?"); QByteArray cmd("heos://browse/play_input?");
QUrlQuery queryParams; QUrlQuery queryParams;
queryParams.addQueryItem("pid", QString::number(playerId)); queryParams.addQueryItem("pid", QString::number(playerId));
queryParams.addQueryItem("input", inputName); queryParams.addQueryItem("input", inputName);
queryParams.addQueryItem("SEQUENCE", QString::number(sequence));
cmd.append(queryParams.toString()); cmd.append(queryParams.toString());
cmd.append("\r\n"); cmd.append("\r\n");
qCDebug(dcDenon) << "playing input source:" << cmd; qCDebug(dcDenon) << "playing input source:" << cmd;
m_socket->write(cmd); m_socket->write(cmd);
return sequence;
} }
void Heos::playUrl(int playerId, const QUrl &mediaUrl) quint32 Heos::playUrl(int playerId, const QUrl &mediaUrl)
{ {
quint32 sequence = QRandomGenerator::global()->generate();
QByteArray cmd("heos://browse/play_stream?"); QByteArray cmd("heos://browse/play_stream?");
QUrlQuery queryParams; QUrlQuery queryParams;
queryParams.addQueryItem("pid", QString::number(playerId)); queryParams.addQueryItem("pid", QString::number(playerId));
queryParams.addQueryItem("url", mediaUrl.toString()); queryParams.addQueryItem("url", mediaUrl.toString());
queryParams.addQueryItem("SEQUENCE", QString::number(sequence));
cmd.append(queryParams.toString()); cmd.append(queryParams.toString());
cmd.append("\r\n"); cmd.append("\r\n");
qCDebug(dcDenon) << "playing url:" << cmd; qCDebug(dcDenon) << "playing url:" << cmd;
m_socket->write(cmd); m_socket->write(cmd);
return sequence;
} }
void Heos::addContainerToQueue(int playerId, const QString &sourceId, const QString &containerId, ADD_CRITERIA addCriteria) quint32 Heos::addContainerToQueue(int playerId, const QString &sourceId, const QString &containerId, ADD_CRITERIA addCriteria)
{ {
quint32 sequence = QRandomGenerator::global()->generate();
QByteArray cmd("heos://browse/add_to_queue?"); QByteArray cmd("heos://browse/add_to_queue?");
QUrlQuery queryParams; QUrlQuery queryParams;
queryParams.addQueryItem("pid", QString::number(playerId)); queryParams.addQueryItem("pid", QString::number(playerId));
queryParams.addQueryItem("sid", sourceId); queryParams.addQueryItem("sid", sourceId);
queryParams.addQueryItem("cid", containerId); queryParams.addQueryItem("cid", containerId);
queryParams.addQueryItem("aid", QString::number(addCriteria)); queryParams.addQueryItem("aid", QString::number(addCriteria));
queryParams.addQueryItem("SEQUENCE", QString::number(sequence));
cmd.append(queryParams.toString()); cmd.append(queryParams.toString());
cmd.append("\r\n"); cmd.append("\r\n");
qCDebug(dcDenon) << "Adding to queue:" << cmd; qCDebug(dcDenon) << "Adding to queue:" << cmd;
m_socket->write(cmd); m_socket->write(cmd);
return sequence;
} }
void Heos::onConnected() void Heos::onConnected()
@ -569,10 +604,31 @@ void Heos::readData()
} else if (command.contains("check_account")) { } else if (command.contains("check_account")) {
qDebug(dcDenon()) << "System command check_account:" << message.toString();
bool signedIn;
QString username = "";
if (message.hasQueryItem("signed_in")){
signedIn = true;
username = message.queryItemValue("un");
} else {
signedIn = false;
}
emit userChanged(signedIn, username);
} else if (command.contains("sign_in")) { } else if (command.contains("sign_in")) {
qDebug(dcDenon()) << "System command sign_in:" << message.toString();
if (message.hasQueryItem("signed_in")) {
bool signedIn = true;
QString username = message.queryItemValue("un");
emit userChanged(signedIn, username);
} // otherwise it will be command under process and we will wait for the event
} else if (command.contains("sign_out")) { } else if (command.contains("sign_out")) {
qDebug(dcDenon()) << "System command sign_out:" << message.toString();
emit userChanged(false, "");
} else if (command.contains("heart_beat")) { } else if (command.contains("heart_beat")) {
} else if (command.contains("reboot")) { } else if (command.contains("reboot")) {
@ -817,6 +873,12 @@ void Heos::readData()
*/ */
} else if (command.startsWith("browse") || command.startsWith(" browse")) { } else if (command.startsWith("browse") || command.startsWith(" browse")) {
quint32 sequenceNumber = 0;
if (message.hasQueryItem("SEQUENCE")) {
qDebug(dcDenon) << "Sequence number" << message.queryItemValue("SEQUENCE");
sequenceNumber = message.queryItemValue("SEQUENCE").toUInt();
}
if (command.contains("get_music_sources") || command.contains("get_source_info")) { if (command.contains("get_music_sources") || command.contains("get_source_info")) {
qDebug(dcDenon()) << "Get music source request response received" << command; qDebug(dcDenon()) << "Get music source request response received" << command;
QVariantList payloadVariantList = jsonDoc.toVariant().toMap().value("payload").toList(); QVariantList payloadVariantList = jsonDoc.toVariant().toMap().value("payload").toList();
@ -832,10 +894,11 @@ void Heos::readData()
source.serviceUsername = payloadEntryVariant.toMap().value("service_username").toString(); source.serviceUsername = payloadEntryVariant.toMap().value("service_username").toString();
musicSources.append(source); musicSources.append(source);
} }
emit musicSourcesReceived(musicSources); emit musicSourcesReceived(sequenceNumber, musicSources);
} }
} else if (command.contains("browse/browse")) { } else if (command.contains("browse/browse")) {
qDebug(dcDenon()) << "Browse response:" << jsonDoc.toVariant().toMap().value("payload");
QVariantList payloadVariantList = jsonDoc.toVariant().toMap().value("payload").toList(); QVariantList payloadVariantList = jsonDoc.toVariant().toMap().value("payload").toList();
QString sourceId = message.queryItemValue("sid"); QString sourceId = message.queryItemValue("sid");
QString containerId = message.queryItemValue("cid"); QString containerId = message.queryItemValue("cid");
@ -889,7 +952,7 @@ void Heos::readData()
mediaItems.append(media); mediaItems.append(media);
} }
} }
emit browseRequestReceived(sourceId, containerId, musicSources, mediaItems); emit browseRequestReceived(sequenceNumber, sourceId, containerId, musicSources, mediaItems);
} }
else { else {
int errorId = message.queryItemValue("eid").toInt(); int errorId = message.queryItemValue("eid").toInt();
@ -1059,7 +1122,7 @@ void Heos::readData()
} }
} else if (command.contains("user_changed")) { } else if (command.contains("user_changed")) {
qDebug(dcDenon()) << "Event user changed"; qDebug(dcDenon()) << "Event user changed" << message.toString();
bool signedIn; bool signedIn;
QString username; QString username;
if (message.hasQueryItem("signed_out")){ if (message.hasQueryItem("signed_out")){

View File

@ -106,18 +106,19 @@ public:
void groupVolumeDown(int groupId, int step = 5); void groupVolumeDown(int groupId, int step = 5);
//Browse Get Commands //Browse Get Commands
void getMusicSources(); quint32 getMusicSources();
void getSourceInfo(const QString &sourceId); quint32 getSourceInfo(const QString &sourceId);
void getSearchCriteria(const QString &sourceId); quint32 getSearchCriteria(const QString &sourceId);
void browseSource(const QString &sourceId); quint32 browseSource(const QString &sourceId);
void browseSourceContainers(const QString &sourceId, const QString &containerId); quint32 browseSourceContainers(const QString &sourceId, const QString &containerId);
quint32 addContainerToQueue(int playerId, const QString &sourceId, const QString &containerId, ADD_CRITERIA addCriteria);
// Controllers can add custom argument SEQUENCE=<number> in browse commands to associate command and response.
//Play commands //Play commands
void playStation(int playerId, const QString &sourceId, const QString &containerId, const QString &mediaId, const QString &stationName); quint32 playStation(int playerId, const QString &sourceId, const QString &containerId, const QString &mediaId, const QString &stationName);
void playPresetStation(int playerId, int presetNumber); quint32 playPresetStation(int playerId, int presetNumber);
void playInputSource(int playerId, const QString &inputName); //Validity of Inputs depends on the type of source HEOS devic quint32 playInputSource(int playerId, const QString &inputName); //Validity of Inputs depends on the type of source HEOS devie
void playUrl(int playerId, const QUrl &url); quint32 playUrl(int playerId, const QUrl &url);
void addContainerToQueue(int playerId, const QString &sourceId, const QString &containerId, ADD_CRITERIA addCriteria);
private: private:
bool m_eventRegistered = false; bool m_eventRegistered = false;
@ -155,8 +156,8 @@ signals:
void sourcesChanged(); void sourcesChanged();
void nowPlayingMediaStatusReceived(int playerId, const QString &sourceId, const QString &artist, const QString &album, const QString &song, const QString &artwork); void nowPlayingMediaStatusReceived(int playerId, const QString &sourceId, const QString &artist, const QString &album, const QString &song, const QString &artwork);
void musicSourcesReceived(QList<MusicSourceObject> musicSources); //callback of getMusicSource, not associated to a playerId void musicSourcesReceived(quint32 sequenceNumber, QList<MusicSourceObject> musicSources); //callback of getMusicSource, not associated to a playerId
void browseRequestReceived(const QString &sourceId, const QString &containerId, QList<MusicSourceObject> musicSources, QList<MediaObject> mediaItems); //callback of browseSource void browseRequestReceived(quint32 sequenceNumber, const QString &sourceId, const QString &containerId, QList<MusicSourceObject> musicSources, QList<MediaObject> mediaItems); //callback of browseSource
void browseErrorReceived(const QString &sourceId, const QString &containerId, int errorId, const QString &errorMessage); void browseErrorReceived(const QString &sourceId, const QString &containerId, int errorId, const QString &errorMessage);
void userChanged(bool signedIn, const QString &userName); void userChanged(bool signedIn, const QString &userName);

View File

@ -167,7 +167,43 @@ void IntegrationPluginDenon::discoverThings(ThingDiscoveryInfo *info)
>>>>>>> tryna to fix discovery:denon/deviceplugindenon.cpp >>>>>>> tryna to fix discovery:denon/deviceplugindenon.cpp
} }
<<<<<<< HEAD:denon/integrationplugindenon.cpp
void IntegrationPluginDenon::setupThing(ThingSetupInfo *info) void IntegrationPluginDenon::setupThing(ThingSetupInfo *info)
=======
void DevicePluginDenon::startPairing(DevicePairingInfo *info)
{
info->finish(Device::DeviceErrorNoError, QT_TR_NOOP("Please enter your HEOS account credentials. Leave empty if you doesn't have any. Some features like music browsing won't be available."));
}
void DevicePluginDenon::confirmPairing(DevicePairingInfo *info, const QString &username, const QString &password)
{
if (info->deviceClassId() == heosDeviceClassId) {
if (username.isEmpty()) { //device connection will be setup without an user account
info->finish(Device::DeviceErrorNoError);
}
QHostAddress address(info->params().paramValue(heosDeviceIpParamTypeId).toString());
Heos *heos = createHeosConnection(address);
m_unfinishedHeosConnections.insert(info->deviceId(), heos);
m_unfinishedHeosPairings.insert(heos, info);
connect(info, &DevicePairingInfo::aborted, this, [heos, this] {
m_unfinishedHeosPairings.remove(heos);
heos->deleteLater();
});
heos->connectDevice();
heos->setUserAccount(username, password);;
pluginStorage()->beginGroup(info->deviceId().toString());
pluginStorage()->setValue("username", username);
pluginStorage()->setValue("password", password);
pluginStorage()->endGroup();
}
}
void DevicePluginDenon::setupDevice(DeviceSetupInfo *info)
>>>>>>> playing favorites do work now:denon/deviceplugindenon.cpp
{ {
Thing *thing = info->thing(); Thing *thing = info->thing();
@ -195,7 +231,7 @@ void IntegrationPluginDenon::setupThing(ThingSetupInfo *info)
m_asyncAvrSetups.insert(denonConnection, info); m_asyncAvrSetups.insert(denonConnection, info);
// In case the setup is cancelled before we finish it... // In case the setup is cancelled before we finish it...
connect(info, &QObject::destroyed, this, [this, info, denonConnection]() { m_asyncAvrSetups.remove(denonConnection); }); connect(info, &QObject::destroyed, this, [this, denonConnection]() { m_asyncAvrSetups.remove(denonConnection); });
denonConnection->connectDevice(); denonConnection->connectDevice();
return; return;
@ -210,6 +246,7 @@ void IntegrationPluginDenon::setupThing(ThingSetupInfo *info)
return; return;
} }
<<<<<<< HEAD:denon/integrationplugindenon.cpp
Heos *heos = new Heos(address, this); Heos *heos = new Heos(address, this);
connect(heos, &Heos::connectionStatusChanged, this, &IntegrationPluginDenon::onHeosConnectionChanged); connect(heos, &Heos::connectionStatusChanged, this, &IntegrationPluginDenon::onHeosConnectionChanged);
connect(heos, &Heos::playersChanged, this, &IntegrationPluginDenon::onHeosPlayersChanged); connect(heos, &Heos::playersChanged, this, &IntegrationPluginDenon::onHeosPlayersChanged);
@ -234,16 +271,46 @@ void IntegrationPluginDenon::setupThing(ThingSetupInfo *info)
m_asyncHeosSetups.insert(heos, info); m_asyncHeosSetups.insert(heos, info);
// In case the setup is cancelled before we finish it... // In case the setup is cancelled before we finish it...
connect(info, &QObject::destroyed, this, [this, info, heos]() { m_asyncHeosSetups.remove(heos); }); connect(info, &QObject::destroyed, this, [this, info, heos]() { m_asyncHeosSetups.remove(heos); });
=======
Heos *heos;
if (m_unfinishedHeosConnections.contains(device->id())) {
heos = m_unfinishedHeosConnections.take(device->id());
info->finish(Device::DeviceErrorNoError);
} else {
heos = createHeosConnection(address);
m_asyncHeosSetups.insert(heos, info);
// In case the setup is cancelled before we finish it...
connect(info, &QObject::destroyed, this, [this, heos]() { m_asyncHeosSetups.remove(heos); });
heos->connectDevice();
pluginStorage()->beginGroup(device->id().toString());
if (pluginStorage()->contains("username")) {
QString username = pluginStorage()->value("username").toString();
QString password = pluginStorage()->value("password").toString();
heos->setUserAccount(username, password);
}
pluginStorage()->endGroup();
}
m_heosConnections.insert(device->id(), heos);
>>>>>>> playing favorites do work now:denon/deviceplugindenon.cpp
heos->connectDevice();
return; return;
<<<<<<< HEAD:denon/integrationplugindenon.cpp
} }
if (thing->thingClassId() == heosPlayerThingClassId) { if (thing->thingClassId() == heosPlayerThingClassId) {
info->finish(Thing::ThingErrorNoError); info->finish(Thing::ThingErrorNoError);
=======
} else if (device->deviceClassId() == heosPlayerDeviceClassId) {
info->finish(Device::DeviceErrorNoError);
>>>>>>> playing favorites do work now:denon/deviceplugindenon.cpp
return; return;
} else {
info->finish(Device::DeviceErrorDeviceClassNotFound);
} }
<<<<<<< HEAD:denon/integrationplugindenon.cpp
info->finish(Thing::ThingErrorThingClassNotFound); info->finish(Thing::ThingErrorThingClassNotFound);
=======
>>>>>>> playing favorites do work now:denon/deviceplugindenon.cpp
} }
void IntegrationPluginDenon::thingRemoved(Thing *thing) void IntegrationPluginDenon::thingRemoved(Thing *thing)
@ -258,11 +325,19 @@ void IntegrationPluginDenon::thingRemoved(Thing *thing)
denonConnection->disconnectDevice(); denonConnection->disconnectDevice();
denonConnection->deleteLater(); denonConnection->deleteLater();
} }
<<<<<<< HEAD:denon/integrationplugindenon.cpp
} else if (thing->thingClassId() == heosThingClassId) { } else if (thing->thingClassId() == heosThingClassId) {
if (m_heos.contains(thing->id())) { if (m_heos.contains(thing->id())) {
Heos *heos = m_heos.take(thing->id()); Heos *heos = m_heos.take(thing->id());
=======
} else if (device->deviceClassId() == heosDeviceClassId) {
if (m_heosConnections.contains(device->id())) {
Heos *heos = m_heosConnections.take(device->id());
>>>>>>> playing favorites do work now:denon/deviceplugindenon.cpp
heos->deleteLater(); heos->deleteLater();
} }
pluginStorage()->remove(device->id().toString());
} }
if (myThings().empty()) { if (myThings().empty()) {
@ -325,9 +400,15 @@ void IntegrationPluginDenon::executeAction(ThingActionInfo *info)
} else if (device->deviceClassId() == heosPlayerDeviceClassId) { } else if (device->deviceClassId() == heosPlayerDeviceClassId) {
>>>>>>> tryna to fix discovery:denon/deviceplugindenon.cpp >>>>>>> tryna to fix discovery:denon/deviceplugindenon.cpp
<<<<<<< HEAD:denon/integrationplugindenon.cpp
Thing *heosThing = myThings().findById(thing->parentId()); Thing *heosThing = myThings().findById(thing->parentId());
Heos *heos = m_heos.value(heosThing->id()); Heos *heos = m_heos.value(heosThing->id());
int playerId = thing->paramValue(heosPlayerThingPlayerIdParamTypeId).toInt(); int playerId = thing->paramValue(heosPlayerThingPlayerIdParamTypeId).toInt();
=======
Device *heosDevice = myDevices().findById(device->parentId());
Heos *heos = m_heosConnections.value(heosDevice->id());
int playerId = device->paramValue(heosPlayerDevicePlayerIdParamTypeId).toInt();
>>>>>>> playing favorites do work now:denon/deviceplugindenon.cpp
if (action.actionTypeId() == heosPlayerAlertActionTypeId) { if (action.actionTypeId() == heosPlayerAlertActionTypeId) {
heos->playUrl(playerId, m_notificationUrl); heos->playUrl(playerId, m_notificationUrl);
@ -438,8 +519,13 @@ void IntegrationPluginDenon::executeAction(ThingActionInfo *info)
void IntegrationPluginDenon::postSetupThing(Thing *thing) void IntegrationPluginDenon::postSetupThing(Thing *thing)
{ {
<<<<<<< HEAD:denon/integrationplugindenon.cpp
if (thing->thingClassId() == heosThingClassId) { if (thing->thingClassId() == heosThingClassId) {
Heos *heos = m_heos.value(thing->id()); Heos *heos = m_heos.value(thing->id());
=======
if (device->deviceClassId() == heosDeviceClassId) {
Heos *heos = m_heosConnections.value(device->id());
>>>>>>> playing favorites do work now:denon/deviceplugindenon.cpp
device->setStateValue(heosConnectedStateTypeId, heos->connected()); device->setStateValue(heosConnectedStateTypeId, heos->connected());
heos->getPlayers(); heos->getPlayers();
heos->getGroups(); heos->getGroups();
@ -456,7 +542,7 @@ void IntegrationPluginDenon::postSetupThing(Thing *thing)
} else if (device->deviceClassId() == heosPlayerDeviceClassId) { } else if (device->deviceClassId() == heosPlayerDeviceClassId) {
device->setStateValue(heosPlayerConnectedStateTypeId, true); device->setStateValue(heosPlayerConnectedStateTypeId, true);
Device *heosDevice = myDevices().findById(device->parentId()); Device *heosDevice = myDevices().findById(device->parentId());
Heos *heos = m_heos.value(heosDevice->id()); Heos *heos = m_heosConnections.value(heosDevice->id());
int playerId = device->paramValue(heosPlayerDevicePlayerIdParamTypeId).toInt(); int playerId = device->paramValue(heosPlayerDevicePlayerIdParamTypeId).toInt();
>>>>>>> tryna to fix discovery:denon/deviceplugindenon.cpp >>>>>>> tryna to fix discovery:denon/deviceplugindenon.cpp
heos->getPlayerState(playerId); heos->getPlayerState(playerId);
@ -488,8 +574,13 @@ void IntegrationPluginDenon::onPluginTimer()
foreach(Thing *thing, myThings()) { foreach(Thing *thing, myThings()) {
<<<<<<< HEAD:denon/integrationplugindenon.cpp
if (thing->thingClassId() == heosThingClassId) { if (thing->thingClassId() == heosThingClassId) {
Heos *heos = m_heos.value(thing->id()); Heos *heos = m_heos.value(thing->id());
=======
if (device->deviceClassId() == heosDeviceClassId) {
Heos *heos = m_heosConnections.value(device->id());
>>>>>>> playing favorites do work now:denon/deviceplugindenon.cpp
heos->getPlayers(); heos->getPlayers();
heos->registerForChangeEvents(true); heos->registerForChangeEvents(true);
<<<<<<< HEAD:denon/integrationplugindenon.cpp <<<<<<< HEAD:denon/integrationplugindenon.cpp
@ -502,10 +593,11 @@ void IntegrationPluginDenon::onPluginTimer()
======= =======
} else if (device->deviceClassId() == heosPlayerDeviceClassId) { } else if (device->deviceClassId() == heosPlayerDeviceClassId) {
Device *heosDevice = myDevices().findById(device->parentId()); Device *heosDevice = myDevices().findById(device->parentId());
Heos *heos = m_heos.value(heosDevice->id()); Heos *heos = m_heosConnections.value(heosDevice->id());
int playerId = device->paramValue(heosPlayerDevicePlayerIdParamTypeId).toInt(); int playerId = device->paramValue(heosPlayerDevicePlayerIdParamTypeId).toInt();
>>>>>>> tryna to fix discovery:denon/deviceplugindenon.cpp >>>>>>> tryna to fix discovery:denon/deviceplugindenon.cpp
//TODO check if event stream is sufficent and remove polling
heos->getPlayerState(playerId); heos->getPlayerState(playerId);
heos->getPlayMode(playerId); heos->getPlayMode(playerId);
heos->getVolume(playerId); heos->getVolume(playerId);
@ -647,14 +739,14 @@ void IntegrationPluginDenon::onHeosConnectionChanged(bool status)
thing->setStateValue(heosConnectedStateTypeId, status); thing->setStateValue(heosConnectedStateTypeId, status);
======= =======
if (status) { if (status) {
// and from the first setup
if (m_asyncHeosSetups.contains(heos)) { if (m_asyncHeosSetups.contains(heos)) {
DeviceSetupInfo *info = m_asyncHeosSetups.take(heos); DeviceSetupInfo *info = m_asyncHeosSetups.take(heos);
info->finish(Device::DeviceErrorNoError); info->finish(Device::DeviceErrorNoError);
} }
} }
Device *device = myDevices().findById(m_heos.key(heos)); Device *device = myDevices().findById(m_heosConnections.key(heos));
if (!device) if (!device)
return; return;
@ -663,11 +755,17 @@ void IntegrationPluginDenon::onHeosConnectionChanged(bool status)
device->setStateValue(heosConnectedStateTypeId, status); device->setStateValue(heosConnectedStateTypeId, status);
>>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp >>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp
// update connection status for all child devices // update connection status for all child devices
<<<<<<< HEAD:denon/integrationplugindenon.cpp
foreach (Thing *playerDevice, myThings()) { foreach (Thing *playerDevice, myThings()) {
if (playerDevice->thingClassId() == heosPlayerThingClassId) { if (playerDevice->thingClassId() == heosPlayerThingClassId) {
if (playerDevice->parentId() == thing->id()) { if (playerDevice->parentId() == thing->id()) {
playerDevice->setStateValue(heosPlayerConnectedStateTypeId, status); playerDevice->setStateValue(heosPlayerConnectedStateTypeId, status);
} }
=======
foreach (Device *playerDevice, myDevices().filterByParentDeviceId(device->id())) {
if (playerDevice->deviceClassId() == heosPlayerDeviceClassId) {
playerDevice->setStateValue(heosPlayerConnectedStateTypeId, status);
>>>>>>> playing favorites do work now:denon/deviceplugindenon.cpp
} }
} }
} }
@ -686,6 +784,13 @@ void IntegrationPluginDenon::onHeosPlayersReceived(QList<HeosPlayer *> heosPlaye
>>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp >>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp
Heos *heos = static_cast<Heos *>(sender()); Heos *heos = static_cast<Heos *>(sender());
<<<<<<< HEAD:denon/integrationplugindenon.cpp
=======
Device *device = myDevices().findById(m_heosConnections.key(heos));
if (!device) {
return;
}
>>>>>>> playing favorites do work now:denon/deviceplugindenon.cpp
<<<<<<< HEAD:denon/integrationplugindenon.cpp <<<<<<< HEAD:denon/integrationplugindenon.cpp
Thing *thing = myThings().findById(m_heos.key(heos)); Thing *thing = myThings().findById(m_heos.key(heos));
@ -729,6 +834,7 @@ void IntegrationPluginDenon::onHeosPlayStateReceived(int playerId, PLAYER_STATE
======= =======
//TODO remove devices //TODO remove devices
//autoDeviceDisappeared();
//TODO remove player from player Buffer //TODO remove player from player Buffer
autoDevicesAppeared(heosPlayerDescriptors); autoDevicesAppeared(heosPlayerDescriptors);
} }
@ -891,9 +997,14 @@ void IntegrationPluginDenon::onHeosNowPlayingMediaStatusReceived(int playerId, c
>>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp >>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp
} }
<<<<<<< HEAD:denon/integrationplugindenon.cpp
void IntegrationPluginDenon::onHeosMusicSourcesReceived(QList<MusicSourceObject> musicSources) void IntegrationPluginDenon::onHeosMusicSourcesReceived(QList<MusicSourceObject> musicSources)
=======
void DevicePluginDenon::onHeosMusicSourcesReceived(quint32 sequenceNumber, QList<MusicSourceObject> musicSources)
>>>>>>> playing favorites do work now:denon/deviceplugindenon.cpp
{ {
Q_UNUSED(sequenceNumber)
Heos *heos = static_cast<Heos *>(sender()); Heos *heos = static_cast<Heos *>(sender());
if (m_pendingGetSourcesRequest.contains(heos)) { if (m_pendingGetSourcesRequest.contains(heos)) {
BrowseResult *result = m_pendingGetSourcesRequest.take(heos); BrowseResult *result = m_pendingGetSourcesRequest.take(heos);
@ -902,7 +1013,12 @@ void IntegrationPluginDenon::onHeosMusicSourcesReceived(QList<MusicSourceObject>
item.setDisplayName(source.name); item.setDisplayName(source.name);
item.setId("source=" + QString::number(source.sourceId)); item.setId("source=" + QString::number(source.sourceId));
item.setExecutable(false); item.setExecutable(false);
item.setBrowsable(true); item.setBrowsable(source.available);
if (!source.available) {
item.setDescription(tr("Service is not available"));
} else {
item.setDescription(source.serviceUsername);
}
item.setIcon(BrowserItem::BrowserIconMusic); item.setIcon(BrowserItem::BrowserIconMusic);
if (source.name == "Amazon") { if (source.name == "Amazon") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconAmazon); item.setMediaIcon(MediaBrowserItem::MediaBrowserIconAmazon);
@ -936,10 +1052,15 @@ void IntegrationPluginDenon::onHeosMusicSourcesReceived(QList<MusicSourceObject>
} }
} }
<<<<<<< HEAD:denon/integrationplugindenon.cpp
void IntegrationPluginDenon::onHeosMediaItemsReceived(QList<MediaObject> mediaItems) void IntegrationPluginDenon::onHeosMediaItemsReceived(QList<MediaObject> mediaItems)
void IntegrationPluginDenon::onHeosBrowseRequestReceived(const QString &sourceId, const QString &containerId, QList<MusicSourceObject> musicSources, QList<MediaObject> mediaItems) void IntegrationPluginDenon::onHeosBrowseRequestReceived(const QString &sourceId, const QString &containerId, QList<MusicSourceObject> musicSources, QList<MediaObject> mediaItems)
=======
void DevicePluginDenon::onHeosBrowseRequestReceived(quint32 sequenceNumber, const QString &sourceId, const QString &containerId, QList<MusicSourceObject> musicSources, QList<MediaObject> mediaItems)
>>>>>>> playing favorites do work now:denon/deviceplugindenon.cpp
{ {
Q_UNUSED(sequenceNumber)
QString identifier; QString identifier;
if (containerId.isEmpty()) { if (containerId.isEmpty()) {
identifier = sourceId; identifier = sourceId;
@ -1062,8 +1183,34 @@ void IntegrationPluginDenon::onHeosGroupsChanged()
heos->getPlayers(); heos->getPlayers();
} }
<<<<<<< HEAD:denon/integrationplugindenon.cpp
void IntegrationPluginDenon::onAvahiServiceEntryAdded(const ZeroConfServiceEntry &serviceEntry) void IntegrationPluginDenon::onAvahiServiceEntryAdded(const ZeroConfServiceEntry &serviceEntry)
>>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp >>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp
=======
void DevicePluginDenon::onHeosUserChanged(bool signedIn, const QString &userName)
{
Q_UNUSED(userName)
Heos *heos = static_cast<Heos *>(sender());
if (m_unfinishedHeosPairings.contains(heos)) {
DevicePairingInfo *info = m_unfinishedHeosPairings.take(heos);
if (signedIn) {
info->finish(Device::DeviceErrorNoError);
} else {
info->finish(Device::DeviceErrorAuthenticationFailure, tr("Wrong username or password"));
m_unfinishedHeosConnections.remove(info->deviceId());
heos->deleteLater();
}
}
if (m_heosConnections.values().contains(heos)) {
Device *device = myDevices().findById(m_heosConnections.key(heos));
device->setStateValue(heosLoggedInStateTypeId, signedIn);
device->setStateValue(heosUserDisplayNameStateTypeId, userName);
}
}
void DevicePluginDenon::onAvahiServiceEntryAdded(const ZeroConfServiceEntry &serviceEntry)
>>>>>>> playing favorites do work now:denon/deviceplugindenon.cpp
{ {
qCDebug(dcDenon()) << "Avahi service entry added:" << serviceEntry; qCDebug(dcDenon()) << "Avahi service entry added:" << serviceEntry;
} }
@ -1087,7 +1234,7 @@ void IntegrationPluginDenon::onPluginConfigurationChanged(const ParamTypeId &par
void IntegrationPluginDenon::browseDevice(BrowseResult *result) void IntegrationPluginDenon::browseDevice(BrowseResult *result)
{ {
Heos *heos = m_heos.value(result->device()->parentId()); Heos *heos = m_heosConnections.value(result->device()->parentId());
if (!heos) { if (!heos) {
result->finish(Device::DeviceErrorHardwareNotAvailable); result->finish(Device::DeviceErrorHardwareNotAvailable);
return; return;
@ -1179,7 +1326,7 @@ void IntegrationPluginDenon::browseDevice(BrowseResult *result)
void IntegrationPluginDenon::browserItem(BrowserItemResult *result) void IntegrationPluginDenon::browserItem(BrowserItemResult *result)
{ {
Heos *heos = m_heos.value(result->device()->parentId()); Heos *heos = m_heosConnections.value(result->device()->parentId());
if (!heos) { if (!heos) {
result->finish(Device::DeviceErrorHardwareNotAvailable); result->finish(Device::DeviceErrorHardwareNotAvailable);
return; return;
@ -1190,7 +1337,7 @@ void IntegrationPluginDenon::browserItem(BrowserItemResult *result)
void IntegrationPluginDenon::executeBrowserItem(BrowserActionInfo *info) void IntegrationPluginDenon::executeBrowserItem(BrowserActionInfo *info)
{ {
Heos *heos = m_heos.value(info->device()->parentId()); Heos *heos = m_heosConnections.value(info->device()->parentId());
if (!heos) { if (!heos) {
info->finish(Device::DeviceErrorHardwareNotAvailable); info->finish(Device::DeviceErrorHardwareNotAvailable);
return; return;
@ -1216,7 +1363,7 @@ void IntegrationPluginDenon::executeBrowserItem(BrowserActionInfo *info)
void IntegrationPluginDenon::executeBrowserItemAction(BrowserItemActionInfo *info) void IntegrationPluginDenon::executeBrowserItemAction(BrowserItemActionInfo *info)
{ {
Heos *heos = m_heos.value(info->device()->parentId()); Heos *heos = m_heosConnections.value(info->device()->parentId());
if (!heos) { if (!heos) {
info->finish(Device::DeviceErrorHardwareNotAvailable); info->finish(Device::DeviceErrorHardwareNotAvailable);
return; return;
@ -1254,3 +1401,27 @@ void IntegrationPluginDenon::executeBrowserItemAction(BrowserItemActionInfo *inf
info->finish(Device::DeviceErrorNoError); info->finish(Device::DeviceErrorNoError);
return; return;
} }
Heos *DevicePluginDenon::createHeosConnection(const QHostAddress &address)
{
Heos *heos = new Heos(address, this);
connect(heos, &Heos::connectionStatusChanged, this, &DevicePluginDenon::onHeosConnectionChanged);
connect(heos, &Heos::playersChanged, this, &DevicePluginDenon::onHeosPlayersChanged);
connect(heos, &Heos::playersRecieved, this, &DevicePluginDenon::onHeosPlayersReceived);
connect(heos, &Heos::playerInfoRecieved, this, &DevicePluginDenon::onHeosPlayerInfoRecieved);
connect(heos, &Heos::playerPlayStateReceived, this, &DevicePluginDenon::onHeosPlayStateReceived);
connect(heos, &Heos::playerRepeatModeReceived, this, &DevicePluginDenon::onHeosRepeatModeReceived);
connect(heos, &Heos::playerShuffleModeReceived, this, &DevicePluginDenon::onHeosShuffleModeReceived);
connect(heos, &Heos::playerMuteStatusReceived, this, &DevicePluginDenon::onHeosMuteStatusReceived);
connect(heos, &Heos::playerVolumeReceived, this, &DevicePluginDenon::onHeosVolumeStatusReceived);
connect(heos, &Heos::nowPlayingMediaStatusReceived, this, &DevicePluginDenon::onHeosNowPlayingMediaStatusReceived);
connect(heos, &Heos::playerNowPlayingChanged, this, &DevicePluginDenon::onHeosPlayerNowPlayingChanged);
connect(heos, &Heos::musicSourcesReceived, this, &DevicePluginDenon::onHeosMusicSourcesReceived);
connect(heos, &Heos::browseRequestReceived, this, &DevicePluginDenon::onHeosBrowseRequestReceived);
connect(heos, &Heos::browseErrorReceived, this, &DevicePluginDenon::onHeosBrowseErrorReceived);
connect(heos, &Heos::playerQueueChanged, this, &DevicePluginDenon::onHeosPlayerQueueChanged);
connect(heos, &Heos::groupsReceived, this, &DevicePluginDenon::onHeosGroupsReceived);
connect(heos, &Heos::groupsChanged, this, &DevicePluginDenon::onHeosGroupsChanged);
connect(heos, &Heos::userChanged, this, &DevicePluginDenon::onHeosUserChanged);
return heos;
}

View File

@ -57,12 +57,24 @@ class IntegrationPluginDenon : public IntegrationPlugin
public: public:
explicit IntegrationPluginDenon(); explicit IntegrationPluginDenon();
<<<<<<< HEAD:denon/integrationplugindenon.h
void init() override; void init() override;
void discoverThings(ThingDiscoveryInfo *info) override; void discoverThings(ThingDiscoveryInfo *info) override;
void setupThing(ThingSetupInfo *info) override; void setupThing(ThingSetupInfo *info) override;
void postSetupThing(Thing *thing) override; void postSetupThing(Thing *thing) override;
void executeAction(ThingActionInfo *info) override; void executeAction(ThingActionInfo *info) override;
void thingRemoved(Thing *thing) override; void thingRemoved(Thing *thing) override;
=======
void discoverDevices(DeviceDiscoveryInfo *info) override;
void startPairing(DevicePairingInfo *info) override;
void confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) override;
void setupDevice(DeviceSetupInfo *info) override;
void postSetupDevice(Device *device) override;
void executeAction(DeviceActionInfo *info) override;
void deviceRemoved(Device *device) override;
>>>>>>> playing favorites do work now:denon/deviceplugindenon.h
void browseThing(BrowseResult *result) override; void browseThing(BrowseResult *result) override;
void browserItem(BrowserItemResult *result) override; void browserItem(BrowserItemResult *result) override;
@ -73,8 +85,15 @@ private:
PluginTimer *m_pluginTimer = nullptr; PluginTimer *m_pluginTimer = nullptr;
ZeroConfServiceBrowser *m_serviceBrowser = nullptr; ZeroConfServiceBrowser *m_serviceBrowser = nullptr;
<<<<<<< HEAD:denon/integrationplugindenon.h
QHash<ThingId, AvrConnection*> m_avrConnections; QHash<ThingId, AvrConnection*> m_avrConnections;
QHash<ThingId, Heos*> m_heos; QHash<ThingId, Heos*> m_heos;
=======
QHash<DeviceId, AvrConnection*> m_avrConnections;
QHash<DeviceId, Heos*> m_heosConnections;
QHash<DeviceId, Heos*> m_unfinishedHeosConnections;
QHash<Heos *, DevicePairingInfo *> m_unfinishedHeosPairings;
>>>>>>> playing favorites do work now:denon/deviceplugindenon.h
QHash<AvrConnection*, ThingSetupInfo*> m_asyncAvrSetups; QHash<AvrConnection*, ThingSetupInfo*> m_asyncAvrSetups;
QHash<Heos*, ThingSetupInfo*> m_asyncHeosSetups; QHash<Heos*, ThingSetupInfo*> m_asyncHeosSetups;
@ -94,6 +113,8 @@ private:
QHash<int, GroupObject> m_groupBuffer; QHash<int, GroupObject> m_groupBuffer;
QHash<int, HeosPlayer *> m_playerBuffer; QHash<int, HeosPlayer *> m_playerBuffer;
Heos *createHeosConnection(const QHostAddress &address);
private slots: private slots:
void onPluginTimer(); void onPluginTimer();
@ -107,15 +128,15 @@ private slots:
void onHeosMuteStatusReceived(int playerId, bool mute); void onHeosMuteStatusReceived(int playerId, bool mute);
void onHeosVolumeStatusReceived(int playerId, int volume); void onHeosVolumeStatusReceived(int playerId, int volume);
void onHeosNowPlayingMediaStatusReceived(int playerId, const QString &sourceId, const QString &artist, const QString &album, const QString &song, const QString &artwork); void onHeosNowPlayingMediaStatusReceived(int playerId, const QString &sourceId, const QString &artist, const QString &album, const QString &song, const QString &artwork);
void onHeosMusicSourcesReceived(QList<MusicSourceObject> musicSources); void onHeosMusicSourcesReceived(quint32 sequenceNumber, QList<MusicSourceObject> musicSources);
void onHeosBrowseRequestReceived(const QString &sourceId, const QString &containerId, QList<MusicSourceObject> musicSources, QList<MediaObject> mediaItems); void onHeosBrowseRequestReceived(quint32 sequenceNumber, const QString &sourceId, const QString &containerId, QList<MusicSourceObject> musicSources, QList<MediaObject> mediaItems);
void onHeosBrowseErrorReceived(const QString &sourceId, const QString &containerId, int errorId, const QString &errorMessage); void onHeosBrowseErrorReceived(const QString &sourceId, const QString &containerId, int errorId, const QString &errorMessage);
void onHeosPlayerNowPlayingChanged(int playerId); void onHeosPlayerNowPlayingChanged(int playerId);
void onHeosPlayerQueueChanged(int playerId); void onHeosPlayerQueueChanged(int playerId);
void onHeosGroupsReceived(QList<GroupObject> groups); void onHeosGroupsReceived(QList<GroupObject> groups);
void onHeosGroupsChanged(); void onHeosGroupsChanged();
void onHeosUserChanged(bool signedIn, const QString &userName);
void onAvahiServiceEntryAdded(const ZeroConfServiceEntry &serviceEntry); void onAvahiServiceEntryAdded(const ZeroConfServiceEntry &serviceEntry);
void onAvahiServiceEntryRemoved(const ZeroConfServiceEntry &serviceEntry); void onAvahiServiceEntryRemoved(const ZeroConfServiceEntry &serviceEntry);

View File

@ -171,6 +171,7 @@
"name": "heos", "name": "heos",
"displayName": "Heos", "displayName": "Heos",
"createMethods": ["discovery"], "createMethods": ["discovery"],
"setupMethod": "userandpassword",
"interfaces": ["gateway"], "interfaces": ["gateway"],
"paramTypes": [ "paramTypes": [
{ {
@ -201,6 +202,22 @@
"displayNameEvent": "Connected changed", "displayNameEvent": "Connected changed",
"defaultValue": false, "defaultValue": false,
"type": "bool" "type": "bool"
},
{
"id": "ab689a6e-eb71-4a41-a267-ba1afe7e2f56",
"name": "loggedIn",
"displayName": "Logged in",
"displayNameEvent": "Logged in changed",
"defaultValue": true,
"type": "bool"
},
{
"id": "77756132-5fa4-409e-969e-d23bcee72356",
"name": "userDisplayName",
"displayName": "User name",
"displayNameEvent": "User name changed",
"type": "QString",
"defaultValue": ""
} }
] ]
}, },
@ -367,7 +384,7 @@
{ {
"id": "a718f7e9-0b54-4403-b661-49f7b0d13085", "id": "a718f7e9-0b54-4403-b661-49f7b0d13085",
"name": "skipBack", "name": "skipBack",
"displayName": "Akip back" "displayName": "Skip back"
}, },
{ {
"id": "c4b29c09-e3b3-4843-b6d9-e032f3fc1d78", "id": "c4b29c09-e3b3-4843-b6d9-e032f3fc1d78",