From 78ae8b1f77dfc0a8ad91af65073e505bf8633d22 Mon Sep 17 00:00:00 2001 From: Exeldro Date: Wed, 20 Aug 2025 18:16:10 +0200 Subject: [PATCH] requesthandler: Add Canvas support --- CMakeLists.txt | 2 + docs/docs/generate_md.py | 1 + src/eventhandler/EventHandler.cpp | 57 ++++++++ src/eventhandler/EventHandler.h | 9 ++ src/eventhandler/EventHandler_Canvases.cpp | 88 ++++++++++++ src/eventhandler/EventHandler_SceneItems.cpp | 35 +++++ src/eventhandler/EventHandler_Scenes.cpp | 15 +++ src/eventhandler/types/EventSubscription.h | 15 ++- src/requesthandler/RequestHandler.cpp | 3 + src/requesthandler/RequestHandler.h | 3 + .../RequestHandler_Canvases.cpp | 62 +++++++++ src/requesthandler/RequestHandler_Filters.cpp | 16 +++ src/requesthandler/RequestHandler_Inputs.cpp | 2 + .../RequestHandler_SceneItems.cpp | 42 +++++- src/requesthandler/RequestHandler_Scenes.cpp | 126 ++++++++++++++---- src/requesthandler/RequestHandler_Sources.cpp | 6 + src/requesthandler/RequestHandler_Ui.cpp | 2 + src/requesthandler/rpc/Request.cpp | 35 ++++- src/requesthandler/rpc/Request.h | 3 + src/utils/Obs.h | 3 + src/utils/Obs_ArrayHelper.cpp | 30 ++++- src/utils/Obs_NumberHelper.cpp | 8 +- 22 files changed, 526 insertions(+), 37 deletions(-) create mode 100644 src/eventhandler/EventHandler_Canvases.cpp create mode 100644 src/requesthandler/RequestHandler_Canvases.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 540577276..e576877c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,7 @@ target_sources( PRIVATE # cmake-format: sortable src/eventhandler/EventHandler.cpp src/eventhandler/EventHandler.h + src/eventhandler/EventHandler_Canvases.cpp src/eventhandler/EventHandler_Config.cpp src/eventhandler/EventHandler_Filters.cpp src/eventhandler/EventHandler_General.cpp @@ -80,6 +81,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 diff --git a/docs/docs/generate_md.py b/docs/docs/generate_md.py index ee7462815..fc1db33a3 100644 --- a/docs/docs/generate_md.py +++ b/docs/docs/generate_md.py @@ -18,6 +18,7 @@ 'General', 'Config', 'Sources', + 'Canvas', 'Scenes', 'Inputs', 'Transitions', diff --git a/src/eventhandler/EventHandler.cpp b/src/eventhandler/EventHandler.cpp index 05e46ab6f..dd789a8d0 100644 --- a/src/eventhandler/EventHandler.cpp +++ b/src/eventhandler/EventHandler.cpp @@ -28,10 +28,15 @@ EventHandler::EventHandler() signal_handler_t *coreSignalHandler = obs_get_signal_handler(); if (coreSignalHandler) { coreSignals.emplace_back(coreSignalHandler, "source_create", SourceCreatedMultiHandler, this); + coreSignals.emplace_back(coreSignalHandler, "source_create_canvas", SourceCreatedMultiHandler, this); coreSignals.emplace_back(coreSignalHandler, "source_destroy", SourceDestroyedMultiHandler, this); coreSignals.emplace_back(coreSignalHandler, "source_remove", SourceRemovedMultiHandler, this); coreSignals.emplace_back(coreSignalHandler, "source_rename", SourceRenamedMultiHandler, this); coreSignals.emplace_back(coreSignalHandler, "source_update", SourceUpdatedMultiHandler, this); + coreSignals.emplace_back(coreSignalHandler, "canvas_create", CanvasCreatedMultiHandler, this); + coreSignals.emplace_back(coreSignalHandler, "canvas_destroy", CanvasDestroyedMultiHandler, this); + coreSignals.emplace_back(coreSignalHandler, "canvas_remove", CanvasRemovedMultiHandler, this); + coreSignals.emplace_back(coreSignalHandler, "canvas_rename", CanvasRenamedMultiHandler, this); } else { blog(LOG_ERROR, "[EventHandler::EventHandler] Unable to get libobs signal handler!"); } @@ -599,6 +604,58 @@ void EventHandler::SourceUpdatedMultiHandler(void *param, calldata_t *data) } } +void EventHandler::CanvasCreatedMultiHandler(void *param, calldata_t *data) +{ + auto eventHandler = static_cast(param); + obs_canvas_t *canvas = GetCalldataPointer(data, "canvas"); + if (!canvas) + return; + + signal_handler_t *sh = obs_canvas_get_signal_handler(canvas); + signal_handler_connect(sh, "source_rename", SourceRenamedMultiHandler, eventHandler); + + eventHandler->HandleCanvasCreated(canvas); +} + +void EventHandler::CanvasDestroyedMultiHandler(void *param, calldata_t *data) +{ + auto eventHandler = static_cast(param); + obs_canvas_t *canvas = GetCalldataPointer(data, "canvas"); + if (!canvas) + return; + + if (!obs_canvas_removed(canvas)) + eventHandler->HandleCanvasRemoved(canvas); +} + +void EventHandler::CanvasRemovedMultiHandler(void *param, calldata_t *data) +{ + auto eventHandler = static_cast(param); + obs_canvas_t *canvas = GetCalldataPointer(data, "canvas"); + if (!canvas) + return; + + signal_handler_t *sh = obs_canvas_get_signal_handler(canvas); + signal_handler_disconnect(sh, "source_rename", SourceRenamedMultiHandler, eventHandler); + + eventHandler->HandleCanvasRemoved(canvas); +} + +void EventHandler::CanvasRenamedMultiHandler(void *param, calldata_t *data) +{ + auto eventHandler = static_cast(param); + obs_canvas_t *canvas = GetCalldataPointer(data, "canvas"); + if (!canvas) + return; + + std::string oldCanvasName = calldata_string(data, "prev_name"); + std::string canvasName = calldata_string(data, "new_name"); + if (oldCanvasName.empty() || canvasName.empty()) + return; + + eventHandler->HandleCanvasNameChanged(canvas, oldCanvasName, canvasName); +} + void EventHandler::StreamOutputReconnectHandler(void *param, calldata_t *) { auto eventHandler = static_cast(param); diff --git a/src/eventhandler/EventHandler.h b/src/eventhandler/EventHandler.h index 0811c52a5..7d32cf1b4 100644 --- a/src/eventhandler/EventHandler.h +++ b/src/eventhandler/EventHandler.h @@ -76,6 +76,10 @@ class EventHandler { static void SourceRemovedMultiHandler(void *param, calldata_t *data); static void SourceRenamedMultiHandler(void *param, calldata_t *data); static void SourceUpdatedMultiHandler(void *param, calldata_t *data); + static void CanvasCreatedMultiHandler(void *param, calldata_t *data); + static void CanvasDestroyedMultiHandler(void *param, calldata_t *data); + static void CanvasRemovedMultiHandler(void *param, calldata_t *data); + static void CanvasRenamedMultiHandler(void *param, calldata_t *data); // Signal handler: media sources static void SourceMediaPauseMultiHandler(void *param, calldata_t *data); @@ -100,6 +104,11 @@ class EventHandler { void HandleCurrentProfileChanged(); void HandleProfileListChanged(); + // Canvases + void HandleCanvasCreated(obs_canvas_t *canvas); + void HandleCanvasRemoved(obs_canvas_t *canvas); + void HandleCanvasNameChanged(obs_canvas_t *canvas, std::string oldCanvasName, std::string canvasName); + // Scenes void HandleSceneCreated(obs_source_t *source); void HandleSceneRemoved(obs_source_t *source); diff --git a/src/eventhandler/EventHandler_Canvases.cpp b/src/eventhandler/EventHandler_Canvases.cpp new file mode 100644 index 000000000..6151e74e9 --- /dev/null +++ b/src/eventhandler/EventHandler_Canvases.cpp @@ -0,0 +1,88 @@ +/* +obs-websocket +Copyright (C) 2016-2021 Stephane Lepin +Copyright (C) 2020-2021 Kyle Manning + +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 +*/ + +#include "EventHandler.h" + +/** + * A new canvas has been created. + * + * @dataField canvasName | String | Name of the new canvas + * @dataField canvasUuid | String | UUID of the new canvas + * + * @eventType CanvasCreated + * @eventSubscription Canvases + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.7.0 + * @api events + * @category canvas + */ +void EventHandler::HandleCanvasCreated(obs_canvas_t *canvas) +{ + json eventData; + eventData["canvasName"] = obs_canvas_get_name(canvas); + eventData["canvasUuid"] = obs_canvas_get_uuid(canvas); + BroadcastEvent(EventSubscription::Canvases, "CanvasCreated", eventData); +} + +/** + * A canvas has been removed. + * + * @dataField canvasName | String | Name of the removed canvas + * @dataField canvasUuid | String | UUID of the removed canvas + * + * @eventType CanvasRemoved + * @eventSubscription Canvases + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.7.0 + * @api events + * @category canvas + */ +void EventHandler::HandleCanvasRemoved(obs_canvas_t *canvas) +{ + json eventData; + eventData["canvasName"] = obs_canvas_get_name(canvas); + eventData["canvasUuid"] = obs_canvas_get_uuid(canvas); + BroadcastEvent(EventSubscription::Canvases, "CanvasRemoved", eventData); +} + +/** + * The name of a canvas has changed. + * + * @dataField canvasUuid | String | UUID of the canvas + * @dataField oldCanvasName | String | Old name of the canvas + * @dataField canvasName | String | New name of the canvas + * + * @eventType CanvasNameChanged + * @eventSubscription Canvases + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.7.0 + * @api events + * @category canvas + */ +void EventHandler::HandleCanvasNameChanged(obs_canvas_t *canvas, std::string oldCanvasName, std::string canvasName) +{ + json eventData; + eventData["canvasUuid"] = obs_canvas_get_uuid(canvas); + eventData["oldCanvasName"] = oldCanvasName; + eventData["canvasName"] = canvasName; + BroadcastEvent(EventSubscription::Canvases, "CanvasNameChanged", eventData); +} diff --git a/src/eventhandler/EventHandler_SceneItems.cpp b/src/eventhandler/EventHandler_SceneItems.cpp index bad166321..ebd871a60 100644 --- a/src/eventhandler/EventHandler_SceneItems.cpp +++ b/src/eventhandler/EventHandler_SceneItems.cpp @@ -56,6 +56,11 @@ void EventHandler::HandleSceneItemCreated(void *param, calldata_t *data) eventData["sourceUuid"] = obs_source_get_uuid(obs_sceneitem_get_source(sceneItem)); eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem); eventData["sceneItemIndex"] = obs_sceneitem_get_order_position(sceneItem); + OBSCanvasAutoRelease canvas = obs_source_get_canvas(obs_scene_get_source(scene)); + if (canvas) { + eventData["canvasName"] = obs_canvas_get_name(canvas); + eventData["canvasUuid"] = obs_canvas_get_uuid(canvas); + } eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemCreated", eventData); } @@ -96,6 +101,11 @@ void EventHandler::HandleSceneItemRemoved(void *param, calldata_t *data) eventData["sourceName"] = obs_source_get_name(obs_sceneitem_get_source(sceneItem)); eventData["sourceUuid"] = obs_source_get_uuid(obs_sceneitem_get_source(sceneItem)); eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem); + OBSCanvasAutoRelease canvas = obs_source_get_canvas(obs_scene_get_source(scene)); + if (canvas) { + eventData["canvasName"] = obs_canvas_get_name(canvas); + eventData["canvasUuid"] = obs_canvas_get_uuid(canvas); + } eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemRemoved", eventData); } @@ -126,6 +136,11 @@ void EventHandler::HandleSceneItemListReindexed(void *param, calldata_t *data) eventData["sceneName"] = obs_source_get_name(obs_scene_get_source(scene)); eventData["sceneUuid"] = obs_source_get_uuid(obs_scene_get_source(scene)); eventData["sceneItems"] = Utils::Obs::ArrayHelper::GetSceneItemList(scene, true); + OBSCanvasAutoRelease canvas = obs_source_get_canvas(obs_scene_get_source(scene)); + if (canvas) { + eventData["canvasName"] = obs_canvas_get_name(canvas); + eventData["canvasUuid"] = obs_canvas_get_uuid(canvas); + } eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemListReindexed", eventData); } @@ -164,6 +179,11 @@ void EventHandler::HandleSceneItemEnableStateChanged(void *param, calldata_t *da eventData["sceneUuid"] = obs_source_get_uuid(obs_scene_get_source(scene)); eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem); eventData["sceneItemEnabled"] = sceneItemEnabled; + OBSCanvasAutoRelease canvas = obs_source_get_canvas(obs_scene_get_source(scene)); + if (canvas) { + eventData["canvasName"] = obs_canvas_get_name(canvas); + eventData["canvasUuid"] = obs_canvas_get_uuid(canvas); + } eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemEnableStateChanged", eventData); } @@ -202,6 +222,11 @@ void EventHandler::HandleSceneItemLockStateChanged(void *param, calldata_t *data eventData["sceneUuid"] = obs_source_get_uuid(obs_scene_get_source(scene)); eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem); eventData["sceneItemLocked"] = sceneItemLocked; + OBSCanvasAutoRelease canvas = obs_source_get_canvas(obs_scene_get_source(scene)); + if (canvas) { + eventData["canvasName"] = obs_canvas_get_name(canvas); + eventData["canvasUuid"] = obs_canvas_get_uuid(canvas); + } eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemLockStateChanged", eventData); } @@ -236,6 +261,11 @@ void EventHandler::HandleSceneItemSelected(void *param, calldata_t *data) eventData["sceneName"] = obs_source_get_name(obs_scene_get_source(scene)); eventData["sceneUuid"] = obs_source_get_uuid(obs_scene_get_source(scene)); eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem); + OBSCanvasAutoRelease canvas = obs_source_get_canvas(obs_scene_get_source(scene)); + if (canvas) { + eventData["canvasName"] = obs_canvas_get_name(canvas); + eventData["canvasUuid"] = obs_canvas_get_uuid(canvas); + } eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemSelected", eventData); } @@ -275,5 +305,10 @@ void EventHandler::HandleSceneItemTransformChanged(void *param, calldata_t *data eventData["sceneUuid"] = obs_source_get_uuid(obs_scene_get_source(scene)); eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem); eventData["sceneItemTransform"] = Utils::Obs::ObjectHelper::GetSceneItemTransform(sceneItem); + OBSCanvasAutoRelease canvas = obs_source_get_canvas(obs_scene_get_source(scene)); + if (canvas) { + eventData["canvasName"] = obs_canvas_get_name(canvas); + eventData["canvasUuid"] = obs_canvas_get_uuid(canvas); + } eventHandler->BroadcastEvent(EventSubscription::SceneItemTransformChanged, "SceneItemTransformChanged", eventData); } diff --git a/src/eventhandler/EventHandler_Scenes.cpp b/src/eventhandler/EventHandler_Scenes.cpp index b8dcdf6e7..4480899ba 100644 --- a/src/eventhandler/EventHandler_Scenes.cpp +++ b/src/eventhandler/EventHandler_Scenes.cpp @@ -40,6 +40,11 @@ void EventHandler::HandleSceneCreated(obs_source_t *source) eventData["sceneName"] = obs_source_get_name(source); eventData["sceneUuid"] = obs_source_get_uuid(source); eventData["isGroup"] = obs_source_is_group(source); + OBSCanvasAutoRelease canvas = obs_source_get_canvas(source); + if (canvas) { + eventData["canvasName"] = obs_canvas_get_name(canvas); + eventData["canvasUuid"] = obs_canvas_get_uuid(canvas); + } BroadcastEvent(EventSubscription::Scenes, "SceneCreated", eventData); } @@ -64,6 +69,11 @@ void EventHandler::HandleSceneRemoved(obs_source_t *source) eventData["sceneName"] = obs_source_get_name(source); eventData["sceneUuid"] = obs_source_get_uuid(source); eventData["isGroup"] = obs_source_is_group(source); + OBSCanvasAutoRelease canvas = obs_source_get_canvas(source); + if (canvas) { + eventData["canvasName"] = obs_canvas_get_name(canvas); + eventData["canvasUuid"] = obs_canvas_get_uuid(canvas); + } BroadcastEvent(EventSubscription::Scenes, "SceneRemoved", eventData); } @@ -88,6 +98,11 @@ void EventHandler::HandleSceneNameChanged(obs_source_t *source, std::string oldS eventData["sceneUuid"] = obs_source_get_uuid(source); eventData["oldSceneName"] = oldSceneName; eventData["sceneName"] = sceneName; + OBSCanvasAutoRelease canvas = obs_source_get_canvas(source); + if (canvas) { + eventData["canvasName"] = obs_canvas_get_name(canvas); + eventData["canvasUuid"] = obs_canvas_get_uuid(canvas); + } BroadcastEvent(EventSubscription::Scenes, "SceneNameChanged", eventData); } diff --git a/src/eventhandler/types/EventSubscription.h b/src/eventhandler/types/EventSubscription.h index e996bddf0..3b408df3d 100644 --- a/src/eventhandler/types/EventSubscription.h +++ b/src/eventhandler/types/EventSubscription.h @@ -154,17 +154,28 @@ namespace EventSubscription { */ Ui = (1 << 10), /** + * Subscription value to receive events in the `Canvases` category. + * + * @enumIdentifier Canvases + * @enumValue (1 << 11) + * @enumType EventSubscription + * @rpcVersion -1 + * @initialVersion 5.7.0 + * @api enums + */ + Canvases = (1 << 11), + /** * Helper to receive all non-high-volume events. * * @enumIdentifier All - * @enumValue (General | Config | Scenes | Inputs | Transitions | Filters | Outputs | SceneItems | MediaInputs | Vendors | Ui) + * @enumValue (General | Config | Scenes | Inputs | Transitions | Filters | Outputs | SceneItems | MediaInputs | Vendors | Ui | Canvases) * @enumType EventSubscription * @rpcVersion -1 * @initialVersion 5.0.0 * @api enums */ All = (General | Config | Scenes | Inputs | Transitions | Filters | Outputs | SceneItems | MediaInputs | Vendors | - Ui), + Ui | Canvases), /** * Subscription value to receive the `InputVolumeMeters` high-volume event. * diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index c077215e8..02a750f10 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -53,6 +53,9 @@ const std::unordered_map RequestHandler::_han {"GetRecordDirectory", &RequestHandler::GetRecordDirectory}, {"SetRecordDirectory", &RequestHandler::SetRecordDirectory}, + // Canvases + {"GetCanvasList", &RequestHandler::GetCanvasList}, + // Sources {"GetSourceActive", &RequestHandler::GetSourceActive}, {"GetSourceScreenshot", &RequestHandler::GetSourceScreenshot}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 082a6a1bc..49898aebc 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -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 &); diff --git a/src/requesthandler/RequestHandler_Canvases.cpp b/src/requesthandler/RequestHandler_Canvases.cpp new file mode 100644 index 000000000..26d545a67 --- /dev/null +++ b/src/requesthandler/RequestHandler_Canvases.cpp @@ -0,0 +1,62 @@ +/* +obs-websocket +Copyright (C) 2016-2021 Stephane Lepin +Copyright (C) 2020-2021 Kyle Manning + +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 +*/ + +#include "RequestHandler.h" + +/** + * Gets an array of canvases in OBS. + * + * @responseField canvases | Array | Array of canvases + * + * @requestType GetCanvasList + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.7.0 + * @api requests + * @category canvas + */ +RequestResult RequestHandler::GetCanvasList(const Request &request) +{ + json responseData; + std::vector ret; + + obs_enum_canvases( + [](void *param, obs_canvas_t *canvas) { + auto ret = static_cast *>(param); + json canvasJson; + canvasJson["canvasName"] = obs_canvas_get_name(canvas); + canvasJson["canvasUuid"] = obs_canvas_get_uuid(canvas); + canvasJson["flags"] = obs_canvas_get_flags(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); +} diff --git a/src/requesthandler/RequestHandler_Filters.cpp b/src/requesthandler/RequestHandler_Filters.cpp index bbdaac5af..59d7d9aa9 100644 --- a/src/requesthandler/RequestHandler_Filters.cpp +++ b/src/requesthandler/RequestHandler_Filters.cpp @@ -43,6 +43,8 @@ RequestResult RequestHandler::GetSourceFilterKindList(const Request &) /** * Gets an array of all of a source's filters. * + * @requestField ?canvasName | String | Name of the canvas the source is in + * @requestField ?canvasUuid | String | UUID of the canvas the source is in * @requestField ?sourceName | String | Name of the source * @requestField ?sourceUuid | String | UUID of the source * @@ -107,6 +109,8 @@ RequestResult RequestHandler::GetSourceFilterDefaultSettings(const Request &requ /** * Creates a new filter, adding it to the specified source. * + * @requestField ?canvasName | String | Name of the canvas the source is in + * @requestField ?canvasUuid | String | UUID of the canvas the source is in * @requestField ?sourceName | String | Name of the source to add the filter to * @requestField ?sourceUuid | String | UUID of the source to add the filter to * @requestField filterName | String | Name of the new filter to be created @@ -161,6 +165,8 @@ RequestResult RequestHandler::CreateSourceFilter(const Request &request) /** * Removes a filter from a source. * + * @requestField ?canvasName | String | Name of the canvas the source is in + * @requestField ?canvasUuid | String | UUID of the canvas the source is in * @requestField ?sourceName | String | Name of the source the filter is on * @requestField ?sourceUuid | String | UUID of the source the filter is on * @requestField filterName | String | Name of the filter to remove @@ -188,6 +194,8 @@ RequestResult RequestHandler::RemoveSourceFilter(const Request &request) /** * Sets the name of a source filter (rename). * + * @requestField ?canvasName | String | Name of the canvas the source is in + * @requestField ?canvasUuid | String | UUID of the canvas the source is in * @requestField ?sourceName | String | Name of the source the filter is on * @requestField ?sourceUuid | String | UUID of the source the filter is on * @requestField filterName | String | Current name of the filter @@ -222,6 +230,8 @@ RequestResult RequestHandler::SetSourceFilterName(const Request &request) /** * Gets the info for a specific source filter. * + * @requestField ?canvasName | String | Name of the canvas the source is in + * @requestField ?canvasUuid | String | UUID of the canvas the source is in * @requestField ?sourceName | String | Name of the source * @requestField ?sourceUuid | String | UUID of the source * @requestField filterName | String | Name of the filter @@ -262,6 +272,8 @@ RequestResult RequestHandler::GetSourceFilter(const Request &request) /** * Sets the index position of a filter on a source. * + * @requestField ?canvasName | String | Name of the canvas the source is in + * @requestField ?canvasUuid | String | UUID of the canvas the source is in * @requestField ?sourceName | String | Name of the source the filter is on * @requestField ?sourceUuid | String | UUID of the source the filter is on * @requestField filterName | String | Name of the filter @@ -292,6 +304,8 @@ RequestResult RequestHandler::SetSourceFilterIndex(const Request &request) /** * Sets the settings of a source filter. * + * @requestField ?canvasName | String | Name of the canvas the source is in + * @requestField ?canvasUuid | String | UUID of the canvas the source is in * @requestField ?sourceName | String | Name of the source the filter is on * @requestField ?sourceUuid | String | UUID of the source the filter is on * @requestField filterName | String | Name of the filter to set the settings of @@ -341,6 +355,8 @@ RequestResult RequestHandler::SetSourceFilterSettings(const Request &request) /** * Sets the enable state of a source filter. * + * @requestField ?canvasName | String | Name of the canvas the source is in + * @requestField ?canvasUuid | String | UUID of the canvas the source is in * @requestField ?sourceName | String | Name of the source the filter is on * @requestField ?sourceUuid | String | UUID of the source the filter is on * @requestField filterName | String | Name of the filter diff --git a/src/requesthandler/RequestHandler_Inputs.cpp b/src/requesthandler/RequestHandler_Inputs.cpp index bdd881775..38fc7f793 100644 --- a/src/requesthandler/RequestHandler_Inputs.cpp +++ b/src/requesthandler/RequestHandler_Inputs.cpp @@ -123,6 +123,8 @@ RequestResult RequestHandler::GetSpecialInputs(const Request &) /** * Creates a new input, adding it as a scene item to the specified scene. * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene to add the input to as a scene item * @requestField ?sceneUuid | String | UUID of the scene to add the input to as a scene item * @requestField inputName | String | Name of the new input to created diff --git a/src/requesthandler/RequestHandler_SceneItems.cpp b/src/requesthandler/RequestHandler_SceneItems.cpp index 146fb6546..d39faded9 100644 --- a/src/requesthandler/RequestHandler_SceneItems.cpp +++ b/src/requesthandler/RequestHandler_SceneItems.cpp @@ -24,8 +24,10 @@ with this program. If not, see * * Scenes only * - * @requestField ?sceneName | String | Name of the scene to get the items of - * @requestField ?sceneUuid | String | UUID of the scene to get the items of + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in + * @requestField ?sceneName | String | Name of the scene to get the items of + * @requestField ?sceneUuid | String | UUID of the scene to get the items of * * @responseField sceneItems | Array | Array of scene items in the scene * @@ -57,8 +59,10 @@ RequestResult RequestHandler::GetSceneItemList(const Request &request) * * Groups only * - * @requestField ?sceneName | String | Name of the group to get the items of - * @requestField ?sceneUuid | String | UUID of the group to get the items of + * @requestField ?canvasName | String | Name of the canvas the group is in + * @requestField ?canvasUuid | String | UUID of the canvas the group is in + * @requestField ?sceneName | String | Name of the group to get the items of + * @requestField ?sceneUuid | String | UUID of the group to get the items of * * @responseField sceneItems | Array | Array of scene items in the group * @@ -88,6 +92,8 @@ RequestResult RequestHandler::GetGroupSceneItemList(const Request &request) * * Scenes and Groups * + * @requestField ?canvasName | String | Name of the canvas the scene or group is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene or group is in * @requestField ?sceneName | String | Name of the scene or group to search in * @requestField ?sceneUuid | String | UUID of the scene or group to search in * @requestField sourceName | String | Name of the source to find @@ -133,6 +139,8 @@ RequestResult RequestHandler::GetSceneItemId(const Request &request) /** * Gets the source associated with a scene item. * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene the item is in * @requestField ?sceneUuid | String | UUID of the scene the item is in * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 @@ -169,6 +177,8 @@ RequestResult RequestHandler::GetSceneItemSource(const Request &request) * * Scenes only * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene to create the new item in * @requestField ?sceneUuid | String | UUID of the scene to create the new item in * @requestField ?sourceName | String | Name of the source to add to the scene @@ -223,6 +233,8 @@ RequestResult RequestHandler::CreateSceneItem(const Request &request) * * Scenes only * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene the item is in * @requestField ?sceneUuid | String | UUID of the scene the item is in * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 @@ -253,6 +265,8 @@ RequestResult RequestHandler::RemoveSceneItem(const Request &request) * * Scenes only * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene the item is in * @requestField ?sceneUuid | String | UUID of the scene the item is in * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 @@ -330,6 +344,8 @@ RequestResult RequestHandler::DuplicateSceneItem(const Request &request) * * Scenes and Groups * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene the item is in * @requestField ?sceneUuid | String | UUID of the scene the item is in * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 @@ -361,6 +377,8 @@ RequestResult RequestHandler::GetSceneItemTransform(const Request &request) /** * Sets the transform and crop info of a scene item. * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene the item is in * @requestField ?sceneUuid | String | UUID of the scene the item is in * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 @@ -526,6 +544,8 @@ RequestResult RequestHandler::SetSceneItemTransform(const Request &request) * * Scenes and Groups * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene the item is in * @requestField ?sceneUuid | String | UUID of the scene the item is in * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 @@ -559,6 +579,8 @@ RequestResult RequestHandler::GetSceneItemEnabled(const Request &request) * * Scenes and Groups * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene the item is in * @requestField ?sceneUuid | String | UUID of the scene the item is in * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 @@ -592,6 +614,8 @@ RequestResult RequestHandler::SetSceneItemEnabled(const Request &request) * * Scenes and Groups * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene the item is in * @requestField ?sceneUuid | String | UUID of the scene the item is in * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 @@ -625,6 +649,8 @@ RequestResult RequestHandler::GetSceneItemLocked(const Request &request) * * Scenes and Group * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene the item is in * @requestField ?sceneUuid | String | UUID of the scene the item is in * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 @@ -660,6 +686,8 @@ RequestResult RequestHandler::SetSceneItemLocked(const Request &request) * * Scenes and Groups * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene the item is in * @requestField ?sceneUuid | String | UUID of the scene the item is in * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 @@ -693,6 +721,8 @@ RequestResult RequestHandler::GetSceneItemIndex(const Request &request) * * Scenes and Groups * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene the item is in * @requestField ?sceneUuid | String | UUID of the scene the item is in * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 @@ -736,6 +766,8 @@ RequestResult RequestHandler::SetSceneItemIndex(const Request &request) * * Scenes and Groups * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene the item is in * @requestField ?sceneUuid | String | UUID of the scene the item is in * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 @@ -771,6 +803,8 @@ RequestResult RequestHandler::GetSceneItemBlendMode(const Request &request) * * Scenes and Groups * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene the item is in * @requestField ?sceneUuid | String | UUID of the scene the item is in * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 diff --git a/src/requesthandler/RequestHandler_Scenes.cpp b/src/requesthandler/RequestHandler_Scenes.cpp index 47ede5dda..2fbcab71c 100644 --- a/src/requesthandler/RequestHandler_Scenes.cpp +++ b/src/requesthandler/RequestHandler_Scenes.cpp @@ -20,8 +20,11 @@ with this program. If not, see #include "RequestHandler.h" /** - * Gets an array of all scenes in OBS. + * Gets an array of scenes in OBS. * + * @requestField ?canvasName | String | Name of the canvas the scenes are in + * @requestField ?canvasUuid | String | UUID of the canvas the scenes are in + * * @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 @@ -35,29 +38,56 @@ with this program. If not, see * @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", "canvasUuid", 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(); + if (canvas) + responseData["scenes"] = Utils::Obs::ArrayHelper::GetCanvasSceneList(canvas); + else + responseData["scenes"] = Utils::Obs::ArrayHelper::GetSceneList(); return RequestResult::Success(responseData); } @@ -76,11 +106,19 @@ 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", "canvasUuid", statusCode, comment); + if (statusCode == RequestStatus::ResourceNotFound) + return RequestResult::Error(statusCode, comment); - responseData["groups"] = Utils::Obs::ArrayHelper::GetGroupList(); + if (canvas) + responseData["groups"] = Utils::Obs::ArrayHelper::GetCanvasGroupList(canvas); + else + responseData["groups"] = Utils::Obs::ArrayHelper::GetGroupList(); return RequestResult::Success(responseData); } @@ -115,8 +153,8 @@ RequestResult RequestHandler::GetCurrentProgramScene(const Request &) /** * Sets the current program scene. * - * @requestField ?sceneName | String | Scene name to set as the current program scene - * @requestField ?sceneUuid | String | Scene UUID to set as the current program scene + * @requestField ?sceneName | String | Scene name to set as the current program scene + * @requestField ?sceneUuid | String | Scene UUID to set as the current program scene * * @requestType SetCurrentProgramScene * @complexity 1 @@ -133,6 +171,13 @@ RequestResult RequestHandler::SetCurrentProgramScene(const Request &request) if (!scene) return RequestResult::Error(statusCode, comment); + OBSCanvasAutoRelease sceneCanvas = obs_source_get_canvas(scene); + OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas(); + if (sceneCanvas != mainCanvas) + return RequestResult::Error( + RequestStatus::InvalidResourceState, + "The specified scene is not from the main canvas and cannot be set as the program scene."); + obs_frontend_set_current_scene(scene); return RequestResult::Success(); @@ -176,8 +221,8 @@ RequestResult RequestHandler::GetCurrentPreviewScene(const Request &) * * Only available when studio mode is enabled. * - * @requestField ?sceneName | String | Scene name to set as the current preview scene - * @requestField ?sceneUuid | String | Scene UUID to set as the current preview scene + * @requestField ?sceneName | String | Scene name to set as the current preview scene + * @requestField ?sceneUuid | String | Scene UUID to set as the current preview scene * * @requestType SetCurrentPreviewScene * @complexity 1 @@ -197,6 +242,13 @@ RequestResult RequestHandler::SetCurrentPreviewScene(const Request &request) if (!scene) return RequestResult::Error(statusCode, comment); + OBSCanvasAutoRelease sceneCanvas = obs_source_get_canvas(scene); + OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas(); + if (sceneCanvas != mainCanvas) + return RequestResult::Error( + RequestStatus::InvalidResourceState, + "The specified scene is not from the main canvas and cannot be set as the preview scene."); + obs_frontend_set_current_preview_scene(scene); return RequestResult::Success(); @@ -242,6 +294,8 @@ RequestResult RequestHandler::CreateScene(const Request &request) /** * Removes a scene from OBS. * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene to remove * @requestField ?sceneUuid | String | UUID of the scene to remove * @@ -256,11 +310,16 @@ RequestResult RequestHandler::RemoveScene(const Request &request) { RequestStatus::RequestStatus statusCode; std::string comment; + OBSCanvasAutoRelease canvas = request.ValidateCanvas("canvasName", "canvasUuid", statusCode, comment); + if (statusCode == RequestStatus::ResourceNotFound) + return RequestResult::Error(statusCode, comment); + OBSSourceAutoRelease scene = request.ValidateScene(statusCode, comment); if (!scene) return RequestResult::Error(statusCode, comment); - if (Utils::Obs::NumberHelper::GetSceneCount() < 2) + if ((canvas && Utils::Obs::NumberHelper::GetCanvasSceneCount(canvas) < 2) || + (!canvas && Utils::Obs::NumberHelper::GetSceneCount() < 2)) return RequestResult::Error(RequestStatus::NotEnoughResources, "You cannot remove the last scene in the collection."); @@ -272,6 +331,8 @@ RequestResult RequestHandler::RemoveScene(const Request &request) /** * Sets the name of a scene (rename). * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene to be renamed * @requestField ?sceneUuid | String | UUID of the scene to be renamed * @requestField newSceneName | String | New name for the scene @@ -287,13 +348,18 @@ RequestResult RequestHandler::SetSceneName(const Request &request) { RequestStatus::RequestStatus statusCode; std::string comment; + OBSCanvasAutoRelease canvas = request.ValidateCanvas("canvasName", "canvasUuid", statusCode, comment); + if (statusCode == RequestStatus::ResourceNotFound) + return RequestResult::Error(statusCode, comment); + OBSSourceAutoRelease scene = request.ValidateScene(statusCode, comment); if (!(scene && request.ValidateString("newSceneName", statusCode, comment))) return RequestResult::Error(statusCode, comment); std::string newSceneName = request.RequestData["newSceneName"]; - OBSSourceAutoRelease existingSource = obs_get_source_by_name(newSceneName.c_str()); + OBSSourceAutoRelease existingSource = canvas ? obs_canvas_get_source_by_name(canvas, newSceneName.c_str()) + : obs_get_source_by_name(newSceneName.c_str()); if (existingSource) return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A source already exists by that new scene name."); @@ -308,8 +374,10 @@ RequestResult RequestHandler::SetSceneName(const Request &request) * * Note: A transition UUID response field is not currently able to be implemented as of 2024-1-18. * - * @requestField ?sceneName | String | Name of the scene - * @requestField ?sceneUuid | String | UUID of the scene + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in + * @requestField ?sceneName | String | Name of the scene + * @requestField ?sceneUuid | String | UUID of the scene * * @responseField transitionName | String | Name of the overridden scene transition, else `null` * @responseField transitionDuration | Number | Duration of the overridden scene transition, else `null` @@ -349,6 +417,8 @@ RequestResult RequestHandler::GetSceneSceneTransitionOverride(const Request &req /** * Sets the scene transition overridden for a scene. * + * @requestField ?canvasName | String | Name of the canvas the scene is in + * @requestField ?canvasUuid | String | UUID of the canvas the scene is in * @requestField ?sceneName | String | Name of the scene * @requestField ?sceneUuid | String | UUID of the scene * @requestField ?transitionName | String | Name of the scene transition to use as override. Specify `null` to remove | Unchanged diff --git a/src/requesthandler/RequestHandler_Sources.cpp b/src/requesthandler/RequestHandler_Sources.cpp index bc246a8f1..11ff06272 100644 --- a/src/requesthandler/RequestHandler_Sources.cpp +++ b/src/requesthandler/RequestHandler_Sources.cpp @@ -114,6 +114,8 @@ bool IsImageFormatValid(std::string format) * * **Compatible with inputs and scenes.** * + * @requestField ?canvasName | String | Name of the canvas the source is in + * @requestField ?canvasUuid | String | UUID of the canvas the source is in * @requestField ?sourceName | String | Name of the source to get the active state of * @requestField ?sourceUuid | String | UUID of the source to get the active state of * @@ -152,6 +154,8 @@ RequestResult RequestHandler::GetSourceActive(const Request &request) * * **Compatible with inputs and scenes.** * + * @requestField ?canvasName | String | Name of the canvas the source is in + * @requestField ?canvasUuid | String | UUID of the canvas the source is in * @requestField ?sourceName | String | Name of the source to take a screenshot of * @requestField ?sourceUuid | String | UUID of the source to take a screenshot of * @requestField imageFormat | String | Image compression format to use. Use `GetVersion` to get compatible image formats @@ -240,6 +244,8 @@ RequestResult RequestHandler::GetSourceScreenshot(const Request &request) * * **Compatible with inputs and scenes.** * + * @requestField ?canvasName | String | Name of the canvas the source is in + * @requestField ?canvasUuid | String | UUID of the canvas the source is in * @requestField ?sourceName | String | Name of the source to take a screenshot of * @requestField ?sourceUuid | String | UUID of the source to take a screenshot of * @requestField imageFormat | String | Image compression format to use. Use `GetVersion` to get compatible image formats diff --git a/src/requesthandler/RequestHandler_Ui.cpp b/src/requesthandler/RequestHandler_Ui.cpp index 29896bda2..c586ae71a 100644 --- a/src/requesthandler/RequestHandler_Ui.cpp +++ b/src/requesthandler/RequestHandler_Ui.cpp @@ -265,6 +265,8 @@ RequestResult RequestHandler::OpenVideoMixProjector(const Request &request) * * Note: This request serves to provide feature parity with 4.x. It is very likely to be changed/deprecated in a future release. * + * @requestField ?canvasName | String | Name of the canvas the source is in + * @requestField ?canvasUuid | String | UUID of the canvas the source is in * @requestField ?sourceName | String | Name of the source to open a projector for * @requestField ?sourceUuid | String | UUID of the source to open a projector for * @requestField ?monitorIndex | Number | Monitor index, use `GetMonitorList` to obtain index | None | -1: Opens projector in windowed mode diff --git a/src/requesthandler/rpc/Request.cpp b/src/requesthandler/rpc/Request.cpp index dc9320a95..40c33fe80 100644 --- a/src/requesthandler/rpc/Request.cpp +++ b/src/requesthandler/rpc/Request.cpp @@ -214,9 +214,14 @@ bool Request::ValidateArray(const std::string &keyName, RequestStatus::RequestSt obs_source_t *Request::ValidateSource(const std::string &nameKeyName, const std::string &uuidKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const { + OBSCanvasAutoRelease canvas = ValidateCanvas("canvasName", "canvasUuid", statusCode, comment); + if (statusCode == RequestStatus::ResourceNotFound) + return nullptr; + if (ValidateString(nameKeyName, statusCode, comment)) { std::string sourceName = RequestData[nameKeyName]; - obs_source_t *ret = obs_get_source_by_name(sourceName.c_str()); + obs_source_t *ret = canvas ? obs_canvas_get_source_by_name(canvas, sourceName.c_str()) + : obs_get_source_by_name(sourceName.c_str()); if (!ret) { statusCode = RequestStatus::ResourceNotFound; comment = std::string("No source was found by the name of `") + sourceName + "`."; @@ -383,3 +388,31 @@ obs_output_t *Request::ValidateOutput(const std::string &keyName, RequestStatus: return ret; } + +obs_canvas_t *Request::ValidateCanvas(const std::string &nameKeyName, const std::string &uuidKeyName, + RequestStatus::RequestStatus &statusCode, std::string &comment) const +{ + if (ValidateString(nameKeyName, statusCode, comment)) { + std::string canvasName = RequestData[nameKeyName]; + obs_canvas_t *ret = obs_get_canvas_by_name(canvasName.c_str()); + if (!ret) { + statusCode = RequestStatus::ResourceNotFound; + comment = std::string("No canvas was found by the name of `") + canvasName + "`."; + return nullptr; + } + return ret; + } + + if (ValidateString(uuidKeyName, statusCode, comment)) { + std::string canvasUuid = RequestData[uuidKeyName]; + obs_canvas_t *ret = obs_get_canvas_by_uuid(canvasUuid.c_str()); + if (!ret) { + statusCode = RequestStatus::ResourceNotFound; + comment = std::string("No canvas was found by the UUID of `") + canvasUuid + "`."; + return nullptr; + } + return ret; + } + + return nullptr; +} diff --git a/src/requesthandler/rpc/Request.h b/src/requesthandler/rpc/Request.h index 77eb2c5ca..ebe539dd0 100644 --- a/src/requesthandler/rpc/Request.h +++ b/src/requesthandler/rpc/Request.h @@ -76,6 +76,9 @@ 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 &nameKeyName, const std::string &uuidKeyName, + RequestStatus::RequestStatus &statusCode, + std::string &comment) const; std::string RequestType; bool HasRequestData; diff --git a/src/utils/Obs.h b/src/utils/Obs.h index 47fe214c5..869910326 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -241,6 +241,7 @@ namespace Utils { namespace NumberHelper { uint64_t GetOutputDuration(obs_output_t *output); size_t GetSceneCount(); + size_t GetCanvasSceneCount(obs_canvas_t *canvas); size_t GetSourceFilterIndex(obs_source_t *source, obs_source_t *filter); } @@ -250,7 +251,9 @@ namespace Utils { std::vector GetHotkeyList(); std::vector GetHotkeyNameList(); std::vector GetSceneList(); + std::vector GetCanvasSceneList(obs_canvas_t *canvas); std::vector GetGroupList(); + std::vector GetCanvasGroupList(obs_canvas_t *canvas); std::vector GetSceneItemList(obs_scene_t *scene, bool basic = false); std::vector GetInputList(std::string inputKind = ""); std::vector GetInputKindList(bool unversioned = false, bool includeDisabled = false); diff --git a/src/utils/Obs_ArrayHelper.cpp b/src/utils/Obs_ArrayHelper.cpp index 0ed224a55..cb1a7d1e8 100644 --- a/src/utils/Obs_ArrayHelper.cpp +++ b/src/utils/Obs_ArrayHelper.cpp @@ -110,7 +110,35 @@ std::vector Utils::Obs::ArrayHelper::GetSceneList() return ret; } +std::vector Utils::Obs::ArrayHelper::GetCanvasSceneList(obs_canvas_t *canvas) +{ + std::vector ret; + + obs_canvas_enum_scenes( + canvas, + [](void *param, obs_source_t *scene) { + auto ret = static_cast *>(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; + } + + return ret; +} + std::vector Utils::Obs::ArrayHelper::GetGroupList() +{ + OBSCanvasAutoRelease canvas = obs_get_main_canvas(); + return GetCanvasGroupList(canvas); +} + +std::vector Utils::Obs::ArrayHelper::GetCanvasGroupList(obs_canvas_t *canvas) { std::vector ret; @@ -125,7 +153,7 @@ std::vector Utils::Obs::ArrayHelper::GetGroupList() return true; }; - obs_enum_scenes(cb, &ret); + obs_canvas_enum_scenes(canvas, cb, &ret); return ret; } diff --git a/src/utils/Obs_NumberHelper.cpp b/src/utils/Obs_NumberHelper.cpp index 74b032be8..e1538b784 100644 --- a/src/utils/Obs_NumberHelper.cpp +++ b/src/utils/Obs_NumberHelper.cpp @@ -36,6 +36,12 @@ uint64_t Utils::Obs::NumberHelper::GetOutputDuration(obs_output_t *output) } size_t Utils::Obs::NumberHelper::GetSceneCount() +{ + OBSCanvasAutoRelease canvas = obs_get_main_canvas(); + return GetCanvasSceneCount(canvas); +} + +size_t Utils::Obs::NumberHelper::GetCanvasSceneCount(obs_canvas_t *canvas) { size_t ret; auto sceneEnumProc = [](void *param, obs_source_t *scene) { @@ -48,7 +54,7 @@ size_t Utils::Obs::NumberHelper::GetSceneCount() return true; }; - obs_enum_scenes(sceneEnumProc, &ret); + obs_canvas_enum_scenes(canvas, sceneEnumProc, &ret); return ret; }