diff --git a/PROTOCOL.md b/PROTOCOL.md
index c08ff818..0f805344 100644
--- a/PROTOCOL.md
+++ b/PROTOCOL.md
@@ -13,7 +13,7 @@ The protocol in general is based on the OBS Remote protocol created by Bill Hami
- **Scenes**
- ["SwitchScenes"](#switchscenes)
- ["ScenesChanged"](#sceneschanged)
- - **Sources / Scene Items**
+ - **Scene Items**
- ["SourceOrderChanged"](#sourceorderchanged)
- ["SceneItemAdded"](#sceneitemadded)
- ["SceneItemRemoved"](#sceneitemremoved)
@@ -85,8 +85,10 @@ The protocol in general is based on the OBS Remote protocol created by Bill Hami
- ["SetVolume"](#setvolume)
- ["GetVolume"](#getvolume)
- ["SetMute"](#setmute)
+ - ["GetMute"](#getmute)
- ["ToggleMute"](#togglemute)
- - ["SetSourceRender"](#setsourcerender)
+ - **Scene Items**
+ - ["SetSceneItemRender"](#setsourcerender) (a.k.a `SetSourceRender`)
- ["SetSceneItemPosition"](#setsceneitemposition)
- ["SetSceneItemTransform"](#setsceneitemtransform)
- ["SetSceneItemCrop"](#setsceneitemcrop)
@@ -246,7 +248,6 @@ A request to start streaming has been issued.
#### "StreamStarted"
Streaming started successfully.
-*New in OBS Studio*
---
@@ -258,31 +259,26 @@ A request to stop streaming has been issued.
#### "StreamStopped"
Streaming stopped successfully.
-*New in OBS Studio*
---
#### "RecordingStarting"
A request to start recording has been issued.
-*New in OBS Studio*
---
#### "RecordingStarted"
Recording started successfully.
-*New in OBS Studio*
---
#### "RecordingStopping"
A request to stop streaming has been issued.
-*New in OBS Studio*
---
#### "RecordingStopped"
Recording stopped successfully.
-*New in OBS Studio*
---
@@ -302,8 +298,7 @@ Sent every 2 seconds with the following information :
---
#### "Exiting"
-OBS is exiting.
-*New in OBS Studio*
+OBS is exiting.
---
@@ -488,7 +483,6 @@ Toggles recording on or off.
__Request fields__ : none
__Response__ : always OK. No additional fields.
-*New in OBS Studio*
---
@@ -497,7 +491,6 @@ Start streaming.
__Request fields__ : none
__Response__ : always OK. No additional fields.
-*New in OBS Studio*
---
@@ -506,7 +499,6 @@ Stop streaming.
__Request fields__ : none
__Response__ : always OK. No additional fields.
-*New in OBS Studio*
---
@@ -515,7 +507,6 @@ Start recording.
__Request fields__ : none
__Response__ : always OK. No additional fields.
-*New in OBS Studio*
---
@@ -524,7 +515,6 @@ Stop recording.
__Request fields__ : none
__Response__ : always OK. No additional fields.
-*New in OBS Studio*
---
@@ -552,8 +542,6 @@ __Response__ : always OK, with these additional fields :
Objects in the "transitions" array have only one field :
- **"name"** (string) : name of the transition
-*New in OBS Studio*
-
---
#### "GetCurrentTransition"
@@ -564,17 +552,13 @@ __Response__ : always OK, with these additional fields :
- **"name"** (string) : name of the selected transition
- **"duration"** (integer, only if transition supports this) : transition duration
-*New in OBS Studio*
-
---
#### "SetCurrentTransition"
__Request fields__ :
- **"transition-name"** (string) : The name of the transition.
-__Response__ : OK if specified transition exists, error otherwise.
-
-*New in OBS Studio*
+__Response__ : OK if specified transition exists, error otherwise.
---
@@ -586,8 +570,6 @@ __Request fields__ :
__Response__ : always OK.
-*New in OBS Studio*
-
---
#### "GetTransitionDuration"
@@ -597,8 +579,6 @@ __Request fields__ : none
__Response__ : always OK, with these additional fields :
- **"transition-duration"** (integer) : current transition duration, in milliseconds
-*New in OBS Studio*
-
---
#### "SetVolume"
@@ -610,8 +590,6 @@ __Request fields__ :
__Response__ : OK if specified source exists, error otherwise.
-*Updated for OBS Studio*
-
---
#### "GetVolume"
@@ -621,11 +599,9 @@ __Request fields__ :
- **"source"** (string) : name of the source
__Response__ : OK if source exists, with these additional fields :
-- **"name"** (string) : name of the requested source
-- **"volume"** (double) : volume of the requested source, on a linear scale (0.0 to 1.0)
-- **"muted"** (bool) : mute status of the requested source
-
-*Updated for OBS Studio*
+- **"name"** (string) : source name
+- **"volume"** (double) : source volume, on a linear scale (0.0 to 1.0)
+- **"muted"** (bool) : source mute status
---
@@ -638,7 +614,17 @@ __Request fields__ :
__Response__ : OK if specified source exists, error otherwise.
-*Updated for OBS Studio*
+---
+
+#### "GetMute"
+Get mute status of a specific source.
+
+__Request fields__ :
+- **"source"** (string) : the name of the source
+
+__Response__ : OK if source exists, with these additional fields :
+- **"name"** (string) : source name
+- **"muted"** (bool) : source mute status
---
@@ -650,8 +636,6 @@ __Request fields__ :
__Response__ : OK if specified source exists, error otherwise.
-*Updated for OBS Studio*
-
---
#### "SetSceneItemPosition"
@@ -663,8 +647,6 @@ __Request fields__ :
__Response__ : OK if specified item exists, error otherwise.
-*New in OBS Studio*
-
---
#### "SetSceneItemTransform"
@@ -677,8 +659,6 @@ __Request fields__ :
__Response__ : OK if specified item exists, error otherwise.
-*New in OBS Studio*
-
---
#### "SetSceneItemCrop"
diff --git a/README.md b/README.md
index 48ca1b56..220998ad 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,11 @@ Follow the project on Twitter for news & updates : [@obswebsocket](https://twitt
## Downloads
Binaries for Windows and Linux are available in the [Releases](https://github.com/Palakis/obs-websocket/releases) section.
-## Sponsors
+## Supporters
+[Support Class](http://supportclass.net) designs and develops professional livestreams, with services ranging from broadcast graphics design and integration to event organization, along many other skills.
+
+They have contributed financially to the project and made possible the addition of several features into obs-websocket. Many thanks to them!
+
[](http://supportclass.net)
## Using obs-websocket
diff --git a/WSRequestHandler.cpp b/WSRequestHandler.cpp
index c2af012f..d8f8958f 100644
--- a/WSRequestHandler.cpp
+++ b/WSRequestHandler.cpp
@@ -23,10 +23,15 @@ with this program. If not, see
#include "Config.h"
#include "Utils.h"
+bool str_valid(const char* str)
+{
+ return (str != nullptr && strlen(str) > 0);
+}
+
WSRequestHandler::WSRequestHandler(QWebSocket *client) :
_messageId(0),
_requestType(""),
- _requestData(nullptr)
+ data(nullptr)
{
_client = client;
@@ -62,6 +67,7 @@ WSRequestHandler::WSRequestHandler(QWebSocket *client) :
messageMap["GetVolume"] = WSRequestHandler::HandleGetVolume;
messageMap["ToggleMute"] = WSRequestHandler::HandleToggleMute;
messageMap["SetMute"] = WSRequestHandler::HandleSetMute;
+ messageMap["GetMute"] = WSRequestHandler::HandleGetMute;
messageMap["SetCurrentSceneCollection"] = WSRequestHandler::HandleSetCurrentSceneCollection;
messageMap["GetCurrentSceneCollection"] = WSRequestHandler::HandleGetCurrentSceneCollection;
@@ -89,8 +95,8 @@ void WSRequestHandler::processIncomingMessage(QString textMessage)
QByteArray msgData = textMessage.toUtf8();
const char *msg = msgData;
- _requestData = obs_data_create_from_json(msg);
- if (!_requestData)
+ data = obs_data_create_from_json(msg);
+ if (!data)
{
if (!msg)
{
@@ -102,8 +108,15 @@ void WSRequestHandler::processIncomingMessage(QString textMessage)
return;
}
- _requestType = obs_data_get_string(_requestData, "request-type");
- _messageId = obs_data_get_string(_requestData, "message-id");
+ if (!hasField("request-type") ||
+ !hasField("message-id"))
+ {
+ SendErrorResponse("missing request parameters");
+ return;
+ }
+
+ _requestType = obs_data_get_string(data, "request-type");
+ _messageId = obs_data_get_string(data, "message-id");
if (Config::Current()->AuthRequired
&& (_client->property(PROP_AUTHENTICATED).toBool() == false)
@@ -116,23 +129,17 @@ void WSRequestHandler::processIncomingMessage(QString textMessage)
void (*handlerFunc)(WSRequestHandler*) = (messageMap[_requestType]);
if (handlerFunc != NULL)
- {
handlerFunc(this);
- }
else
- {
SendErrorResponse("invalid request type");
- }
- obs_data_release(_requestData);
+ obs_data_release(data);
}
WSRequestHandler::~WSRequestHandler()
{
- if (_requestData != NULL)
- {
- obs_data_release(_requestData);
- }
+ if (data)
+ obs_data_release(data);
}
void WSRequestHandler::SendOKResponse(obs_data_t *additionalFields)
@@ -141,10 +148,8 @@ void WSRequestHandler::SendOKResponse(obs_data_t *additionalFields)
obs_data_set_string(response, "status", "ok");
obs_data_set_string(response, "message-id", _messageId);
- if (additionalFields != NULL)
- {
+ if (additionalFields)
obs_data_apply(response, additionalFields);
- }
_client->sendTextMessage(obs_data_get_json(response));
@@ -163,22 +168,30 @@ void WSRequestHandler::SendErrorResponse(const char *errorMessage)
obs_data_release(response);
}
-void WSRequestHandler::HandleGetVersion(WSRequestHandler *owner)
+bool WSRequestHandler::hasField(const char* name)
+{
+ if (!name || !data)
+ return false;
+
+ return obs_data_has_user_value(data, name);
+}
+
+void WSRequestHandler::HandleGetVersion(WSRequestHandler *req)
{
const char* obs_version = Utils::OBSVersionString();
obs_data_t *data = obs_data_create();
- obs_data_set_double(data, "version", 1.2);
+ obs_data_set_double(data, "version", API_VERSION);
obs_data_set_string(data, "obs-websocket-version", OBS_WEBSOCKET_VERSION);
obs_data_set_string(data, "obs-studio-version", obs_version);
- owner->SendOKResponse(data);
+ req->SendOKResponse(data);
obs_data_release(data);
bfree((void*)obs_version);
}
-void WSRequestHandler::HandleGetAuthRequired(WSRequestHandler *owner)
+void WSRequestHandler::HandleGetAuthRequired(WSRequestHandler *req)
{
bool authRequired = Config::Current()->AuthRequired;
@@ -191,50 +204,62 @@ void WSRequestHandler::HandleGetAuthRequired(WSRequestHandler *owner)
obs_data_set_string(data, "salt", Config::Current()->Salt);
}
- owner->SendOKResponse(data);
+ req->SendOKResponse(data);
obs_data_release(data);
}
-void WSRequestHandler::HandleAuthenticate(WSRequestHandler *owner)
+void WSRequestHandler::HandleAuthenticate(WSRequestHandler *req)
{
- const char *auth = obs_data_get_string(owner->_requestData, "auth");
- if (!auth || strlen(auth) < 1)
+ if (!req->hasField("auth"))
{
- owner->SendErrorResponse("auth not specified!");
+ req->SendErrorResponse("missing request parameters");
return;
}
- if ((owner->_client->property(PROP_AUTHENTICATED).toBool() == false) && Config::Current()->CheckAuth(auth))
+ const char *auth = obs_data_get_string(req->data, "auth");
+ if (!str_valid(auth))
{
- owner->_client->setProperty(PROP_AUTHENTICATED, true);
- owner->SendOKResponse();
+ req->SendErrorResponse("auth not specified!");
+ return;
+ }
+
+ if ((req->_client->property(PROP_AUTHENTICATED).toBool() == false) && Config::Current()->CheckAuth(auth))
+ {
+ req->_client->setProperty(PROP_AUTHENTICATED, true);
+ req->SendOKResponse();
}
else
{
- owner->SendErrorResponse("Authentication Failed.");
+ req->SendErrorResponse("Authentication Failed.");
}
}
-void WSRequestHandler::HandleSetCurrentScene(WSRequestHandler *owner)
+void WSRequestHandler::HandleSetCurrentScene(WSRequestHandler *req)
{
- const char *sceneName = obs_data_get_string(owner->_requestData, "scene-name");
+ if (!req->hasField("scene-name"))
+ {
+ req->SendErrorResponse("missing request parameters");
+ return;
+ }
+
+ const char *sceneName = obs_data_get_string(req->data, "scene-name");
obs_source_t *source = obs_get_source_by_name(sceneName);
if (source)
{
obs_frontend_set_current_scene(source);
- owner->SendOKResponse();
+ req->SendOKResponse();
}
else
{
- owner->SendErrorResponse("requested scene does not exist");
+ req->SendErrorResponse("requested scene does not exist");
}
obs_source_release(source);
}
-void WSRequestHandler::HandleGetCurrentScene(WSRequestHandler *owner)
+void WSRequestHandler::HandleGetCurrentScene(WSRequestHandler *req)
{
obs_source_t *current_scene = obs_frontend_get_current_scene();
const char *name = obs_source_get_name(current_scene);
@@ -245,14 +270,14 @@ void WSRequestHandler::HandleGetCurrentScene(WSRequestHandler *owner)
obs_data_set_string(data, "name", name);
obs_data_set_array(data, "sources", scene_items);
- owner->SendOKResponse(data);
+ req->SendOKResponse(data);
obs_data_release(data);
obs_data_array_release(scene_items);
obs_source_release(current_scene);
}
-void WSRequestHandler::HandleGetSceneList(WSRequestHandler *owner)
+void WSRequestHandler::HandleGetSceneList(WSRequestHandler *req)
{
obs_source_t *current_scene = obs_frontend_get_current_scene();
obs_data_array_t *scenes = Utils::GetScenes();
@@ -261,27 +286,35 @@ void WSRequestHandler::HandleGetSceneList(WSRequestHandler *owner)
obs_data_set_string(data, "current-scene", obs_source_get_name(current_scene));
obs_data_set_array(data, "scenes", scenes);
- owner->SendOKResponse(data);
+ req->SendOKResponse(data);
obs_data_release(data);
obs_data_array_release(scenes);
obs_source_release(current_scene);
}
-void WSRequestHandler::HandleSetSceneItemRender(WSRequestHandler *owner)
+void WSRequestHandler::HandleSetSceneItemRender(WSRequestHandler *req)
{
- const char *itemName = obs_data_get_string(owner->_requestData, "source");
- bool isVisible = obs_data_get_bool(owner->_requestData, "render");
- if (itemName == NULL)
+ if (!req->hasField("source") ||
+ !req->hasField("render"))
{
- owner->SendErrorResponse("invalid request parameters");
+ req->SendErrorResponse("missing request parameters");
return;
}
- const char *sceneName = obs_data_get_string(owner->_requestData, "scene-name");
+ const char *itemName = obs_data_get_string(req->data, "source");
+ bool isVisible = obs_data_get_bool(req->data, "render");
+
+ if (!itemName)
+ {
+ req->SendErrorResponse("invalid request parameters");
+ return;
+ }
+
+ const char *sceneName = obs_data_get_string(req->data, "scene-name");
obs_source_t *scene = Utils::GetSceneFromNameOrCurrent(sceneName);
if (scene == NULL) {
- owner->SendErrorResponse("requested scene doesn't exist");
+ req->SendErrorResponse("requested scene doesn't exist");
return;
}
@@ -290,17 +323,17 @@ void WSRequestHandler::HandleSetSceneItemRender(WSRequestHandler *owner)
{
obs_sceneitem_set_visible(sceneItem, isVisible);
obs_sceneitem_release(sceneItem);
- owner->SendOKResponse();
+ req->SendOKResponse();
}
else
{
- owner->SendErrorResponse("specified scene item doesn't exist");
+ req->SendErrorResponse("specified scene item doesn't exist");
}
obs_source_release(scene);
}
-void WSRequestHandler::HandleGetStreamingStatus(WSRequestHandler *owner)
+void WSRequestHandler::HandleGetStreamingStatus(WSRequestHandler *req)
{
obs_data_t *data = obs_data_create();
obs_data_set_bool(data, "streaming", obs_frontend_streaming_active());
@@ -322,11 +355,11 @@ void WSRequestHandler::HandleGetStreamingStatus(WSRequestHandler *owner)
bfree((void*)tc);
}
- owner->SendOKResponse(data);
+ req->SendOKResponse(data);
obs_data_release(data);
}
-void WSRequestHandler::HandleStartStopStreaming(WSRequestHandler *owner)
+void WSRequestHandler::HandleStartStopStreaming(WSRequestHandler *req)
{
if (obs_frontend_streaming_active())
{
@@ -337,10 +370,10 @@ void WSRequestHandler::HandleStartStopStreaming(WSRequestHandler *owner)
obs_frontend_streaming_start();
}
- owner->SendOKResponse();
+ req->SendOKResponse();
}
-void WSRequestHandler::HandleStartStopRecording(WSRequestHandler *owner)
+void WSRequestHandler::HandleStartStopRecording(WSRequestHandler *req)
{
if (obs_frontend_recording_active())
{
@@ -351,42 +384,42 @@ void WSRequestHandler::HandleStartStopRecording(WSRequestHandler *owner)
obs_frontend_recording_start();
}
- owner->SendOKResponse();
+ req->SendOKResponse();
}
-void WSRequestHandler::HandleStartStreaming(WSRequestHandler *owner)
+void WSRequestHandler::HandleStartStreaming(WSRequestHandler *req)
{
if (obs_frontend_streaming_active() == false)
obs_frontend_streaming_start();
- owner->SendOKResponse();
+ req->SendOKResponse();
}
-void WSRequestHandler::HandleStopStreaming(WSRequestHandler *owner)
+void WSRequestHandler::HandleStopStreaming(WSRequestHandler *req)
{
if (obs_frontend_streaming_active() == true)
obs_frontend_streaming_stop();
- owner->SendOKResponse();
+ req->SendOKResponse();
}
-void WSRequestHandler::HandleStartRecording(WSRequestHandler *owner)
+void WSRequestHandler::HandleStartRecording(WSRequestHandler *req)
{
if (obs_frontend_recording_active() == false)
obs_frontend_recording_start();
- owner->SendOKResponse();
+ req->SendOKResponse();
}
-void WSRequestHandler::HandleStopRecording(WSRequestHandler *owner)
+void WSRequestHandler::HandleStopRecording(WSRequestHandler *req)
{
if (obs_frontend_recording_active() == true)
obs_frontend_recording_stop();
- owner->SendOKResponse();
+ req->SendOKResponse();
}
-void WSRequestHandler::HandleGetTransitionList(WSRequestHandler *owner)
+void WSRequestHandler::HandleGetTransitionList(WSRequestHandler *req)
{
obs_source_t *current_transition = obs_frontend_get_current_transition();
obs_frontend_source_list transitionList = {};
@@ -409,14 +442,14 @@ void WSRequestHandler::HandleGetTransitionList(WSRequestHandler *owner)
obs_data_set_string(response, "current-transition", obs_source_get_name(current_transition));
obs_data_set_array(response, "transitions", transitions);
- owner->SendOKResponse(response);
+ req->SendOKResponse(response);
obs_data_release(response);
obs_data_array_release(transitions);
obs_source_release(current_transition);
}
-void WSRequestHandler::HandleGetCurrentTransition(WSRequestHandler *owner)
+void WSRequestHandler::HandleGetCurrentTransition(WSRequestHandler *req)
{
obs_source_t *current_transition = obs_frontend_get_current_transition();
@@ -428,190 +461,280 @@ void WSRequestHandler::HandleGetCurrentTransition(WSRequestHandler *owner)
obs_data_set_int(response, "duration", Utils::GetTransitionDuration());
}
- owner->SendOKResponse(response);
+ req->SendOKResponse(response);
obs_data_release(response);
obs_source_release(current_transition);
}
-void WSRequestHandler::HandleSetCurrentTransition(WSRequestHandler *owner)
+void WSRequestHandler::HandleSetCurrentTransition(WSRequestHandler *req)
{
- const char *name = obs_data_get_string(owner->_requestData, "transition-name");
+ if (!req->hasField("transition-name"))
+ {
+ req->SendErrorResponse("missing request parameters");
+ return;
+ }
+
+ const char *name = obs_data_get_string(req->data, "transition-name");
bool success = Utils::SetTransitionByName(name);
if (success)
- owner->SendOKResponse();
+ req->SendOKResponse();
else
- owner->SendErrorResponse("requested transition does not exist");
+ req->SendErrorResponse("requested transition does not exist");
}
-void WSRequestHandler::HandleSetTransitionDuration(WSRequestHandler *owner)
+void WSRequestHandler::HandleSetTransitionDuration(WSRequestHandler *req)
{
- int ms = obs_data_get_int(owner->_requestData, "duration");
+ if (!req->hasField("duration"))
+ {
+ req->SendErrorResponse("missing request parameters");
+ return;
+ }
+
+ int ms = obs_data_get_int(req->data, "duration");
Utils::SetTransitionDuration(ms);
- owner->SendOKResponse();
+ req->SendOKResponse();
}
-void WSRequestHandler::HandleGetTransitionDuration(WSRequestHandler *owner)
+void WSRequestHandler::HandleGetTransitionDuration(WSRequestHandler *req)
{
obs_data_t* response = obs_data_create();
obs_data_set_int(response, "transition-duration", Utils::GetTransitionDuration());
- owner->SendOKResponse(response);
+ req->SendOKResponse(response);
obs_data_release(response);
}
-void WSRequestHandler::HandleSetVolume(WSRequestHandler *owner)
+void WSRequestHandler::HandleSetVolume(WSRequestHandler *req)
{
- const char *item_name = obs_data_get_string(owner->_requestData, "source");
- float item_volume = obs_data_get_double(owner->_requestData, "volume");
-
- if (item_name == NULL || item_volume < 0.0 || item_volume > 1.0)
+ if (!req->hasField("source") ||
+ !req->hasField("volume"))
{
- owner->SendErrorResponse("invalid request parameters");
+ req->SendErrorResponse("missing request parameters");
return;
}
- obs_source_t* item = obs_get_source_by_name(item_name);
- if (!item)
+ const char *source_name = obs_data_get_string(req->data, "source");
+ float source_volume = obs_data_get_double(req->data, "volume");
+
+ if (source_name == NULL || strlen(source_name) < 1 ||
+ source_volume < 0.0 || source_volume > 1.0)
{
- owner->SendErrorResponse("specified source doesn't exist");
+ req->SendErrorResponse("invalid request parameters");
return;
}
- obs_source_set_volume(item, item_volume);
- owner->SendOKResponse();
+ obs_source_t* source = obs_get_source_by_name(source_name);
+ if (!source)
+ {
+ req->SendErrorResponse("specified source doesn't exist");
+ return;
+ }
- obs_source_release(item);
+ obs_source_set_volume(source, source_volume);
+ req->SendOKResponse();
+
+ obs_source_release(source);
}
-void WSRequestHandler::HandleGetVolume(WSRequestHandler *owner)
+void WSRequestHandler::HandleGetVolume(WSRequestHandler *req)
{
- const char *item_name = obs_data_get_string(owner->_requestData, "source");
-
- if (item_name)
+ if (!req->hasField("source"))
{
- obs_source_t* item = obs_get_source_by_name(item_name);
+ req->SendErrorResponse("missing request parameters");
+ return;
+ }
+
+ const char *source_name = obs_data_get_string(req->data, "source");
+
+ if (str_valid(source_name))
+ {
+ obs_source_t* source = obs_get_source_by_name(source_name);
obs_data_t* response = obs_data_create();
- obs_data_set_string(response, "name", item_name);
- obs_data_set_double(response, "volume", obs_source_get_volume(item));
- obs_data_set_bool(response, "muted", obs_source_muted(item));
+ obs_data_set_string(response, "name", source_name);
+ obs_data_set_double(response, "volume", obs_source_get_volume(source));
+ obs_data_set_bool(response, "muted", obs_source_muted(source));
- owner->SendOKResponse(response);
+ req->SendOKResponse(response);
obs_data_release(response);
- obs_source_release(item);
+ obs_source_release(source);
}
else
{
- owner->SendErrorResponse("invalid request parameters");
+ req->SendErrorResponse("invalid request parameters");
}
}
-void WSRequestHandler::HandleToggleMute(WSRequestHandler *owner) {
- const char *item_name = obs_data_get_string(owner->_requestData, "source");
- if (item_name == NULL)
- {
- owner->SendErrorResponse("invalid request parameters");
- return;
- }
-
- obs_source_t* item = obs_get_source_by_name(item_name);
- if (!item)
- {
- owner->SendErrorResponse("invalid request parameters");
- return;
- }
-
- obs_source_set_muted(item, !obs_source_muted(item));
- owner->SendOKResponse();
-
- obs_source_release(item);
-}
-
-void WSRequestHandler::HandleSetMute(WSRequestHandler *owner)
+void WSRequestHandler::HandleToggleMute(WSRequestHandler *req)
{
- const char *item_name = obs_data_get_string(owner->_requestData, "source");
- bool mute = obs_data_get_bool(owner->_requestData, "mute");
- if (item_name == NULL)
+ if (!req->hasField("source"))
{
- owner->SendErrorResponse("invalid request parameters");
+ req->SendErrorResponse("missing request parameters");
return;
}
- obs_source_t* item = obs_get_source_by_name(item_name);
- if (!item)
+ const char *source_name = obs_data_get_string(req->data, "source");
+ if (!str_valid(source_name))
{
- owner->SendErrorResponse("specified source doesn't exist");
+ req->SendErrorResponse("invalid request parameters");
return;
}
- obs_source_set_muted(item, mute);
- owner->SendOKResponse();
+ obs_source_t* source = obs_get_source_by_name(source_name);
+ if (!source)
+ {
+ req->SendErrorResponse("invalid request parameters");
+ return;
+ }
- obs_source_release(item);
+ obs_source_set_muted(source, !obs_source_muted(source));
+ req->SendOKResponse();
+
+ obs_source_release(source);
}
-void WSRequestHandler::HandleSetSceneItemPosition(WSRequestHandler *owner)
+void WSRequestHandler::HandleSetMute(WSRequestHandler *req)
{
- const char *item_name = obs_data_get_string(owner->_requestData, "item");
- if (!item_name)
+ if (!req->hasField("source") ||
+ !req->hasField("mute"))
{
- owner->SendErrorResponse("invalid request parameters");
+ req->SendErrorResponse("mssing request parameters");
return;
}
- const char *scene_name = obs_data_get_string(owner->_requestData, "scene-name");
+ const char *source_name = obs_data_get_string(req->data, "source");
+ bool mute = obs_data_get_bool(req->data, "mute");
+
+ if (!str_valid(source_name))
+ {
+ req->SendErrorResponse("invalid request parameters");
+ return;
+ }
+
+ obs_source_t* source = obs_get_source_by_name(source_name);
+ if (!source)
+ {
+ req->SendErrorResponse("specified source doesn't exist");
+ return;
+ }
+
+ obs_source_set_muted(source, mute);
+ req->SendOKResponse();
+
+ obs_source_release(source);
+}
+
+void WSRequestHandler::HandleGetMute(WSRequestHandler *req)
+{
+ if (!req->hasField("source"))
+ {
+ req->SendErrorResponse("mssing request parameters");
+ return;
+ }
+
+ const char *source_name = obs_data_get_string(req->data, "source");
+
+ if (!str_valid(source_name))
+ {
+ req->SendErrorResponse("invalid request parameters");
+ return;
+ }
+
+ obs_source_t* source = obs_get_source_by_name(source_name);
+ if (!source)
+ {
+ req->SendErrorResponse("specified source doesn't exist");
+ return;
+ }
+
+ obs_data_t* response = obs_data_create();
+ obs_data_set_string(response, "name", obs_source_get_name(source));
+ obs_data_set_bool(response, "muted", obs_source_muted(source));
+
+ req->SendOKResponse(response);
+
+ obs_source_release(source);
+ obs_data_release(response);
+}
+
+void WSRequestHandler::HandleSetSceneItemPosition(WSRequestHandler *req)
+{
+ if (!req->hasField("item") ||
+ !req->hasField("x") || !req->hasField("y"))
+ {
+ req->SendErrorResponse("missing request parameters");
+ return;
+ }
+
+ const char *item_name = obs_data_get_string(req->data, "item");
+ if (!str_valid(item_name))
+ {
+ req->SendErrorResponse("invalid request parameters");
+ return;
+ }
+
+ const char *scene_name = obs_data_get_string(req->data, "scene-name");
obs_source_t *scene = Utils::GetSceneFromNameOrCurrent(scene_name);
- if (scene == NULL) {
- owner->SendErrorResponse("requested scene could not be found");
+ if (!scene) {
+ req->SendErrorResponse("requested scene could not be found");
return;
}
- vec2 item_position = {0};
- item_position.x = obs_data_get_double(owner->_requestData, "x");
- item_position.y = obs_data_get_double(owner->_requestData, "y");
-
obs_sceneitem_t *scene_item = Utils::GetSceneItemFromName(scene, item_name);
if (scene_item)
{
+ vec2 item_position = { 0 };
+ item_position.x = obs_data_get_double(req->data, "x");
+ item_position.y = obs_data_get_double(req->data, "y");
+
obs_sceneitem_set_pos(scene_item, &item_position);
obs_sceneitem_release(scene_item);
- owner->SendOKResponse();
+ req->SendOKResponse();
}
else
{
- owner->SendErrorResponse("specified scene item doesn't exist");
+ req->SendErrorResponse("specified scene item doesn't exist");
}
obs_source_release(scene);
}
-void WSRequestHandler::HandleSetSceneItemTransform(WSRequestHandler *owner)
+void WSRequestHandler::HandleSetSceneItemTransform(WSRequestHandler *req)
{
- const char *item_name = obs_data_get_string(owner->_requestData, "item");
- if (!item_name)
+ if (!req->hasField("item") ||
+ !req->hasField("x-scale") ||
+ !req->hasField("y-scale") ||
+ !req->hasField("rotation"))
{
- owner->SendErrorResponse("invalid request parameters");
+ req->SendErrorResponse("missing request parameters");
return;
}
- const char *scene_name = obs_data_get_string(owner->_requestData, "scene-name");
+ const char *item_name = obs_data_get_string(req->data, "item");
+ if (!str_valid(item_name))
+ {
+ req->SendErrorResponse("invalid request parameters");
+ return;
+ }
+
+ const char *scene_name = obs_data_get_string(req->data, "scene-name");
obs_source_t* scene = Utils::GetSceneFromNameOrCurrent(scene_name);
- if (scene == NULL) {
- owner->SendErrorResponse("requested scene doesn't exist");
+ if (!scene) {
+ req->SendErrorResponse("requested scene doesn't exist");
return;
}
vec2 scale;
- scale.x = obs_data_get_double(owner->_requestData, "x-scale");
- scale.y = obs_data_get_double(owner->_requestData, "y-scale");
+ scale.x = obs_data_get_double(req->data, "x-scale");
+ scale.y = obs_data_get_double(req->data, "y-scale");
- float rotation = obs_data_get_double(owner->_requestData, "rotation");
+ float rotation = obs_data_get_double(req->data, "rotation");
obs_sceneitem_t *scene_item = Utils::GetSceneItemFromName(scene, item_name);
@@ -621,29 +744,35 @@ void WSRequestHandler::HandleSetSceneItemTransform(WSRequestHandler *owner)
obs_sceneitem_set_rot(scene_item, rotation);
obs_sceneitem_release(scene_item);
- owner->SendOKResponse();
+ req->SendOKResponse();
}
else
{
- owner->SendErrorResponse("specified scene item doesn't exist");
+ req->SendErrorResponse("specified scene item doesn't exist");
}
obs_source_release(scene);
}
-void WSRequestHandler::HandleSetSceneItemCrop(WSRequestHandler *owner)
+void WSRequestHandler::HandleSetSceneItemCrop(WSRequestHandler *req)
{
- const char *item_name = obs_data_get_string(owner->_requestData, "item");
- if (!item_name)
+ if (!req->hasField("item"))
{
- owner->SendErrorResponse("invalid request parameters");
+ req->SendErrorResponse("missing request parameters");
return;
}
- const char *scene_name = obs_data_get_string(owner->_requestData, "scene-name");
+ const char *item_name = obs_data_get_string(req->data, "item");
+ if (!str_valid(item_name))
+ {
+ req->SendErrorResponse("invalid request parameters");
+ return;
+ }
+
+ const char *scene_name = obs_data_get_string(req->data, "scene-name");
obs_source_t* scene = Utils::GetSceneFromNameOrCurrent(scene_name);
- if (scene == NULL) {
- owner->SendErrorResponse("requested scene doesn't exist");
+ if (!scene) {
+ req->SendErrorResponse("requested scene doesn't exist");
return;
}
@@ -652,119 +781,131 @@ void WSRequestHandler::HandleSetSceneItemCrop(WSRequestHandler *owner)
if (scene_item)
{
struct obs_sceneitem_crop crop = { 0 };
- crop.top = obs_data_get_int(owner->_requestData, "top");
- crop.bottom = obs_data_get_int(owner->_requestData, "bottom");;
- crop.left = obs_data_get_int(owner->_requestData, "left");;
- crop.right = obs_data_get_int(owner->_requestData, "right");
+ crop.top = obs_data_get_int(req->data, "top");
+ crop.bottom = obs_data_get_int(req->data, "bottom");;
+ crop.left = obs_data_get_int(req->data, "left");;
+ crop.right = obs_data_get_int(req->data, "right");
obs_sceneitem_set_crop(scene_item, &crop);
obs_sceneitem_release(scene_item);
- owner->SendOKResponse();
+ req->SendOKResponse();
}
else
{
- owner->SendErrorResponse("specified scene item doesn't exist");
+ req->SendErrorResponse("specified scene item doesn't exist");
}
obs_source_release(scene);
}
-void WSRequestHandler::HandleSetCurrentSceneCollection(WSRequestHandler *owner)
+void WSRequestHandler::HandleSetCurrentSceneCollection(WSRequestHandler *req)
{
- const char* scene_collection = obs_data_get_string(owner->_requestData, "sc-name");
+ if (!req->hasField("sc-name"))
+ {
+ req->SendErrorResponse("missing request parameters");
+ return;
+ }
- if (scene_collection)
+ const char* scene_collection = obs_data_get_string(req->data, "sc-name");
+
+ if (str_valid(scene_collection))
{
// TODO : Check if specified profile exists and if changing is allowed
obs_frontend_set_current_scene_collection(scene_collection);
- owner->SendOKResponse();
+ req->SendOKResponse();
}
else
{
- owner->SendErrorResponse("invalid request parameters");
+ req->SendErrorResponse("invalid request parameters");
}
}
-void WSRequestHandler::HandleGetCurrentSceneCollection(WSRequestHandler *owner)
+void WSRequestHandler::HandleGetCurrentSceneCollection(WSRequestHandler *req)
{
obs_data_t *response = obs_data_create();
obs_data_set_string(response, "sc-name", obs_frontend_get_current_scene_collection());
- owner->SendOKResponse(response);
+ req->SendOKResponse(response);
obs_data_release(response);
}
-void WSRequestHandler::HandleListSceneCollections(WSRequestHandler *owner)
+void WSRequestHandler::HandleListSceneCollections(WSRequestHandler *req)
{
obs_data_array_t *scene_collections = Utils::GetSceneCollections();
obs_data_t *response = obs_data_create();
obs_data_set_array(response, "scene-collections", scene_collections);
- owner->SendOKResponse(response);
+ req->SendOKResponse(response);
obs_data_release(response);
obs_data_array_release(scene_collections);
}
-void WSRequestHandler::HandleSetCurrentProfile(WSRequestHandler *owner)
+void WSRequestHandler::HandleSetCurrentProfile(WSRequestHandler *req)
{
- const char* profile_name = obs_data_get_string(owner->_requestData, "profile-name");
+ if (!req->hasField("profile-name"))
+ {
+ req->SendErrorResponse("missing request parameters");
+ return;
+ }
- if (profile_name)
+ const char* profile_name = obs_data_get_string(req->data, "profile-name");
+
+ if (str_valid(profile_name))
{
// TODO : check if profile exists
obs_frontend_set_current_profile(profile_name);
- owner->SendOKResponse();
+ req->SendOKResponse();
}
else
{
- owner->SendErrorResponse("invalid request parameters");
+ req->SendErrorResponse("invalid request parameters");
}
}
-void WSRequestHandler::HandleGetCurrentProfile(WSRequestHandler *owner)
+void WSRequestHandler::HandleGetCurrentProfile(WSRequestHandler *req)
{
obs_data_t *response = obs_data_create();
obs_data_set_string(response, "profile-name", obs_frontend_get_current_profile());
- owner->SendOKResponse(response);
+ req->SendOKResponse(response);
obs_data_release(response);
}
-void WSRequestHandler::HandleListProfiles(WSRequestHandler *owner)
+void WSRequestHandler::HandleListProfiles(WSRequestHandler *req)
{
obs_data_array_t *profiles = Utils::GetProfiles();
obs_data_t *response = obs_data_create();
obs_data_set_array(response, "profiles", profiles);
- owner->SendOKResponse(response);
+ req->SendOKResponse(response);
obs_data_release(response);
obs_data_array_release(profiles);
}
-void WSRequestHandler::HandleGetStudioModeStatus(WSRequestHandler *owner)
+void WSRequestHandler::HandleGetStudioModeStatus(WSRequestHandler *req)
{
bool previewActive = Utils::IsPreviewModeActive();
obs_data_t* response = obs_data_create();
obs_data_set_bool(response, "studio-mode", previewActive);
- owner->SendOKResponse(response);
+ req->SendOKResponse(response);
obs_data_release(response);
}
-void WSRequestHandler::HandleGetPreviewScene(WSRequestHandler *owner)
+void WSRequestHandler::HandleGetPreviewScene(WSRequestHandler *req)
{
if (!Utils::IsPreviewModeActive())
{
- owner->SendErrorResponse("studio mode not enabled");
+ req->SendErrorResponse("studio mode not enabled");
return;
}
@@ -778,7 +919,7 @@ void WSRequestHandler::HandleGetPreviewScene(WSRequestHandler *owner)
obs_data_set_string(data, "name", name);
obs_data_set_array(data, "sources", scene_items);
- owner->SendOKResponse(data);
+ req->SendOKResponse(data);
obs_data_release(data);
obs_data_array_release(scene_items);
@@ -786,52 +927,57 @@ void WSRequestHandler::HandleGetPreviewScene(WSRequestHandler *owner)
obs_scene_release(preview_scene);
}
-void WSRequestHandler::HandleSetPreviewScene(WSRequestHandler *owner)
+void WSRequestHandler::HandleSetPreviewScene(WSRequestHandler *req)
{
if (!Utils::IsPreviewModeActive())
{
- owner->SendErrorResponse("studio mode not enabled");
+ req->SendErrorResponse("studio mode not enabled");
return;
}
- if (!obs_data_has_user_value(owner->_requestData, "scene-name"))
+ if (!req->hasField("scene-name"))
{
- owner->SendErrorResponse("invalid request parameters");
+ req->SendErrorResponse("missing request parameters");
return;
}
- const char* scene_name = obs_data_get_string(owner->_requestData, "scene-name");
+ const char* scene_name = obs_data_get_string(req->data, "scene-name");
Utils::SetPreviewScene(scene_name);
- owner->SendOKResponse();
+ req->SendOKResponse();
}
-void WSRequestHandler::HandleTransitionToProgram(WSRequestHandler *owner)
+void WSRequestHandler::HandleTransitionToProgram(WSRequestHandler *req)
{
if (!Utils::IsPreviewModeActive())
{
- owner->SendErrorResponse("studio mode not enabled");
+ req->SendErrorResponse("studio mode not enabled");
return;
}
- if (obs_data_has_user_value(owner->_requestData, "with-transition"))
+ if (req->hasField("with-transition"))
{
- obs_data_t* transitionInfo = obs_data_get_obj(owner->_requestData, "with-transition");
+ obs_data_t* transitionInfo = obs_data_get_obj(req->data, "with-transition");
- if (obs_data_has_user_value(transitionInfo, "name"))
+ if (req->hasField("name"))
{
const char* transitionName = obs_data_get_string(transitionInfo, "name");
- bool success = Utils::SetTransitionByName(transitionName);
+ if (!str_valid(transitionName))
+ {
+ req->SendErrorResponse("invalid request parameters");
+ return;
+ }
+ bool success = Utils::SetTransitionByName(transitionName);
if (!success)
{
- owner->SendErrorResponse("specified transition doesn't exist");
+ req->SendErrorResponse("specified transition doesn't exist");
obs_data_release(transitionInfo);
return;
}
}
- if (obs_data_has_user_value(transitionInfo, "duration"))
+ if (req->hasField("duration"))
{
int transitionDuration = obs_data_get_int(transitionInfo, "duration");
Utils::SetTransitionDuration(transitionDuration);
@@ -841,28 +987,23 @@ void WSRequestHandler::HandleTransitionToProgram(WSRequestHandler *owner)
}
Utils::TransitionToProgram();
- owner->SendOKResponse();
+ req->SendOKResponse();
}
-void WSRequestHandler::HandleEnableStudioMode(WSRequestHandler *owner)
+void WSRequestHandler::HandleEnableStudioMode(WSRequestHandler *req)
{
Utils::EnablePreviewMode();
- owner->SendOKResponse();
+ req->SendOKResponse();
}
-void WSRequestHandler::HandleDisableStudioMode(WSRequestHandler *owner)
+void WSRequestHandler::HandleDisableStudioMode(WSRequestHandler *req)
{
Utils::DisablePreviewMode();
- owner->SendOKResponse();
+ req->SendOKResponse();
}
-void WSRequestHandler::HandleToggleStudioMode(WSRequestHandler *owner)
+void WSRequestHandler::HandleToggleStudioMode(WSRequestHandler *req)
{
Utils::TogglePreviewMode();
- owner->SendOKResponse();
-}
-
-void WSRequestHandler::ErrNotImplemented(WSRequestHandler *owner)
-{
- owner->SendErrorResponse("not implemented");
+ req->SendOKResponse();
}
\ No newline at end of file
diff --git a/WSRequestHandler.h b/WSRequestHandler.h
index c1c67680..a253e5db 100644
--- a/WSRequestHandler.h
+++ b/WSRequestHandler.h
@@ -32,69 +32,69 @@ class WSRequestHandler : public QObject
explicit WSRequestHandler(QWebSocket *client);
~WSRequestHandler();
void processIncomingMessage(QString textMessage);
+ bool hasField(const char* name);
private:
QWebSocket *_client;
const char *_messageId;
const char *_requestType;
- obs_data_t *_requestData;
+ obs_data_t *data;
QMap messageMap;
QSet authNotRequired;
void SendOKResponse(obs_data_t *additionalFields = NULL);
void SendErrorResponse(const char *errorMessage);
- static void ErrNotImplemented(WSRequestHandler *owner);
- static void HandleGetVersion(WSRequestHandler *owner);
- static void HandleGetAuthRequired(WSRequestHandler *owner);
- static void HandleAuthenticate(WSRequestHandler *owner);
+ static void HandleGetVersion(WSRequestHandler *req);
+ static void HandleGetAuthRequired(WSRequestHandler *req);
+ static void HandleAuthenticate(WSRequestHandler *req);
- static void HandleSetCurrentScene(WSRequestHandler *owner);
- static void HandleGetCurrentScene(WSRequestHandler *owner);
- static void HandleGetSceneList(WSRequestHandler *owner);
+ static void HandleSetCurrentScene(WSRequestHandler *req);
+ static void HandleGetCurrentScene(WSRequestHandler *req);
+ static void HandleGetSceneList(WSRequestHandler *req);
- static void HandleSetSceneItemRender(WSRequestHandler *owner);
- static void HandleSetSceneItemPosition(WSRequestHandler *owner);
- static void HandleSetSceneItemTransform(WSRequestHandler *owner);
- static void HandleSetSceneItemCrop(WSRequestHandler *owner);
+ static void HandleSetSceneItemRender(WSRequestHandler *req);
+ static void HandleSetSceneItemPosition(WSRequestHandler *req);
+ static void HandleSetSceneItemTransform(WSRequestHandler *req);
+ static void HandleSetSceneItemCrop(WSRequestHandler *req);
- static void HandleGetStreamingStatus(WSRequestHandler *owner);
- static void HandleStartStopStreaming(WSRequestHandler *owner);
- static void HandleStartStopRecording(WSRequestHandler *owner);
- static void HandleStartStreaming(WSRequestHandler *owner);
- static void HandleStopStreaming(WSRequestHandler *owner);
- static void HandleStartRecording(WSRequestHandler *owner);
- static void HandleStopRecording(WSRequestHandler *owner);
+ static void HandleGetStreamingStatus(WSRequestHandler *req);
+ static void HandleStartStopStreaming(WSRequestHandler *req);
+ static void HandleStartStopRecording(WSRequestHandler *req);
+ static void HandleStartStreaming(WSRequestHandler *req);
+ static void HandleStopStreaming(WSRequestHandler *req);
+ static void HandleStartRecording(WSRequestHandler *req);
+ static void HandleStopRecording(WSRequestHandler *req);
- static void HandleGetTransitionList(WSRequestHandler *owner);
- static void HandleGetCurrentTransition(WSRequestHandler *owner);
- static void HandleSetCurrentTransition(WSRequestHandler *owner);
+ static void HandleGetTransitionList(WSRequestHandler *req);
+ static void HandleGetCurrentTransition(WSRequestHandler *req);
+ static void HandleSetCurrentTransition(WSRequestHandler *req);
- static void HandleSetVolume(WSRequestHandler *owner);
- static void HandleGetVolume(WSRequestHandler *owner);
- static void HandleToggleMute(WSRequestHandler *owner);
- static void HandleSetMute(WSRequestHandler *owner);
- // TODO : GetMute
+ static void HandleSetVolume(WSRequestHandler *req);
+ static void HandleGetVolume(WSRequestHandler *req);
+ static void HandleToggleMute(WSRequestHandler *req);
+ static void HandleSetMute(WSRequestHandler *req);
+ static void HandleGetMute(WSRequestHandler *req);
- static void HandleSetCurrentSceneCollection(WSRequestHandler *owner);
- static void HandleGetCurrentSceneCollection(WSRequestHandler *owner);
- static void HandleListSceneCollections(WSRequestHandler *owner);
+ static void HandleSetCurrentSceneCollection(WSRequestHandler *req);
+ static void HandleGetCurrentSceneCollection(WSRequestHandler *req);
+ static void HandleListSceneCollections(WSRequestHandler *req);
- static void HandleSetCurrentProfile(WSRequestHandler *owner);
- static void HandleGetCurrentProfile(WSRequestHandler *owner);
- static void HandleListProfiles(WSRequestHandler *owner);
+ static void HandleSetCurrentProfile(WSRequestHandler *req);
+ static void HandleGetCurrentProfile(WSRequestHandler *req);
+ static void HandleListProfiles(WSRequestHandler *req);
- static void HandleSetTransitionDuration(WSRequestHandler *owner);
- static void HandleGetTransitionDuration(WSRequestHandler *owner);
+ static void HandleSetTransitionDuration(WSRequestHandler *req);
+ static void HandleGetTransitionDuration(WSRequestHandler *req);
- static void HandleGetStudioModeStatus(WSRequestHandler *owner);
- static void HandleGetPreviewScene(WSRequestHandler *owner);
- static void HandleSetPreviewScene(WSRequestHandler *owner);
- static void HandleTransitionToProgram(WSRequestHandler *owner);
- static void HandleEnableStudioMode(WSRequestHandler *owner);
- static void HandleDisableStudioMode(WSRequestHandler *owner);
- static void HandleToggleStudioMode(WSRequestHandler *owner);
+ static void HandleGetStudioModeStatus(WSRequestHandler *req);
+ static void HandleGetPreviewScene(WSRequestHandler *req);
+ static void HandleSetPreviewScene(WSRequestHandler *req);
+ static void HandleTransitionToProgram(WSRequestHandler *req);
+ static void HandleEnableStudioMode(WSRequestHandler *req);
+ static void HandleDisableStudioMode(WSRequestHandler *req);
+ static void HandleToggleStudioMode(WSRequestHandler *req);
};
#endif // WSPROTOCOL_H
diff --git a/obs-websocket.h b/obs-websocket.h
index 5114d720..ed6f87d0 100644
--- a/obs-websocket.h
+++ b/obs-websocket.h
@@ -21,6 +21,7 @@ with this program. If not, see
#define PROP_AUTHENTICATED "wsclient_authenticated"
#define OBS_WEBSOCKET_VERSION "4.1.0"
+#define API_VERSION 1.3
#define blog(level, msg, ...) blog(level, "[obs-websocket] " msg, ##__VA_ARGS__)