added join/unjoin group

This commit is contained in:
nymea 2019-10-15 15:14:02 +02:00 committed by bernhard.trinnes
parent 9388a563ff
commit daaf76ed58
7 changed files with 462 additions and 106 deletions

View File

@ -53,7 +53,7 @@ Heos::~Heos()
m_socket->close();
}
void Heos::connectHeos()
void Heos::connectDevice()
{
if (m_socket->state() == QAbstractSocket::ConnectingState) {
return;
@ -61,6 +61,18 @@ void Heos::connectHeos()
m_socket->connectToHost(m_hostAddress, 1255);
}
bool Heos::connected()
{
return m_socket->isOpen();
}
void Heos::disconnectDevice()
{
m_socket->close();
}
/********************************
* PLAYER COMMANDS
********************************/
@ -182,17 +194,19 @@ void Heos::getNowPlayingMedia(int playerId)
m_socket->write(cmd);
}
HeosPlayer *Heos::getPlayer(int playerId)
{
return m_heosPlayers.value(playerId);
}
void Heos::getPlayers()
{
QByteArray cmd = "heos://player/get_players\r\n";
m_socket->write(cmd);
}
void Heos::getPlayerInfo(int playerId)
{
QByteArray cmd = "heos://player/get_player_info?pid=" + QVariant(playerId).toByteArray() + "\r\n";
qCDebug(dcDenon) << "Get player info:" << cmd;
m_socket->write(cmd);
}
void Heos::getVolume(int playerId)
{
QByteArray cmd = "heos://player/get_volume?pid=" + QVariant(playerId).toByteArray() + "\r\n";
@ -331,6 +345,19 @@ void Heos::setGroupMute(int groupId, bool mute)
m_socket->write(cmd);
}
void Heos::setGroup(QList<int> playerIds)
{
QByteArray cmd = "heos://group/set_group?pid=";
foreach(int playerId, playerIds) {
cmd.append(QVariant(playerId).toByteArray());
cmd.append(',');
}
cmd.resize(cmd.size()-1); //remove last ','
cmd.append("\r\n");
qCDebug(dcDenon) << "Set group:" << cmd;
m_socket->write(cmd);
}
void Heos::toggleGroupMute(int groupId)
{
QByteArray cmd = "heos://group/toggle_mute?gid=" + QVariant(groupId).toByteArray() + "\r\n";
@ -483,7 +510,7 @@ void Heos::onDisconnected()
{
qCDebug(dcDenon()) << "Disconnected from" << m_hostAddress.toString() << "try reconnecting in 5 seconds";
QTimer::singleShot(5000, this, [this](){
connectHeos();
connectDevice();
});
emit connectionStatusChanged(false);
}
@ -495,7 +522,6 @@ void Heos::onError(QAbstractSocket::SocketError socketError)
void Heos::readData()
{
QByteArray data;
QJsonParseError error;
@ -534,9 +560,11 @@ void Heos::readData()
if (enabled.contains("off")) {
qDebug(dcDenon) << "Events are disabled";
m_eventRegistered = false;
emit systemEventsEnabled(false);
} else {
qDebug(dcDenon) << "Events are enabled";
m_eventRegistered = true;
emit systemEventsEnabled(true);
}
} else if (command.contains("check_account")) {
@ -551,8 +579,9 @@ void Heos::readData()
} else if (command.contains("prettify_json_response")) {
} else {
qDebug(dcDenon) << "Unhandled Heos system command" << command;
}
}
/* 4.2 Player Commands
* 4.2.1 Get Players
* 4.2.2 Get Player Info
@ -578,7 +607,7 @@ void Heos::readData()
* 4.2.25 Get QuickSelects [LS AVR Only]
* 4.2.26 Check for Firmware Update
*/
if (command.startsWith("player")) {
} else if (command.startsWith("player")) {
int playerId = 0;
if (message.hasQueryItem("pid")) {
playerId = message.queryItemValue("pid").toInt();
@ -586,28 +615,45 @@ void Heos::readData()
if (command.contains("get_players")) {
QVariantList payloadVariantList = jsonDoc.toVariant().toMap().value("payload").toList();
QList<HeosPlayer *> players;
foreach (const QVariant &payloadEntryVariant, payloadVariantList) {
playerId = payloadEntryVariant.toMap().value("pid").toInt();
if(!m_heosPlayers.contains(playerId)){
QString serialNumber = payloadEntryVariant.toMap().value("serial").toString();
QString name = payloadEntryVariant.toMap().value("name").toString();
HeosPlayer *heosPlayer = new HeosPlayer(playerId, name, serialNumber, this);
m_heosPlayers.insert(playerId, heosPlayer);
emit playerDiscovered(heosPlayer);
}
HeosPlayer *player = new HeosPlayer(payloadEntryVariant.toMap().value("pid").toInt());
player->setSerialNumber(payloadEntryVariant.toMap().value("serial").toString());
player->setName(payloadEntryVariant.toMap().value("name").toString());
getPlayerInfo(player->playerId());
players.append(player);
}
}else if (command.contains("get_player_info")) {
emit playersRecieved(players);
} else if (command.contains("get_player_info")) {
//update heos player info
int pid = dataMap.value("payload").toMap().value("pid").toInt();
HeosPlayer *player = new HeosPlayer(pid);
player->setName(dataMap.value("payload").toMap().value("name").toString());
if (dataMap.value("payload").toMap().contains("gid")) {
player->setGroupId(dataMap.value("payload").toMap().value("gid").toInt());
} else {
player->setGroupId(-1); //no group assigned
}
player->setPlayerModel(dataMap.value("payload").toMap().value("model").toString());
player->setPlayerVersion(dataMap.value("payload").toMap().value("version").toString());
player->setLineOut(dataMap.value("payload").toMap().value("lineout").toString());
player->setControl(dataMap.value("payload").toMap().value("control").toString());
player->setSerialNumber(dataMap.value("payload").toMap().value("serial").toString());
player->setNetwork(dataMap.value("payload").toMap().value("network").toString());
emit playerInfoRecieved(player);
} else if (command.contains("get_now_playing_media")) {
QString artist = dataMap.value("payload").toMap().value("artist").toString();
QString song = dataMap.value("payload").toMap().value("song").toString();
QString artwork = dataMap.value("payload").toMap().value("image_url").toString();
QString album = dataMap.value("payload").toMap().value("album").toString();
SOURCE_ID sourceId = SOURCE_ID(dataMap.value("payload").toMap().value("sid").toInt());
QString sourceId = dataMap.value("payload").toMap().value("sid").toString();
qDebug(dcDenon) << "Now playing" << playerId << sourceId << artist << album << song;
emit nowPlayingMediaStatusReceived(playerId, sourceId, artist, album, song, artwork);
}else if (command.contains("get_play_state") || command.contains("set_play_state")) {
} else if (command.contains("get_play_state") || command.contains("set_play_state")) {
if (message.hasQueryItem("state")) {
PLAYER_STATE playState = PLAYER_STATE_STOP;
if (message.queryItemValue("state").contains("play")) {
@ -657,22 +703,23 @@ void Heos::readData()
QVariantMap payloadVariantMap = jsonDoc.toVariant().toMap().value("payload").toMap();
bool updateExist = payloadVariantMap.value("update").toString().contains("exist");
emit playerUpdateAvailable(playerId, updateExist);
} else {
qDebug(dcDenon) << "Unhandled Heos group command" << command;
}
}
/*
* 4.3 Group Commands
* 4.3.1 Get Groups
* 4.3.2 Get Group Info
* 4.3.3 Set Group
* 4.3.4 Get Group Volume
* 4.3.5 Set Group Volume
* 4.2.6 Group Volume Up
* 4.2.7 Group Volume Down
* 4.3.8 Get Group Mute
* 4.3.9 Set Group Mute
* 4.3.10 Toggle Group Mute
*/
if (command.startsWith("group")) {
* 4.3 Group Commands
* 4.3.1 Get Groups
* 4.3.2 Get Group Info
* 4.3.3 Set Group
* 4.3.4 Get Group Volume
* 4.3.5 Set Group Volume
* 4.2.6 Group Volume Up
* 4.2.7 Group Volume Down
* 4.3.8 Get Group Mute
* 4.3.9 Set Group Mute
* 4.3.10 Toggle Group Mute
*/
} else if (command.startsWith("group")) {
int groupId = 0;
if (message.hasQueryItem("gid")) {
qDebug(dcDenon) << "Group id" << message.queryItemValue("gid");
@ -698,8 +745,32 @@ void Heos::readData()
}
emit groupsReceived(groups);
} else if (command.contains("get_group_info")) {
QVariantMap payloadVariantMap = jsonDoc.toVariant().toMap().value("payload").toMap();
GroupObject group;
group.groupId = payloadVariantMap.value("gid").toInt();
group.name = payloadVariantMap.value("name").toString();
if (!payloadVariantMap.value("players").toList().isEmpty()) {
QVariantList playerlist = payloadVariantMap.value("players").toList();
foreach (const QVariant &playerVariant, playerlist) {
PlayerObject player;
player.name = playerVariant.toMap().value("name").toString();
player.playerId = playerVariant.toMap().value("pid").toInt();
group.players.append(player);
}
}
emit groupInfoReceived(group);
} else if (command.contains("set_group")) {
if (message.hasQueryItem("gid")) {
int groupId = message.queryItemValue("gid").toInt();
QString groupName = message.queryItemValue("name");
emit setGroupReceived(groupId, groupName);
} else {
//No group Id so it must have been an ungoup request
int playerId = message.queryItemValue("pid").toInt();
emit deleteGroupReceived(playerId);
}
} else if (command.contains("get_volume") || command.contains("set_volume")) {
@ -722,8 +793,10 @@ void Heos::readData()
}
} else if (command.contains("toggle_mute")) {
} else {
qDebug(dcDenon) << "Unhandled Heos group command" << command;
}
}
/* 4.4 Browse Commands
* 4.4.1 Get Music Sources - "command": "browse/get_music_sources"
@ -742,7 +815,7 @@ void Heos::readData()
* 4.4.15 Delete HEOS Playlist - "command": "browse/delete_playlist "
* 4.4.17 Retrieve Album Metadata - "command": "browse/retrieve_metadata",
*/
if (command.startsWith("browse") || command.startsWith(" browse")) {
} else if (command.startsWith("browse") || command.startsWith(" browse")) {
if (command.contains("get_music_sources") || command.contains("get_source_info")) {
qDebug(dcDenon()) << "Get music source request response received" << command;
@ -835,8 +908,10 @@ void Heos::readData()
} else if (command.contains("retrieve_metadata")) {
} else {
qDebug(dcDenon) << "Unhandled Heos browse command" << command;
}
}
/*
* 5. Change Events (Unsolicited Responses) 5.1 Sources Changed
@ -853,7 +928,7 @@ void Heos::readData()
* 5.12 Group Volume Changed
* 5.13 User Changed
*/
if (command.startsWith("event")) {
} else if (command.startsWith("event")) {
if (command.contains("sources_changed")) {
emit sourcesChanged();
@ -864,7 +939,7 @@ void Heos::readData()
emit groupsChanged();
} else if (command.contains("player_state_changed")) {
qDebug() << "Player state changed";
qDebug(dcDenon()) << "Player state changed";
if (message.hasQueryItem("pid")) {
int playerId = message.queryItemValue("pid").toInt();
if (message.hasQueryItem("state")) {
@ -880,13 +955,13 @@ void Heos::readData()
}
}
} else if (command.contains("player_now_playing_changed")) {
qDebug(dcDenon()) << "Player now playing changed";
qDebug(dcDenon()) << "Player now playing changed, player id:" << message.queryItemValue("pid").toInt();
if (message.hasQueryItem("pid")) {
int playerId = message.queryItemValue("pid").toInt();
emit playerNowPlayingChanged(playerId);
}
} else if (command.contains("player_now_playing_progress")) {
qDebug(dcDenon()) << "Player now playing progress";
//qDebug(dcDenon()) << "Player now playing progress";
if (message.hasQueryItem("pid")) {
int playerId = message.queryItemValue("pid").toInt();
int currentPossition = message.queryItemValue("cur_pos").toInt();
@ -994,7 +1069,11 @@ void Heos::readData()
username = message.queryItemValue("un");
}
emit userChanged(signedIn, username);
} else {
qDebug(dcDenon) << "Unhandled Heos event";
}
} else {
qDebug(dcDenon) << "Unhandled Heos category" << command;
}
}
}

View File

@ -38,6 +38,11 @@
#include "heosplayer.h"
#include "heostypes.h"
#include "devices/device.h"
#include "types/mediabrowseritem.h"
#include "devices/browseresult.h"
#include "devices/browseritemresult.h"
class Heos : public QObject
{
Q_OBJECT
@ -46,10 +51,12 @@ public:
explicit Heos(const QHostAddress &hostAddress, QObject *parent = nullptr);
~Heos();
void connectHeos();
void connectDevice();
void disconnectDevice();
bool connected();
void setAddress(QHostAddress address);
QHostAddress getAddress();
HeosPlayer *getPlayer(int playerId);
// Heos system commands
void registerForChangeEvents(bool state); //By default HEOS speaker does not send Change events. Controller needs to send this command with enable=on when it is ready to receive unsolicit responses from CLI. Please refer to "Driver Initialization" section regarding when to register for change events.
@ -62,6 +69,7 @@ public:
//Player Get Calls
void getPlayers(); //get a list of players associated with this heos master
void getPlayerInfo(int playerId);
void getPlayerState(int playerId);
void getVolume(int playerId);
void getNowPlayingMedia(int playerId);
@ -87,9 +95,12 @@ public:
void getGroupInfo(int groupId);
void getGroupVolume(int groupId);
void getGroupMute(int groupId);
//Group Set Calls
void setGroupVolume(int groupId, bool volume);
void setGroupMute(int groupId, bool mute);
void setGroup(QList<int> playerIds);
void deleteGroup(int leadPlayerId);
void toggleGroupMute(int groupId);
void groupVolumeUp(int groupId, int step = 5);
void groupVolumeDown(int groupId, int step = 5);
@ -101,8 +112,6 @@ public:
void browseSource(const QString &sourceId);
void browseSourceContainers(const QString &sourceId, const QString &containerId);
//void search();
//Play commands
void playStation(int playerId, const QString &sourceId, const QString &containerId, const QString &mediaId, const QString &stationName);
void playPresetStation(int playerId, int presetNumber);
@ -114,14 +123,15 @@ private:
bool m_eventRegistered = false;
QHostAddress m_hostAddress;
QTcpSocket *m_socket = nullptr;
QHash<int, HeosPlayer*> m_heosPlayers;
void setConnected(const bool &connected);
signals:
void playerDiscovered(HeosPlayer *heosPlayer);
void connectionStatusChanged(bool status);
void systemEventsEnabled(bool status);
void playersChanged();
void playersRecieved(QList<HeosPlayer *> heosPlayers);
void playerInfoRecieved(HeosPlayer *heosPlayers);
void playerQueueChanged(int playerId);
void playerPlayStateReceived(int playerId, PLAYER_STATE state);
void playerShuffleModeReceived(int playerId, bool shuffle);
@ -134,12 +144,16 @@ signals:
void playerNowPlayingChanged(int playerId);
void groupsReceived(QList<GroupObject> groups); // Callback of getGroups()
void groupInfoReceived(GroupObject group);
void groupVolumeReceived(int groupId, int volume);
void groupMuteStatusReceived(int groupId, bool mute);
void groupsChanged();
void setGroupReceived(int groupId, const QString &groupName); // Callback of setGroup()
void deleteGroupReceived(int leadPlayerId); // Callback of deleteGroup();
void sourcesChanged();
void nowPlayingMediaStatusReceived(int playerId, SOURCE_ID source, QString artist, QString album, QString Song, 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 browseRequestReceived(const QString &sourceId, const QString &containerId, QList<MusicSourceObject> musicSources, QList<MediaObject> mediaItems); //callback of browseSource

View File

@ -30,15 +30,13 @@
#include "heosplayer.h"
HeosPlayer::HeosPlayer(int playerId, QObject *parent) :
QObject(parent),
HeosPlayer::HeosPlayer(int playerId) :
m_playerId(playerId)
{
}
HeosPlayer::HeosPlayer(int playerId, QString name, QString serialNumber, QObject *parent) :
QObject(parent),
HeosPlayer::HeosPlayer(int playerId, const QString &name, const QString &serialNumber) :
m_playerId(playerId),
m_serialNumber(serialNumber),
m_name(name)
@ -50,7 +48,7 @@ QString HeosPlayer::name()
return m_name;
}
void HeosPlayer::setName(QString name)
void HeosPlayer::setName(const QString &name)
{
m_name = name;
}
@ -75,29 +73,59 @@ QString HeosPlayer::playerModel()
return m_playerModel;
}
void HeosPlayer::setPlayerModel(const QString &playerModel)
{
m_playerModel = playerModel;
}
QString HeosPlayer::playerVersion()
{
return m_playerVersion;
}
void HeosPlayer::setPlayerVersion(const QString &playerVersion)
{
m_playerVersion = playerVersion;
}
QString HeosPlayer::network()
{
return m_network;
}
void HeosPlayer::setNetwork(const QString &network)
{
m_network = network;
}
QString HeosPlayer::serialNumber()
{
return m_serialNumber;
}
void HeosPlayer::setSerialNumber(const QString &serialNumber)
{
m_serialNumber = serialNumber;
}
QString HeosPlayer::lineOut()
{
return m_lineOut;
}
void HeosPlayer::setLineOut(const QString &lineout)
{
m_lineOut = lineout;
}
QString HeosPlayer::control()
{
return m_control;
}
void HeosPlayer::setControl(const QString &control)
{
m_control = control;
}

View File

@ -31,26 +31,31 @@
#ifndef HEOSPLAYER_H
#define HEOSPLAYER_H
#include <QObject>
#include <QString>
class HeosPlayer : public QObject
class HeosPlayer
{
Q_OBJECT
public:
explicit HeosPlayer(int playerId, QObject *parent = nullptr);
explicit HeosPlayer(int playerId, QString name, QString serialNumber, QObject *parent = nullptr);
explicit HeosPlayer(int playerId);
explicit HeosPlayer(int playerId, const QString &name, const QString &serialNumber);
QString name();
void setName(QString name);
void setName(const QString &name);
int playerId();
int groupId();
void setGroupId(int groupId);
QString playerModel();
void setPlayerModel(const QString &playerModel);
QString playerVersion();
void setPlayerVersion(const QString &playerVersion);
QString network();
void setNetwork(const QString &network);
QString serialNumber();
void setSerialNumber(const QString &serialNumber);
QString lineOut();
void setLineOut(const QString &lineout);
QString control();
void setControl(const QString &control);
private:
int m_playerId;
@ -62,7 +67,6 @@ private:
QString m_playerModel;
QString m_playerVersion;
QString m_control;
};
#endif // HEOSPLAYER_H

View File

@ -37,12 +37,14 @@
#include "network/upnp/upnpdiscoveryreply.h"
#include "platform/platformzeroconfcontroller.h"
#include "network/zeroconf/zeroconfservicebrowser.h"
#include "types/mediabrowseritem.h"
#include <QDebug>
#include <QStringList>
#include <QJsonDocument>
#include <QTimer>
#include <QUrl>
#include <QUrlQuery>
IntegrationPluginDenon::IntegrationPluginDenon()
{
@ -184,36 +186,43 @@ void IntegrationPluginDenon::setupThing(ThingSetupInfo *info)
denonConnection->connectDevice();
return;
}
if (thing->thingClassId() == heosThingClassId) {
qCDebug(dcDenon) << "Setup Denon device" << thing->paramValue(heosThingIpParamTypeId).toString();
} else if (device->deviceClassId() == heosDeviceClassId) {
qCDebug(dcDenon) << "Setup Denon device" << device->paramValue(heosDeviceIpParamTypeId).toString();
QHostAddress address(device->paramValue(heosDeviceIpParamTypeId).toString());
if (address.isNull()) {
qCWarning(dcDenon) << "Could not parse ip address" << device->paramValue(heosDeviceIpParamTypeId).toString();
info->finish(Device::DeviceErrorInvalidParameter, QT_TR_NOOP("The given IP address is not valid."));
return;
}
QHostAddress address(thing->paramValue(heosThingIpParamTypeId).toString());
Heos *heos = new Heos(address, this);
connect(heos, &Heos::connectionStatusChanged, this, &IntegrationPluginDenon::onHeosConnectionChanged);
connect(heos, &Heos::playerDiscovered, this, &IntegrationPluginDenon::onHeosPlayerDiscovered);
connect(heos, &Heos::playStateReceived, this, &IntegrationPluginDenon::onHeosPlayStateReceived);
connect(heos, &Heos::repeatModeReceived, this, &IntegrationPluginDenon::onHeosRepeatModeReceived);
connect(heos, &Heos::shuffleModeReceived, this, &IntegrationPluginDenon::onHeosShuffleModeReceived);
connect(heos, &Heos::muteStatusReceived, this, &IntegrationPluginDenon::onHeosMuteStatusReceived);
connect(heos, &Heos::volumeStatusReceived, this, &IntegrationPluginDenon::onHeosVolumeStatusReceived);
connect(heos, &Heos::playersChanged, this, &IntegrationPluginDenon::onHeosPlayersChanged);
connect(heos, &Heos::playersRecieved, this, &IntegrationPluginDenon::onHeosPlayersReceived);
connect(heos, &Heos::playerInfoRecieved, this, &IntegrationPluginDenon::onHeosPlayerInfoRecieved);
connect(heos, &Heos::playerPlayStateReceived, this, &IntegrationPluginDenon::onHeosPlayStateReceived);
connect(heos, &Heos::playerRepeatModeReceived, this, &IntegrationPluginDenon::onHeosRepeatModeReceived);
connect(heos, &Heos::playerShuffleModeReceived, this, &IntegrationPluginDenon::onHeosShuffleModeReceived);
connect(heos, &Heos::playerMuteStatusReceived, this, &IntegrationPluginDenon::onHeosMuteStatusReceived);
connect(heos, &Heos::playerVolumeReceived, this, &IntegrationPluginDenon::onHeosVolumeStatusReceived);
connect(heos, &Heos::nowPlayingMediaStatusReceived, this, &IntegrationPluginDenon::onHeosNowPlayingMediaStatusReceived);
connect(heos, &Heos::playerNowPlayingChanged, this, &IntegrationPluginDenon::onHeosPlayerNowPlayingChanged);
connect(heos, &Heos::musicSourcesReceived, this, &IntegrationPluginDenon::onHeosMusicSourcesReceived);
connect(heos, &Heos::mediaItemsReceived, this, &IntegrationPluginDenon::onHeosMediaItemsReceived);
connect(heos, &Heos::browseRequestReceived, this, &IntegrationPluginDenon::onHeosBrowseRequestReceived);
connect(heos, &Heos::browseErrorReceived, this, &IntegrationPluginDenon::onHeosBrowseErrorReceived);
connect(heos, &Heos::playerQueueChanged, this, &IntegrationPluginDenon::onHeosPlayerQueueChanged);
connect(heos, &Heos::groupsReceived, this, &IntegrationPluginDenon::onHeosGroupsReceived);
connect(heos, &Heos::groupsChanged, this, &IntegrationPluginDenon::onHeosGroupsChanged);
m_heos.insert(thing->id(), heos);
m_heos.insert(device->id(), heos);
m_asyncHeosSetups.insert(heos, info);
// In case the setup is cancelled before we finish it...
connect(info, &QObject::destroyed, this, [this, info, heos]() { m_asyncHeosSetups.remove(heos); });
heos->connectHeos();
heos->connectDevice();
return;
}
@ -228,24 +237,24 @@ void IntegrationPluginDenon::thingRemoved(Thing *thing)
{
qCDebug(dcDenon) << "Delete " << thing->name();
AvrConnection *denonConnection = m_avrConnections.take(thing->id());
if (thing->thingClassId() == AVRX1000ThingClassId) {
AvrConnection *denonConnection = m_avrConnections.value(thing->id());
m_avrConnections.remove(thing->id());
denonConnection->disconnectDevice();
denonConnection->deleteLater();
}
if (thing->thingClassId() == heosThingClassId) {
if (m_avrConnections.contains(thing->id())) {
AvrConnection *denonConnection = m_avrConnections.take(thing->id());
denonConnection->disconnectDevice();
denonConnection->deleteLater();
}
} else if (thing->thingClassId() == heosThingClassId) {
if (m_heos.contains(thing->id())) {
Heos *heos = m_heos.take(thing->id());
heos->deleteLater();
}
}
if (myThings().empty()) {
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
m_pluginTimer = nullptr;
}
}
@ -376,7 +385,9 @@ void IntegrationPluginDenon::postSetupThing(Thing *thing)
{
if (thing->thingClassId() == heosThingClassId) {
Heos *heos = m_heos.value(thing->id());
device->setStateValue(heosConnectedStateTypeId, heos->connected());
heos->getPlayers();
heos->getGroups();
}
if (thing->thingClassId() == heosPlayerThingClassId) {
@ -547,6 +558,7 @@ void IntegrationPluginDenon::onHeosConnectionChanged(bool status)
{
Heos *heos = static_cast<Heos *>(sender());
heos->registerForChangeEvents(true);
<<<<<<< HEAD:denon/integrationplugindenon.cpp
Thing *thing = myThings().findById(m_heos.key(heos));
if (!thing)
@ -563,6 +575,24 @@ void IntegrationPluginDenon::onHeosConnectionChanged(bool status)
}
}
thing->setStateValue(heosConnectedStateTypeId, status);
=======
if (status) {
// and from the first setup
if (m_asyncHeosSetups.contains(heos)) {
DeviceSetupInfo *info = m_asyncHeosSetups.take(heos);
info->finish(Device::DeviceErrorNoError);
}
}
Device *device = myDevices().findById(m_heos.key(heos));
if (!device)
return;
if (device->deviceClassId() == heosDeviceClassId) {
// if the device is connected
device->setStateValue(heosConnectedStateTypeId, status);
>>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp
// update connection status for all child devices
foreach (Thing *playerDevice, myThings()) {
if (playerDevice->thingClassId() == heosPlayerThingClassId) {
@ -574,23 +604,45 @@ void IntegrationPluginDenon::onHeosConnectionChanged(bool status)
}
}
void DevicePluginDenon::onHeosPlayersChanged()
void IntegrationPluginDenon::onHeosPlayersChanged()
{
Heos *heos = static_cast<Heos *>(sender());
heos->getPlayers();
}
<<<<<<< HEAD:denon/integrationplugindenon.cpp
void IntegrationPluginDenon::onHeosPlayerDiscovered(HeosPlayer *heosPlayer) {
=======
void IntegrationPluginDenon::onHeosPlayersReceived(QList<HeosPlayer *> heosPlayers) {
>>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp
Heos *heos = static_cast<Heos *>(sender());
<<<<<<< HEAD:denon/integrationplugindenon.cpp
Thing *thing = myThings().findById(m_heos.key(heos));
foreach (Thing *heosPlayerThing, myThings()) {
if(heosPlayerThing->thingClassId() == heosPlayerThingClassId) {
if (heosPlayerThing->paramValue(heosPlayerThingPlayerIdParamTypeId).toInt() == heosPlayer->playerId())
return;
=======
QList<DeviceDescriptor> heosPlayerDescriptors;
foreach (HeosPlayer *player, heosPlayers) {
DeviceDescriptor descriptor(heosPlayerDeviceClassId, player->name(), player->playerModel(), device->id());
ParamList params;
if (!myDevices().filterByParam(heosPlayerDevicePlayerIdParamTypeId, player->playerId()).isEmpty()) {
continue;
>>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp
}
params.append(Param(heosPlayerDeviceModelParamTypeId, player->playerModel()));
params.append(Param(heosPlayerDevicePlayerIdParamTypeId, player->playerId()));
params.append(Param(heosPlayerDeviceSerialNumberParamTypeId, player->serialNumber()));
params.append(Param(heosPlayerDeviceVersionParamTypeId, player->playerVersion()));
descriptor.setParams(params);
qCDebug(dcDenon) << "Found new heos player" << player->name();
heosPlayerDescriptors.append(descriptor);
}
<<<<<<< HEAD:denon/integrationplugindenon.cpp
QList<ThingDescriptor> heosPlayerDescriptors;
ThingDescriptor descriptor(heosPlayerThingClassId, heosPlayer->name(), heosPlayer->playerModel(), thing->id());
ParamList params;
@ -605,6 +657,21 @@ void IntegrationPluginDenon::onHeosPlayerDiscovered(HeosPlayer *heosPlayer) {
}
void IntegrationPluginDenon::onHeosPlayStateReceived(int playerId, PLAYER_STATE state)
=======
//TODO remove devices
//TODO remove player from player Buffer
autoDevicesAppeared(heosPlayerDescriptors);
}
void IntegrationPluginDenon::onHeosPlayerInfoRecieved(HeosPlayer *heosPlayer)
{
qDebug(dcDenon()) << "Heos player info received" << heosPlayer->name() << heosPlayer->playerId() << heosPlayer->groupId();
m_playerBuffer.insert(heosPlayer->playerId(), heosPlayer);
}
void IntegrationPluginDenon::onHeosPlayStateReceived(int playerId, PLAYER_STATE state)
>>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp
{
foreach(Thing *thing, myThings().filterByParam(heosPlayerThingPlayerIdParamTypeId, playerId)) {
if (state == PLAYER_STATE_PAUSE) {
@ -657,6 +724,7 @@ void IntegrationPluginDenon::onHeosVolumeStatusReceived(int playerId, int volume
}
}
<<<<<<< HEAD:denon/integrationplugindenon.cpp
void IntegrationPluginDenon::onHeosNowPlayingMediaStatusReceived(int playerId, SOURCE_ID sourceId, QString artist, QString album, QString song, QString artwork)
{
foreach(Thing *thing, myThings().filterByParam(heosPlayerThingPlayerIdParamTypeId, playerId)) {
@ -739,6 +807,19 @@ void IntegrationPluginDenon::onHeosNowPlayingMediaStatusReceived(int playerId, S
thing->setStateValue(heosPlayerSourceStateTypeId, source);
break;
}
=======
void IntegrationPluginDenon::onHeosNowPlayingMediaStatusReceived(int playerId, const QString &sourceId, const QString &artist, const QString &album, const QString &song, const QString &artwork)
{
Device *device = myDevices().filterByParam(heosPlayerDevicePlayerIdParamTypeId, playerId).first();
if (!device)
return;
device->setStateValue(heosPlayerArtistStateTypeId, artist);
device->setStateValue(heosPlayerTitleStateTypeId, song);
device->setStateValue(heosPlayerArtworkStateTypeId, artwork);
device->setStateValue(heosPlayerCollectionStateTypeId, album);
device->setStateValue(heosPlayerSourceStateTypeId, sourceId);
>>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp
}
@ -748,12 +829,37 @@ void IntegrationPluginDenon::onHeosMusicSourcesReceived(QList<MusicSourceObject>
if (m_pendingGetSourcesRequest.contains(heos)) {
BrowseResult *result = m_pendingGetSourcesRequest.take(heos);
foreach(MusicSourceObject source, musicSources) {
BrowserItem item;
MediaBrowserItem item;
item.setDisplayName(source.name);
item.setId("source=" + QString::number(source.sourceId));
item.setThumbnail(source.image_url);
item.setExecutable(false);
item.setBrowsable(true);
item.setIcon(BrowserItem::BrowserIconMusic);
if (source.name == "Amazon") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconAmazon);
} else if (source.name == "Deezer") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconDeezer);
} else if (source.name == "Napster") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconNapster);
} else if (source.name == "SoundCloud") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconSoundCloud);
} else if (source.name == "Tidal") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconTidal);
} else if (source.name == "TuneIn") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconTuneIn);
} else if (source.name == "Local Music") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconDisk);
} else if (source.name == "Playlists") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconPlaylist);
} else if (source.name == "History") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconRecentlyPlayed);
} else if (source.name == "AUX Input") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconAux);
} else if (source.name == "Favorites") {
item.setIcon(BrowserItem::BrowserIconFavorites);
} else {
item.setThumbnail(source.image_url);
}
result->addItem(item);
qDebug(dcDenon()) << "Music source received:" << source.name << source.type << source.sourceId << source.image_url;
}
@ -763,7 +869,7 @@ void IntegrationPluginDenon::onHeosMusicSourcesReceived(QList<MusicSourceObject>
void IntegrationPluginDenon::onHeosMediaItemsReceived(QList<MediaObject> mediaItems)
void DevicePluginDenon::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)
{
QString identifier;
if (containerId.isEmpty()) {
@ -784,7 +890,7 @@ void IntegrationPluginDenon::onHeosBrowseRequestReceived(QList<MusicSourceObject
if (m_pendingBrowseResult.contains(browseRequest)) {
BrowseResult *result = m_pendingBrowseResult.take(browseRequest);
foreach(MediaObject media, mediaItems) {
BrowserItem item;
MediaBrowserItem item;
qDebug(dcDenon()) << "Adding Item" << media.name << media.mediaId << media.containerId << media.mediaType;
item.setDisplayName(media.name);
if (media.mediaType == MEDIA_TYPE_CONTAINER) {
@ -800,12 +906,36 @@ void IntegrationPluginDenon::onHeosBrowseRequestReceived(QList<MusicSourceObject
result->addItem(item);
}
foreach(MusicSourceObject source, musicSources) {
BrowserItem item;
MediaBrowserItem item;
item.setDisplayName(source.name);
qDebug(dcDenon()) << "Adding Item" << source.name << source.sourceId;
//item.setDescription("test");
item.setId("source=" + QString::number(source.sourceId));
item.setThumbnail(source.image_url);
item.setIcon(BrowserItem::BrowserIconMusic);
if (source.name.contains("Amazon")) {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconAmazon);
} else if (source.name == "Deezer") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconDeezer);
} else if (source.name == "Napster") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconNapster);
} else if (source.name == "SoundCloud") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconSoundCloud);
} else if (source.name == "Tidal") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconTidal);
} else if (source.name == "TuneIn") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconTuneIn);
} else if (source.name == "Local Music") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconDisk);
} else if (source.name == "Playlists") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconPlaylist);
} else if (source.name == "History") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconRecentlyPlayed);
} else if (source.name == "AUX Input") {
item.setMediaIcon(MediaBrowserItem::MediaBrowserIconAux);
} else if (source.name == "Favorites") {
item.setIcon(BrowserItem::BrowserIconFavorites);
} else {
item.setThumbnail(source.image_url);
}
item.setExecutable(false);
item.setBrowsable(true);
result->addItem(item);
@ -839,13 +969,31 @@ void IntegrationPluginDenon::onHeosPlayerNowPlayingChanged(int playerId)
}
void DevicePluginDenon::onHeosPlayerQueueChanged(int playerId)
void IntegrationPluginDenon::onHeosPlayerQueueChanged(int playerId)
{
Heos *heos = static_cast<Heos *>(sender());
heos->getNowPlayingMedia(playerId);
}
<<<<<<< HEAD:denon/integrationplugindenon.cpp
void IntegrationPluginDenon::onAvahiServiceEntryAdded(const ZeroConfServiceEntry &serviceEntry)
=======
void IntegrationPluginDenon::onHeosGroupsReceived(QList<GroupObject> groups)
{
m_groupBuffer.clear();
foreach(GroupObject group, groups) {
m_groupBuffer.insert(group.groupId, group);
}
}
void IntegrationPluginDenon::onHeosGroupsChanged()
{
Heos *heos = static_cast<Heos *>(sender());
heos->getGroups();
}
void IntegrationPluginDenon::onAvahiServiceEntryAdded(const ZeroConfServiceEntry &serviceEntry)
>>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp
{
qCDebug(dcDenon()) << "Avahi service entry added:" << serviceEntry;
}
@ -877,9 +1025,55 @@ void IntegrationPluginDenon::browseDevice(BrowseResult *result)
if (result->itemId().isEmpty()) {
qDebug(dcDenon()) << "Browse source";
MediaBrowserItem item;
item.setId("type=group");
item.setIcon(BrowserItem::BrowserIcon::BrowserIconPackage);
item.setBrowsable(true);
item.setExecutable(false);
item.setDisplayName("Groups");
result->addItem(item);
heos->getMusicSources();
m_pendingGetSourcesRequest.insert(heos, result);
connect(result, &QObject::destroyed, this, [this, heos](){m_pendingGetSourcesRequest.remove(heos);});
} else if (result->itemId().startsWith("type=group")){
qDebug(dcDenon()) << "Browse source" << result->itemId();
int pid = result->device()->paramValue(heosPlayerDevicePlayerIdParamTypeId).toInt();
HeosPlayer *browsingPlayer = m_playerBuffer.value(pid);
foreach (GroupObject group, m_groupBuffer) {
MediaBrowserItem item;
item.setBrowsable(true);
item.setExecutable(true);
item.setIcon(BrowserItem::BrowserIconFolder);
item.setDisplayName(group.name);
item.setId(result->itemId() + "&" + "group=" + QString::number(group.groupId));
// if player is already part of the group set action type id to unjoin
if (browsingPlayer->groupId() == group.groupId) {
item.setActionTypeIds(QList<ActionTypeId>() << heosPlayerUnjoinBrowserItemActionTypeId);
} else {
item.setActionTypeIds(QList<ActionTypeId>() << heosPlayerJoinBrowserItemActionTypeId);
}
result->addItem(item);
}
foreach (HeosPlayer *player, m_playerBuffer.values()) {
qDebug(dcDenon) << "Adding group item" << player->name();
if (browsingPlayer->playerId() == player->playerId()) { //player is the current browsing device
continue;
}
if (player->groupId() != -1) {// Dont display players that are already assigned to a group
continue;
}
MediaBrowserItem item;
item.setBrowsable(true);
item.setExecutable(true);
item.setIcon(BrowserItem::BrowserIconFile);
item.setDisplayName(player->name());
item.setId(result->itemId() + "&player=" + QString::number(player->playerId()));
item.setActionTypeIds(QList<ActionTypeId>() << heosPlayerJoinBrowserItemActionTypeId);
result->addItem(item);
}
result->finish(Device::DeviceErrorNoError);
} else if (result->itemId().startsWith("source=")){
qDebug(dcDenon()) << "Browse source" << result->itemId();
@ -943,11 +1137,41 @@ void IntegrationPluginDenon::executeBrowserItem(BrowserActionInfo *info)
void IntegrationPluginDenon::executeBrowserItemAction(BrowserItemActionInfo *info)
{
Heos *kodi = m_heos.value(info->device()->parentId());
if (!kodi) {
Heos *heos = m_heos.value(info->device()->parentId());
if (!heos) {
info->finish(Device::DeviceErrorHardwareNotAvailable);
return;
}
qDebug(dcDenon()) << "Execute browse item action called";
QUrlQuery query(info->browserItemAction().itemId());
if (info->browserItemAction().actionTypeId() == heosPlayerJoinBrowserItemActionTypeId) {
if (query.hasQueryItem("player")) {
QList<int> playerIds;
playerIds.append(query.queryItemValue("player").toInt());
playerIds.append(info->device()->paramValue(heosPlayerDevicePlayerIdParamTypeId).toInt());
heos->setGroup(playerIds);
} else if(query.hasQueryItem("group")) {
GroupObject group = m_groupBuffer.value(query.queryItemValue("group").toInt());
qDebug(dcDenon()) << "Execute browse item action called, Group:" << query.queryItemValue("group").toInt() << group.name;
QList<int> playerIds;
foreach(PlayerObject player, group.players) {
playerIds.append(player.playerId);
}
playerIds.append(info->device()->paramValue(heosPlayerDevicePlayerIdParamTypeId).toInt());
heos->setGroup(playerIds);
}
} else if (info->browserItemAction().actionTypeId() == heosPlayerUnjoinBrowserItemActionTypeId) {
if(query.hasQueryItem("group")) {
GroupObject group = m_groupBuffer.value(query.queryItemValue("group").toInt());
QList<int> playerIds;
foreach(PlayerObject player, group.players) {
if (player.playerId != info->device()->paramValue(heosPlayerDevicePlayerIdParamTypeId).toInt())
playerIds.append(player.playerId);
}
heos->setGroup(playerIds);
}
}
info->finish(Device::DeviceErrorNoError);
return;
}

View File

@ -91,24 +91,31 @@ private:
QHash<int, BrowserItemActionInfo*> m_pendingBrowserItemActions;
QHash<QString, MediaObject> m_mediaObjects;
QHash<int, GroupObject> m_groupBuffer;
QHash<int, HeosPlayer *> m_playerBuffer;
private slots:
void onPluginTimer();
void onHeosConnectionChanged(bool status);
void onHeosPlayersChanged();
void onHeosPlayerDiscovered(HeosPlayer *heosPlayer);
void onHeosPlayersReceived(QList<HeosPlayer *> players);
void onHeosPlayerInfoRecieved(HeosPlayer *player);
void onHeosPlayStateReceived(int playerId, PLAYER_STATE state);
void onHeosShuffleModeReceived(int playerId, bool shuffle);
void onHeosRepeatModeReceived(int playerId, REPEAT_MODE repeatMode);
void onHeosMuteStatusReceived(int playerId, bool mute);
void onHeosVolumeStatusReceived(int playerId, int volume);
void onHeosNowPlayingMediaStatusReceived(int playerId, SOURCE_ID source, QString artist, QString album, QString Song, 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 onHeosMediaItemsReceived(QList<MediaObject> mediaItems);
void onHeosBrowseRequestReceived(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 onHeosPlayerNowPlayingChanged(int playerId);
void onHeosPlayerQueueChanged(int playerId);
void onHeosGroupsReceived(QList<GroupObject> groups);
void onHeosGroupsChanged();
void onAvahiServiceEntryAdded(const ZeroConfServiceEntry &serviceEntry);
void onAvahiServiceEntryRemoved(const ZeroConfServiceEntry &serviceEntry);

View File

@ -392,14 +392,14 @@
],
"browserItemActionTypes": [
{
"id": "34167b7d-c9d0-486c-b82b-0778d69599ea",
"name": "updateLibrary",
"displayName": "Update library"
"id": "73112a01-84c7-4b1d-8b86-71672c110d06",
"name": "join",
"displayName": "Join group"
},
{
"id": "02bcfbbe-d929-439e-a04f-68ace25e93a7",
"name": "cleanLibrary",
"displayName": "Clean library"
"id": "1b866b95-1fc7-4b45-ad71-c85e43fcc367",
"name": "unjoin",
"displayName": "Unjoin group"
}
]
}