added missing files
parent
73caf35616
commit
5498905a49
|
|
@ -0,0 +1,16 @@
|
|||
include(../plugins.pri)
|
||||
|
||||
QT += \
|
||||
network \
|
||||
websockets \
|
||||
|
||||
TARGET = $$qtLibraryTarget(nymea_devicepluginbose)
|
||||
|
||||
SOURCES += \
|
||||
devicepluginbose.cpp \
|
||||
soundtouch.cpp
|
||||
|
||||
HEADERS += \
|
||||
devicepluginbose.h \
|
||||
soundtouch.h \
|
||||
soundtouchtypes.h
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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 library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "devicepluginbose.h"
|
||||
#include "devices/device.h"
|
||||
#include "plugininfo.h"
|
||||
#include "platform/platformzeroconfcontroller.h"
|
||||
#include "network/zeroconf/zeroconfservicebrowser.h"
|
||||
#include "network/zeroconf/zeroconfserviceentry.h"
|
||||
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
|
||||
DevicePluginBose::DevicePluginBose()
|
||||
{
|
||||
}
|
||||
|
||||
DevicePluginBose::~DevicePluginBose()
|
||||
{
|
||||
}
|
||||
|
||||
void DevicePluginBose::init()
|
||||
{
|
||||
}
|
||||
|
||||
Device::DeviceSetupStatus DevicePluginBose::setupDevice(Device *device)
|
||||
{
|
||||
if (!m_pluginTimer) {
|
||||
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(2);
|
||||
connect(m_pluginTimer, &PluginTimer::timeout, this, &DevicePluginBose::onPluginTimer);
|
||||
}
|
||||
|
||||
if (device->deviceClassId() == soundtouchDeviceClassId) {
|
||||
|
||||
connect(device, &Device::nameChanged, this, &DevicePluginBose::onDeviceNameChanged);
|
||||
|
||||
QString ipAddress = device->paramValue(soundtouchDeviceIpParamTypeId).toString();
|
||||
SoundTouch *soundTouch = new SoundTouch(hardwareManager()->networkManager(), ipAddress, this);
|
||||
connect(soundTouch, &SoundTouch::connectionChanged, this, &DevicePluginBose::onConnectionChanged);
|
||||
|
||||
connect(soundTouch, &SoundTouch::infoReceived, this, &DevicePluginBose::onInfoObjectReceived);
|
||||
connect(soundTouch, &SoundTouch::nowPlayingReceived, this, &DevicePluginBose::onNowPlayingObjectReceived);
|
||||
connect(soundTouch, &SoundTouch::volumeReceived, this, &DevicePluginBose::onVolumeObjectReceived);
|
||||
connect(soundTouch, &SoundTouch::sourcesReceived, this, &DevicePluginBose::onSourcesObjectReceived);
|
||||
|
||||
soundTouch->getInfo();
|
||||
soundTouch->getNowPlaying();
|
||||
soundTouch->getVolume();
|
||||
soundTouch->getSources();
|
||||
|
||||
m_soundTouch.insert(device, soundTouch);
|
||||
|
||||
return Device::DeviceSetupStatusSuccess;
|
||||
}
|
||||
return Device::DeviceSetupStatusFailure;
|
||||
}
|
||||
|
||||
void DevicePluginBose::deviceRemoved(Device *device)
|
||||
{
|
||||
if (device->deviceClassId() == soundtouchDeviceClassId) {
|
||||
SoundTouch *soundTouch = m_soundTouch.value(device);
|
||||
soundTouch->deleteLater();
|
||||
}
|
||||
|
||||
if (m_pluginTimer && myDevices().isEmpty()) {
|
||||
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
|
||||
}
|
||||
}
|
||||
|
||||
Device::DeviceError DevicePluginBose::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms)
|
||||
{
|
||||
Q_UNUSED(params)
|
||||
Q_UNUSED(deviceClassId)
|
||||
|
||||
ZeroConfServiceBrowser *serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_soundtouch._tcp");
|
||||
QTimer::singleShot(5000, this, [this, serviceBrowser](){
|
||||
QList<DeviceDescriptor> descriptors;
|
||||
foreach (const ZeroConfServiceEntry avahiEntry, serviceBrowser->serviceEntries()) {
|
||||
qCDebug(dcBose) << "Zeroconf entry:" << avahiEntry;
|
||||
|
||||
QString playerId = avahiEntry.hostName().split(".").first();
|
||||
DeviceDescriptor descriptor(soundtouchDeviceClassId, avahiEntry.name(), avahiEntry.hostAddress().toString());
|
||||
ParamList params;
|
||||
params << Param(soundtouchDeviceIpParamTypeId, avahiEntry.hostAddress().toString());
|
||||
params << Param(soundtouchDevicePlayerIdParamTypeId, playerId);
|
||||
descriptor.setParams(params);
|
||||
descriptors << descriptor;
|
||||
}
|
||||
emit devicesDiscovered(soundtouchDeviceClassId, descriptors);
|
||||
serviceBrowser->deleteLater();
|
||||
});
|
||||
|
||||
return Device::DeviceErrorAsync;
|
||||
}
|
||||
|
||||
Device::DeviceError DevicePluginBose::executeAction(Device *device, const Action &action)
|
||||
{
|
||||
if (device->deviceClassId() == soundtouchDeviceClassId) {
|
||||
SoundTouch *soundTouch = m_soundTouch.value(device);
|
||||
|
||||
if (action.actionTypeId() == soundtouchPowerActionTypeId) {
|
||||
//bool power = action.param(soundtouchPowerActionPowerParamTypeId).value().toBool();
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_POWER); //only toggling possible
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
if (action.actionTypeId() == soundtouchMuteActionTypeId) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_MUTE);
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
if (action.actionTypeId() == soundtouchPlayActionTypeId) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PLAY);
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
if (action.actionTypeId() == soundtouchPauseActionTypeId) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PAUSE);
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
if (action.actionTypeId() == soundtouchStopActionTypeId) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_STOP);
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
if (action.actionTypeId() == soundtouchSkipNextActionTypeId) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_NEXT_TRACK);
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
if (action.actionTypeId() == soundtouchSkipBackActionTypeId) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PREV_TRACK);
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
|
||||
if (action.actionTypeId() == soundtouchShuffleActionTypeId) {
|
||||
|
||||
bool shuffle = action.param(soundtouchShuffleActionShuffleParamTypeId).value().toBool();
|
||||
if (shuffle) {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_SHUFFLE_ON);
|
||||
} else {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_SHUFFLE_OFF);
|
||||
}
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
|
||||
if (action.actionTypeId() == soundtouchRepeatActionTypeId) {
|
||||
|
||||
QString repeat = action.param(soundtouchRepeatActionRepeatParamTypeId).value().toString();
|
||||
if (repeat == "None") {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_OFF);
|
||||
} else if (repeat == "One") {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_ONE);
|
||||
} else if (repeat == "All") {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_REPEAT_ALL);
|
||||
}
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
|
||||
if (action.actionTypeId() == soundtouchVolumeActionTypeId) {
|
||||
int volume = action.param(soundtouchVolumeActionVolumeParamTypeId).value().toInt();
|
||||
soundTouch->setVolume(volume);
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
|
||||
if (action.actionTypeId() == soundtouchPlaybackStatusActionTypeId) {
|
||||
QString status = action.param(soundtouchPlaybackStatusActionPlaybackStatusParamTypeId).value().toString();
|
||||
if (status == "Playing") {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PLAY);
|
||||
} else if (status == "Paused") {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_PAUSE);
|
||||
} else if (status == "Stopped") {
|
||||
soundTouch->setKey(KEY_VALUE::KEY_VALUE_STOP);
|
||||
}
|
||||
return Device::DeviceErrorNoError;
|
||||
}
|
||||
|
||||
return Device::DeviceErrorActionTypeNotFound;
|
||||
}
|
||||
return Device::DeviceErrorDeviceClassNotFound;
|
||||
}
|
||||
|
||||
void DevicePluginBose::onPluginTimer()
|
||||
{
|
||||
foreach(SoundTouch *soundTouch, m_soundTouch.values()) {
|
||||
soundTouch->getInfo();
|
||||
soundTouch->getNowPlaying();
|
||||
soundTouch->getVolume();
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginBose::onConnectionChanged(bool connected)
|
||||
{
|
||||
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
||||
Device *device = m_soundTouch.key(soundtouch);
|
||||
device->setStateValue(soundtouchConnectedStateTypeId, connected);
|
||||
}
|
||||
|
||||
void DevicePluginBose::onDeviceNameChanged()
|
||||
{
|
||||
Device *device = static_cast<Device*>(sender());
|
||||
SoundTouch *soundtouch = m_soundTouch.value(device);
|
||||
soundtouch->setName(device->name());
|
||||
}
|
||||
|
||||
void DevicePluginBose::onInfoObjectReceived(InfoObject infoObject)
|
||||
{
|
||||
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
||||
Device *device = m_soundTouch.key(soundtouch);
|
||||
device->setName(infoObject.name);
|
||||
}
|
||||
|
||||
void DevicePluginBose::onNowPlayingObjectReceived(NowPlayingObject nowPlaying)
|
||||
{
|
||||
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
||||
Device *device = m_soundTouch.key(soundtouch);
|
||||
|
||||
device->setStateValue(soundtouchTitleStateTypeId, nowPlaying.track);
|
||||
device->setStateValue(soundtouchArtistStateTypeId, nowPlaying.artist);
|
||||
device->setStateValue(soundtouchCollectionStateTypeId, nowPlaying.album);
|
||||
device->setStateValue(soundtouchArtworkStateTypeId, nowPlaying.art.url);
|
||||
device->setStateValue(soundtouchShuffleStateTypeId, ( nowPlaying.shuffleSetting == SHUFFLE_STATUS_SHUFFLE_ON ));
|
||||
|
||||
switch (nowPlaying.repeatSettings) {
|
||||
case REPEAT_STATUS_REPEAT_ONE:
|
||||
device->setStateValue(soundtouchRepeatStateTypeId, "One");
|
||||
break;
|
||||
case REPEAT_STATUS_REPEAT_ALL:
|
||||
device->setStateValue(soundtouchRepeatStateTypeId, "All");
|
||||
break;
|
||||
case REPEAT_STATUS_REPEAT_OFF:
|
||||
device->setStateValue(soundtouchRepeatStateTypeId, "None");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (nowPlaying.playStatus) {
|
||||
case PLAY_STATUS_PLAY_STATE:
|
||||
device->setStateValue(soundtouchPlaybackStatusStateTypeId, "Playing");
|
||||
break;
|
||||
case PLAY_STATUS_PAUSE_STATE:
|
||||
case PLAY_STATUS_BUFFERING_STATE:
|
||||
device->setStateValue(soundtouchPlaybackStatusStateTypeId, "Paused");
|
||||
break;
|
||||
case PLAY_STATUS_STOP_STATE:
|
||||
device->setStateValue(soundtouchPlaybackStatusStateTypeId, "Stopped");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DevicePluginBose::onVolumeObjectReceived(VolumeObject volume)
|
||||
{
|
||||
SoundTouch *soundtouch = static_cast<SoundTouch *>(sender());
|
||||
Device *device = m_soundTouch.key(soundtouch);
|
||||
device->setStateValue(soundtouchVolumeStateTypeId, volume.actualVolume);
|
||||
device->setStateValue(soundtouchMuteStateTypeId, volume.muteEnabled);
|
||||
}
|
||||
|
||||
void DevicePluginBose::onSourcesObjectReceived(SourcesObject sources)
|
||||
{
|
||||
foreach (SourceItemObject sourceItem, sources.sourceItems) {
|
||||
qDebug(dcBose()) << "Source:" << sources.deviceId << sourceItem.source << sourceItem.displayName;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io *
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Lesser General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2.1 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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 library; If not, see *
|
||||
* <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef DEVICEPLUGINBOSE_H
|
||||
#define DEVICEPLUGINBOSE_H
|
||||
|
||||
#include "devices/deviceplugin.h"
|
||||
#include "plugintimer.h"
|
||||
#include "soundtouch.h"
|
||||
#include "soundtouchtypes.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QDebug>
|
||||
|
||||
class DevicePluginBose : public DevicePlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "devicepluginbose.json")
|
||||
Q_INTERFACES(DevicePlugin)
|
||||
|
||||
public:
|
||||
explicit DevicePluginBose();
|
||||
~DevicePluginBose() override;
|
||||
|
||||
void init() override;
|
||||
Device::DeviceSetupStatus setupDevice(Device *device) override;
|
||||
void deviceRemoved(Device *device) override;
|
||||
Device::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override;
|
||||
Device::DeviceError executeAction(Device *device, const Action &action) override;
|
||||
|
||||
private:
|
||||
PluginTimer *m_pluginTimer = nullptr;
|
||||
|
||||
QHash<Device *, SoundTouch *> m_soundTouch;
|
||||
QHash<int, ActionId> m_pendingActions;
|
||||
|
||||
private slots:
|
||||
void onPluginTimer();
|
||||
void onConnectionChanged(bool connected);
|
||||
void onDeviceNameChanged();
|
||||
|
||||
void onInfoObjectReceived(InfoObject infoObject);
|
||||
void onNowPlayingObjectReceived(NowPlayingObject nowPlaying);
|
||||
void onVolumeObjectReceived(VolumeObject volume);
|
||||
void onSourcesObjectReceived(SourcesObject sources);
|
||||
};
|
||||
|
||||
#endif // DEVICEPLUGINBOSE_H
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
{
|
||||
"id": "472a3f24-b05c-49b3-ad9a-dfda608b6760",
|
||||
"name": "Bose",
|
||||
"displayName": "Bose",
|
||||
"vendors": [
|
||||
{
|
||||
"id": "433c45cd-5bc1-4239-a8a1-487c70ffdfc7",
|
||||
"name": "bose",
|
||||
"displayName": "Bose",
|
||||
"deviceClasses": [
|
||||
{
|
||||
"id": "f9b7a3f5-6353-48b1-afc1-66f914412f82",
|
||||
"name": "soundtouch",
|
||||
"displayName": "SoundTouch",
|
||||
"interfaces": ["extendedvolumecontroller", "mediametadataprovider", "shufflerepeat", "connectable"],
|
||||
"createMethods": ["discovery"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "1a897065-57c6-49b3-bac9-1e5db27859e5",
|
||||
"name": "ip",
|
||||
"displayName": "IP",
|
||||
"type" : "QString",
|
||||
"inputType": "IPv4Address"
|
||||
},
|
||||
{
|
||||
"id": "3eb95eef-e8ba-4d44-8a21-7d8038b74c4d",
|
||||
"name": "playerId",
|
||||
"displayName": "Player ID",
|
||||
"type" : "QString"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "09dfbd40-c97c-4a20-9ecd-f80e389a4864",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "connected changed",
|
||||
"defaultValue": false,
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"id": "5bac4ad7-f55c-4301-8d72-f2783d9909ff",
|
||||
"name": "power",
|
||||
"displayName": "Power",
|
||||
"displayNameEvent": "Power changed",
|
||||
"displayNameAction": "Set power",
|
||||
"defaultValue": false,
|
||||
"type": "bool",
|
||||
"writable": true
|
||||
},
|
||||
{
|
||||
"id": "bc98cdb0-4d0e-48ca-afc7-922e49bb7813",
|
||||
"name": "mute",
|
||||
"displayName": "mute",
|
||||
"displayNameEvent": "Mute changed",
|
||||
"displayNameAction": "Set mute",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"writable": true
|
||||
},
|
||||
{
|
||||
"id": "9dfe5d78-4c3f-497c-bab1-bb9fdf7e93a9",
|
||||
"name": "volume",
|
||||
"displayName": "volume",
|
||||
"displayNameEvent": "volume changed",
|
||||
"displayNameAction": "Set volume",
|
||||
"unit": "Percentage",
|
||||
"type": "int",
|
||||
"minValue": 0,
|
||||
"maxValue": 100,
|
||||
"defaultValue": 50,
|
||||
"writable": true
|
||||
},
|
||||
{
|
||||
"id": "2dd512b7-40c2-488e-8d4f-6519edaa6f74",
|
||||
"name": "playbackStatus",
|
||||
"displayName": "playback status",
|
||||
"type": "QString",
|
||||
"possibleValues": ["Playing", "Paused", "Stopped"],
|
||||
"defaultValue": "Stopped",
|
||||
"displayNameEvent": "playback status changed",
|
||||
"displayNameAction": "set playback status",
|
||||
"writable": true
|
||||
},
|
||||
{
|
||||
"id": "f2209fec-cceb-46ad-8189-4caf42166e6b",
|
||||
"type": "QString",
|
||||
"name": "title",
|
||||
"displayName": "Title",
|
||||
"displayNameEvent": "Title changed",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "8cb920a3-3bf1-4231-92d4-8ac27e7b3d65",
|
||||
"type": "QString",
|
||||
"name": "artist",
|
||||
"displayName": "Artist",
|
||||
"displayNameEvent": "Artist changed",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "ce399eec-9f6a-4903-9916-0e90e38b255e",
|
||||
"type": "QString",
|
||||
"name": "collection",
|
||||
"displayName": "Collection",
|
||||
"displayNameEvent": "Collection changed",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "44304c82-c2f6-433b-b62b-815382617d0b",
|
||||
"type": "QString",
|
||||
"name": "artwork",
|
||||
"displayName": "Artwork",
|
||||
"displayNameEvent": "Artwork changed",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "5913aa2a-629d-4de5-bf44-a4a1f130c118",
|
||||
"type": "bool",
|
||||
"name": "shuffle",
|
||||
"displayName": "Shuffle",
|
||||
"displayNameEvent": "Shuffle changed",
|
||||
"displayNameAction": "Set shuffle",
|
||||
"defaultValue": false,
|
||||
"writable": true
|
||||
},
|
||||
{
|
||||
"id": "bc02c28e-3f5d-4de4-b9b5-c0b1576c6e7e",
|
||||
"type": "QString",
|
||||
"name": "repeat",
|
||||
"displayName": "Repeat",
|
||||
"displayNameEvent": "Repeat changed",
|
||||
"displayNameAction": "Set repeat",
|
||||
"possibleValues": ["None", "One", "All"],
|
||||
"defaultValue": "None",
|
||||
"writable": true
|
||||
}
|
||||
],
|
||||
"eventTypes": [
|
||||
{
|
||||
"id": "2535a1eb-7643-4874-98f6-b027fdff6311",
|
||||
"name": "onPlayerPlay",
|
||||
"displayName": "player play"
|
||||
},
|
||||
{
|
||||
"id": "99498b1c-e9c0-480a-9e91-662ee79ba976",
|
||||
"name": "onPlayerPause",
|
||||
"displayName": "player pause"
|
||||
},
|
||||
{
|
||||
"id": "a02ce255-3abb-435d-a92e-7f99c952ecb2",
|
||||
"name": "onPlayerStop",
|
||||
"displayName": "player stop"
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
{
|
||||
"id": "a180807d-1265-4831-9d86-a421767418dd",
|
||||
"name": "skipBack",
|
||||
"displayName": "skip back"
|
||||
},
|
||||
{
|
||||
"id": "ae3cbe03-ee3e-410e-abbd-efabc2402198",
|
||||
"name": "stop",
|
||||
"displayName": "stop"
|
||||
},
|
||||
{
|
||||
"id": "4d2ee668-a2e3-4795-8b96-0c800b703b46",
|
||||
"name": "play",
|
||||
"displayName": "play"
|
||||
},
|
||||
{
|
||||
"id": "3cf341cb-fe63-40bc-a450-9678d18e91e3",
|
||||
"name": "pause",
|
||||
"displayName": "pause"
|
||||
},
|
||||
{
|
||||
"id": "85d7126a-b123-4a28-aeb4-d84bcfb4d14f",
|
||||
"name": "skipNext",
|
||||
"displayName": "skipNext"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue