fixed volume action
parent
855c6cb3d1
commit
dbaecd9c1b
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Bose Soundtouch
|
||||||
|
|
||||||
|
This plug-in controls Bose speakers throught the local API.
|
||||||
|
|
||||||
|
## Device Setup
|
||||||
|
|
||||||
|
To connect the speaker to the WiFi the Bose App is required. This plug-in
|
||||||
|
supports device discovery.
|
||||||
|
|
@ -1,24 +1,30 @@
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* *
|
*
|
||||||
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io
|
* Copyright 2013 - 2020, nymea GmbH
|
||||||
* *
|
* Contact: contact@nymea.io
|
||||||
* This file is part of nymea. *
|
*
|
||||||
* *
|
* This file is part of nymea.
|
||||||
* This library is free software; you can redistribute it and/or *
|
* This project including source code and documentation is protected by copyright law, and
|
||||||
* modify it under the terms of the GNU Lesser General Public *
|
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||||
* License as published by the Free Software Foundation; either *
|
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||||
* version 2.1 of the License, or (at your option) any later version. *
|
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||||
* *
|
* of use of nymea GmbH, available under https://nymea.io/license
|
||||||
* This library is distributed in the hope that it will be useful, *
|
*
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
* GNU Lesser General Public License Usage
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
|
||||||
* Lesser General Public License for more details. *
|
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||||
* *
|
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||||
* You should have received a copy of the GNU Lesser General Public *
|
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
* License along with this library; If not, see *
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
* <http://www.gnu.org/licenses/>. *
|
* See the GNU Lesser General Public License for more details.
|
||||||
* *
|
*
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||||
|
* If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* For any further details and any questions please contact us under contact@nymea.io
|
||||||
|
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||||
|
*
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
#include "devicepluginbose.h"
|
#include "devicepluginbose.h"
|
||||||
#include "devices/device.h"
|
#include "devices/device.h"
|
||||||
|
|
@ -52,7 +58,6 @@ void DevicePluginBose::setupDevice(DeviceSetupInfo *info)
|
||||||
QString ipAddress = info->device()->paramValue(soundtouchDeviceIpParamTypeId).toString();
|
QString ipAddress = info->device()->paramValue(soundtouchDeviceIpParamTypeId).toString();
|
||||||
SoundTouch *soundTouch = new SoundTouch(hardwareManager()->networkManager(), ipAddress, this);
|
SoundTouch *soundTouch = new SoundTouch(hardwareManager()->networkManager(), ipAddress, this);
|
||||||
connect(soundTouch, &SoundTouch::connectionChanged, this, &DevicePluginBose::onConnectionChanged);
|
connect(soundTouch, &SoundTouch::connectionChanged, this, &DevicePluginBose::onConnectionChanged);
|
||||||
|
|
||||||
connect(soundTouch, &SoundTouch::infoReceived, this, &DevicePluginBose::onInfoObjectReceived);
|
connect(soundTouch, &SoundTouch::infoReceived, this, &DevicePluginBose::onInfoObjectReceived);
|
||||||
connect(soundTouch, &SoundTouch::nowPlayingReceived, this, &DevicePluginBose::onNowPlayingObjectReceived);
|
connect(soundTouch, &SoundTouch::nowPlayingReceived, this, &DevicePluginBose::onNowPlayingObjectReceived);
|
||||||
connect(soundTouch, &SoundTouch::volumeReceived, this, &DevicePluginBose::onVolumeObjectReceived);
|
connect(soundTouch, &SoundTouch::volumeReceived, this, &DevicePluginBose::onVolumeObjectReceived);
|
||||||
|
|
@ -60,15 +65,7 @@ void DevicePluginBose::setupDevice(DeviceSetupInfo *info)
|
||||||
connect(soundTouch, &SoundTouch::bassReceived, this, &DevicePluginBose::onBassObjectReceived);
|
connect(soundTouch, &SoundTouch::bassReceived, this, &DevicePluginBose::onBassObjectReceived);
|
||||||
connect(soundTouch, &SoundTouch::bassCapabilitiesReceived, this, &DevicePluginBose::onBassCapabilitiesObjectReceived);
|
connect(soundTouch, &SoundTouch::bassCapabilitiesReceived, this, &DevicePluginBose::onBassCapabilitiesObjectReceived);
|
||||||
connect(soundTouch, &SoundTouch::zoneReceived, this, &DevicePluginBose::onZoneObjectReceived);
|
connect(soundTouch, &SoundTouch::zoneReceived, this, &DevicePluginBose::onZoneObjectReceived);
|
||||||
|
connect(soundTouch, &SoundTouch::requestExecuted, this, &DevicePluginBose::onRequestExecuted);
|
||||||
soundTouch->getInfo();
|
|
||||||
soundTouch->getNowPlaying();
|
|
||||||
soundTouch->getVolume();
|
|
||||||
soundTouch->getSources();
|
|
||||||
soundTouch->getBass();
|
|
||||||
soundTouch->getBassCapabilities();
|
|
||||||
soundTouch->getZone();
|
|
||||||
|
|
||||||
m_soundTouch.insert(info->device(), soundTouch);
|
m_soundTouch.insert(info->device(), soundTouch);
|
||||||
|
|
||||||
info->finish(Device::DeviceErrorNoError);
|
info->finish(Device::DeviceErrorNoError);
|
||||||
|
|
@ -79,7 +76,16 @@ void DevicePluginBose::setupDevice(DeviceSetupInfo *info)
|
||||||
|
|
||||||
void DevicePluginBose::postSetupDevice(Device *device)
|
void DevicePluginBose::postSetupDevice(Device *device)
|
||||||
{
|
{
|
||||||
Q_UNUSED(device)
|
if (device->deviceClassId() == soundtouchDeviceClassId) {
|
||||||
|
SoundTouch *soundTouch = m_soundTouch.value(device);
|
||||||
|
soundTouch->getInfo();
|
||||||
|
soundTouch->getNowPlaying();
|
||||||
|
soundTouch->getVolume();
|
||||||
|
soundTouch->getSources();
|
||||||
|
soundTouch->getBass();
|
||||||
|
soundTouch->getBassCapabilities();
|
||||||
|
soundTouch->getZone();
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_pluginTimer) {
|
if (!m_pluginTimer) {
|
||||||
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(2);
|
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(2);
|
||||||
|
|
@ -137,82 +143,83 @@ void DevicePluginBose::executeAction(DeviceActionInfo *info)
|
||||||
|
|
||||||
if (action.actionTypeId() == soundtouchPowerActionTypeId) {
|
if (action.actionTypeId() == soundtouchPowerActionTypeId) {
|
||||||
//bool power = action.param(soundtouchPowerActionPowerParamTypeId).value().toBool();
|
//bool power = action.param(soundtouchPowerActionPowerParamTypeId).value().toBool();
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_POWER); //only toggling possible
|
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_POWER); //only toggling possible
|
||||||
info->finish(Device::DeviceErrorNoError);
|
m_pendingActions.insert(requestId, info);
|
||||||
return;
|
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||||
}
|
|
||||||
if (action.actionTypeId() == soundtouchMuteActionTypeId) {
|
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_MUTE);
|
|
||||||
info->finish(Device::DeviceErrorNoError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (action.actionTypeId() == soundtouchPlayActionTypeId) {
|
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PLAY);
|
|
||||||
info->finish(Device::DeviceErrorNoError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (action.actionTypeId() == soundtouchPauseActionTypeId) {
|
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PAUSE);
|
|
||||||
info->finish(Device::DeviceErrorNoError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (action.actionTypeId() == soundtouchStopActionTypeId) {
|
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_STOP);
|
|
||||||
info->finish(Device::DeviceErrorNoError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (action.actionTypeId() == soundtouchSkipNextActionTypeId) {
|
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_NEXT_TRACK);
|
|
||||||
info->finish(Device::DeviceErrorNoError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (action.actionTypeId() == soundtouchSkipBackActionTypeId) {
|
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PREV_TRACK);
|
|
||||||
info->finish(Device::DeviceErrorNoError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.actionTypeId() == soundtouchShuffleActionTypeId) {
|
} else if (action.actionTypeId() == soundtouchMuteActionTypeId) {
|
||||||
|
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_MUTE); //only toggling possible
|
||||||
|
m_pendingActions.insert(requestId, info);
|
||||||
|
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||||
|
|
||||||
|
} else if (action.actionTypeId() == soundtouchPlayActionTypeId) {
|
||||||
|
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_PLAY);
|
||||||
|
m_pendingActions.insert(requestId, info);
|
||||||
|
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||||
|
|
||||||
|
} else if (action.actionTypeId() == soundtouchPauseActionTypeId) {
|
||||||
|
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_PAUSE);
|
||||||
|
m_pendingActions.insert(requestId, info);
|
||||||
|
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||||
|
|
||||||
|
} else if (action.actionTypeId() == soundtouchStopActionTypeId) {
|
||||||
|
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_STOP);
|
||||||
|
m_pendingActions.insert(requestId, info);
|
||||||
|
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||||
|
|
||||||
|
} else if (action.actionTypeId() == soundtouchSkipNextActionTypeId) {
|
||||||
|
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_NEXT_TRACK);
|
||||||
|
m_pendingActions.insert(requestId, info);
|
||||||
|
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||||
|
|
||||||
|
} else if (action.actionTypeId() == soundtouchSkipBackActionTypeId) {
|
||||||
|
QUuid requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_PREV_TRACK);
|
||||||
|
m_pendingActions.insert(requestId, info);
|
||||||
|
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||||
|
|
||||||
|
} else if (action.actionTypeId() == soundtouchShuffleActionTypeId) {
|
||||||
|
|
||||||
|
QUuid requestId;
|
||||||
bool shuffle = action.param(soundtouchShuffleActionShuffleParamTypeId).value().toBool();
|
bool shuffle = action.param(soundtouchShuffleActionShuffleParamTypeId).value().toBool();
|
||||||
if (shuffle) {
|
if (shuffle) {
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_SHUFFLE_ON);
|
requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_SHUFFLE_ON);
|
||||||
} else {
|
} else {
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_SHUFFLE_OFF);
|
requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_SHUFFLE_OFF);
|
||||||
}
|
|
||||||
info->finish(Device::DeviceErrorNoError);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
m_pendingActions.insert(requestId, info);
|
||||||
|
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||||
|
|
||||||
if (action.actionTypeId() == soundtouchRepeatActionTypeId) {
|
} else if (action.actionTypeId() == soundtouchRepeatActionTypeId) {
|
||||||
|
|
||||||
|
QUuid requestId;
|
||||||
QString repeat = action.param(soundtouchRepeatActionRepeatParamTypeId).value().toString();
|
QString repeat = action.param(soundtouchRepeatActionRepeatParamTypeId).value().toString();
|
||||||
if (repeat == "None") {
|
if (repeat == "None") {
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_OFF);
|
requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_OFF);
|
||||||
} else if (repeat == "One") {
|
} else if (repeat == "One") {
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_ONE);
|
requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_ONE);
|
||||||
} else if (repeat == "All") {
|
} else if (repeat == "All") {
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_ALL);
|
requestId = soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_ALL);
|
||||||
}
|
|
||||||
info->finish(Device::DeviceErrorNoError);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
m_pendingActions.insert(requestId, info);
|
||||||
|
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||||
|
|
||||||
|
} else if (action.actionTypeId() == soundtouchVolumeActionTypeId) {
|
||||||
|
|
||||||
if (action.actionTypeId() == soundtouchVolumeActionTypeId) {
|
|
||||||
int volume = action.param(soundtouchVolumeActionVolumeParamTypeId).value().toInt();
|
int volume = action.param(soundtouchVolumeActionVolumeParamTypeId).value().toInt();
|
||||||
soundTouch->setVolume(volume);
|
QUuid requestId = soundTouch->setVolume(volume);
|
||||||
info->finish(Device::DeviceErrorNoError);
|
m_pendingActions.insert(requestId, info);
|
||||||
return;
|
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||||
}
|
|
||||||
|
} else if (action.actionTypeId() == soundtouchBassActionTypeId) {
|
||||||
|
|
||||||
if (action.actionTypeId() == soundtouchBassActionTypeId) {
|
|
||||||
int bass = action.param(soundtouchBassActionBassParamTypeId).value().toInt();
|
int bass = action.param(soundtouchBassActionBassParamTypeId).value().toInt();
|
||||||
soundTouch->setBass(bass);
|
QUuid requestId = soundTouch->setBass(bass);
|
||||||
info->finish(Device::DeviceErrorNoError);
|
m_pendingActions.insert(requestId, info);
|
||||||
return;
|
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||||
}
|
|
||||||
|
|
||||||
if (action.actionTypeId() == soundtouchPlaybackStatusActionTypeId) {
|
} else if (action.actionTypeId() == soundtouchPlaybackStatusActionTypeId) {
|
||||||
|
|
||||||
|
QUuid requestId;
|
||||||
QString status = action.param(soundtouchPlaybackStatusActionPlaybackStatusParamTypeId).value().toString();
|
QString status = action.param(soundtouchPlaybackStatusActionPlaybackStatusParamTypeId).value().toString();
|
||||||
if (status == "Playing") {
|
if (status == "Playing") {
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PLAY);
|
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PLAY);
|
||||||
|
|
@ -221,15 +228,49 @@ void DevicePluginBose::executeAction(DeviceActionInfo *info)
|
||||||
} else if (status == "Stopped") {
|
} else if (status == "Stopped") {
|
||||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_STOP);
|
soundTouch->setKey(KEY_VALUE::KEY_VALUE_STOP);
|
||||||
}
|
}
|
||||||
info->finish(Device::DeviceErrorNoError);
|
m_pendingActions.insert(requestId, info);
|
||||||
return;
|
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_pendingActions.remove(requestId);});
|
||||||
}
|
|
||||||
|
|
||||||
|
} else {
|
||||||
info->finish(Device::DeviceErrorActionTypeNotFound);
|
info->finish(Device::DeviceErrorActionTypeNotFound);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
info->finish(Device::DeviceErrorDeviceClassNotFound);
|
info->finish(Device::DeviceErrorDeviceClassNotFound);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginBose::browseDevice(BrowseResult *result)
|
||||||
|
{
|
||||||
|
Device *device = result->device();
|
||||||
|
if (device->deviceClassId() == soundtouchDeviceClassId) {
|
||||||
|
SoundTouch *soundTouch = m_soundTouch.value(device);
|
||||||
|
QUuid requestId = soundTouch->getSources();
|
||||||
|
m_asyncBrowseResults.insert(requestId, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginBose::browserItem(BrowserItemResult *result)
|
||||||
|
{
|
||||||
|
Device *device = result->device();
|
||||||
|
if (device->deviceClassId() == soundtouchDeviceClassId) {
|
||||||
|
//SoundTouch *soundTouch = m_soundTouch.value(device);
|
||||||
|
//QUuid requestId = soundTouch->getSources();
|
||||||
|
//m_asyncBrowseResults.insert(requestId, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginBose::executeBrowserItem(BrowserActionInfo *info)
|
||||||
|
{
|
||||||
|
Device *device = info->device();
|
||||||
|
if (device->deviceClassId() == soundtouchDeviceClassId) {
|
||||||
|
SoundTouch *soundTouch = m_soundTouch.value(device);
|
||||||
|
ContentItemObject contentItem;
|
||||||
|
QUuid requestId = soundTouch->setSource(contentItem);
|
||||||
|
m_asyncExecuteBroweItems.insert(requestId, info);
|
||||||
|
connect(info, &BrowserActionInfo::aborted, this, [this, requestId]{m_asyncExecuteBroweItems.remove(requestId);});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DevicePluginBose::onPluginTimer()
|
void DevicePluginBose::onPluginTimer()
|
||||||
{
|
{
|
||||||
|
|
@ -256,15 +297,36 @@ void DevicePluginBose::onDeviceNameChanged()
|
||||||
soundtouch->setName(device->name());
|
soundtouch->setName(device->name());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginBose::onInfoObjectReceived(InfoObject infoObject)
|
void DevicePluginBose::onRequestExecuted(QUuid requestId, bool success)
|
||||||
{
|
{
|
||||||
|
if (m_pendingActions.contains(requestId)) {
|
||||||
|
DeviceActionInfo *info = m_pendingActions.value(requestId);
|
||||||
|
if (success) {
|
||||||
|
info->finish(Device::DeviceErrorNoError);
|
||||||
|
} else {
|
||||||
|
info->finish(Device::DeviceErrorHardwareFailure);
|
||||||
|
}
|
||||||
|
} else if (m_asyncBrowseResults.contains(requestId)) {
|
||||||
|
if (!success) {
|
||||||
|
BrowseResult *result = m_asyncBrowseResults.take(requestId);
|
||||||
|
result->finish(Device::DeviceErrorHardwareFailure);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//This request was not an action or browse request
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevicePluginBose::onInfoObjectReceived(QUuid requestId, InfoObject infoObject)
|
||||||
|
{
|
||||||
|
Q_UNUSED(requestId);
|
||||||
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
||||||
Device *device = m_soundTouch.key(soundtouch);
|
Device *device = m_soundTouch.key(soundtouch);
|
||||||
device->setName(infoObject.name);
|
device->setName(infoObject.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginBose::onNowPlayingObjectReceived(NowPlayingObject nowPlaying)
|
void DevicePluginBose::onNowPlayingObjectReceived(QUuid requestId, NowPlayingObject nowPlaying)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(requestId);
|
||||||
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
||||||
Device *device = m_soundTouch.key(soundtouch);
|
Device *device = m_soundTouch.key(soundtouch);
|
||||||
|
|
||||||
|
|
@ -302,43 +364,56 @@ void DevicePluginBose::onNowPlayingObjectReceived(NowPlayingObject nowPlaying)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginBose::onVolumeObjectReceived(VolumeObject volume)
|
void DevicePluginBose::onVolumeObjectReceived(QUuid requestId, VolumeObject volume)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(requestId);
|
||||||
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
||||||
Device *device = m_soundTouch.key(soundtouch);
|
Device *device = m_soundTouch.key(soundtouch);
|
||||||
device->setStateValue(soundtouchVolumeStateTypeId, volume.actualVolume);
|
device->setStateValue(soundtouchVolumeStateTypeId, volume.actualVolume);
|
||||||
device->setStateValue(soundtouchMuteStateTypeId, volume.muteEnabled);
|
device->setStateValue(soundtouchMuteStateTypeId, volume.muteEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginBose::onSourcesObjectReceived(SourcesObject sources)
|
void DevicePluginBose::onSourcesObjectReceived(QUuid requestId, SourcesObject sources)
|
||||||
{
|
{
|
||||||
|
if (m_asyncBrowseResults.contains(requestId)) {
|
||||||
|
BrowseResult *result = m_asyncBrowseResults.value(requestId);
|
||||||
foreach (SourceItemObject sourceItem, sources.sourceItems) {
|
foreach (SourceItemObject sourceItem, sources.sourceItems) {
|
||||||
qDebug(dcBose()) << "Source:" << sources.deviceId << sourceItem.source << sourceItem.displayName;
|
qDebug(dcBose()) << "Source:" << sources.deviceId << sourceItem.source << sourceItem.displayName;
|
||||||
|
BrowserItem item("sources"+sourceItem.source, sourceItem.displayName, false, true);
|
||||||
|
result->addItem(item);
|
||||||
|
}
|
||||||
|
result->finish(Device::DeviceErrorNoError);
|
||||||
|
} else {
|
||||||
|
qCWarning(dcBose()) << "Received sources without an associated BrowseResult";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginBose::onBassObjectReceived(BassObject bass)
|
void DevicePluginBose::onBassObjectReceived(QUuid requestId, BassObject bass)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(requestId);
|
||||||
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
||||||
Device *device = m_soundTouch.key(soundtouch);
|
Device *device = m_soundTouch.key(soundtouch);
|
||||||
device->setStateValue(soundtouchBassStateTypeId, bass.actualBass);
|
device->setStateValue(soundtouchBassStateTypeId, bass.actualBass);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginBose::onBassCapabilitiesObjectReceived(BassCapabilitiesObject bassCapabilities)
|
void DevicePluginBose::onBassCapabilitiesObjectReceived(QUuid requestId, BassCapabilitiesObject bassCapabilities)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(requestId);
|
||||||
qDebug(dcBose()) << "Bass capabilities (max, min, default):" << bassCapabilities.bassMax << bassCapabilities.bassMin << bassCapabilities.bassDefault;
|
qDebug(dcBose()) << "Bass capabilities (max, min, default):" << bassCapabilities.bassMax << bassCapabilities.bassMin << bassCapabilities.bassDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginBose::onGroupObjectReceived(GroupObject group)
|
void DevicePluginBose::onGroupObjectReceived(QUuid requestId, GroupObject group)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(requestId);
|
||||||
qDebug(dcBose()) << "Group" << group.name << group.status;
|
qDebug(dcBose()) << "Group" << group.name << group.status;
|
||||||
foreach (RolesObject role, group.roles) {
|
foreach (RolesObject role, group.roles) {
|
||||||
qDebug(dcBose()) << "-> member:" << role.groupRole.deviceID;
|
qDebug(dcBose()) << "-> member:" << role.groupRole.deviceID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginBose::onZoneObjectReceived(ZoneObject zone)
|
void DevicePluginBose::onZoneObjectReceived(QUuid requestId, ZoneObject zone)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(requestId);
|
||||||
qDebug(dcBose()) << "Zone master" << zone.deviceID;
|
qDebug(dcBose()) << "Zone master" << zone.deviceID;
|
||||||
foreach (MemberObject member, zone.members) {
|
foreach (MemberObject member, zone.members) {
|
||||||
qDebug(dcBose()) << "-> member:" << member.deviceID;
|
qDebug(dcBose()) << "-> member:" << member.deviceID;
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,30 @@
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* *
|
*
|
||||||
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io *
|
* Copyright 2013 - 2020, nymea GmbH
|
||||||
* *
|
* Contact: contact@nymea.io
|
||||||
* This file is part of nymea. *
|
*
|
||||||
* *
|
* This file is part of nymea.
|
||||||
* This library is free software; you can redistribute it and/or *
|
* This project including source code and documentation is protected by copyright law, and
|
||||||
* modify it under the terms of the GNU Lesser General Public *
|
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||||
* License as published by the Free Software Foundation; either *
|
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||||
* version 2.1 of the License, or (at your option) any later version. *
|
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||||
* *
|
* of use of nymea GmbH, available under https://nymea.io/license
|
||||||
* This library is distributed in the hope that it will be useful, *
|
*
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
* GNU Lesser General Public License Usage
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
|
||||||
* Lesser General Public License for more details. *
|
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||||
* *
|
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||||
* You should have received a copy of the GNU Lesser General Public *
|
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
* License along with this library; If not, see *
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
* <http://www.gnu.org/licenses/>. *
|
* See the GNU Lesser General Public License for more details.
|
||||||
* *
|
*
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||||
|
* If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* For any further details and any questions please contact us under contact@nymea.io
|
||||||
|
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||||
|
*
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
#ifndef DEVICEPLUGINBOSE_H
|
#ifndef DEVICEPLUGINBOSE_H
|
||||||
#define DEVICEPLUGINBOSE_H
|
#define DEVICEPLUGINBOSE_H
|
||||||
|
|
@ -30,6 +36,7 @@
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
class DevicePluginBose : public DevicePlugin
|
class DevicePluginBose : public DevicePlugin
|
||||||
{
|
{
|
||||||
|
|
@ -48,25 +55,32 @@ public:
|
||||||
void deviceRemoved(Device *device) override;
|
void deviceRemoved(Device *device) override;
|
||||||
void executeAction(DeviceActionInfo *info) override;
|
void executeAction(DeviceActionInfo *info) override;
|
||||||
|
|
||||||
|
void browseDevice(BrowseResult *result) override;
|
||||||
|
void browserItem(BrowserItemResult *result) override;
|
||||||
|
void executeBrowserItem(BrowserActionInfo *info) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PluginTimer *m_pluginTimer = nullptr;
|
PluginTimer *m_pluginTimer = nullptr;
|
||||||
|
|
||||||
QHash<Device *, SoundTouch *> m_soundTouch;
|
QHash<Device *, SoundTouch *> m_soundTouch;
|
||||||
QHash<int, ActionId> m_pendingActions;
|
QHash<QUuid, DeviceActionInfo *> m_pendingActions;
|
||||||
|
QHash<QUuid, BrowseResult *> m_asyncBrowseResults;
|
||||||
|
QHash<QUuid, BrowserActionInfo *> m_asyncExecuteBroweItems;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onPluginTimer();
|
void onPluginTimer();
|
||||||
void onConnectionChanged(bool connected);
|
void onConnectionChanged(bool connected);
|
||||||
void onDeviceNameChanged();
|
void onDeviceNameChanged();
|
||||||
|
void onRequestExecuted(QUuid requestId, bool success);
|
||||||
|
|
||||||
void onInfoObjectReceived(InfoObject infoObject);
|
void onInfoObjectReceived(QUuid requestId, InfoObject infoObject);
|
||||||
void onNowPlayingObjectReceived(NowPlayingObject nowPlaying);
|
void onNowPlayingObjectReceived(QUuid requestId, NowPlayingObject nowPlaying);
|
||||||
void onVolumeObjectReceived(VolumeObject volume);
|
void onVolumeObjectReceived(QUuid requestId, VolumeObject volume);
|
||||||
void onSourcesObjectReceived(SourcesObject sources);
|
void onSourcesObjectReceived(QUuid requestId, SourcesObject sources);
|
||||||
void onBassObjectReceived(BassObject bass);
|
void onBassObjectReceived(QUuid requestId, BassObject bass);
|
||||||
void onBassCapabilitiesObjectReceived(BassCapabilitiesObject bassCapabilities);
|
void onBassCapabilitiesObjectReceived(QUuid requestId, BassCapabilitiesObject bassCapabilities);
|
||||||
void onGroupObjectReceived(GroupObject group);
|
void onGroupObjectReceived(QUuid requestId, GroupObject group);
|
||||||
void onZoneObjectReceived(ZoneObject zone);
|
void onZoneObjectReceived(QUuid requestId, ZoneObject zone);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DEVICEPLUGINBOSE_H
|
#endif // DEVICEPLUGINBOSE_H
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
"displayName": "SoundTouch",
|
"displayName": "SoundTouch",
|
||||||
"interfaces": ["extendedvolumecontroller", "mediametadataprovider", "shufflerepeat", "connectable"],
|
"interfaces": ["extendedvolumecontroller", "mediametadataprovider", "shufflerepeat", "connectable"],
|
||||||
"createMethods": ["discovery"],
|
"createMethods": ["discovery"],
|
||||||
|
"browsable": true,
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "1a897065-57c6-49b3-bac9-1e5db27859e5",
|
"id": "1a897065-57c6-49b3-bac9-1e5db27859e5",
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,30 @@
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* *
|
*
|
||||||
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io *
|
* Copyright 2013 - 2020, nymea GmbH
|
||||||
* *
|
* Contact: contact@nymea.io
|
||||||
* This file is part of nymea. *
|
*
|
||||||
* *
|
* This file is part of nymea.
|
||||||
* This library is free software; you can redistribute it and/or *
|
* This project including source code and documentation is protected by copyright law, and
|
||||||
* modify it under the terms of the GNU Lesser General Public *
|
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||||
* License as published by the Free Software Foundation; either *
|
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||||
* version 2.1 of the License, or (at your option) any later version. *
|
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||||
* *
|
* of use of nymea GmbH, available under https://nymea.io/license
|
||||||
* This library is distributed in the hope that it will be useful, *
|
*
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
* GNU Lesser General Public License Usage
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
|
||||||
* Lesser General Public License for more details. *
|
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||||
* *
|
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||||
* You should have received a copy of the GNU Lesser General Public *
|
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
* License along with this library; If not, see *
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
* <http://www.gnu.org/licenses/>. *
|
* See the GNU Lesser General Public License for more details.
|
||||||
* *
|
*
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||||
|
* If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* For any further details and any questions please contact us under contact@nymea.io
|
||||||
|
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||||
|
*
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
#include "soundtouch.h"
|
#include "soundtouch.h"
|
||||||
#include "hardwaremanager.h"
|
#include "hardwaremanager.h"
|
||||||
|
|
@ -30,113 +36,133 @@ SoundTouch::SoundTouch(NetworkAccessManager *networkAccessManager, QString ipAdd
|
||||||
m_networkAccessManager(networkAccessManager),
|
m_networkAccessManager(networkAccessManager),
|
||||||
m_ipAddress(ipAddress)
|
m_ipAddress(ipAddress)
|
||||||
{
|
{
|
||||||
m_websocket = new QWebSocket();
|
//THIS CODE IS LEFT INTENTIONALLY
|
||||||
connect(m_websocket, &QWebSocket::connected, this, &SoundTouch::onWebsocketConnected);
|
//m_websocket = new QWebSocket();
|
||||||
connect(m_websocket, &QWebSocket::disconnected, this, &SoundTouch::onWebsocketDisconnected);
|
//connect(m_websocket, &QWebSocket::connected, this, &SoundTouch::onWebsocketConnected);
|
||||||
connect(m_websocket, &QWebSocket::textMessageReceived, this, &SoundTouch::onWebsocketMessageReceived);
|
//connect(m_websocket, &QWebSocket::disconnected, this, &SoundTouch::onWebsocketDisconnected);
|
||||||
QUrl url;
|
//connect(m_websocket, &QWebSocket::textMessageReceived, this, &SoundTouch::onWebsocketMessageReceived);
|
||||||
url.setHost(m_ipAddress);
|
//QUrl url;
|
||||||
url.setScheme("ws");
|
//url.setHost(m_ipAddress);
|
||||||
url.setPort(8080);
|
//url.setScheme("ws");
|
||||||
qDebug(dcBose) << "Connecting websocket to" << url;
|
//url.setPort(8080);
|
||||||
|
//qDebug(dcBose) << "Connecting websocket to" << url;
|
||||||
//TODO missing websocket subprotocol "gabbo"
|
//TODO missing websocket subprotocol "gabbo"
|
||||||
//Seems QWebsockets doesn't support subprotocols
|
//QWebsockets doesn't support subprotocols
|
||||||
m_websocket->open(url);
|
//m_websocket->open(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::getInfo()
|
QUuid SoundTouch::getInfo()
|
||||||
{
|
{
|
||||||
|
QUuid requestId;
|
||||||
if (!m_getRepliesPending) {
|
if (!m_getRepliesPending) {
|
||||||
sendGetRequest("/info");
|
requestId = sendGetRequest("/info");
|
||||||
} else {
|
} else {
|
||||||
if (!m_getRequestQueue.contains("/info"))
|
if (!m_getRequestQueue.contains("/info"))
|
||||||
m_getRequestQueue.append("/info");
|
m_getRequestQueue.append("/info");
|
||||||
}
|
}
|
||||||
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::getVolume()
|
QUuid SoundTouch::getVolume()
|
||||||
{
|
{
|
||||||
|
QUuid requestId;
|
||||||
if (!m_getRepliesPending) {
|
if (!m_getRepliesPending) {
|
||||||
sendGetRequest("/volume");
|
requestId = sendGetRequest("/volume");
|
||||||
} else {
|
} else {
|
||||||
if (!m_getRequestQueue.contains("/volume"))
|
if (!m_getRequestQueue.contains("/volume"))
|
||||||
m_getRequestQueue.append("/volume");
|
m_getRequestQueue.append("/volume");
|
||||||
}
|
}
|
||||||
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::getNowPlaying()
|
QUuid SoundTouch::getNowPlaying()
|
||||||
{
|
{
|
||||||
|
QUuid requestId;
|
||||||
if (!m_getRepliesPending) {
|
if (!m_getRepliesPending) {
|
||||||
sendGetRequest("/now_playing");
|
requestId = sendGetRequest("/now_playing");
|
||||||
} else {
|
} else {
|
||||||
if (!m_getRequestQueue.contains("/now_playing"))
|
if (!m_getRequestQueue.contains("/now_playing"))
|
||||||
m_getRequestQueue.append("/now_playing");
|
m_getRequestQueue.append("/now_playing");
|
||||||
}
|
}
|
||||||
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::getBass()
|
QUuid SoundTouch::getBass()
|
||||||
{
|
{
|
||||||
|
QUuid requestId;
|
||||||
if (!m_getRepliesPending) {
|
if (!m_getRepliesPending) {
|
||||||
sendGetRequest("/bass");
|
requestId = sendGetRequest("/bass");
|
||||||
} else {
|
} else {
|
||||||
if (!m_getRequestQueue.contains("/bass"))
|
if (!m_getRequestQueue.contains("/bass"))
|
||||||
m_getRequestQueue.append("/bass");
|
m_getRequestQueue.append("/bass");
|
||||||
}
|
}
|
||||||
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::getGroup()
|
QUuid SoundTouch::getGroup()
|
||||||
{
|
{
|
||||||
|
QUuid requestId;
|
||||||
if (!m_getRepliesPending) {
|
if (!m_getRepliesPending) {
|
||||||
sendGetRequest("/getGroup");
|
requestId = sendGetRequest("/getGroup");
|
||||||
} else {
|
} else {
|
||||||
if (!m_getRequestQueue.contains("/getGroup"))
|
if (!m_getRequestQueue.contains("/getGroup"))
|
||||||
m_getRequestQueue.append("/getGroup");
|
m_getRequestQueue.append("/getGroup");
|
||||||
}
|
}
|
||||||
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::getSources()
|
QUuid SoundTouch::getSources()
|
||||||
{
|
{
|
||||||
|
QUuid requestId;
|
||||||
if (!m_getRepliesPending) {
|
if (!m_getRepliesPending) {
|
||||||
sendGetRequest("/sources");
|
requestId = sendGetRequest("/sources");
|
||||||
} else {
|
} else {
|
||||||
if (!m_getRequestQueue.contains("/sources"))
|
if (!m_getRequestQueue.contains("/sources"))
|
||||||
m_getRequestQueue.append("/sources");
|
m_getRequestQueue.append("/sources");
|
||||||
}
|
}
|
||||||
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::getZone()
|
QUuid SoundTouch::getZone()
|
||||||
{
|
{
|
||||||
|
QUuid requestId;
|
||||||
if (!m_getRepliesPending) {
|
if (!m_getRepliesPending) {
|
||||||
sendGetRequest("/getZone");
|
requestId = sendGetRequest("/getZone");
|
||||||
} else {
|
} else {
|
||||||
if (!m_getRequestQueue.contains("/getZone"))
|
if (!m_getRequestQueue.contains("/getZone"))
|
||||||
m_getRequestQueue.append("/getZone");
|
m_getRequestQueue.append("/getZone");
|
||||||
}
|
}
|
||||||
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::getPresets()
|
QUuid SoundTouch::getPresets()
|
||||||
{
|
{
|
||||||
|
QUuid requestId;
|
||||||
if (!m_getRepliesPending) {
|
if (!m_getRepliesPending) {
|
||||||
sendGetRequest("/presets");
|
requestId = sendGetRequest("/presets");
|
||||||
} else {
|
} else {
|
||||||
if (!m_getRequestQueue.contains("/presets"))
|
if (!m_getRequestQueue.contains("/presets"))
|
||||||
m_getRequestQueue.append("/presets");
|
m_getRequestQueue.append("/presets");
|
||||||
}
|
}
|
||||||
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SoundTouch::getBassCapabilities()
|
QUuid SoundTouch::getBassCapabilities()
|
||||||
{
|
{
|
||||||
|
QUuid requestId;
|
||||||
if (!m_getRepliesPending) {
|
if (!m_getRepliesPending) {
|
||||||
sendGetRequest("/bassCapabilities");
|
requestId = sendGetRequest("/bassCapabilities");
|
||||||
} else {
|
} else {
|
||||||
if (!m_getRequestQueue.contains("/bassCapabilities"))
|
if (!m_getRequestQueue.contains("/bassCapabilities"))
|
||||||
m_getRequestQueue.append("/bassCapabilities");
|
m_getRequestQueue.append("/bassCapabilities");
|
||||||
}
|
}
|
||||||
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::setKey(KEY_VALUE keyValue)
|
QUuid SoundTouch::setKey(KEY_VALUE keyValue)
|
||||||
{
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
QUrl url;
|
QUrl url;
|
||||||
url.setHost(m_ipAddress);
|
url.setHost(m_ipAddress);
|
||||||
url.setScheme("http");
|
url.setScheme("http");
|
||||||
|
|
@ -199,13 +225,24 @@ void SoundTouch::setKey(KEY_VALUE keyValue)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qWarning(dcBose) << "key not yet implemented";
|
qWarning(dcBose) << "key not yet implemented";
|
||||||
return;
|
return "0";
|
||||||
}
|
}
|
||||||
xml.writeEndElement(); //key
|
xml.writeEndElement(); //key
|
||||||
xml.writeEndDocument();
|
xml.writeEndDocument();
|
||||||
qDebug(dcBose) << "Sending request" << url << content;
|
//qDebug(dcBose) << "Sending request" << url << content;
|
||||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||||
|
emit requestExecuted(requestId, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO parse error
|
||||||
|
});
|
||||||
|
|
||||||
if (keyValue == KEY_VALUE_POWER) {
|
if (keyValue == KEY_VALUE_POWER) {
|
||||||
QUrl url;
|
QUrl url;
|
||||||
|
|
@ -223,12 +260,14 @@ void SoundTouch::setKey(KEY_VALUE keyValue)
|
||||||
xml.writeEndElement(); //key
|
xml.writeEndElement(); //key
|
||||||
xml.writeEndDocument();
|
xml.writeEndDocument();
|
||||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
connect(reply, &QNetworkReply::finished, this, [reply] {reply->deleteLater();});
|
||||||
}
|
}
|
||||||
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::setVolume(int volume)
|
QUuid SoundTouch::setVolume(int volume)
|
||||||
{
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
QUrl url;
|
QUrl url;
|
||||||
url.setHost(m_ipAddress);
|
url.setHost(m_ipAddress);
|
||||||
url.setScheme("http");
|
url.setScheme("http");
|
||||||
|
|
@ -240,11 +279,24 @@ void SoundTouch::setVolume(int volume)
|
||||||
content.append("</volume>");
|
content.append("</volume>");
|
||||||
//qDebug(dcBose) << "Sending request" << url << content;
|
//qDebug(dcBose) << "Sending request" << url << content;
|
||||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||||
|
emit requestExecuted(requestId, false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::setSource(ContentItemObject contentItem)
|
//TODO parse error
|
||||||
|
});
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid SoundTouch::setSource(ContentItemObject contentItem)
|
||||||
{
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
QUrl url;
|
QUrl url;
|
||||||
url.setHost(m_ipAddress);
|
url.setHost(m_ipAddress);
|
||||||
url.setScheme("http");
|
url.setScheme("http");
|
||||||
|
|
@ -261,11 +313,24 @@ void SoundTouch::setSource(ContentItemObject contentItem)
|
||||||
qDebug(dcBose) << "Sending request" << url << content;
|
qDebug(dcBose) << "Sending request" << url << content;
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||||
|
emit requestExecuted(requestId, false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::setZone(ZoneObject zone)
|
//TODO parse error
|
||||||
|
});
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid SoundTouch::setZone(ZoneObject zone)
|
||||||
{
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
QUrl url;
|
QUrl url;
|
||||||
url.setHost(m_ipAddress);
|
url.setHost(m_ipAddress);
|
||||||
url.setScheme("http");
|
url.setScheme("http");
|
||||||
|
|
@ -284,11 +349,24 @@ void SoundTouch::setZone(ZoneObject zone)
|
||||||
xml.writeEndDocument();
|
xml.writeEndDocument();
|
||||||
qDebug(dcBose) << "Sending request" << url << content;
|
qDebug(dcBose) << "Sending request" << url << content;
|
||||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||||
|
emit requestExecuted(requestId, false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::addZoneSlave(ZoneObject zone)
|
//TODO parse error
|
||||||
|
});
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid SoundTouch::addZoneSlave(ZoneObject zone)
|
||||||
{
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
QUrl url;
|
QUrl url;
|
||||||
url.setHost(m_ipAddress);
|
url.setHost(m_ipAddress);
|
||||||
url.setScheme("http");
|
url.setScheme("http");
|
||||||
|
|
@ -307,11 +385,25 @@ void SoundTouch::addZoneSlave(ZoneObject zone)
|
||||||
xml.writeEndDocument();
|
xml.writeEndDocument();
|
||||||
qDebug(dcBose) << "Sending request" << url << content;
|
qDebug(dcBose) << "Sending request" << url << content;
|
||||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||||
|
emit requestExecuted(requestId, false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::removeZoneSlave(ZoneObject zone)
|
//TODO parse error
|
||||||
|
});
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid SoundTouch::removeZoneSlave(ZoneObject zone)
|
||||||
{
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
QUrl url;
|
QUrl url;
|
||||||
url.setHost(m_ipAddress);
|
url.setHost(m_ipAddress);
|
||||||
url.setScheme("http");
|
url.setScheme("http");
|
||||||
|
|
@ -330,11 +422,24 @@ void SoundTouch::removeZoneSlave(ZoneObject zone)
|
||||||
xml.writeEndDocument();
|
xml.writeEndDocument();
|
||||||
qDebug(dcBose) << "Sending request" << url << content;
|
qDebug(dcBose) << "Sending request" << url << content;
|
||||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||||
|
emit requestExecuted(requestId, false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::setBass(int volume)
|
//TODO parse error
|
||||||
|
});
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid SoundTouch::setBass(int volume)
|
||||||
{
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
QUrl url;
|
QUrl url;
|
||||||
url.setHost(m_ipAddress);
|
url.setHost(m_ipAddress);
|
||||||
url.setScheme("http");
|
url.setScheme("http");
|
||||||
|
|
@ -346,11 +451,24 @@ void SoundTouch::setBass(int volume)
|
||||||
content.append("</bass>");
|
content.append("</bass>");
|
||||||
qDebug(dcBose) << "Sending request" << url << content;
|
qDebug(dcBose) << "Sending request" << url << content;
|
||||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||||
|
emit requestExecuted(requestId, false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::setName(QString name)
|
//TODO parse error
|
||||||
|
});
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid SoundTouch::setName(QString name)
|
||||||
{
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
QUrl url;
|
QUrl url;
|
||||||
url.setHost(m_ipAddress);
|
url.setHost(m_ipAddress);
|
||||||
url.setScheme("http");
|
url.setScheme("http");
|
||||||
|
|
@ -362,11 +480,24 @@ void SoundTouch::setName(QString name)
|
||||||
content.append("</name>");
|
content.append("</name>");
|
||||||
qDebug(dcBose) << "Sending request" << url << content;
|
qDebug(dcBose) << "Sending request" << url << content;
|
||||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||||
|
reply->deleteLater();
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
// Check HTTP status code
|
||||||
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||||
|
emit requestExecuted(requestId, false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::setSpeaker(PlayInfoObject playInfo)
|
//TODO parse error
|
||||||
|
});
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid SoundTouch::setSpeaker(PlayInfoObject playInfo)
|
||||||
{
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
QUrl url;
|
QUrl url;
|
||||||
url.setHost(m_ipAddress);
|
url.setHost(m_ipAddress);
|
||||||
url.setScheme("http");
|
url.setScheme("http");
|
||||||
|
|
@ -386,7 +517,10 @@ void SoundTouch::setSpeaker(PlayInfoObject playInfo)
|
||||||
xml.writeEndDocument();
|
xml.writeEndDocument();
|
||||||
qDebug(dcBose) << "Sending request" << url << content;
|
qDebug(dcBose) << "Sending request" << url << content;
|
||||||
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
QNetworkReply *reply = m_networkAccessManager->post(QNetworkRequest(url), content);
|
||||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||||
|
|
||||||
|
});
|
||||||
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::onWebsocketConnected()
|
void SoundTouch::onWebsocketConnected()
|
||||||
|
|
@ -408,11 +542,36 @@ void SoundTouch::onWebsocketDisconnected()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::onRestRequestFinished() {
|
void SoundTouch::onRestRequestError(QNetworkReply::NetworkError error)
|
||||||
|
{
|
||||||
|
Q_UNUSED(error)
|
||||||
|
|
||||||
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
|
||||||
|
qWarning(dcBose) << "Rest Error" << reply->errorString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundTouch::onWebsocketMessageReceived(QString message)
|
||||||
|
{
|
||||||
|
qDebug(dcBose) << "Websocket message received:" << message;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUuid SoundTouch::sendGetRequest(QString path)
|
||||||
|
{
|
||||||
|
QUuid requestId = QUuid::createUuid();
|
||||||
|
QUrl url;
|
||||||
|
url.setHost(m_ipAddress);
|
||||||
|
url.setScheme("http");
|
||||||
|
url.setPort(m_port);
|
||||||
|
url.setPath(path);
|
||||||
|
//qDebug(dcBose) << "Sending request" << url;
|
||||||
|
QNetworkRequest request = QNetworkRequest(url);
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkAccessManager->get(request);
|
||||||
|
m_getRepliesPending = true;
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||||
|
reply->deleteLater();
|
||||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
if (m_getRequestQueue.isEmpty()) {
|
if (m_getRequestQueue.isEmpty()) {
|
||||||
|
|
@ -424,12 +583,55 @@ void SoundTouch::onRestRequestFinished() {
|
||||||
// Check HTTP status code
|
// Check HTTP status code
|
||||||
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
if (status != 200 || reply->error() != QNetworkReply::NoError) {
|
||||||
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
qCWarning(dcBose()) << "Request error:" << reply->errorString() << "request:" << reply->url().path();
|
||||||
|
emit requestExecuted(requestId, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
emit requestExecuted(requestId, true);
|
||||||
QByteArray data = reply->readAll();
|
QByteArray data = reply->readAll();
|
||||||
//qDebug(dcBose) << data;
|
parseData(requestId, data);
|
||||||
|
});
|
||||||
|
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRestRequestError(QNetworkReply::NetworkError)));
|
||||||
|
return requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundTouch::emitRequestStatus(QUuid requestId, const QByteArray &data)
|
||||||
|
{
|
||||||
|
QXmlStreamReader xml;
|
||||||
|
xml.addData(data);
|
||||||
|
|
||||||
|
if (xml.readNextStartElement()) {
|
||||||
|
if (xml.name() == "status") {
|
||||||
|
//QString status = xml.readElementText();
|
||||||
|
emit requestExecuted(requestId, true);
|
||||||
|
} else if (xml.name() == "errors") {
|
||||||
|
emit requestExecuted(requestId, false);
|
||||||
|
QString deviceId;
|
||||||
|
if(xml.attributes().hasAttribute("deviceID")) {
|
||||||
|
deviceId = xml.attributes().value("deviceID").toString();
|
||||||
|
}
|
||||||
|
while(xml.readNextStartElement()){
|
||||||
|
if(xml.name() == "error"){
|
||||||
|
ErrorObject error;
|
||||||
|
error.deviceId = deviceId;
|
||||||
|
error.error = xml.readElementText();
|
||||||
|
if(xml.attributes().hasAttribute("value")) {
|
||||||
|
error.value = xml.attributes().value("value").toInt();
|
||||||
|
}
|
||||||
|
if(xml.attributes().hasAttribute("name")) {
|
||||||
|
error.name = xml.attributes().value("name").toString();
|
||||||
|
}
|
||||||
|
if(xml.attributes().hasAttribute("severity")) {
|
||||||
|
error.severity = xml.attributes().value("severity").toString();
|
||||||
|
}
|
||||||
|
emit errorReceived(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundTouch::parseData(QUuid requestId, const QByteArray &data)
|
||||||
|
{
|
||||||
QXmlStreamReader xml;
|
QXmlStreamReader xml;
|
||||||
xml.addData(data);
|
xml.addData(data);
|
||||||
|
|
||||||
|
|
@ -482,7 +684,7 @@ void SoundTouch::onRestRequestFinished() {
|
||||||
xml.skipCurrentElement();
|
xml.skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit infoReceived(info);
|
emit infoReceived(requestId, info);
|
||||||
} else if (xml.name() == "nowPlaying") {
|
} else if (xml.name() == "nowPlaying") {
|
||||||
NowPlayingObject nowPlaying;
|
NowPlayingObject nowPlaying;
|
||||||
if(xml.attributes().hasAttribute("deviceID")) {
|
if(xml.attributes().hasAttribute("deviceID")) {
|
||||||
|
|
@ -585,7 +787,7 @@ void SoundTouch::onRestRequestFinished() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emit nowPlayingReceived(nowPlaying);
|
emit nowPlayingReceived(requestId, nowPlaying);
|
||||||
} else if (xml.name() == "volume") {
|
} else if (xml.name() == "volume") {
|
||||||
VolumeObject volumeObject;
|
VolumeObject volumeObject;
|
||||||
if(xml.attributes().hasAttribute("deviceID")) {
|
if(xml.attributes().hasAttribute("deviceID")) {
|
||||||
|
|
@ -606,7 +808,7 @@ void SoundTouch::onRestRequestFinished() {
|
||||||
xml.skipCurrentElement();
|
xml.skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit volumeReceived(volumeObject);
|
emit volumeReceived(requestId, volumeObject);
|
||||||
} else if (xml.name() == "sources") {
|
} else if (xml.name() == "sources") {
|
||||||
SourcesObject sourcesObject;
|
SourcesObject sourcesObject;
|
||||||
if(xml.attributes().hasAttribute("deviceID")) {
|
if(xml.attributes().hasAttribute("deviceID")) {
|
||||||
|
|
@ -643,7 +845,7 @@ void SoundTouch::onRestRequestFinished() {
|
||||||
xml.skipCurrentElement();
|
xml.skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit sourcesReceived(sourcesObject);
|
emit sourcesReceived(requestId, sourcesObject);
|
||||||
} else if (xml.name() == "bass") {
|
} else if (xml.name() == "bass") {
|
||||||
BassObject bassObject;
|
BassObject bassObject;
|
||||||
if(xml.attributes().hasAttribute("deviceID")) {
|
if(xml.attributes().hasAttribute("deviceID")) {
|
||||||
|
|
@ -661,7 +863,7 @@ void SoundTouch::onRestRequestFinished() {
|
||||||
xml.skipCurrentElement();
|
xml.skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit bassReceived(bassObject);
|
emit bassReceived(requestId, bassObject);
|
||||||
} else if (xml.name() == "bassCapabilities") {
|
} else if (xml.name() == "bassCapabilities") {
|
||||||
BassCapabilitiesObject bassCapabilities;
|
BassCapabilitiesObject bassCapabilities;
|
||||||
|
|
||||||
|
|
@ -686,7 +888,7 @@ void SoundTouch::onRestRequestFinished() {
|
||||||
xml.skipCurrentElement();
|
xml.skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit bassCapabilitiesReceived(bassCapabilities);
|
emit bassCapabilitiesReceived(requestId, bassCapabilities);
|
||||||
} else if (xml.name() == "presets") {
|
} else if (xml.name() == "presets") {
|
||||||
PresetObject preset;
|
PresetObject preset;
|
||||||
if(xml.attributes().hasAttribute("id")) {
|
if(xml.attributes().hasAttribute("id")) {
|
||||||
|
|
@ -713,7 +915,7 @@ void SoundTouch::onRestRequestFinished() {
|
||||||
xml.skipCurrentElement();
|
xml.skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit presetsReceived(preset);
|
emit presetsReceived(requestId, preset);
|
||||||
|
|
||||||
} else if (xml.name() == "group") {
|
} else if (xml.name() == "group") {
|
||||||
GroupObject group;
|
GroupObject group;
|
||||||
|
|
@ -735,7 +937,7 @@ void SoundTouch::onRestRequestFinished() {
|
||||||
xml.skipCurrentElement();
|
xml.skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit groupReceived(group);
|
emit groupReceived(requestId, group);
|
||||||
} else if (xml.name() == "zone") {
|
} else if (xml.name() == "zone") {
|
||||||
ZoneObject zone;
|
ZoneObject zone;
|
||||||
if(xml.attributes().hasAttribute("master")) {
|
if(xml.attributes().hasAttribute("master")) {
|
||||||
|
|
@ -753,43 +955,10 @@ void SoundTouch::onRestRequestFinished() {
|
||||||
}
|
}
|
||||||
zone.members.append(member);
|
zone.members.append(member);
|
||||||
}
|
}
|
||||||
emit zoneReceived(zone);
|
emit zoneReceived(requestId, zone);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
xml.skipCurrentElement();
|
xml.skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundTouch::onRestRequestError(QNetworkReply::NetworkError error)
|
|
||||||
{
|
|
||||||
Q_UNUSED(error)
|
|
||||||
|
|
||||||
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
|
||||||
reply->deleteLater();
|
|
||||||
|
|
||||||
qWarning(dcBose) << "Rest Error" << reply->errorString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SoundTouch::onWebsocketMessageReceived(QString message)
|
|
||||||
{
|
|
||||||
qDebug(dcBose) << "Websocket message received:" << message;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundTouch::sendGetRequest(QString path)
|
|
||||||
{
|
|
||||||
QUrl url;
|
|
||||||
url.setHost(m_ipAddress);
|
|
||||||
url.setScheme("http");
|
|
||||||
url.setPort(m_port);
|
|
||||||
url.setPath(path);
|
|
||||||
//qDebug(dcBose) << "Sending request" << url;
|
|
||||||
QNetworkRequest request = QNetworkRequest(url);
|
|
||||||
|
|
||||||
QNetworkReply *reply = m_networkAccessManager->get(request);
|
|
||||||
m_getRepliesPending = true;
|
|
||||||
connect(reply, &QNetworkReply::finished, this, &SoundTouch::onRestRequestFinished);
|
|
||||||
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRestRequestError(QNetworkReply::NetworkError)));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,30 @@
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* *
|
*
|
||||||
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io *
|
* Copyright 2013 - 2020, nymea GmbH
|
||||||
* *
|
* Contact: contact@nymea.io
|
||||||
* This file is part of nymea. *
|
*
|
||||||
* *
|
* This file is part of nymea.
|
||||||
* This library is free software; you can redistribute it and/or *
|
* This project including source code and documentation is protected by copyright law, and
|
||||||
* modify it under the terms of the GNU Lesser General Public *
|
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||||
* License as published by the Free Software Foundation; either *
|
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||||
* version 2.1 of the License, or (at your option) any later version. *
|
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||||
* *
|
* of use of nymea GmbH, available under https://nymea.io/license
|
||||||
* This library is distributed in the hope that it will be useful, *
|
*
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
* GNU Lesser General Public License Usage
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
|
||||||
* Lesser General Public License for more details. *
|
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||||
* *
|
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||||
* You should have received a copy of the GNU Lesser General Public *
|
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
* License along with this library; If not, see *
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
* <http://www.gnu.org/licenses/>. *
|
* See the GNU Lesser General Public License for more details.
|
||||||
* *
|
*
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||||
|
* If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* For any further details and any questions please contact us under contact@nymea.io
|
||||||
|
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||||
|
*
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
#ifndef SOUNDTOUCH_H
|
#ifndef SOUNDTOUCH_H
|
||||||
#define SOUNDTOUCH_H
|
#define SOUNDTOUCH_H
|
||||||
|
|
@ -26,6 +32,7 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
#include <QtWebSockets/QtWebSockets>
|
#include <QtWebSockets/QtWebSockets>
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
#include "extern-plugininfo.h"
|
#include "extern-plugininfo.h"
|
||||||
#include "soundtouchtypes.h"
|
#include "soundtouchtypes.h"
|
||||||
|
|
@ -40,37 +47,32 @@ class SoundTouch : public QObject
|
||||||
public:
|
public:
|
||||||
explicit SoundTouch(NetworkAccessManager *networkAccessManager, QString ipAddress, QObject *parent = nullptr);
|
explicit SoundTouch(NetworkAccessManager *networkAccessManager, QString ipAddress, QObject *parent = nullptr);
|
||||||
|
|
||||||
void getInfo(); //Get basic information about a product.
|
QUuid getInfo(); //Get basic information about a product.
|
||||||
void getVolume(); //Get the current volume and mute status of a product.
|
QUuid getVolume(); //Get the current volume and mute status of a product.
|
||||||
void getNowPlaying(); //Get information about what's playing on a product.
|
QUuid getNowPlaying(); //Get information about what's playing on a product.
|
||||||
void getBass(); //Get the bass level of a product, if supported.
|
QUuid getBass(); //Get the bass level of a product, if supported.
|
||||||
void getGroup(); //Get the current left/right stereo pair configuration of a product.
|
QUuid getGroup(); //Get the current left/right stereo pair configuration of a product.
|
||||||
void getSources(); //Get available sources for a product.
|
QUuid getZone(); //Get the current multiroom zone state of a product.
|
||||||
void getZone(); //Get the current multiroom zone state of a product.
|
QUuid getBassCapabilities(); //Get whether a product supports reducing bass.
|
||||||
void getPresets(); //Get information related to the user's SoundTouch presets.
|
QUuid getSources(); //Get available sources for a product.
|
||||||
void getBassCapabilities(); //Get whether a product supports reducing bass.
|
QUuid getPresets(); //Get information related to the user's SoundTouch presets.
|
||||||
|
|
||||||
void setKey(KEY_VALUE keyValue); //Start and control playback on a product.
|
|
||||||
void setVolume(int volume); //Set the volume of a product.
|
|
||||||
void setSource(ContentItemObject contentItem); //Select a product's source.
|
|
||||||
void setZone(ZoneObject zone); //Create a zone of synced products.
|
|
||||||
void addZoneSlave(ZoneObject zone); //Add one or more slave product(s) to a multiroom zone.
|
|
||||||
void removeZoneSlave(ZoneObject zone); //Remove one or more slave product(s) from a multiroom zone.
|
|
||||||
void setBass(int volume); //Set the bass level of a product, if supported.*/
|
|
||||||
void setName(QString name); //Set the products user-facing name.
|
|
||||||
void setSpeaker(PlayInfoObject playInfo); //initiate playback of a specified network-accessible audio file on a Bose SoundTouch product.
|
|
||||||
|
|
||||||
|
//ACTIONS
|
||||||
|
QUuid setKey(KEY_VALUE keyValue); //Start and control playback on a product.
|
||||||
|
QUuid setVolume(int volume); //Set the volume of a product.
|
||||||
|
QUuid setSource(ContentItemObject contentItem); //Select a product's source.
|
||||||
|
QUuid setZone(ZoneObject zone); //Create a zone of synced products.
|
||||||
|
QUuid addZoneSlave(ZoneObject zone); //Add one or more slave product(s) to a multiroom zone.
|
||||||
|
QUuid removeZoneSlave(ZoneObject zone); //Remove one or more slave product(s) from a multiroom zone.
|
||||||
|
QUuid setBass(int volume); //Set the bass level of a product, if supported.*/
|
||||||
|
QUuid setName(QString name); //Set the products user-facing name.
|
||||||
|
QUuid setSpeaker(PlayInfoObject playInfo); //initiate playback of a specified network-accessible audio file on a Bose SoundTouch product.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum RequestType {
|
QUuid sendGetRequest(QString path);
|
||||||
Get,
|
//Get calls are getting queued to don't overstrain the device
|
||||||
Post
|
//Post calls must be sent immediately
|
||||||
};
|
//If an get call of the same URL is already in the queu the new one will be ignored
|
||||||
|
|
||||||
void sendGetRequest(QString path);
|
|
||||||
//get calls are getting queued to don't overstrain the device
|
|
||||||
//post calls must get sent immediately
|
|
||||||
//if an get call of the same URL is already in the queu the new one will be ignored
|
|
||||||
QList<QString> m_getRequestQueue;
|
QList<QString> m_getRequestQueue;
|
||||||
bool m_getRepliesPending = false;
|
bool m_getRepliesPending = false;
|
||||||
|
|
||||||
|
|
@ -78,26 +80,29 @@ private:
|
||||||
QString m_ipAddress;
|
QString m_ipAddress;
|
||||||
int m_port = 8090;
|
int m_port = 8090;
|
||||||
QWebSocket *m_websocket = nullptr;
|
QWebSocket *m_websocket = nullptr;
|
||||||
|
void emitRequestStatus(QUuid requestId, const QByteArray &data); //returns the status, -1 in case of error
|
||||||
|
void parseData(QUuid requestId, const QByteArray &data);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void connectionChanged(bool connected);
|
void connectionChanged(bool connected);
|
||||||
|
|
||||||
void infoReceived(InfoObject info);
|
void infoReceived(QUuid requestId, InfoObject info);
|
||||||
void nowPlayingReceived(NowPlayingObject nowPlaying);
|
void nowPlayingReceived(QUuid requestId, NowPlayingObject nowPlaying);
|
||||||
void volumeReceived(VolumeObject volume);
|
void volumeReceived(QUuid requestId, VolumeObject volume);
|
||||||
void sourcesReceived(SourcesObject sources);
|
void sourcesReceived(QUuid requestId, SourcesObject sources);
|
||||||
void zoneReceived(ZoneObject);
|
void zoneReceived(QUuid requestId, ZoneObject);
|
||||||
void bassCapabilitiesReceived(BassCapabilitiesObject bassCapabilities);
|
void bassCapabilitiesReceived(QUuid requestId, BassCapabilitiesObject bassCapabilities);
|
||||||
void bassReceived(BassObject bass);
|
void bassReceived(QUuid requestId, BassObject bass);
|
||||||
void presetsReceived(PresetObject presets);
|
void presetsReceived(QUuid requestId, PresetObject presets);
|
||||||
void groupReceived(GroupObject group);
|
void groupReceived(QUuid requestId, GroupObject group);
|
||||||
|
|
||||||
|
void requestExecuted(QUuid requestId, bool success);
|
||||||
|
void errorReceived(ErrorObject error);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onWebsocketConnected();
|
void onWebsocketConnected();
|
||||||
void onWebsocketDisconnected();
|
void onWebsocketDisconnected();
|
||||||
void onWebsocketMessageReceived(QString message);
|
void onWebsocketMessageReceived(QString message);
|
||||||
void onRestRequestFinished();
|
|
||||||
void onRestRequestError(QNetworkReply::NetworkError error);
|
void onRestRequestError(QNetworkReply::NetworkError error);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,30 @@
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* *
|
*
|
||||||
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io *
|
* Copyright 2013 - 2020, nymea GmbH
|
||||||
* *
|
* Contact: contact@nymea.io
|
||||||
* This file is part of nymea. *
|
*
|
||||||
* *
|
* This file is part of nymea.
|
||||||
* This library is free software; you can redistribute it and/or *
|
* This project including source code and documentation is protected by copyright law, and
|
||||||
* modify it under the terms of the GNU Lesser General Public *
|
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||||||
* License as published by the Free Software Foundation; either *
|
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||||||
* version 2.1 of the License, or (at your option) any later version. *
|
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||||||
* *
|
* of use of nymea GmbH, available under https://nymea.io/license
|
||||||
* This library is distributed in the hope that it will be useful, *
|
*
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
* GNU Lesser General Public License Usage
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
|
||||||
* Lesser General Public License for more details. *
|
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
|
||||||
* *
|
* Lesser General Public License as published by the Free Software Foundation; version 3.
|
||||||
* You should have received a copy of the GNU Lesser General Public *
|
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
* License along with this library; If not, see *
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
* <http://www.gnu.org/licenses/>. *
|
* See the GNU Lesser General Public License for more details.
|
||||||
* *
|
*
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* You should have received a copy of the GNU Lesser General Public License along with this project.
|
||||||
|
* If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* For any further details and any questions please contact us under contact@nymea.io
|
||||||
|
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||||||
|
*
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
#ifndef SOUNDTOUCHTYPES_H
|
#ifndef SOUNDTOUCHTYPES_H
|
||||||
#define SOUNDTOUCHTYPES_H
|
#define SOUNDTOUCHTYPES_H
|
||||||
|
|
@ -246,5 +252,14 @@ struct PlayInfoObject {
|
||||||
QString message; //Element. This indicates further details about the notification. This text will appear on the device display (when available) and the SoundTouch application screen. If a message string is not provided, the field with be blank.
|
QString message; //Element. This indicates further details about the notification. This text will appear on the device display (when available) and the SoundTouch application screen. If a message string is not provided, the field with be blank.
|
||||||
int volume; //Element. This indicates the desired volume level while playing the notification. The value represents a percentage (0 to 100) of the full audible range of the speaker device. A value less than 10 or greater than 70 will result in an error and not play the notification. Upon completion of the notification, the speaker volume will return to its original value. If not present, the notification will play at the existing volume level.
|
int volume; //Element. This indicates the desired volume level while playing the notification. The value represents a percentage (0 to 100) of the full audible range of the speaker device. A value less than 10 or greater than 70 will result in an error and not play the notification. Upon completion of the notification, the speaker volume will return to its original value. If not present, the notification will play at the existing volume level.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ErrorObject{
|
||||||
|
QString deviceId;
|
||||||
|
int value;
|
||||||
|
QString name;
|
||||||
|
QString severity;
|
||||||
|
QString error;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // SOUNDTOUCHTYPES_H
|
#endif // SOUNDTOUCHTYPES_H
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue