Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ target_sources(
src/requesthandler/RequestBatchHandler.h
src/requesthandler/RequestHandler.cpp
src/requesthandler/RequestHandler.h
src/requesthandler/RequestHandler_Canvases.cpp
src/requesthandler/RequestHandler_Config.cpp
src/requesthandler/RequestHandler_Filters.cpp
src/requesthandler/RequestHandler_General.cpp
Expand Down
3 changes: 3 additions & 0 deletions src/requesthandler/RequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ const std::unordered_map<std::string, RequestMethodHandler> RequestHandler::_han
{"GetRecordDirectory", &RequestHandler::GetRecordDirectory},
{"SetRecordDirectory", &RequestHandler::SetRecordDirectory},

// Canvases
{"GetCanvasList", &RequestHandler::GetCanvasList},

// Sources
{"GetSourceActive", &RequestHandler::GetSourceActive},
{"GetSourceScreenshot", &RequestHandler::GetSourceScreenshot},
Expand Down
3 changes: 3 additions & 0 deletions src/requesthandler/RequestHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ class RequestHandler {
RequestResult GetRecordDirectory(const Request &);
RequestResult SetRecordDirectory(const Request &);

// Canvases
RequestResult GetCanvasList(const Request &);

// Sources
RequestResult GetSourceActive(const Request &);
RequestResult GetSourceScreenshot(const Request &);
Expand Down
61 changes: 61 additions & 0 deletions src/requesthandler/RequestHandler_Canvases.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
obs-websocket
Copyright (C) 2016-2021 Stephane Lepin <[email protected]>
Copyright (C) 2020-2021 Kyle Manning <[email protected]>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program 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 General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/

#include "RequestHandler.h"

/**
* Gets an array of canvases in OBS.
*
* @responseField canvases | Array<Object> | Array of canvases
*
* @requestType GetCanvasList
* @complexity 2
* @rpcVersion -1
* @initialVersion 5.0.0
* @api requests
* @category scenes
*/
RequestResult RequestHandler::GetCanvasList(const Request &request)
{
json responseData;
std::vector<json> ret;

obs_enum_canvases(
[](void *param, obs_canvas_t *canvas) {
auto ret = static_cast<std::vector<json> *>(param);
json canvasJson;
canvasJson["canvasName"] = obs_canvas_get_name(canvas);
canvasJson["canvasUuid"] = obs_canvas_get_uuid(canvas);
struct obs_video_info ovi;
if (obs_canvas_get_video_info(canvas, &ovi)) {
canvasJson["fpsNumerator"] = ovi.fps_num;
canvasJson["fpsDenominator"] = ovi.fps_den;
canvasJson["baseWidth"] = ovi.base_width;
canvasJson["baseHeight"] = ovi.base_height;
canvasJson["outputWidth"] = ovi.output_width;
canvasJson["outputHeight"] = ovi.output_height;
}
ret->push_back(canvasJson);
return true;
},
&ret);
responseData["canvases"] = ret;

return RequestResult::Success(responseData);
}
71 changes: 51 additions & 20 deletions src/requesthandler/RequestHandler_Scenes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include "RequestHandler.h"

/**
* Gets an array of all scenes in OBS.
* Gets an array of scenes in OBS.
*
* @requestField ?canvasName | String | Canvas name to get the scenes from. If not specified, the main canvas will be used.
*
* @responseField currentProgramSceneName | String | Current program scene name. Can be `null` if internal state desync
* @responseField currentProgramSceneUuid | String | Current program scene UUID. Can be `null` if internal state desync
* @responseField currentPreviewSceneName | String | Current preview scene name. `null` if not in studio mode
Expand All @@ -35,29 +37,53 @@ with this program. If not, see <https://www.gnu.org/licenses/>
* @api requests
* @category scenes
*/
RequestResult RequestHandler::GetSceneList(const Request &)
RequestResult RequestHandler::GetSceneList(const Request &request)
{
json responseData;

OBSSourceAutoRelease currentProgramScene = obs_frontend_get_current_scene();
if (currentProgramScene) {
responseData["currentProgramSceneName"] = obs_source_get_name(currentProgramScene);
responseData["currentProgramSceneUuid"] = obs_source_get_uuid(currentProgramScene);
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSCanvasAutoRelease canvas = request.ValidateCanvas("canvasName", statusCode, comment);
if (statusCode == RequestStatus::ResourceNotFound)
return RequestResult::Error(statusCode, comment);
if (canvas) {
OBSSourceAutoRelease programSource = obs_canvas_get_channel(canvas, 0);
if (programSource && obs_source_get_type(programSource) == OBS_SOURCE_TYPE_TRANSITION) {
OBSSourceAutoRelease activeSource = obs_transition_get_active_source(programSource);
if (activeSource) {
responseData["currentProgramSceneName"] = obs_source_get_name(activeSource);
responseData["currentProgramSceneUuid"] = obs_source_get_uuid(activeSource);
} else {
responseData["currentProgramSceneName"] = nullptr;
responseData["currentProgramSceneUuid"] = nullptr;
}
} else if (programSource && obs_source_is_scene(programSource)) {
responseData["currentProgramSceneName"] = obs_source_get_name(programSource);
responseData["currentProgramSceneUuid"] = obs_source_get_uuid(programSource);
} else {
responseData["currentProgramSceneName"] = nullptr;
responseData["currentProgramSceneUuid"] = nullptr;
}
} else {
responseData["currentProgramSceneName"] = nullptr;
responseData["currentProgramSceneUuid"] = nullptr;
}
OBSSourceAutoRelease currentProgramScene = obs_frontend_get_current_scene();
if (currentProgramScene) {
responseData["currentProgramSceneName"] = obs_source_get_name(currentProgramScene);
responseData["currentProgramSceneUuid"] = obs_source_get_uuid(currentProgramScene);
} else {
responseData["currentProgramSceneName"] = nullptr;
responseData["currentProgramSceneUuid"] = nullptr;
}

OBSSourceAutoRelease currentPreviewScene = obs_frontend_get_current_preview_scene();
if (currentPreviewScene) {
responseData["currentPreviewSceneName"] = obs_source_get_name(currentPreviewScene);
responseData["currentPreviewSceneUuid"] = obs_source_get_uuid(currentPreviewScene);
} else {
responseData["currentPreviewSceneName"] = nullptr;
responseData["currentPreviewSceneUuid"] = nullptr;
OBSSourceAutoRelease currentPreviewScene = obs_frontend_get_current_preview_scene();
if (currentPreviewScene) {
responseData["currentPreviewSceneName"] = obs_source_get_name(currentPreviewScene);
responseData["currentPreviewSceneUuid"] = obs_source_get_uuid(currentPreviewScene);
} else {
responseData["currentPreviewSceneName"] = nullptr;
responseData["currentPreviewSceneUuid"] = nullptr;
}
}

responseData["scenes"] = Utils::Obs::ArrayHelper::GetSceneList();
responseData["scenes"] = Utils::Obs::ArrayHelper::GetSceneList(canvas);

return RequestResult::Success(responseData);
}
Expand All @@ -76,11 +102,16 @@ RequestResult RequestHandler::GetSceneList(const Request &)
* @api requests
* @category scenes
*/
RequestResult RequestHandler::GetGroupList(const Request &)
RequestResult RequestHandler::GetGroupList(const Request &request)
{
json responseData;
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSCanvasAutoRelease canvas = request.ValidateCanvas("canvasName", statusCode, comment);
if (statusCode == RequestStatus::ResourceNotFound)
return RequestResult::Error(statusCode, comment);

responseData["groups"] = Utils::Obs::ArrayHelper::GetGroupList();
responseData["groups"] = Utils::Obs::ArrayHelper::GetGroupList(canvas);

return RequestResult::Success(responseData);
}
Expand Down
18 changes: 18 additions & 0 deletions src/requesthandler/rpc/Request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,3 +383,21 @@ obs_output_t *Request::ValidateOutput(const std::string &keyName, RequestStatus:

return ret;
}

obs_canvas_t *Request::ValidateCanvas(const std::string &keyName, RequestStatus::RequestStatus &statusCode,
std::string &comment) const
{
if (!ValidateString(keyName, statusCode, comment))
return nullptr;

std::string canvasName = RequestData[keyName];

obs_canvas_t *ret = obs_get_canvas_by_name(canvasName.c_str());
if (!ret) {
statusCode = RequestStatus::ResourceNotFound;
comment = std::string("No canvas was found with the name `") + canvasName + "`.";
return nullptr;
}

return ret;
}
2 changes: 2 additions & 0 deletions src/requesthandler/rpc/Request.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ struct Request {
const ObsWebSocketSceneFilter filter = OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY) const;
obs_output_t *ValidateOutput(const std::string &keyName, RequestStatus::RequestStatus &statusCode,
std::string &comment) const;
obs_canvas_t *ValidateCanvas(const std::string &keyName, RequestStatus::RequestStatus &statusCode,
std::string &comment) const;

std::string RequestType;
bool HasRequestData;
Expand Down
4 changes: 2 additions & 2 deletions src/utils/Obs.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@ namespace Utils {
std::vector<std::string> GetProfileList();
std::vector<obs_hotkey_t *> GetHotkeyList();
std::vector<std::string> GetHotkeyNameList();
std::vector<json> GetSceneList();
std::vector<std::string> GetGroupList();
std::vector<json> GetSceneList(obs_canvas_t* canvas = NULL);
std::vector<std::string> GetGroupList(obs_canvas_t *canvas = NULL);
std::vector<json> GetSceneItemList(obs_scene_t *scene, bool basic = false);
std::vector<json> GetInputList(std::string inputKind = "");
std::vector<std::string> GetInputKindList(bool unversioned = false, bool includeDisabled = false);
Expand Down
57 changes: 39 additions & 18 deletions src/utils/Obs_ArrayHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,33 +84,50 @@ std::vector<std::string> Utils::Obs::ArrayHelper::GetHotkeyNameList()
return ret;
}

std::vector<json> Utils::Obs::ArrayHelper::GetSceneList()
std::vector<json> Utils::Obs::ArrayHelper::GetSceneList(obs_canvas_t *canvas)
{
obs_frontend_source_list sceneList = {};
obs_frontend_get_scenes(&sceneList);

std::vector<json> ret;
ret.reserve(sceneList.sources.num);
for (size_t i = 0; i < sceneList.sources.num; i++) {
obs_source_t *scene = sceneList.sources.array[i];
if (canvas) {
obs_canvas_enum_scenes(
canvas,
[](void *param, obs_source_t *scene) {
auto ret = static_cast<std::vector<json> *>(param);
json sceneJson;
sceneJson["sceneName"] = obs_source_get_name(scene);
sceneJson["sceneUuid"] = obs_source_get_uuid(scene);
ret->push_back(sceneJson);
return true;
},
&ret);
for (size_t i = 0; i < ret.size(); i++) {
ret[i]["sceneIndex"] = i + 1;
}
} else {

json sceneJson;
sceneJson["sceneName"] = obs_source_get_name(scene);
sceneJson["sceneUuid"] = obs_source_get_uuid(scene);
sceneJson["sceneIndex"] = sceneList.sources.num - i - 1;
obs_frontend_source_list sceneList = {};
obs_frontend_get_scenes(&sceneList);

ret.push_back(sceneJson);
}
ret.reserve(sceneList.sources.num);
for (size_t i = 0; i < sceneList.sources.num; i++) {
obs_source_t *scene = sceneList.sources.array[i];

obs_frontend_source_list_free(&sceneList);
json sceneJson;
sceneJson["sceneName"] = obs_source_get_name(scene);
sceneJson["sceneUuid"] = obs_source_get_uuid(scene);
sceneJson["sceneIndex"] = sceneList.sources.num - i - 1;

// Reverse the vector order to match other array returns
std::reverse(ret.begin(), ret.end());
ret.push_back(sceneJson);
}

obs_frontend_source_list_free(&sceneList);

// Reverse the vector order to match other array returns
std::reverse(ret.begin(), ret.end());
}
return ret;
}

std::vector<std::string> Utils::Obs::ArrayHelper::GetGroupList()
std::vector<std::string> Utils::Obs::ArrayHelper::GetGroupList(obs_canvas_t *canvas)
{
std::vector<std::string> ret;

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

obs_enum_scenes(cb, &ret);
if (canvas) {
obs_canvas_enum_scenes(canvas, cb, &ret);
} else {
obs_enum_scenes(cb, &ret);
}

return ret;
}
Expand Down