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(); m_socket->close();
} }
void Heos::connectHeos() void Heos::connectDevice()
{ {
if (m_socket->state() == QAbstractSocket::ConnectingState) { if (m_socket->state() == QAbstractSocket::ConnectingState) {
return; return;
@ -61,6 +61,18 @@ void Heos::connectHeos()
m_socket->connectToHost(m_hostAddress, 1255); m_socket->connectToHost(m_hostAddress, 1255);
} }
bool Heos::connected()
{
return m_socket->isOpen();
}
void Heos::disconnectDevice()
{
m_socket->close();
}
/******************************** /********************************
* PLAYER COMMANDS * PLAYER COMMANDS
********************************/ ********************************/
@ -182,17 +194,19 @@ void Heos::getNowPlayingMedia(int playerId)
m_socket->write(cmd); m_socket->write(cmd);
} }
HeosPlayer *Heos::getPlayer(int playerId)
{
return m_heosPlayers.value(playerId);
}
void Heos::getPlayers() void Heos::getPlayers()
{ {
QByteArray cmd = "heos://player/get_players\r\n"; QByteArray cmd = "heos://player/get_players\r\n";
m_socket->write(cmd); 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) void Heos::getVolume(int playerId)
{ {
QByteArray cmd = "heos://player/get_volume?pid=" + QVariant(playerId).toByteArray() + "\r\n"; 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); 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) void Heos::toggleGroupMute(int groupId)
{ {
QByteArray cmd = "heos://group/toggle_mute?gid=" + QVariant(groupId).toByteArray() + "\r\n"; 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"; qCDebug(dcDenon()) << "Disconnected from" << m_hostAddress.toString() << "try reconnecting in 5 seconds";
QTimer::singleShot(5000, this, [this](){ QTimer::singleShot(5000, this, [this](){
connectHeos(); connectDevice();
}); });
emit connectionStatusChanged(false); emit connectionStatusChanged(false);
} }
@ -495,7 +522,6 @@ void Heos::onError(QAbstractSocket::SocketError socketError)
void Heos::readData() void Heos::readData()
{ {
QByteArray data; QByteArray data;
QJsonParseError error; QJsonParseError error;
@ -534,9 +560,11 @@ void Heos::readData()
if (enabled.contains("off")) { if (enabled.contains("off")) {
qDebug(dcDenon) << "Events are disabled"; qDebug(dcDenon) << "Events are disabled";
m_eventRegistered = false; m_eventRegistered = false;
emit systemEventsEnabled(false);
} else { } else {
qDebug(dcDenon) << "Events are enabled"; qDebug(dcDenon) << "Events are enabled";
m_eventRegistered = true; m_eventRegistered = true;
emit systemEventsEnabled(true);
} }
} else if (command.contains("check_account")) { } else if (command.contains("check_account")) {
@ -551,8 +579,9 @@ void Heos::readData()
} else if (command.contains("prettify_json_response")) { } else if (command.contains("prettify_json_response")) {
} else {
qDebug(dcDenon) << "Unhandled Heos system command" << command;
} }
}
/* 4.2 Player Commands /* 4.2 Player Commands
* 4.2.1 Get Players * 4.2.1 Get Players
* 4.2.2 Get Player Info * 4.2.2 Get Player Info
@ -578,7 +607,7 @@ void Heos::readData()
* 4.2.25 Get QuickSelects [LS AVR Only] * 4.2.25 Get QuickSelects [LS AVR Only]
* 4.2.26 Check for Firmware Update * 4.2.26 Check for Firmware Update
*/ */
if (command.startsWith("player")) { } else if (command.startsWith("player")) {
int playerId = 0; int playerId = 0;
if (message.hasQueryItem("pid")) { if (message.hasQueryItem("pid")) {
playerId = message.queryItemValue("pid").toInt(); playerId = message.queryItemValue("pid").toInt();
@ -586,28 +615,45 @@ void Heos::readData()
if (command.contains("get_players")) { if (command.contains("get_players")) {
QVariantList payloadVariantList = jsonDoc.toVariant().toMap().value("payload").toList(); QVariantList payloadVariantList = jsonDoc.toVariant().toMap().value("payload").toList();
QList<HeosPlayer *> players;
foreach (const QVariant &payloadEntryVariant, payloadVariantList) { foreach (const QVariant &payloadEntryVariant, payloadVariantList) {
playerId = payloadEntryVariant.toMap().value("pid").toInt(); HeosPlayer *player = new HeosPlayer(payloadEntryVariant.toMap().value("pid").toInt());
if(!m_heosPlayers.contains(playerId)){ player->setSerialNumber(payloadEntryVariant.toMap().value("serial").toString());
QString serialNumber = payloadEntryVariant.toMap().value("serial").toString(); player->setName(payloadEntryVariant.toMap().value("name").toString());
QString name = payloadEntryVariant.toMap().value("name").toString(); getPlayerInfo(player->playerId());
HeosPlayer *heosPlayer = new HeosPlayer(playerId, name, serialNumber, this); players.append(player);
m_heosPlayers.insert(playerId, heosPlayer);
emit playerDiscovered(heosPlayer);
}
} }
}else if (command.contains("get_player_info")) { emit playersRecieved(players);
} else if (command.contains("get_player_info")) {
//update heos 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")) { } else if (command.contains("get_now_playing_media")) {
QString artist = dataMap.value("payload").toMap().value("artist").toString(); QString artist = dataMap.value("payload").toMap().value("artist").toString();
QString song = dataMap.value("payload").toMap().value("song").toString(); QString song = dataMap.value("payload").toMap().value("song").toString();
QString artwork = dataMap.value("payload").toMap().value("image_url").toString(); QString artwork = dataMap.value("payload").toMap().value("image_url").toString();
QString album = dataMap.value("payload").toMap().value("album").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); 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")) { if (message.hasQueryItem("state")) {
PLAYER_STATE playState = PLAYER_STATE_STOP; PLAYER_STATE playState = PLAYER_STATE_STOP;
if (message.queryItemValue("state").contains("play")) { if (message.queryItemValue("state").contains("play")) {
@ -657,22 +703,23 @@ void Heos::readData()
QVariantMap payloadVariantMap = jsonDoc.toVariant().toMap().value("payload").toMap(); QVariantMap payloadVariantMap = jsonDoc.toVariant().toMap().value("payload").toMap();
bool updateExist = payloadVariantMap.value("update").toString().contains("exist"); bool updateExist = payloadVariantMap.value("update").toString().contains("exist");
emit playerUpdateAvailable(playerId, updateExist); emit playerUpdateAvailable(playerId, updateExist);
} else {
qDebug(dcDenon) << "Unhandled Heos group command" << command;
} }
}
/* /*
* 4.3 Group Commands * 4.3 Group Commands
* 4.3.1 Get Groups * 4.3.1 Get Groups
* 4.3.2 Get Group Info * 4.3.2 Get Group Info
* 4.3.3 Set Group * 4.3.3 Set Group
* 4.3.4 Get Group Volume * 4.3.4 Get Group Volume
* 4.3.5 Set Group Volume * 4.3.5 Set Group Volume
* 4.2.6 Group Volume Up * 4.2.6 Group Volume Up
* 4.2.7 Group Volume Down * 4.2.7 Group Volume Down
* 4.3.8 Get Group Mute * 4.3.8 Get Group Mute
* 4.3.9 Set Group Mute * 4.3.9 Set Group Mute
* 4.3.10 Toggle Group Mute * 4.3.10 Toggle Group Mute
*/ */
if (command.startsWith("group")) { } else if (command.startsWith("group")) {
int groupId = 0; int groupId = 0;
if (message.hasQueryItem("gid")) { if (message.hasQueryItem("gid")) {
qDebug(dcDenon) << "Group id" << message.queryItemValue("gid"); qDebug(dcDenon) << "Group id" << message.queryItemValue("gid");
@ -698,8 +745,32 @@ void Heos::readData()
} }
emit groupsReceived(groups); emit groupsReceived(groups);
} else if (command.contains("get_group_info")) { } 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")) { } 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")) { } else if (command.contains("get_volume") || command.contains("set_volume")) {
@ -722,8 +793,10 @@ void Heos::readData()
} }
} else if (command.contains("toggle_mute")) { } else if (command.contains("toggle_mute")) {
} else {
qDebug(dcDenon) << "Unhandled Heos group command" << command;
} }
}
/* 4.4 Browse Commands /* 4.4 Browse Commands
* 4.4.1 Get Music Sources - "command": "browse/get_music_sources" * 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.15 Delete HEOS Playlist - "command": "browse/delete_playlist "
* 4.4.17 Retrieve Album Metadata - "command": "browse/retrieve_metadata", * 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")) { 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;
@ -835,8 +908,10 @@ void Heos::readData()
} else if (command.contains("retrieve_metadata")) { } else if (command.contains("retrieve_metadata")) {
} else {
qDebug(dcDenon) << "Unhandled Heos browse command" << command;
} }
}
/* /*
* 5. Change Events (Unsolicited Responses) 5.1 Sources Changed * 5. Change Events (Unsolicited Responses) 5.1 Sources Changed
@ -853,7 +928,7 @@ void Heos::readData()
* 5.12 Group Volume Changed * 5.12 Group Volume Changed
* 5.13 User Changed * 5.13 User Changed
*/ */
if (command.startsWith("event")) { } else if (command.startsWith("event")) {
if (command.contains("sources_changed")) { if (command.contains("sources_changed")) {
emit sourcesChanged(); emit sourcesChanged();
@ -864,7 +939,7 @@ void Heos::readData()
emit groupsChanged(); emit groupsChanged();
} else if (command.contains("player_state_changed")) { } else if (command.contains("player_state_changed")) {
qDebug() << "Player state changed"; qDebug(dcDenon()) << "Player state changed";
if (message.hasQueryItem("pid")) { if (message.hasQueryItem("pid")) {
int playerId = message.queryItemValue("pid").toInt(); int playerId = message.queryItemValue("pid").toInt();
if (message.hasQueryItem("state")) { if (message.hasQueryItem("state")) {
@ -880,13 +955,13 @@ void Heos::readData()
} }
} }
} else if (command.contains("player_now_playing_changed")) { } 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")) { if (message.hasQueryItem("pid")) {
int playerId = message.queryItemValue("pid").toInt(); int playerId = message.queryItemValue("pid").toInt();
emit playerNowPlayingChanged(playerId); emit playerNowPlayingChanged(playerId);
} }
} else if (command.contains("player_now_playing_progress")) { } else if (command.contains("player_now_playing_progress")) {
qDebug(dcDenon()) << "Player now playing progress"; //qDebug(dcDenon()) << "Player now playing progress";
if (message.hasQueryItem("pid")) { if (message.hasQueryItem("pid")) {
int playerId = message.queryItemValue("pid").toInt(); int playerId = message.queryItemValue("pid").toInt();
int currentPossition = message.queryItemValue("cur_pos").toInt(); int currentPossition = message.queryItemValue("cur_pos").toInt();
@ -994,7 +1069,11 @@ void Heos::readData()
username = message.queryItemValue("un"); username = message.queryItemValue("un");
} }
emit userChanged(signedIn, username); 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 "heosplayer.h"
#include "heostypes.h" #include "heostypes.h"
#include "devices/device.h"
#include "types/mediabrowseritem.h"
#include "devices/browseresult.h"
#include "devices/browseritemresult.h"
class Heos : public QObject class Heos : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -46,10 +51,12 @@ public:
explicit Heos(const QHostAddress &hostAddress, QObject *parent = nullptr); explicit Heos(const QHostAddress &hostAddress, QObject *parent = nullptr);
~Heos(); ~Heos();
void connectHeos(); void connectDevice();
void disconnectDevice();
bool connected();
void setAddress(QHostAddress address); void setAddress(QHostAddress address);
QHostAddress getAddress(); QHostAddress getAddress();
HeosPlayer *getPlayer(int playerId);
// Heos system commands // 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. 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 //Player Get Calls
void getPlayers(); //get a list of players associated with this heos master void getPlayers(); //get a list of players associated with this heos master
void getPlayerInfo(int playerId);
void getPlayerState(int playerId); void getPlayerState(int playerId);
void getVolume(int playerId); void getVolume(int playerId);
void getNowPlayingMedia(int playerId); void getNowPlayingMedia(int playerId);
@ -87,9 +95,12 @@ public:
void getGroupInfo(int groupId); void getGroupInfo(int groupId);
void getGroupVolume(int groupId); void getGroupVolume(int groupId);
void getGroupMute(int groupId); void getGroupMute(int groupId);
//Group Set Calls //Group Set Calls
void setGroupVolume(int groupId, bool volume); void setGroupVolume(int groupId, bool volume);
void setGroupMute(int groupId, bool mute); void setGroupMute(int groupId, bool mute);
void setGroup(QList<int> playerIds);
void deleteGroup(int leadPlayerId);
void toggleGroupMute(int groupId); void toggleGroupMute(int groupId);
void groupVolumeUp(int groupId, int step = 5); void groupVolumeUp(int groupId, int step = 5);
void groupVolumeDown(int groupId, int step = 5); void groupVolumeDown(int groupId, int step = 5);
@ -101,8 +112,6 @@ public:
void browseSource(const QString &sourceId); void browseSource(const QString &sourceId);
void browseSourceContainers(const QString &sourceId, const QString &containerId); void browseSourceContainers(const QString &sourceId, const QString &containerId);
//void search();
//Play commands //Play commands
void playStation(int playerId, const QString &sourceId, const QString &containerId, const QString &mediaId, const QString &stationName); void playStation(int playerId, const QString &sourceId, const QString &containerId, const QString &mediaId, const QString &stationName);
void playPresetStation(int playerId, int presetNumber); void playPresetStation(int playerId, int presetNumber);
@ -114,14 +123,15 @@ private:
bool m_eventRegistered = false; bool m_eventRegistered = false;
QHostAddress m_hostAddress; QHostAddress m_hostAddress;
QTcpSocket *m_socket = nullptr; QTcpSocket *m_socket = nullptr;
QHash<int, HeosPlayer*> m_heosPlayers;
void setConnected(const bool &connected); void setConnected(const bool &connected);
signals: signals:
void playerDiscovered(HeosPlayer *heosPlayer);
void connectionStatusChanged(bool status); void connectionStatusChanged(bool status);
void systemEventsEnabled(bool status);
void playersChanged(); void playersChanged();
void playersRecieved(QList<HeosPlayer *> heosPlayers);
void playerInfoRecieved(HeosPlayer *heosPlayers);
void playerQueueChanged(int playerId); void playerQueueChanged(int playerId);
void playerPlayStateReceived(int playerId, PLAYER_STATE state); void playerPlayStateReceived(int playerId, PLAYER_STATE state);
void playerShuffleModeReceived(int playerId, bool shuffle); void playerShuffleModeReceived(int playerId, bool shuffle);
@ -134,12 +144,16 @@ signals:
void playerNowPlayingChanged(int playerId); void playerNowPlayingChanged(int playerId);
void groupsReceived(QList<GroupObject> groups); // Callback of getGroups() void groupsReceived(QList<GroupObject> groups); // Callback of getGroups()
void groupInfoReceived(GroupObject group);
void groupVolumeReceived(int groupId, int volume); void groupVolumeReceived(int groupId, int volume);
void groupMuteStatusReceived(int groupId, bool mute); void groupMuteStatusReceived(int groupId, bool mute);
void groupsChanged(); void groupsChanged();
void setGroupReceived(int groupId, const QString &groupName); // Callback of setGroup()
void deleteGroupReceived(int leadPlayerId); // Callback of deleteGroup();
void sourcesChanged(); 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 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 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" #include "heosplayer.h"
HeosPlayer::HeosPlayer(int playerId, QObject *parent) : HeosPlayer::HeosPlayer(int playerId) :
QObject(parent),
m_playerId(playerId) m_playerId(playerId)
{ {
} }
HeosPlayer::HeosPlayer(int playerId, QString name, QString serialNumber, QObject *parent) : HeosPlayer::HeosPlayer(int playerId, const QString &name, const QString &serialNumber) :
QObject(parent),
m_playerId(playerId), m_playerId(playerId),
m_serialNumber(serialNumber), m_serialNumber(serialNumber),
m_name(name) m_name(name)
@ -50,7 +48,7 @@ QString HeosPlayer::name()
return m_name; return m_name;
} }
void HeosPlayer::setName(QString name) void HeosPlayer::setName(const QString &name)
{ {
m_name = name; m_name = name;
} }
@ -75,29 +73,59 @@ QString HeosPlayer::playerModel()
return m_playerModel; return m_playerModel;
} }
void HeosPlayer::setPlayerModel(const QString &playerModel)
{
m_playerModel = playerModel;
}
QString HeosPlayer::playerVersion() QString HeosPlayer::playerVersion()
{ {
return m_playerVersion; return m_playerVersion;
} }
void HeosPlayer::setPlayerVersion(const QString &playerVersion)
{
m_playerVersion = playerVersion;
}
QString HeosPlayer::network() QString HeosPlayer::network()
{ {
return m_network; return m_network;
} }
void HeosPlayer::setNetwork(const QString &network)
{
m_network = network;
}
QString HeosPlayer::serialNumber() QString HeosPlayer::serialNumber()
{ {
return m_serialNumber; return m_serialNumber;
} }
void HeosPlayer::setSerialNumber(const QString &serialNumber)
{
m_serialNumber = serialNumber;
}
QString HeosPlayer::lineOut() QString HeosPlayer::lineOut()
{ {
return m_lineOut; return m_lineOut;
} }
void HeosPlayer::setLineOut(const QString &lineout)
{
m_lineOut = lineout;
}
QString HeosPlayer::control() QString HeosPlayer::control()
{ {
return m_control; return m_control;
} }
void HeosPlayer::setControl(const QString &control)
{
m_control = control;
}

View File

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

View File

@ -37,12 +37,14 @@
#include "network/upnp/upnpdiscoveryreply.h" #include "network/upnp/upnpdiscoveryreply.h"
#include "platform/platformzeroconfcontroller.h" #include "platform/platformzeroconfcontroller.h"
#include "network/zeroconf/zeroconfservicebrowser.h" #include "network/zeroconf/zeroconfservicebrowser.h"
#include "types/mediabrowseritem.h"
#include <QDebug> #include <QDebug>
#include <QStringList> #include <QStringList>
#include <QJsonDocument> #include <QJsonDocument>
#include <QTimer> #include <QTimer>
#include <QUrl> #include <QUrl>
#include <QUrlQuery>
IntegrationPluginDenon::IntegrationPluginDenon() IntegrationPluginDenon::IntegrationPluginDenon()
{ {
@ -184,36 +186,43 @@ void IntegrationPluginDenon::setupThing(ThingSetupInfo *info)
denonConnection->connectDevice(); denonConnection->connectDevice();
return; return;
}
if (thing->thingClassId() == heosThingClassId) { } else if (device->deviceClassId() == heosDeviceClassId) {
qCDebug(dcDenon) << "Setup Denon device" << thing->paramValue(heosThingIpParamTypeId).toString(); 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); Heos *heos = new Heos(address, this);
connect(heos, &Heos::connectionStatusChanged, this, &IntegrationPluginDenon::onHeosConnectionChanged); connect(heos, &Heos::connectionStatusChanged, this, &IntegrationPluginDenon::onHeosConnectionChanged);
connect(heos, &Heos::playerDiscovered, this, &IntegrationPluginDenon::onHeosPlayerDiscovered); connect(heos, &Heos::playersChanged, this, &IntegrationPluginDenon::onHeosPlayersChanged);
connect(heos, &Heos::playStateReceived, this, &IntegrationPluginDenon::onHeosPlayStateReceived); connect(heos, &Heos::playersRecieved, this, &IntegrationPluginDenon::onHeosPlayersReceived);
connect(heos, &Heos::repeatModeReceived, this, &IntegrationPluginDenon::onHeosRepeatModeReceived); connect(heos, &Heos::playerInfoRecieved, this, &IntegrationPluginDenon::onHeosPlayerInfoRecieved);
connect(heos, &Heos::shuffleModeReceived, this, &IntegrationPluginDenon::onHeosShuffleModeReceived); connect(heos, &Heos::playerPlayStateReceived, this, &IntegrationPluginDenon::onHeosPlayStateReceived);
connect(heos, &Heos::muteStatusReceived, this, &IntegrationPluginDenon::onHeosMuteStatusReceived); connect(heos, &Heos::playerRepeatModeReceived, this, &IntegrationPluginDenon::onHeosRepeatModeReceived);
connect(heos, &Heos::volumeStatusReceived, this, &IntegrationPluginDenon::onHeosVolumeStatusReceived); 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::nowPlayingMediaStatusReceived, this, &IntegrationPluginDenon::onHeosNowPlayingMediaStatusReceived);
connect(heos, &Heos::playerNowPlayingChanged, this, &IntegrationPluginDenon::onHeosPlayerNowPlayingChanged);
connect(heos, &Heos::musicSourcesReceived, this, &IntegrationPluginDenon::onHeosMusicSourcesReceived); connect(heos, &Heos::musicSourcesReceived, this, &IntegrationPluginDenon::onHeosMusicSourcesReceived);
connect(heos, &Heos::mediaItemsReceived, this, &IntegrationPluginDenon::onHeosMediaItemsReceived);
connect(heos, &Heos::browseRequestReceived, this, &IntegrationPluginDenon::onHeosBrowseRequestReceived); connect(heos, &Heos::browseRequestReceived, this, &IntegrationPluginDenon::onHeosBrowseRequestReceived);
connect(heos, &Heos::browseErrorReceived, this, &IntegrationPluginDenon::onHeosBrowseErrorReceived); connect(heos, &Heos::browseErrorReceived, this, &IntegrationPluginDenon::onHeosBrowseErrorReceived);
connect(heos, &Heos::playerQueueChanged, this, &IntegrationPluginDenon::onHeosPlayerQueueChanged); 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); 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->connectHeos(); heos->connectDevice();
return; return;
} }
@ -228,24 +237,24 @@ void IntegrationPluginDenon::thingRemoved(Thing *thing)
{ {
qCDebug(dcDenon) << "Delete " << thing->name(); qCDebug(dcDenon) << "Delete " << thing->name();
AvrConnection *denonConnection = m_avrConnections.take(thing->id());
if (thing->thingClassId() == AVRX1000ThingClassId) { 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())) { if (m_avrConnections.contains(thing->id())) {
AvrConnection *denonConnection = m_avrConnections.take(thing->id()); AvrConnection *denonConnection = m_avrConnections.take(thing->id());
denonConnection->disconnectDevice(); denonConnection->disconnectDevice();
denonConnection->deleteLater(); 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()) { if (myThings().empty()) {
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer); hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
m_pluginTimer = nullptr;
} }
} }
@ -376,7 +385,9 @@ void IntegrationPluginDenon::postSetupThing(Thing *thing)
{ {
if (thing->thingClassId() == heosThingClassId) { if (thing->thingClassId() == heosThingClassId) {
Heos *heos = m_heos.value(thing->id()); Heos *heos = m_heos.value(thing->id());
device->setStateValue(heosConnectedStateTypeId, heos->connected());
heos->getPlayers(); heos->getPlayers();
heos->getGroups();
} }
if (thing->thingClassId() == heosPlayerThingClassId) { if (thing->thingClassId() == heosPlayerThingClassId) {
@ -547,6 +558,7 @@ void IntegrationPluginDenon::onHeosConnectionChanged(bool status)
{ {
Heos *heos = static_cast<Heos *>(sender()); Heos *heos = static_cast<Heos *>(sender());
heos->registerForChangeEvents(true); heos->registerForChangeEvents(true);
<<<<<<< HEAD:denon/integrationplugindenon.cpp
Thing *thing = myThings().findById(m_heos.key(heos)); Thing *thing = myThings().findById(m_heos.key(heos));
if (!thing) if (!thing)
@ -563,6 +575,24 @@ void IntegrationPluginDenon::onHeosConnectionChanged(bool status)
} }
} }
thing->setStateValue(heosConnectedStateTypeId, 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 // update connection status for all child devices
foreach (Thing *playerDevice, myThings()) { foreach (Thing *playerDevice, myThings()) {
if (playerDevice->thingClassId() == heosPlayerThingClassId) { 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 *heos = static_cast<Heos *>(sender());
heos->getPlayers(); heos->getPlayers();
} }
<<<<<<< HEAD:denon/integrationplugindenon.cpp
void IntegrationPluginDenon::onHeosPlayerDiscovered(HeosPlayer *heosPlayer) { void IntegrationPluginDenon::onHeosPlayerDiscovered(HeosPlayer *heosPlayer) {
=======
void IntegrationPluginDenon::onHeosPlayersReceived(QList<HeosPlayer *> heosPlayers) {
>>>>>>> added join/unjoin group:denon/IntegrationPlugindenon.cpp
Heos *heos = static_cast<Heos *>(sender()); Heos *heos = static_cast<Heos *>(sender());
<<<<<<< HEAD:denon/integrationplugindenon.cpp
Thing *thing = myThings().findById(m_heos.key(heos)); Thing *thing = myThings().findById(m_heos.key(heos));
foreach (Thing *heosPlayerThing, myThings()) { foreach (Thing *heosPlayerThing, myThings()) {
if(heosPlayerThing->thingClassId() == heosPlayerThingClassId) { if(heosPlayerThing->thingClassId() == heosPlayerThingClassId) {
if (heosPlayerThing->paramValue(heosPlayerThingPlayerIdParamTypeId).toInt() == heosPlayer->playerId()) if (heosPlayerThing->paramValue(heosPlayerThingPlayerIdParamTypeId).toInt() == heosPlayer->playerId())
return; 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; QList<ThingDescriptor> heosPlayerDescriptors;
ThingDescriptor descriptor(heosPlayerThingClassId, heosPlayer->name(), heosPlayer->playerModel(), thing->id()); ThingDescriptor descriptor(heosPlayerThingClassId, heosPlayer->name(), heosPlayer->playerModel(), thing->id());
ParamList params; ParamList params;
@ -605,6 +657,21 @@ void IntegrationPluginDenon::onHeosPlayerDiscovered(HeosPlayer *heosPlayer) {
} }
void IntegrationPluginDenon::onHeosPlayStateReceived(int playerId, PLAYER_STATE state) 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)) { foreach(Thing *thing, myThings().filterByParam(heosPlayerThingPlayerIdParamTypeId, playerId)) {
if (state == PLAYER_STATE_PAUSE) { 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) void IntegrationPluginDenon::onHeosNowPlayingMediaStatusReceived(int playerId, SOURCE_ID sourceId, QString artist, QString album, QString song, QString artwork)
{ {
foreach(Thing *thing, myThings().filterByParam(heosPlayerThingPlayerIdParamTypeId, playerId)) { foreach(Thing *thing, myThings().filterByParam(heosPlayerThingPlayerIdParamTypeId, playerId)) {
@ -739,6 +807,19 @@ void IntegrationPluginDenon::onHeosNowPlayingMediaStatusReceived(int playerId, S
thing->setStateValue(heosPlayerSourceStateTypeId, source); thing->setStateValue(heosPlayerSourceStateTypeId, source);
break; 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)) { if (m_pendingGetSourcesRequest.contains(heos)) {
BrowseResult *result = m_pendingGetSourcesRequest.take(heos); BrowseResult *result = m_pendingGetSourcesRequest.take(heos);
foreach(MusicSourceObject source, musicSources) { foreach(MusicSourceObject source, musicSources) {
BrowserItem item; MediaBrowserItem item;
item.setDisplayName(source.name); item.setDisplayName(source.name);
item.setId("source=" + QString::number(source.sourceId)); item.setId("source=" + QString::number(source.sourceId));
item.setThumbnail(source.image_url);
item.setExecutable(false); item.setExecutable(false);
item.setBrowsable(true); 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); result->addItem(item);
qDebug(dcDenon()) << "Music source received:" << source.name << source.type << source.sourceId << source.image_url; 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 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; QString identifier;
if (containerId.isEmpty()) { if (containerId.isEmpty()) {
@ -784,7 +890,7 @@ void IntegrationPluginDenon::onHeosBrowseRequestReceived(QList<MusicSourceObject
if (m_pendingBrowseResult.contains(browseRequest)) { if (m_pendingBrowseResult.contains(browseRequest)) {
BrowseResult *result = m_pendingBrowseResult.take(browseRequest); BrowseResult *result = m_pendingBrowseResult.take(browseRequest);
foreach(MediaObject media, mediaItems) { foreach(MediaObject media, mediaItems) {
BrowserItem item; MediaBrowserItem item;
qDebug(dcDenon()) << "Adding Item" << media.name << media.mediaId << media.containerId << media.mediaType; qDebug(dcDenon()) << "Adding Item" << media.name << media.mediaId << media.containerId << media.mediaType;
item.setDisplayName(media.name); item.setDisplayName(media.name);
if (media.mediaType == MEDIA_TYPE_CONTAINER) { if (media.mediaType == MEDIA_TYPE_CONTAINER) {
@ -800,12 +906,36 @@ void IntegrationPluginDenon::onHeosBrowseRequestReceived(QList<MusicSourceObject
result->addItem(item); result->addItem(item);
} }
foreach(MusicSourceObject source, musicSources) { foreach(MusicSourceObject source, musicSources) {
BrowserItem item; MediaBrowserItem item;
item.setDisplayName(source.name); item.setDisplayName(source.name);
qDebug(dcDenon()) << "Adding Item" << source.name << source.sourceId; qDebug(dcDenon()) << "Adding Item" << source.name << source.sourceId;
//item.setDescription("test");
item.setId("source=" + QString::number(source.sourceId)); 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.setExecutable(false);
item.setBrowsable(true); item.setBrowsable(true);
result->addItem(item); 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 *heos = static_cast<Heos *>(sender());
heos->getNowPlayingMedia(playerId); heos->getNowPlayingMedia(playerId);
} }
<<<<<<< HEAD:denon/integrationplugindenon.cpp
void IntegrationPluginDenon::onAvahiServiceEntryAdded(const ZeroConfServiceEntry &serviceEntry) 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; qCDebug(dcDenon()) << "Avahi service entry added:" << serviceEntry;
} }
@ -877,9 +1025,55 @@ void IntegrationPluginDenon::browseDevice(BrowseResult *result)
if (result->itemId().isEmpty()) { if (result->itemId().isEmpty()) {
qDebug(dcDenon()) << "Browse source"; 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(); heos->getMusicSources();
m_pendingGetSourcesRequest.insert(heos, result); m_pendingGetSourcesRequest.insert(heos, result);
connect(result, &QObject::destroyed, this, [this, heos](){m_pendingGetSourcesRequest.remove(heos);}); 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=")){ } else if (result->itemId().startsWith("source=")){
qDebug(dcDenon()) << "Browse source" << result->itemId(); qDebug(dcDenon()) << "Browse source" << result->itemId();
@ -943,11 +1137,41 @@ void IntegrationPluginDenon::executeBrowserItem(BrowserActionInfo *info)
void IntegrationPluginDenon::executeBrowserItemAction(BrowserItemActionInfo *info) void IntegrationPluginDenon::executeBrowserItemAction(BrowserItemActionInfo *info)
{ {
Heos *kodi = m_heos.value(info->device()->parentId()); Heos *heos = m_heos.value(info->device()->parentId());
if (!kodi) { if (!heos) {
info->finish(Device::DeviceErrorHardwareNotAvailable); info->finish(Device::DeviceErrorHardwareNotAvailable);
return; 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; return;
} }

View File

@ -91,24 +91,31 @@ private:
QHash<int, BrowserItemActionInfo*> m_pendingBrowserItemActions; QHash<int, BrowserItemActionInfo*> m_pendingBrowserItemActions;
QHash<QString, MediaObject> m_mediaObjects; QHash<QString, MediaObject> m_mediaObjects;
QHash<int, GroupObject> m_groupBuffer;
QHash<int, HeosPlayer *> m_playerBuffer;
private slots: private slots:
void onPluginTimer(); void onPluginTimer();
void onHeosConnectionChanged(bool status); void onHeosConnectionChanged(bool status);
void onHeosPlayersChanged(); void onHeosPlayersChanged();
void onHeosPlayerDiscovered(HeosPlayer *heosPlayer); void onHeosPlayersReceived(QList<HeosPlayer *> players);
void onHeosPlayerInfoRecieved(HeosPlayer *player);
void onHeosPlayStateReceived(int playerId, PLAYER_STATE state); void onHeosPlayStateReceived(int playerId, PLAYER_STATE state);
void onHeosShuffleModeReceived(int playerId, bool shuffle); void onHeosShuffleModeReceived(int playerId, bool shuffle);
void onHeosRepeatModeReceived(int playerId, REPEAT_MODE repeatMode); void onHeosRepeatModeReceived(int playerId, REPEAT_MODE repeatMode);
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, 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 onHeosMusicSourcesReceived(QList<MusicSourceObject> musicSources);
//void onHeosMediaItemsReceived(QList<MediaObject> mediaItems);
void onHeosBrowseRequestReceived(const QString &sourceId, const QString &containerId, QList<MusicSourceObject> musicSources, 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 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 onHeosGroupsChanged();
void onAvahiServiceEntryAdded(const ZeroConfServiceEntry &serviceEntry); void onAvahiServiceEntryAdded(const ZeroConfServiceEntry &serviceEntry);
void onAvahiServiceEntryRemoved(const ZeroConfServiceEntry &serviceEntry); void onAvahiServiceEntryRemoved(const ZeroConfServiceEntry &serviceEntry);

View File

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