first working version
This commit is contained in:
parent
4254d3cb3c
commit
ac58d41ea6
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
701
sonos/sonos.cpp
701
sonos/sonos.cpp
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
174
sonos/sonos.h
174
sonos/sonos.h
@ -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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user