Skip to content

Commit ef48772

Browse files
committed
requesthandler: Add Canvas support
1 parent 40d26db commit ef48772

File tree

9 files changed

+180
-40
lines changed

9 files changed

+180
-40
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ target_sources(
8080
src/requesthandler/RequestBatchHandler.h
8181
src/requesthandler/RequestHandler.cpp
8282
src/requesthandler/RequestHandler.h
83+
src/requesthandler/RequestHandler_Canvases.cpp
8384
src/requesthandler/RequestHandler_Config.cpp
8485
src/requesthandler/RequestHandler_Filters.cpp
8586
src/requesthandler/RequestHandler_General.cpp

src/requesthandler/RequestHandler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ const std::unordered_map<std::string, RequestMethodHandler> RequestHandler::_han
5353
{"GetRecordDirectory", &RequestHandler::GetRecordDirectory},
5454
{"SetRecordDirectory", &RequestHandler::SetRecordDirectory},
5555

56+
// Canvases
57+
{"GetCanvasList", &RequestHandler::GetCanvasList},
58+
5659
// Sources
5760
{"GetSourceActive", &RequestHandler::GetSourceActive},
5861
{"GetSourceScreenshot", &RequestHandler::GetSourceScreenshot},

src/requesthandler/RequestHandler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ class RequestHandler {
7272
RequestResult GetRecordDirectory(const Request &);
7373
RequestResult SetRecordDirectory(const Request &);
7474

75+
// Canvases
76+
RequestResult GetCanvasList(const Request &);
77+
7578
// Sources
7679
RequestResult GetSourceActive(const Request &);
7780
RequestResult GetSourceScreenshot(const Request &);
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
obs-websocket
3+
Copyright (C) 2016-2021 Stephane Lepin <[email protected]>
4+
Copyright (C) 2020-2021 Kyle Manning <[email protected]>
5+
6+
This program is free software; you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation; either version 2 of the License, or
9+
(at your option) any later version.
10+
11+
This program is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License along
17+
with this program. If not, see <https://www.gnu.org/licenses/>
18+
*/
19+
20+
#include "RequestHandler.h"
21+
22+
/**
23+
* Gets an array of canvases in OBS.
24+
*
25+
* @responseField canvases | Array<Object> | Array of canvases
26+
*
27+
* @requestType GetCanvasList
28+
* @complexity 2
29+
* @rpcVersion -1
30+
* @initialVersion 5.0.0
31+
* @api requests
32+
* @category scenes
33+
*/
34+
RequestResult RequestHandler::GetCanvasList(const Request &request)
35+
{
36+
json responseData;
37+
std::vector<json> ret;
38+
39+
obs_enum_canvases(
40+
[](void *param, obs_canvas_t *canvas) {
41+
auto ret = static_cast<std::vector<json> *>(param);
42+
json canvasJson;
43+
canvasJson["canvasName"] = obs_canvas_get_name(canvas);
44+
canvasJson["canvasUuid"] = obs_canvas_get_uuid(canvas);
45+
struct obs_video_info ovi;
46+
if (obs_canvas_get_video_info(canvas, &ovi)) {
47+
canvasJson["fpsNumerator"] = ovi.fps_num;
48+
canvasJson["fpsDenominator"] = ovi.fps_den;
49+
canvasJson["baseWidth"] = ovi.base_width;
50+
canvasJson["baseHeight"] = ovi.base_height;
51+
canvasJson["outputWidth"] = ovi.output_width;
52+
canvasJson["outputHeight"] = ovi.output_height;
53+
}
54+
ret->push_back(canvasJson);
55+
return true;
56+
},
57+
&ret);
58+
responseData["canvases"] = ret;
59+
60+
return RequestResult::Success(responseData);
61+
}

src/requesthandler/RequestHandler_Scenes.cpp

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ with this program. If not, see <https://www.gnu.org/licenses/>
2020
#include "RequestHandler.h"
2121

2222
/**
23-
* Gets an array of all scenes in OBS.
23+
* Gets an array of scenes in OBS.
2424
*
25+
* @requestField ?canvasName | String | Canvas name to get the scenes from. If not specified, the main canvas will be used.
26+
*
2527
* @responseField currentProgramSceneName | String | Current program scene name. Can be `null` if internal state desync
2628
* @responseField currentProgramSceneUuid | String | Current program scene UUID. Can be `null` if internal state desync
2729
* @responseField currentPreviewSceneName | String | Current preview scene name. `null` if not in studio mode
@@ -35,29 +37,53 @@ with this program. If not, see <https://www.gnu.org/licenses/>
3537
* @api requests
3638
* @category scenes
3739
*/
38-
RequestResult RequestHandler::GetSceneList(const Request &)
40+
RequestResult RequestHandler::GetSceneList(const Request &request)
3941
{
4042
json responseData;
41-
42-
OBSSourceAutoRelease currentProgramScene = obs_frontend_get_current_scene();
43-
if (currentProgramScene) {
44-
responseData["currentProgramSceneName"] = obs_source_get_name(currentProgramScene);
45-
responseData["currentProgramSceneUuid"] = obs_source_get_uuid(currentProgramScene);
43+
RequestStatus::RequestStatus statusCode;
44+
std::string comment;
45+
OBSCanvasAutoRelease canvas = request.ValidateCanvas("canvasName", statusCode, comment);
46+
if (statusCode == RequestStatus::ResourceNotFound)
47+
return RequestResult::Error(statusCode, comment);
48+
if (canvas) {
49+
OBSSourceAutoRelease programSource = obs_canvas_get_channel(canvas, 0);
50+
if (programSource && obs_source_get_type(programSource) == OBS_SOURCE_TYPE_TRANSITION) {
51+
OBSSourceAutoRelease activeSource = obs_transition_get_active_source(programSource);
52+
if (activeSource) {
53+
responseData["currentProgramSceneName"] = obs_source_get_name(activeSource);
54+
responseData["currentProgramSceneUuid"] = obs_source_get_uuid(activeSource);
55+
} else {
56+
responseData["currentProgramSceneName"] = nullptr;
57+
responseData["currentProgramSceneUuid"] = nullptr;
58+
}
59+
} else if (programSource && obs_source_is_scene(programSource)) {
60+
responseData["currentProgramSceneName"] = obs_source_get_name(programSource);
61+
responseData["currentProgramSceneUuid"] = obs_source_get_uuid(programSource);
62+
} else {
63+
responseData["currentProgramSceneName"] = nullptr;
64+
responseData["currentProgramSceneUuid"] = nullptr;
65+
}
4666
} else {
47-
responseData["currentProgramSceneName"] = nullptr;
48-
responseData["currentProgramSceneUuid"] = nullptr;
49-
}
67+
OBSSourceAutoRelease currentProgramScene = obs_frontend_get_current_scene();
68+
if (currentProgramScene) {
69+
responseData["currentProgramSceneName"] = obs_source_get_name(currentProgramScene);
70+
responseData["currentProgramSceneUuid"] = obs_source_get_uuid(currentProgramScene);
71+
} else {
72+
responseData["currentProgramSceneName"] = nullptr;
73+
responseData["currentProgramSceneUuid"] = nullptr;
74+
}
5075

51-
OBSSourceAutoRelease currentPreviewScene = obs_frontend_get_current_preview_scene();
52-
if (currentPreviewScene) {
53-
responseData["currentPreviewSceneName"] = obs_source_get_name(currentPreviewScene);
54-
responseData["currentPreviewSceneUuid"] = obs_source_get_uuid(currentPreviewScene);
55-
} else {
56-
responseData["currentPreviewSceneName"] = nullptr;
57-
responseData["currentPreviewSceneUuid"] = nullptr;
76+
OBSSourceAutoRelease currentPreviewScene = obs_frontend_get_current_preview_scene();
77+
if (currentPreviewScene) {
78+
responseData["currentPreviewSceneName"] = obs_source_get_name(currentPreviewScene);
79+
responseData["currentPreviewSceneUuid"] = obs_source_get_uuid(currentPreviewScene);
80+
} else {
81+
responseData["currentPreviewSceneName"] = nullptr;
82+
responseData["currentPreviewSceneUuid"] = nullptr;
83+
}
5884
}
5985

60-
responseData["scenes"] = Utils::Obs::ArrayHelper::GetSceneList();
86+
responseData["scenes"] = Utils::Obs::ArrayHelper::GetSceneList(canvas);
6187

6288
return RequestResult::Success(responseData);
6389
}
@@ -76,11 +102,16 @@ RequestResult RequestHandler::GetSceneList(const Request &)
76102
* @api requests
77103
* @category scenes
78104
*/
79-
RequestResult RequestHandler::GetGroupList(const Request &)
105+
RequestResult RequestHandler::GetGroupList(const Request &request)
80106
{
81107
json responseData;
108+
RequestStatus::RequestStatus statusCode;
109+
std::string comment;
110+
OBSCanvasAutoRelease canvas = request.ValidateCanvas("canvasName", statusCode, comment);
111+
if (statusCode == RequestStatus::ResourceNotFound)
112+
return RequestResult::Error(statusCode, comment);
82113

83-
responseData["groups"] = Utils::Obs::ArrayHelper::GetGroupList();
114+
responseData["groups"] = Utils::Obs::ArrayHelper::GetGroupList(canvas);
84115

85116
return RequestResult::Success(responseData);
86117
}

src/requesthandler/rpc/Request.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,3 +383,21 @@ obs_output_t *Request::ValidateOutput(const std::string &keyName, RequestStatus:
383383

384384
return ret;
385385
}
386+
387+
obs_canvas_t *Request::ValidateCanvas(const std::string &keyName, RequestStatus::RequestStatus &statusCode,
388+
std::string &comment) const
389+
{
390+
if (!ValidateString(keyName, statusCode, comment))
391+
return nullptr;
392+
393+
std::string canvasName = RequestData[keyName];
394+
395+
obs_canvas_t *ret = obs_get_canvas_by_name(canvasName.c_str());
396+
if (!ret) {
397+
statusCode = RequestStatus::ResourceNotFound;
398+
comment = std::string("No canvas was found with the name `") + canvasName + "`.";
399+
return nullptr;
400+
}
401+
402+
return ret;
403+
}

src/requesthandler/rpc/Request.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ struct Request {
7676
const ObsWebSocketSceneFilter filter = OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY) const;
7777
obs_output_t *ValidateOutput(const std::string &keyName, RequestStatus::RequestStatus &statusCode,
7878
std::string &comment) const;
79+
obs_canvas_t *ValidateCanvas(const std::string &keyName, RequestStatus::RequestStatus &statusCode,
80+
std::string &comment) const;
7981

8082
std::string RequestType;
8183
bool HasRequestData;

src/utils/Obs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ namespace Utils {
249249
std::vector<std::string> GetProfileList();
250250
std::vector<obs_hotkey_t *> GetHotkeyList();
251251
std::vector<std::string> GetHotkeyNameList();
252-
std::vector<json> GetSceneList();
253-
std::vector<std::string> GetGroupList();
252+
std::vector<json> GetSceneList(obs_canvas_t* canvas = NULL);
253+
std::vector<std::string> GetGroupList(obs_canvas_t *canvas = NULL);
254254
std::vector<json> GetSceneItemList(obs_scene_t *scene, bool basic = false);
255255
std::vector<json> GetInputList(std::string inputKind = "");
256256
std::vector<std::string> GetInputKindList(bool unversioned = false, bool includeDisabled = false);

src/utils/Obs_ArrayHelper.cpp

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -84,33 +84,50 @@ std::vector<std::string> Utils::Obs::ArrayHelper::GetHotkeyNameList()
8484
return ret;
8585
}
8686

87-
std::vector<json> Utils::Obs::ArrayHelper::GetSceneList()
87+
std::vector<json> Utils::Obs::ArrayHelper::GetSceneList(obs_canvas_t *canvas)
8888
{
89-
obs_frontend_source_list sceneList = {};
90-
obs_frontend_get_scenes(&sceneList);
91-
9289
std::vector<json> ret;
93-
ret.reserve(sceneList.sources.num);
94-
for (size_t i = 0; i < sceneList.sources.num; i++) {
95-
obs_source_t *scene = sceneList.sources.array[i];
90+
if (canvas) {
91+
obs_canvas_enum_scenes(
92+
canvas,
93+
[](void *param, obs_source_t *scene) {
94+
auto ret = static_cast<std::vector<json> *>(param);
95+
json sceneJson;
96+
sceneJson["sceneName"] = obs_source_get_name(scene);
97+
sceneJson["sceneUuid"] = obs_source_get_uuid(scene);
98+
ret->push_back(sceneJson);
99+
return true;
100+
},
101+
&ret);
102+
for (size_t i = 0; i < ret.size(); i++) {
103+
ret[i]["sceneIndex"] = i + 1;
104+
}
105+
} else {
96106

97-
json sceneJson;
98-
sceneJson["sceneName"] = obs_source_get_name(scene);
99-
sceneJson["sceneUuid"] = obs_source_get_uuid(scene);
100-
sceneJson["sceneIndex"] = sceneList.sources.num - i - 1;
107+
obs_frontend_source_list sceneList = {};
108+
obs_frontend_get_scenes(&sceneList);
101109

102-
ret.push_back(sceneJson);
103-
}
110+
ret.reserve(sceneList.sources.num);
111+
for (size_t i = 0; i < sceneList.sources.num; i++) {
112+
obs_source_t *scene = sceneList.sources.array[i];
104113

105-
obs_frontend_source_list_free(&sceneList);
114+
json sceneJson;
115+
sceneJson["sceneName"] = obs_source_get_name(scene);
116+
sceneJson["sceneUuid"] = obs_source_get_uuid(scene);
117+
sceneJson["sceneIndex"] = sceneList.sources.num - i - 1;
106118

107-
// Reverse the vector order to match other array returns
108-
std::reverse(ret.begin(), ret.end());
119+
ret.push_back(sceneJson);
120+
}
109121

122+
obs_frontend_source_list_free(&sceneList);
123+
124+
// Reverse the vector order to match other array returns
125+
std::reverse(ret.begin(), ret.end());
126+
}
110127
return ret;
111128
}
112129

113-
std::vector<std::string> Utils::Obs::ArrayHelper::GetGroupList()
130+
std::vector<std::string> Utils::Obs::ArrayHelper::GetGroupList(obs_canvas_t *canvas)
114131
{
115132
std::vector<std::string> ret;
116133

@@ -125,7 +142,11 @@ std::vector<std::string> Utils::Obs::ArrayHelper::GetGroupList()
125142
return true;
126143
};
127144

128-
obs_enum_scenes(cb, &ret);
145+
if (canvas) {
146+
obs_canvas_enum_scenes(canvas, cb, &ret);
147+
} else {
148+
obs_enum_scenes(cb, &ret);
149+
}
129150

130151
return ret;
131152
}

0 commit comments

Comments
 (0)