first working version

This commit is contained in:
nymea 2019-09-03 23:42:49 +02:00 committed by Michael Zanetti
parent 4254d3cb3c
commit ac58d41ea6
4 changed files with 907 additions and 158 deletions

View File

@ -45,7 +45,8 @@ DevicePluginSonos::~DevicePluginSonos()
Device::DeviceSetupStatus DevicePluginSonos::setupDevice(Device *device) Device::DeviceSetupStatus DevicePluginSonos::setupDevice(Device *device)
{ {
if (!m_pluginTimer) { if (!m_pluginTimer) {
hardwareManager()->pluginTimerManager()->registerTimer(1); hardwareManager()->pluginTimerManager()->registerTimer(10);
connect(m_pluginTimer, &PluginTimer::timeout, this, &DevicePluginSonos::onPluginTimer);
} }
if(!m_tokenRefreshTimer) { if(!m_tokenRefreshTimer) {
@ -62,19 +63,25 @@ Device::DeviceSetupStatus DevicePluginSonos::setupDevice(Device *device)
pluginStorage()->endGroup(); pluginStorage()->endGroup();
Sonos *sonos = new Sonos(hardwareManager()->networkManager(), accessToken, this); Sonos *sonos = new Sonos(hardwareManager()->networkManager(), accessToken, this);
connect(sonos, &Sonos::connectionChanged, this, &DevicePluginSonos::onConnectionChanged);
connect(sonos, &Sonos::householdIdsReceived, this, &DevicePluginSonos::onHouseholdIdsReceived);
connect(sonos, &Sonos::groupsReceived, this, &DevicePluginSonos::onGroupsReceived);
connect(sonos, &Sonos::playBackStatusReceived, this, &DevicePluginSonos::onPlayBackStatusReceived);
connect(sonos, &Sonos::metadataStatusReceived, this, &DevicePluginSonos::onMetadataStatusReceived);
connect(sonos, &Sonos::volumeReceived, this, &DevicePluginSonos::onVolumeReceived);
connect(sonos, &Sonos::actionExecuted, this, &DevicePluginSonos::onActionExecuted);
m_sonosConnections.insert(device, sonos); m_sonosConnections.insert(device, sonos);
} }
if (device->deviceClassId() == sonosGroupDeviceClassId) { if (device->deviceClassId() == sonosGroupDeviceClassId) {
//set parent ID
} }
return Device::DeviceSetupStatusSuccess; return Device::DeviceSetupStatusSuccess;
} }
DevicePairingInfo DevicePluginSonos::pairDevice(DevicePairingInfo &devicePairingInfo) DevicePairingInfo DevicePluginSonos::pairDevice(DevicePairingInfo &devicePairingInfo)
{ {
if (devicePairingInfo.deviceClassId() == sonosConnectionDeviceClassId) { if (devicePairingInfo.deviceClassId() == sonosConnectionDeviceClassId) {
QString clientId = "b15cbf8c-a39c-47aa-bd93-635a96e9696c"; QString clientId = "b15cbf8c-a39c-47aa-bd93-635a96e9696c";
QString clientSecret = "c086ba71-e562-430b-a52f-867c6482fd11"; QString clientSecret = "c086ba71-e562-430b-a52f-867c6482fd11";
@ -153,11 +160,12 @@ DevicePairingInfo DevicePluginSonos::confirmPairing(DevicePairingInfo &devicePai
pluginStorage()->setValue("refresh_token", refreshToken); pluginStorage()->setValue("refresh_token", refreshToken);
pluginStorage()->endGroup(); pluginStorage()->endGroup();
/*if (jsonDoc.toVariant().toMap().contains("expires_in")) { if (jsonDoc.toVariant().toMap().contains("expires_in")) {
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt(); int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
qCDebug(dcSonos()) << "expires at" << QDateTime::currentDateTime().addSecs(expireTime).toString(); qCDebug(dcSonos()) << "expires at" << QDateTime::currentDateTime().addSecs(expireTime).toString();
m_tokenRefreshTimer->start((expireTime - 20) * 1000); //m_tokenRefreshTimer->start((expireTime - 20) * 1000);
}*/ //TODO
}
info.setStatus(Device::DeviceErrorNoError); info.setStatus(Device::DeviceErrorNoError);
emit pairingFinished(info); emit pairingFinished(info);
@ -179,7 +187,15 @@ void DevicePluginSonos::postSetupDevice(Device *device)
} }
if (device->deviceClassId() == sonosGroupDeviceClassId) { if (device->deviceClassId() == sonosGroupDeviceClassId) {
Device *parentDevice = myDevices().findById(device->parentId());
Sonos *sonos = m_sonosConnections.value(parentDevice);
if (!sonos) {
return;
}
QString groupId = device->paramValue(sonosGroupDeviceGroupIdParamTypeId).toString();
sonos->getGroupPlaybackStatus(groupId);
sonos->getGroupMetadataStatus(groupId);
sonos->getGroupVolume(groupId);
} }
} }
@ -188,7 +204,7 @@ void DevicePluginSonos::startMonitoringAutoDevices()
{ {
foreach (Device *device, myDevices()) { foreach (Device *device, myDevices()) {
if (device->deviceClassId() == sonosGroupDeviceClassId) { if (device->deviceClassId() == sonosGroupDeviceClassId) {
return; // We already have a Auto Mock device... do nothing. return;
} }
} }
} }
@ -197,13 +213,14 @@ void DevicePluginSonos::deviceRemoved(Device *device)
{ {
qCDebug(dcSonos) << "Delete " << device->name(); qCDebug(dcSonos) << "Delete " << device->name();
if (myDevices().empty()) { if (myDevices().empty()) {
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
m_pluginTimer = nullptr;
} }
} }
Device::DeviceError DevicePluginSonos::executeAction(Device *device, const Action &action) Device::DeviceError DevicePluginSonos::executeAction(Device *device, const Action &action)
{ {
Q_UNUSED(action)
if (device->deviceClassId() == sonosGroupDeviceClassId) { if (device->deviceClassId() == sonosGroupDeviceClassId) {
Sonos *sonos = m_sonosConnections.value(device); Sonos *sonos = m_sonosConnections.value(device);
QByteArray groupId = device->paramValue(sonosGroupDeviceGroupIdParamTypeId).toByteArray(); QByteArray groupId = device->paramValue(sonosGroupDeviceGroupIdParamTypeId).toByteArray();
@ -237,29 +254,41 @@ Device::DeviceError DevicePluginSonos::executeAction(Device *device, const Actio
} }
if (action.actionTypeId() == sonosGroupPauseActionTypeId) { if (action.actionTypeId() == sonosGroupPauseActionTypeId) {
sonos->groupPause(groupId); m_pendingActions.insert(sonos->groupPause(groupId), action.id());
return Device::DeviceErrorNoError; return Device::DeviceErrorAsync;
} }
if (action.actionTypeId() == sonosGroupStopActionTypeId) { if (action.actionTypeId() == sonosGroupStopActionTypeId) {
sonos->groupPause(groupId); m_pendingActions.insert(sonos->groupPause(groupId), action.id());
return Device::DeviceErrorNoError; return Device::DeviceErrorAsync;
} }
if (action.actionTypeId() == sonosGroupMuteActionTypeId) { if (action.actionTypeId() == sonosGroupMuteActionTypeId) {
bool mute = action.param(sonosGroupMuteActionMuteParamTypeId).value().toBool(); bool mute = action.param(sonosGroupMuteActionMuteParamTypeId).value().toBool();
sonos->setGroupMute(groupId, mute); m_pendingActions.insert(sonos->setGroupMute(groupId, mute), action.id());
return Device::DeviceErrorNoError; return Device::DeviceErrorAsync;
} }
if (action.actionTypeId() == sonosGroupSkipNextActionTypeId) { if (action.actionTypeId() == sonosGroupSkipNextActionTypeId) {
sonos->groupSkipToNextTrack(groupId); m_pendingActions.insert(sonos->groupSkipToNextTrack(groupId), action.id());
return Device::DeviceErrorNoError; return Device::DeviceErrorAsync;
} }
if (action.actionTypeId() == sonosGroupSkipBackActionTypeId) { if (action.actionTypeId() == sonosGroupSkipBackActionTypeId) {
sonos->groupSkipToPreviousTrack(groupId); m_pendingActions.insert(sonos->groupSkipToPreviousTrack(groupId), action.id());
return Device::DeviceErrorNoError; return Device::DeviceErrorAsync;
}
if (action.actionTypeId() == sonosGroupPlaybackStatusActionTypeId) {
QString playbackStatus = action.param(sonosGroupPlaybackStatusActionPlaybackStatusParamTypeId).value().toString();
if (playbackStatus == "Playing") {
sonos->groupPlay(groupId);
} else if(playbackStatus == "Stopped") {
sonos->groupPause(groupId);
} else if(playbackStatus == "Paused") {
sonos->groupPause(groupId);
}
return Device::DeviceErrorAsync;
} }
return Device::DeviceErrorActionTypeNotFound; return Device::DeviceErrorActionTypeNotFound;
} }
@ -267,16 +296,36 @@ Device::DeviceError DevicePluginSonos::executeAction(Device *device, const Actio
} }
void DevicePluginSonos::onPluginTimer() void DevicePluginSonos::onPluginTimer()
{ {
foreach (Device *device, myDevices().filterByDeviceClassId(sonosConnectionDeviceClassId)) {
//get groups for each household in order to add or remove groups
Sonos *sonos = m_sonosConnections.value(device);
if (!sonos)
continue;
sonos->getHouseholds();
foreach (Device *groupDevice, myDevices().filterByParentDeviceId(device->id())) {
if (device->deviceClassId() == sonosGroupDeviceClassId) {
//get playback status of each group
QByteArray groupId = groupDevice->paramValue(sonosGroupDeviceGroupIdParamTypeId).toByteArray();
sonos->getGroupPlaybackStatus(groupId);
sonos->getGroupMetadataStatus(groupId);
sonos->getGroupVolume(groupId);
}
}
}
} }
void DevicePluginSonos::onConnectionChanged() void DevicePluginSonos::onConnectionChanged(bool connected)
{ {
Sonos *sonos = static_cast<Sonos *>(sender()); Sonos *sonos = static_cast<Sonos *>(sender());
Device *device = m_sonosConnections.key(sonos); Device *device = m_sonosConnections.key(sonos);
device->setStateValue(sonosConnectionConnectedStateTypeId, false); //TODO device->setStateValue(sonosConnectionConnectedStateTypeId, connected);
//TODO set all groups foreach (Device *groupDevice, myDevices().filterByParentDeviceId(device->id())) {
groupDevice->setStateValue(sonosGroupConnectedStateTypeId, connected);
}
} }
void DevicePluginSonos::onRefreshTimeout() void DevicePluginSonos::onRefreshTimeout()
@ -310,11 +359,89 @@ void DevicePluginSonos::onRefreshTimeout()
}); });
} }
void DevicePluginSonos::onHouseholdIdsReceived(QList<QByteArray> householdIds) void DevicePluginSonos::onHouseholdIdsReceived(QList<QString> householdIds)
{ {
qDebug(dcSonos()) << "Household Id received, start to discover groups";
Sonos *sonos = static_cast<Sonos *>(sender()); Sonos *sonos = static_cast<Sonos *>(sender());
foreach(QByteArray householdId, householdIds) { foreach(QString householdId, householdIds) {
sonos->getGroups(householdId); sonos->getGroups(householdId);
} }
} }
void DevicePluginSonos::onGroupsReceived(QList<Sonos::GroupObject> groupObjects)
{
Sonos *sonos = static_cast<Sonos *>(sender());
Device *parentDevice = m_sonosConnections.key(sonos);
if (!parentDevice)
return;
QList<DeviceDescriptor> deviceDescriptors;
foreach(Sonos::GroupObject groupObject, groupObjects) {
if (!myDevices().filterByParam(sonosGroupDeviceGroupIdParamTypeId, groupObject.groupId).isEmpty()) {
continue;
}
DeviceDescriptor deviceDescriptor(sonosGroupDeviceClassId, groupObject.displayName, "Sonos Group", parentDevice->id());
ParamList params;
params.append(Param(sonosGroupDeviceGroupIdParamTypeId, groupObject.groupId));
deviceDescriptor.setParams(params);
deviceDescriptors.append(deviceDescriptor);
}
if (!deviceDescriptors.isEmpty())
emit autoDevicesAppeared(sonosGroupDeviceClassId, deviceDescriptors);
}
void DevicePluginSonos::onPlayBackStatusReceived(const QString &groupId, Sonos::PlayBackObject playBack)
{
qDebug(dcSonos()) << "Playback status received" << playBack.playbackState;
Device *device = myDevices().findByParams(ParamList() << Param(sonosGroupDeviceGroupIdParamTypeId, groupId));
if (!device)
return;
switch (playBack.playbackState) {
case Sonos::PlayBackStateIdle:
device->setStateValue(sonosGroupPlaybackStatusStateTypeId, "Stopped");
break;
case Sonos::PlayBackStatePause:
device->setStateValue(sonosGroupPlaybackStatusStateTypeId, "Paused");
break;
case Sonos::PlayBackStateBuffering:
case Sonos::PlayBackStatePlaying:
device->setStateValue(sonosGroupPlaybackStatusStateTypeId, "Playing");
break;
}
}
void DevicePluginSonos::onMetadataStatusReceived(const QString &groupId, Sonos::MetadataStatus metaDataStatus)
{
Device *device = myDevices().findByParams(ParamList() << Param(sonosGroupDeviceGroupIdParamTypeId, groupId));
if (!device)
return;
device->setStateValue(sonosGroupTitleStateTypeId, metaDataStatus.currentItem.track.name);
device->setStateValue(sonosGroupArtistStateTypeId, metaDataStatus.currentItem.track.artist.name);
device->setStateValue(sonosGroupCollectionStateTypeId, metaDataStatus.currentItem.track.album.name);
//device->setStateValue(sonosGroupArtworkStateTypeId, metaDataStatus.currentItem.track.imageUrl);
device->setStateValue(sonosGroupArtworkStateTypeId, metaDataStatus.container.imageUrl);
}
void DevicePluginSonos::onVolumeReceived(const QString &groupId, Sonos::GroupVolumeObject groupVolume)
{
Device *device = myDevices().findByParams(ParamList() << Param(sonosGroupDeviceGroupIdParamTypeId, groupId));
if (!device)
return;
device->setStateValue(sonosGroupVolumeStateTypeId, groupVolume.volume);
device->setStateValue(sonosGroupMuteStateTypeId, groupVolume.muted);
}
void DevicePluginSonos::onActionExecuted(QUuid sonosActionId, bool success)
{
if (m_pendingActions.contains(sonosActionId)) {
ActionId nymeaActionId = m_pendingActions.value(sonosActionId);
if (success) {
emit actionExecutionFinished(nymeaActionId, Device::DeviceErrorNoError);
} else {
emit actionExecutionFinished(nymeaActionId, Device::DeviceErrorHardwareFailure);
}
}
}

View File

@ -61,13 +61,18 @@ private:
QByteArray m_sonosConnectionAccessToken; QByteArray m_sonosConnectionAccessToken;
QByteArray m_sonosConnectionRefreshToken; QByteArray m_sonosConnectionRefreshToken;
QHash<QUuid, ActionId> m_pendingActions;
private slots: private slots:
void onPluginTimer(); void onPluginTimer();
void onConnectionChanged(); void onConnectionChanged(bool connected);
void onRefreshTimeout(); void onRefreshTimeout();
void onHouseholdIdsReceived(QList<QByteArray> householdIds); void onHouseholdIdsReceived(QList<QString> householdIds);
void onGroupsReceived(QList<Sonos::GroupObject> groupIds);
void onPlayBackStatusReceived(const QString &groupId, Sonos::PlayBackObject playBack);
void onMetadataStatusReceived(const QString &groupId, Sonos::MetadataStatus metaDataStatus);
void onVolumeReceived(const QString &groupId, Sonos::GroupVolumeObject groupVolume);
void onActionExecuted(QUuid actionId, bool success);
}; };
#endif // DEVICEPLUGINSONOS_H #endif // DEVICEPLUGINSONOS_H

View File

@ -24,6 +24,8 @@
#include "extern-plugininfo.h" #include "extern-plugininfo.h"
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
Sonos::Sonos(NetworkAccessManager *networkmanager, const QByteArray &accessToken, QObject *parent) : Sonos::Sonos(NetworkAccessManager *networkmanager, const QByteArray &accessToken, QObject *parent) :
QObject(parent), QObject(parent),
@ -50,29 +52,40 @@ void Sonos::getHouseholds()
reply->deleteLater(); reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
connectionChanged(true);
// Check HTTP status code // Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) { if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString(); qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
return; return;
} }
qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll(); //qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll();
/*QJsonDocument data = reply->readAll(); QJsonDocument data = QJsonDocument::fromJson(reply->readAll());
if (!data.isObject()) if (!data.isObject()) {
qDebug(dcSonos()) << "Household ID: Recieved invalide JSON object";
return; return;
QList<HouseholdObject> households; }
emit householdObjectsReceived(households);*/ QList<QString> households;
QJsonArray jsonArray = data["households"].toArray();
foreach (const QJsonValue & value, jsonArray) {
QJsonObject obj = value.toObject();
qDebug(dcSonos()) << "Household ID received:" << obj["id"].toString();
households.append(obj["id"].toString());
}
emit householdIdsReceived(households);
}); });
} }
void Sonos::cancelAudioClip() QUuid Sonos::cancelAudioClip()
{ {
QUuid actionId = QUuid::createUuid();
return actionId;
} }
void Sonos::loadAudioClip() QUuid Sonos::loadAudioClip()
{ {
QUuid actionId = QUuid::createUuid();
return actionId;
} }
void Sonos::getFavorites() void Sonos::getFavorites()
@ -80,12 +93,13 @@ void Sonos::getFavorites()
} }
void Sonos::loadFavorite() QUuid Sonos::loadFavorite()
{ {
QUuid actionId = QUuid::createUuid();
return actionId;
} }
void Sonos::getGroups(const QByteArray &householdId) void Sonos::getGroups(const QString &householdId)
{ {
QNetworkRequest request; QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json"); request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
@ -103,124 +117,673 @@ void Sonos::getGroups(const QByteArray &householdId)
return; return;
} }
qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll(); //qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll();
/*QJsonDocument data = reply->readAll(); QJsonDocument data = QJsonDocument::fromJson(reply->readAll());
if (!data.isObject()) if (!data.isObject())
return; return;
QList<HouseholdObject> households; if (!data["groups"].isArray())
emit householdObjectsReceived(households);*/ return;
QJsonArray array = data["groups"].toArray();
QList<GroupObject> groupObjects;
foreach (const QJsonValue & value, array) {
QJsonObject obj = value.toObject();
qDebug(dcSonos()) << "Group ID received:" << obj["id"].toString();
GroupObject group;
group.groupId = obj["id"].toString();
group.displayName = obj["name"].toString();
groupObjects.append(group);
}
emit groupsReceived(groupObjects);
}); });
} }
void Sonos::createGroup(const QByteArray &householdId, QList<QByteArray> playerIds) QUuid Sonos::createGroup(const QString &householdId, QList<QString> playerIds)
{ {
Q_UNUSED(householdId) Q_UNUSED(householdId)
Q_UNUSED(playerIds) Q_UNUSED(playerIds)
QUuid actionId = QUuid::createUuid();
return actionId;
} }
void Sonos::modifyGroupMembers() QUuid Sonos::modifyGroupMembers()
{ {
QUuid actionId = QUuid::createUuid();
return actionId;
} }
void Sonos::setGroupMembers(const QByteArray &groupId) QUuid Sonos::setGroupMembers(const QString &groupId)
{ {
Q_UNUSED(groupId) Q_UNUSED(groupId)
QUuid actionId = QUuid::createUuid();
return actionId;
} }
void Sonos::getGroupVolume(const QByteArray &groupId) void Sonos::getGroupVolume(const QString &groupId)
{ {
Q_UNUSED(groupId) QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/groupVolume"));
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished, this, [reply, groupId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
return;
}
//qDebug(dcSonos()) << "Received response from Sonos" << reply->readAll();
QJsonDocument data = QJsonDocument::fromJson(reply->readAll());
if (!data.isObject())
return;
GroupVolumeObject groupVolume;
groupVolume.volume = data["volume"].toInt();
groupVolume.muted = data["muted"].toBool();
groupVolume.fixed = data["fixed"].toBool();
emit volumeReceived(groupId, groupVolume);
});
} }
void Sonos::setGroupVolume(const QByteArray &groupId, int volume) QUuid Sonos::setGroupVolume(const QString &groupId, int volume)
{ {
Q_UNUSED(groupId) QNetworkRequest request;
Q_UNUSED(volume) request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/groupVolume"));
QUuid actionId = QUuid::createUuid();
QJsonObject object;
object.insert("volume", QJsonValue::fromVariant(volume));
QJsonDocument doc(object);
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
emit actionExecuted(actionId, false);
return;
}
emit actionExecuted(actionId, true);
});
return actionId;
} }
void Sonos::setGroupMute(const QByteArray &groupId, bool mute) QUuid Sonos::setGroupMute(const QString &groupId, bool mute)
{ {
Q_UNUSED(groupId) Q_UNUSED(groupId)
Q_UNUSED(mute) Q_UNUSED(mute)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/groupVolume/mute"));
QUuid actionId = QUuid::createUuid();
QJsonObject object;
object.insert("muted", QJsonValue::fromVariant(mute));
QJsonDocument doc(object);
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
emit actionExecuted(actionId, false);
return;
}
emit actionExecuted(actionId, true);
});
return actionId;
} }
void Sonos::setGroupRelativeVolume(const QByteArray &groupId, int volumeDelta) QUuid Sonos::setGroupRelativeVolume(const QString &groupId, int volumeDelta)
{ {
Q_UNUSED(groupId) QNetworkRequest request;
Q_UNUSED(volumeDelta) request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/groupVolume/relative"));
QUuid actionId = QUuid::createUuid();
QJsonObject object;
object.insert("volumeDelta", QJsonValue::fromVariant(volumeDelta));
QJsonDocument doc(object);
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
emit actionExecuted(actionId, false);
return;
}
emit actionExecuted(actionId, true);
});
return actionId;
} }
void Sonos::getGroupPlaybackStatus(const QByteArray &groupId) void Sonos::getGroupPlaybackStatus(const QString &groupId)
{ {
Q_UNUSED(groupId) QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback"));
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished, this, [reply, this, groupId] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
return;
}
QJsonDocument data = QJsonDocument::fromJson(reply->readAll());
if (!data.isObject())
return;
PlayBackObject playBackObject;
QJsonObject object = data.object();
playBackObject.itemId = object["itemId"].toString();
playBackObject.positionMillis = object["positionMillis"].toInt();
playBackObject.previousItemId = object["previousItemId"].toInt();
playBackObject.previousPositionMillis = object["previousPositionMillis"].toInt();
QString playBackState = object["playbackState"].toString();
if (playBackState.contains("BUFFERING")) {
playBackObject.playbackState = PlayBackStateBuffering;
} else if (playBackState.contains("IDLE")) {
playBackObject.playbackState = PlayBackStateIdle;
} else if (playBackState.contains("PAUSE")) {
playBackObject.playbackState = PlayBackStatePause;
} else if (playBackState.contains("PLAYING")) {
playBackObject.playbackState = PlayBackStatePlaying;
}
playBackObject.isDucking = object["isDucking"].toBool();
playBackObject.queueVersion = object["queueVersion"].toString();
emit playBackStatusReceived(groupId, playBackObject);
});
} }
void Sonos::groupLoadLineIn(const QByteArray &groupId) QUuid Sonos::groupLoadLineIn(const QString &groupId)
{ {
Q_UNUSED(groupId) Q_UNUSED(groupId)
QUuid actionId = QUuid::createUuid();
return actionId;
} }
void Sonos::groupPlay(const QByteArray &groupId) QUuid Sonos::groupPlay(const QString &groupId)
{ {
Q_UNUSED(groupId) QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/play"));
QUuid actionId = QUuid::createUuid();
QNetworkReply *reply = m_networkManager->post(request, "");
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
emit actionExecuted(actionId, false);
return;
}
emit actionExecuted(actionId, true);
});
return actionId;
} }
void Sonos::groupPause(const QByteArray &groupId) QUuid Sonos::groupPause(const QString &groupId)
{ {
Q_UNUSED(groupId) QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/pause"));
QUuid actionId = QUuid::createUuid();
QNetworkReply *reply = m_networkManager->post(request, "");
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
emit actionExecuted(actionId, false);
return;
}
emit actionExecuted(actionId, true);
});
return actionId;
} }
void Sonos::groupSeek(const QByteArray &groupId) QUuid Sonos::groupSeek(const QString &groupId, int possitionMillis)
{ {
Q_UNUSED(groupId) Q_UNUSED(groupId)
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/seek"));
QUuid actionId = QUuid::createUuid();
QJsonObject object;
object.insert("positionMillis", QJsonValue::fromVariant(possitionMillis));
QJsonDocument doc(object);
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
emit actionExecuted(actionId, false);
return;
}
emit actionExecuted(actionId, true);
});
return actionId;
} }
void Sonos::groupSeekRelative(const QByteArray &groupId, int millis) QUuid Sonos::groupSeekRelative(const QString &groupId, int deltaMillis)
{ {
Q_UNUSED(groupId) Q_UNUSED(groupId)
Q_UNUSED(millis) QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/seekRelative"));
QUuid actionId = QUuid::createUuid();
QJsonObject object;
object.insert("deltaMillis", QJsonValue::fromVariant(deltaMillis));
QJsonDocument doc(object);
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
emit actionExecuted(actionId, false);
return;
}
emit actionExecuted(actionId, true);
});
return actionId;
} }
void Sonos::groupSetPlayModes(const QByteArray &groupId, PlayMode playMode) QUuid Sonos::groupSetPlayModes(const QString &groupId, PlayMode playMode)
{ {
Q_UNUSED(groupId) QNetworkRequest request;
Q_UNUSED(playMode) request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/playMode"));
QUuid actionId = QUuid::createUuid();
QJsonObject object;
QJsonObject playModesObject;
playModesObject["repeat"] = playMode.repeat;
playModesObject["repeatOne"] = playMode.repeatOne;
playModesObject["crossfade"] = playMode.crossfade;
playModesObject["shuffle"] = playMode.shuffle;
object.insert("playModes", playModesObject);
QJsonDocument doc(object);
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
emit actionExecuted(actionId, false);
return;
}
emit actionExecuted(actionId, true);
});
return actionId;
} }
void Sonos::groupSetShuffle(const QByteArray &groupId, bool shuffle) QUuid Sonos::groupSetShuffle(const QString &groupId, bool shuffle)
{ {
Q_UNUSED(groupId) QNetworkRequest request;
Q_UNUSED(shuffle) request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/playMode"));
QUuid actionId = QUuid::createUuid();
QJsonObject object;
QJsonObject playModesObject;
playModesObject["shuffle"] = shuffle;
object.insert("playModes", playModesObject);
QJsonDocument doc(object);
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
emit actionExecuted(actionId, false);
return;
}
emit actionExecuted(actionId, true);
});
return actionId;
} }
void Sonos::groupSetRepeat(const QByteArray &groupId, RepeatMode repeatMode) QUuid Sonos::groupSetRepeat(const QString &groupId, RepeatMode repeatMode)
{ {
Q_UNUSED(groupId) QNetworkRequest request;
Q_UNUSED(repeatMode) request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/playMode"));
QUuid actionId = QUuid::createUuid();
QJsonObject object;
QJsonObject playModesObject;
if (repeatMode == RepeatModeAll) {
playModesObject["repeat"] = true;
playModesObject["repeatOne"] = false;
} else if (repeatMode == RepeatModeOne) {
playModesObject["repeat"] = false;
playModesObject["repeatOne"] = true;
} else if (repeatMode == RepeatModeAll) {
playModesObject["repeat"] = false;
playModesObject["repeatOne"] = false;
}
object.insert("playModes", playModesObject);
QJsonDocument doc(object);
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
emit actionExecuted(actionId, false);
return;
}
emit actionExecuted(actionId, true);
});
return actionId;
} }
void Sonos::groupSetCrossfade(const QByteArray &groupId, bool crossfade) QUuid Sonos::groupSetCrossfade(const QString &groupId, bool crossfade)
{ {
Q_UNUSED(groupId) QNetworkRequest request;
Q_UNUSED(crossfade) request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/playMode"));
QUuid actionId = QUuid::createUuid();
QJsonObject object;
QJsonObject playModesObject;
playModesObject["crossfade"] = crossfade;
object.insert("playModes", playModesObject);
QJsonDocument doc(object);
QNetworkReply *reply = m_networkManager->post(request, doc.toBinaryData());
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
emit actionExecuted(actionId, false);
return;
}
emit actionExecuted(actionId, true);
});
return actionId;
} }
void Sonos::groupSkipToNextTrack(const QByteArray &groupId) QUuid Sonos::groupSkipToNextTrack(const QString &groupId)
{ {
Q_UNUSED(groupId) QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/skipToNextTrack"));
QUuid actionId = QUuid::createUuid();
QNetworkReply *reply = m_networkManager->post(request, "");
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
actionExecuted(actionId, false);
return;
}
actionExecuted(actionId, true);
});
return actionId;
} }
void Sonos::groupSkipToPreviousTrack(const QByteArray &groupId) QUuid Sonos::groupSkipToPreviousTrack(const QString &groupId)
{ {
Q_UNUSED(groupId) QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/skipToPreviousTrack"));
QUuid actionId = QUuid::createUuid();
QNetworkReply *reply = m_networkManager->post(request, "");
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
actionExecuted(actionId, false);
return;
}
actionExecuted(actionId, true);
});
return actionId;
} }
void Sonos::groupTogglePlayPause(const QByteArray &groupId) QUuid Sonos::groupTogglePlayPause(const QString &groupId)
{ {
Q_UNUSED(groupId) QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playback/togglePlayPause"));
QUuid actionId = QUuid::createUuid();
QNetworkReply *reply = m_networkManager->post(request, "");
connect(reply, &QNetworkReply::finished, this, [reply, actionId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
actionExecuted(actionId, false);
return;
}
actionExecuted(actionId, true);
});
return actionId;
}
void Sonos::getGroupMetadataStatus(const QString &groupId)
{
QNetworkRequest request;
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Bearer " + m_accessToken);
request.setRawHeader("X-Sonos-Api-Key", m_apiKey);
request.setUrl(QUrl(m_baseControlUrl + "/groups/" + groupId + "/playbackMetadata"));
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished, this, [reply, groupId, this] {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// Check HTTP status code
if (status != 200 || reply->error() != QNetworkReply::NoError) {
qCWarning(dcSonos()) << "Request error:" << status << reply->errorString();
return;
}
QJsonDocument data = QJsonDocument::fromJson(reply->readAll());
if (!data.isObject())
return;
MetadataStatus metaDataStatus;
QJsonObject object = data.object();
if (object.contains("container")) {
ContainerObject container;
QJsonObject containerObject = object["container"].toObject();
container.name = containerObject["name"].toString();
container.type = containerObject["type"].toString();
container.imageUrl = containerObject["imageUrl"].toString();
if (containerObject.contains("service")) {
ServiceObject service;
QJsonObject serviceObject = containerObject.value("artist").toObject();
service.name = serviceObject["name"].toString();
container.service = service;
}
if (containerObject.contains("id")) {
qDebug(dcSonos()) << "Item ID" << containerObject.value("id").toString();
}
metaDataStatus.container = container;
}
if (object.contains("currentItem")) {
QJsonObject currentItemObject = object["currentItem"].toObject();
ItemObject currentItem;
if (currentItemObject.contains("track")) {
TrackObject track;
QJsonObject trackObject = currentItemObject["track"].toObject();
if (trackObject.contains("artist")) {
ArtistObject artist;
QJsonObject artistObject = trackObject["artist"].toObject();
artist.name = artistObject["name"].toString();
//qDebug(dcSonos()) << "Track object contains artist" << artist.name;
track.artist = artist;
}
if (trackObject.contains("album")) {
AlbumObject album;
QJsonObject albumObject = trackObject["album"].toObject();
album.name = albumObject["name"].toString();
//qDebug(dcSonos()) << "Track object contains album" << album.name;
track.album = album;
}
if (trackObject.contains("service")) {
ServiceObject service;
QJsonObject serviceObject = trackObject["service"].toObject();
service.name = serviceObject["name"].toString();
//qDebug(dcSonos()) << "Track object contains service" << service.name;
track.service = service;
}
if (trackObject.contains("id")) {
qDebug(dcSonos()) << "Item ID" << trackObject.value("id").toString();
}
track.type = trackObject["type"].toString();
track.name = trackObject["name"].toString();
track.imageUrl = trackObject["imageUrl"].toString();
track.trackNumber = trackObject["trackNumber"].toInt();
track.durationMillis = trackObject["durationMillis"].toInt();
currentItem.track = track;
}
metaDataStatus.currentItem = currentItem;
}
if (object.contains("nextItem")) {
ItemObject nextItem;
QJsonObject nextItemObject = object["nextItem"].toObject();
if (nextItemObject.contains("track")) {
TrackObject track;
QJsonObject trackObject = nextItemObject.value("track").toObject();
if (trackObject.contains("artist")) {
ArtistObject artist;
QJsonObject artistObject = trackObject.value("artist").toObject();
artist.name = artistObject["name"].toString();
//qDebug(dcSonos()) << "Track object contains artist" << artist.name;
track.artist = artist;
}
if (trackObject.contains("album")) {
AlbumObject album;
QJsonObject albumObject = trackObject.value("album").toObject();
album.name = albumObject["name"].toString();
//qDebug(dcSonos()) << "Track object contains album" << album.name;
track.album = album;
}
if (trackObject.contains("service")) {
ServiceObject service;
QJsonObject serviceObject = trackObject.value("service").toObject();
service.name = serviceObject["name"].toString();
//qDebug(dcSonos()) << "Track object contains service" << service.name;
track.service = service;
}
if (trackObject.contains("id")) {
qDebug(dcSonos()) << "Item ID" << trackObject.value("id").toString();
}
track.type = trackObject["type"].toString();
track.name = trackObject["name"].toString();
track.imageUrl = trackObject["imageUrl"].toString();
track.trackNumber = trackObject["trackNumber"].toInt();
track.durationMillis = trackObject["durationMillis"].toInt();
nextItem.track = track;
}
metaDataStatus.nextItem = nextItem;
}
emit metadataStatusReceived(groupId, metaDataStatus);
});
} }
void Sonos::getPlayerVolume(const QByteArray &playerId) void Sonos::getPlayerVolume(const QByteArray &playerId)
@ -228,22 +791,28 @@ void Sonos::getPlayerVolume(const QByteArray &playerId)
Q_UNUSED(playerId) Q_UNUSED(playerId)
} }
void Sonos::setPlayerVolume(const QByteArray &playerId, int volume) QUuid Sonos::setPlayerVolume(const QByteArray &playerId, int volume)
{ {
Q_UNUSED(playerId) Q_UNUSED(playerId)
Q_UNUSED(volume) Q_UNUSED(volume)
QUuid actionId = QUuid::createUuid();
return actionId;
} }
void Sonos::setPlayerRelativeVolume(const QByteArray &playerId, int volumeDelta) QUuid Sonos::setPlayerRelativeVolume(const QByteArray &playerId, int volumeDelta)
{ {
Q_UNUSED(playerId) Q_UNUSED(playerId)
Q_UNUSED(volumeDelta) Q_UNUSED(volumeDelta)
QUuid actionId = QUuid::createUuid();
return actionId;
} }
void Sonos::setPlayerMute(const QByteArray &playerId, bool mute) QUuid Sonos::setPlayerMute(const QByteArray &playerId, bool mute)
{ {
Q_UNUSED(playerId) Q_UNUSED(playerId)
Q_UNUSED(mute) Q_UNUSED(mute)
QUuid actionId = QUuid::createUuid();
return actionId;
} }
void Sonos::getPlaylist() void Sonos::getPlaylist()
@ -256,9 +825,10 @@ void Sonos::getPlaylists()
} }
void Sonos::loadPlaylist() QUuid Sonos::loadPlaylist()
{ {
QUuid actionId = QUuid::createUuid();
return actionId;
} }
void Sonos::getPlayerSettings() void Sonos::getPlayerSettings()
@ -266,8 +836,9 @@ void Sonos::getPlayerSettings()
} }
void Sonos::setPlayerSettings() QUuid Sonos::setPlayerSettings()
{ {
QUuid actionId = QUuid::createUuid();
return actionId;
} }

View File

@ -39,6 +39,13 @@ public:
RepeatModeNone RepeatModeNone
}; };
enum PlayBackState {
PlayBackStateBuffering,
PlayBackStateIdle,
PlayBackStatePause,
PlayBackStatePlaying
};
struct PlayMode { struct PlayMode {
bool repeat; bool repeat;
bool repeatOne; bool repeatOne;
@ -50,15 +57,20 @@ public:
}; };
/* Represents a Sonos household.*/ /* Represents a Sonos household.*/
struct GroupObject { struct GroupObject {
QByteArray CoordinatorId; //Player acting as the group coordinator for the group QString CoordinatorId; //Player acting as the group coordinator for the group
QByteArray groupId; //The ID of the group. QString groupId; //The ID of the group.
QString playbackState; //The playback state corresponding to the group. QString playbackState; //The playback state corresponding to the group.
QList<QByteArray> playerIds; //The IDs of the primary players in the group. QList<QByteArray> playerIds; //The IDs of the primary players in the group.
QString displayName; //The display name for the group, such as “Living Room” or “Kitchen + 2”. QString displayName; //The display name for the group, such as “Living Room” or “Kitchen + 2”.
}; };
struct GroupVolumeObject {
int volume; //Group volume as an integer between 0 and 100, inclusive.
bool muted; //A value indicating whether or not the group is muted
bool fixed; //A value indicating whether or not the group volume is fixed or changeable.
};
/* /*
* Represents a Sonos household.*/ * Represents a Sonos household.*/
/*struct HouseholdObject { /*struct HouseholdObject {
@ -100,16 +112,7 @@ public:
bool monoMode; bool monoMode;
bool wifiDisabled; bool wifiDisabled;
}; };
/*
* A single music track or audio file. Tracks are identified by type,
* which determines the key values for the object types included.
* The following fields are shared by all types of tracks. */
struct TrackObject
{
bool canCrossfade;
bool canSkip;
int durationMillis;
};
/* The music object identifier for the item in a music service. /* The music object identifier for the item in a music service.
* This identifies the content within a music service, the music service, * This identifies the content within a music service, the music service,
@ -130,17 +133,6 @@ public:
bool isVisible; bool isVisible;
}; };
/* An item in a queue. Used for cloud queue tracks and radio stations that have track-like data
* for the currently playing content. For example, the currentItem and nextItem parameters in the
* metadataStatus event are item object types.*/
struct ItemObject
{
QString itemId;
TrackObject track;
bool deleted;
TrackPoliciesObject policies;
};
/* The artist of the track. */ /* The artist of the track. */
struct ArtistObject struct ArtistObject
{ {
@ -154,7 +146,6 @@ public:
{ {
QString name; QString name;
ArtistObject artist; ArtistObject artist;
//TODO
}; };
struct ContainerObject struct ContainerObject
@ -167,76 +158,131 @@ public:
//tags enum //tags enum
}; };
struct PlayBackObject {
QString itemId;
bool isDucking;
PlayBackState playbackState;
PlayMode playMode;
uint positionMillis;
QString previousItemId;
uint previousPositionMillis;
QString queueVersion;
};
/*
* A single music track or audio file. Tracks are identified by type,
* which determines the key values for the object types included.
* The following fields are shared by all types of tracks. */
struct TrackObject
{
QString type;
QString name;
QString imageUrl;
int trackNumber;
bool canCrossfade;
bool canSkip;
int durationMillis;
ArtistObject artist;
AlbumObject album;
ServiceObject service;
};
/* An item in a queue. Used for cloud queue tracks and radio stations that have track-like data
* for the currently playing content. For example, the currentItem and nextItem parameters in the
* metadataStatus event are item object types.*/
struct ItemObject
{
QString itemId;
TrackObject track;
bool deleted;
TrackPoliciesObject policies;
};
struct MetadataStatus {
ContainerObject container;
ItemObject currentItem;
ItemObject nextItem;
};
explicit Sonos(NetworkAccessManager *networkManager, const QByteArray &accessToken, QObject *parent = nullptr); explicit Sonos(NetworkAccessManager *networkManager, const QByteArray &accessToken, QObject *parent = nullptr);
void setAccessToken(const QByteArray &accessToken); void setAccessToken(const QByteArray &accessToken);
void getHouseholds(); void getHouseholds();
void cancelAudioClip();
void loadAudioClip();
void getFavorites(); void getFavorites();
void loadFavorite(); void getGroups(const QString &householdId);
void getGroups(const QByteArray &householdId); QUuid cancelAudioClip();
void createGroup(const QByteArray &householdId, QList<QByteArray> playerIds); QUuid loadAudioClip();
void modifyGroupMembers(); QUuid loadFavorite();
void setGroupMembers(const QByteArray &groupId);
//group volume QUuid createGroup(const QString &householdId, QList<QString> playerIds);
void getGroupVolume(const QByteArray &groupId); //Get the volume and mute state of a group. QUuid modifyGroupMembers();
void setGroupVolume(const QByteArray &groupId, int volume); //Set group volume to a specific level and unmute the group if muted. QUuid setGroupMembers(const QString &groupId);
void setGroupMute(const QByteArray &groupId, bool mute); //Mute and unmute the group.
void setGroupRelativeVolume(const QByteArray &groupId, int volumeDelta); //Increase or decrease group volume. //Group volume
void getGroupVolume(const QString &groupId); //Get the volume and mute state of a group.
//Group volume actions
QUuid setGroupVolume(const QString &groupId, int volume); //Set group volume to a specific level and unmute the group if muted.
QUuid setGroupMute(const QString &groupId, bool mute); //Mute and unmute the group.
QUuid setGroupRelativeVolume(const QString &groupId, int volumeDelta); //Increase or decrease group volume.
//group playback //group playback
void getGroupPlaybackStatus(const QByteArray &groupId); void getGroupPlaybackStatus(const QString &groupId);
void groupLoadLineIn(const QByteArray &groupId);
void groupPlay(const QByteArray &groupId);
void groupPause(const QByteArray &groupId);
void groupSeek(const QByteArray &groupId);
void groupSeekRelative(const QByteArray &groupId, int deltaMillis);
void groupSetPlayModes(const QByteArray &groupId, PlayMode playMode);
void groupSetShuffle(const QByteArray &groupId, bool shuffle);
void groupSetRepeat(const QByteArray &groupId, RepeatMode repeatMode);
void groupSetCrossfade(const QByteArray &groupId, bool crossfade);
void groupSkipToNextTrack(const QByteArray &groupId); //Group playback actions
void groupSkipToPreviousTrack(const QByteArray &groupId); QUuid groupLoadLineIn(const QString &groupId);
void groupTogglePlayPause(const QByteArray &groupId); QUuid groupPlay(const QString &groupId);
QUuid groupPause(const QString &groupId);
QUuid groupSeek(const QString &groupId, int possitionMillis);
QUuid groupSeekRelative(const QString &groupId, int deltaMillis);
QUuid groupSetPlayModes(const QString &groupId, PlayMode playMode);
QUuid groupSetShuffle(const QString &groupId, bool shuffle);
QUuid groupSetRepeat(const QString &groupId, RepeatMode repeatMode);
QUuid groupSetCrossfade(const QString &groupId, bool crossfade);
QUuid groupSkipToNextTrack(const QString &groupId);
QUuid groupSkipToPreviousTrack(const QString &groupId);
QUuid groupTogglePlayPause(const QString &groupId);
//playbackMetadata //playbackMetadata
void getGroupMetadataStatus(const QString &groupId);
// playerVolume // playerVolume
void getPlayerVolume(const QByteArray &playerId); void getPlayerVolume(const QByteArray &playerId);
void setPlayerVolume(const QByteArray &playerId, int volume); QUuid setPlayerVolume(const QByteArray &playerId, int volume);
void setPlayerRelativeVolume(const QByteArray &playerId, int volumeDelta); QUuid setPlayerRelativeVolume(const QByteArray &playerId, int volumeDelta);
void setPlayerMute(const QByteArray &playerId, bool mute); QUuid setPlayerMute(const QByteArray &playerId, bool mute);
//Playlists API namespace //Playlists API namespace
void getPlaylist(); void getPlaylist();
void getPlaylists(); void getPlaylists();
void loadPlaylist(); QUuid loadPlaylist();
//Settings //Settings
void getPlayerSettings(); void getPlayerSettings();
void setPlayerSettings(); QUuid setPlayerSettings();
private: private:
QByteArray m_baseAuthorizationUrl = "https://api.sonos.com/login/v3/oauth"; QByteArray m_baseAuthorizationUrl = "https://api.sonos.com/login/v3/oauth";
QByteArray m_baseControlUrl = "https://api.ws.sonos.com/control/api/v1"; QByteArray m_baseControlUrl = "https://api.ws.sonos.com/control/api/v1";
QByteArray m_accessToken;
QByteArray m_apiKey = "b15cbf8c-a39c-47aa-bd93-635a96e9696c"; QByteArray m_apiKey = "b15cbf8c-a39c-47aa-bd93-635a96e9696c";
QByteArray m_accessToken;
NetworkAccessManager *m_networkManager = nullptr; NetworkAccessManager *m_networkManager = nullptr;
private slots: private slots:
signals: signals:
void householdIdsReceived(QList<QByteArray> householdIds); void connectionChanged(bool connected);
void householdIdsReceived(QList<QString> householdIds);
void groupsReceived(QList<GroupObject> groups); void groupsReceived(QList<GroupObject> groups);
void playBackStatusReceived(const QString &groupId, PlayBackObject playBack);
void metadataStatusReceived(const QString &groupId, MetadataStatus metaDataStatus);
void volumeReceived(const QString &groupId, GroupVolumeObject groupVolume);
void actionExecuted(QUuid actionId,bool success);
}; };
#endif // SONOS_H #endif // SONOS_H