From 2a331795885974377a012aa97426e1212b708b3e Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Fri, 17 Dec 2021 15:19:38 +0900 Subject: [PATCH 001/128] docs: Fix `scenes` type from `String` to `Object` --- src/requesthandler/RequestHandler_Scenes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requesthandler/RequestHandler_Scenes.cpp b/src/requesthandler/RequestHandler_Scenes.cpp index 80cc4b82..ebcc73e2 100644 --- a/src/requesthandler/RequestHandler_Scenes.cpp +++ b/src/requesthandler/RequestHandler_Scenes.cpp @@ -22,7 +22,7 @@ with this program. If not, see /** * Gets an array of all scenes in OBS. * - * @responseField scenes | Array | Array of scenes in OBS + * @responseField scenes | Array | Array of scenes in OBS * @responseField currentProgramSceneName | String | Current program scene * @responseField currentPreviewSceneName | String | Current preview scene. `null` if not in studio mode * From b3ef9a861e01ff5591229e5bd4afe1db488d9fa3 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Fri, 17 Dec 2021 07:53:30 +0000 Subject: [PATCH 002/128] docs(ci): Update generated docs - 54fd7af [skip ci] --- docs/generated/protocol.json | 2 +- docs/generated/protocol.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index bd906beb..3b1faa5f 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -1952,7 +1952,7 @@ "responseFields": [ { "valueName": "scenes", - "valueType": "Array", + "valueType": "Array", "valueDescription": "Array of scenes in OBS" }, { diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 8a88fe14..428693e2 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -2064,7 +2064,7 @@ Gets an array of all scenes in OBS. | Name | Type | Description | | ---- | :---: | ----------- | -| scenes | Array<String> | Array of scenes in OBS | +| scenes | Array<Object> | Array of scenes in OBS | | currentProgramSceneName | String | Current program scene | | currentPreviewSceneName | String | Current preview scene. `null` if not in studio mode | From edf4e942facf325cc638c3fd5b20b65d71b41969 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 17 Dec 2021 02:38:56 -0800 Subject: [PATCH 003/128] RequestHandler: Use correct output in GetRecordStatus It was using the stream output due to a glitch, surprised nobody reported it yet. --- src/requesthandler/RequestHandler_Record.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requesthandler/RequestHandler_Record.cpp b/src/requesthandler/RequestHandler_Record.cpp index 19a2c14a..e18071c8 100644 --- a/src/requesthandler/RequestHandler_Record.cpp +++ b/src/requesthandler/RequestHandler_Record.cpp @@ -21,7 +21,7 @@ with this program. If not, see RequestResult RequestHandler::GetRecordStatus(const Request&) { - OBSOutputAutoRelease recordOutput = obs_frontend_get_streaming_output(); + OBSOutputAutoRelease recordOutput = obs_frontend_get_recording_output(); uint64_t outputDuration = Utils::Obs::NumberHelper::GetOutputDuration(recordOutput); From c4ab69481bd45a3d82e84eff35889d9ab664ed9b Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 17 Dec 2021 14:35:19 -0800 Subject: [PATCH 004/128] Base: Move AutoRelease helpers to utils + build fix - Moves the AutoRelease helpers to utils/Obs.h - Fixes build using obsproject/obs-studio/pull/5580 --- src/obs-websocket.cpp | 11 ----------- src/obs-websocket.h | 23 +---------------------- src/utils/Obs.cpp | 13 +++++++++++++ src/utils/Obs.h | 25 +++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 33 deletions(-) diff --git a/src/obs-websocket.cpp b/src/obs-websocket.cpp index 4f48e2b6..81804c4b 100644 --- a/src/obs-websocket.cpp +++ b/src/obs-websocket.cpp @@ -129,17 +129,6 @@ bool IsDebugEnabled() return !_config || _config->DebugEnabled; } -void ___source_dummy_addref(obs_source_t*) {} -void ___weak_source_dummy_addref(obs_weak_source_t*) {} -void ___scene_dummy_addref(obs_scene_t*) {} -void ___sceneitem_dummy_addref(obs_sceneitem_t*) {} -void ___data_dummy_addref(obs_data_t*) {} -void ___data_array_dummy_addref(obs_data_array_t*) {} -void ___output_dummy_addref(obs_output_t*) {} -void ___data_item_dummy_addref(obs_data_item_t*) {} -void ___data_item_release(obs_data_item_t* dataItem){ obs_data_item_release(&dataItem); } -void ___properties_dummy_addref(obs_properties_t*) {} - /** * An event has been emitted from a vendor. * diff --git a/src/obs-websocket.h b/src/obs-websocket.h index 46943c5c..c8c7b58f 100644 --- a/src/obs-websocket.h +++ b/src/obs-websocket.h @@ -29,30 +29,9 @@ with this program. If not, see #pragma pop_macro("strtoll") #endif +#include "utils/Obs.h" #include "plugin-macros.generated.h" -// Autorelease object definitions -void ___source_dummy_addref(obs_source_t*); -void ___weak_source_dummy_addref(obs_weak_source_t*); -void ___scene_dummy_addref(obs_scene_t*); -void ___sceneitem_dummy_addref(obs_sceneitem_t*); -void ___data_dummy_addref(obs_data_t*); -void ___data_array_dummy_addref(obs_data_array_t*); -void ___output_dummy_addref(obs_output_t*); -void ___data_item_dummy_addref(obs_data_item_t*); -void ___data_item_release(obs_data_item_t*); -void ___properties_dummy_addref(obs_properties_t*); - -using OBSSourceAutoRelease = OBSRef; -using OBSWeakSourceAutoRelease = OBSRef; -using OBSSceneAutoRelease = OBSRef; -using OBSSceneItemAutoRelease = OBSRef; -using OBSDataAutoRelease = OBSRef; -using OBSDataArrayAutoRelease = OBSRef; -using OBSOutputAutoRelease = OBSRef; -using OBSDataItemAutoRelease = OBSRef; -using OBSPropertiesAutoDestroy = OBSRef; - class Config; typedef std::shared_ptr ConfigPtr; diff --git a/src/utils/Obs.cpp b/src/utils/Obs.cpp index 3b11ebe9..9ba7f4a1 100644 --- a/src/utils/Obs.cpp +++ b/src/utils/Obs.cpp @@ -50,6 +50,19 @@ std::vector ConvertStringArray(char **array) return ret; } +#if !defined(OBS_HAS_AUTORELEASE) +void ___source_dummy_addref(obs_source_t*) {} +void ___weak_source_dummy_addref(obs_weak_source_t*) {} +void ___scene_dummy_addref(obs_scene_t*) {} +void ___sceneitem_dummy_addref(obs_sceneitem_t*) {} +void ___data_dummy_addref(obs_data_t*) {} +void ___data_array_dummy_addref(obs_data_array_t*) {} +void ___output_dummy_addref(obs_output_t*) {} +void ___data_item_dummy_addref(obs_data_item_t*) {} +void ___data_item_release(obs_data_item_t* dataItem){ obs_data_item_release(&dataItem); } +void ___properties_dummy_addref(obs_properties_t*) {} +#endif + std::string Utils::Obs::StringHelper::GetObsVersion() { uint32_t version = obs_get_version(); diff --git a/src/utils/Obs.h b/src/utils/Obs.h index 6a5aaa59..56b9e203 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -24,6 +24,31 @@ with this program. If not, see #include "Json.h" +#if !defined(OBSSourceAutoRelease) +#define OBS_HAS_AUTORELEASE +// Autorelease object definitions +void ___source_dummy_addref(obs_source_t*); +void ___weak_source_dummy_addref(obs_weak_source_t*); +void ___scene_dummy_addref(obs_scene_t*); +void ___sceneitem_dummy_addref(obs_sceneitem_t*); +void ___data_dummy_addref(obs_data_t*); +void ___data_array_dummy_addref(obs_data_array_t*); +void ___output_dummy_addref(obs_output_t*); +void ___data_item_dummy_addref(obs_data_item_t*); +void ___data_item_release(obs_data_item_t*); +void ___properties_dummy_addref(obs_properties_t*); + +using OBSSourceAutoRelease = OBSRef; +using OBSWeakSourceAutoRelease = OBSRef; +using OBSSceneAutoRelease = OBSRef; +using OBSSceneItemAutoRelease = OBSRef; +using OBSDataAutoRelease = OBSRef; +using OBSDataArrayAutoRelease = OBSRef; +using OBSOutputAutoRelease = OBSRef; +using OBSDataItemAutoRelease = OBSRef; +using OBSPropertiesAutoDestroy = OBSRef; +#endif + template T* GetCalldataPointer(const calldata_t *data, const char* name) { void *ptr = nullptr; calldata_get_ptr(data, name, &ptr); From 84e649a6f7f783d0a6455911af214fd7b6c60fff Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 17 Dec 2021 14:47:56 -0800 Subject: [PATCH 005/128] Utils: Tweak some includes --- src/utils/ObsVolumeMeter.cpp | 1 + src/utils/ObsVolumeMeter.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/ObsVolumeMeter.cpp b/src/utils/ObsVolumeMeter.cpp index 0447f312..e5c9c7db 100644 --- a/src/utils/ObsVolumeMeter.cpp +++ b/src/utils/ObsVolumeMeter.cpp @@ -24,6 +24,7 @@ with this program. If not, see #include "Obs.h" #include "ObsVolumeMeter.h" #include "ObsVolumeMeter_Helpers.h" +#include "../obs-websocket.h" Utils::Obs::VolumeMeter::Meter::Meter(obs_source_t *input) : PeakMeterType(SAMPLE_PEAK_METER), diff --git a/src/utils/ObsVolumeMeter.h b/src/utils/ObsVolumeMeter.h index 49d99fc8..75e46faf 100644 --- a/src/utils/ObsVolumeMeter.h +++ b/src/utils/ObsVolumeMeter.h @@ -27,7 +27,7 @@ with this program. If not, see #include #include -#include "../obs-websocket.h" +#include "Obs.h" #include "Json.h" namespace Utils { From a40e79e987587db539fa2dac338e484a0ebef516 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 17 Dec 2021 15:48:59 -0800 Subject: [PATCH 006/128] Utils/Obs: Fix build (again) --- src/utils/Obs.cpp | 13 ------------- src/utils/Obs.h | 39 ++++++++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/utils/Obs.cpp b/src/utils/Obs.cpp index 9ba7f4a1..3b11ebe9 100644 --- a/src/utils/Obs.cpp +++ b/src/utils/Obs.cpp @@ -50,19 +50,6 @@ std::vector ConvertStringArray(char **array) return ret; } -#if !defined(OBS_HAS_AUTORELEASE) -void ___source_dummy_addref(obs_source_t*) {} -void ___weak_source_dummy_addref(obs_weak_source_t*) {} -void ___scene_dummy_addref(obs_scene_t*) {} -void ___sceneitem_dummy_addref(obs_sceneitem_t*) {} -void ___data_dummy_addref(obs_data_t*) {} -void ___data_array_dummy_addref(obs_data_array_t*) {} -void ___output_dummy_addref(obs_output_t*) {} -void ___data_item_dummy_addref(obs_data_item_t*) {} -void ___data_item_release(obs_data_item_t* dataItem){ obs_data_item_release(&dataItem); } -void ___properties_dummy_addref(obs_properties_t*) {} -#endif - std::string Utils::Obs::StringHelper::GetObsVersion() { uint32_t version = obs_get_version(); diff --git a/src/utils/Obs.h b/src/utils/Obs.h index 56b9e203..f5beecad 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -24,29 +24,38 @@ with this program. If not, see #include "Json.h" -#if !defined(OBSSourceAutoRelease) -#define OBS_HAS_AUTORELEASE // Autorelease object definitions -void ___source_dummy_addref(obs_source_t*); -void ___weak_source_dummy_addref(obs_weak_source_t*); -void ___scene_dummy_addref(obs_scene_t*); -void ___sceneitem_dummy_addref(obs_sceneitem_t*); -void ___data_dummy_addref(obs_data_t*); -void ___data_array_dummy_addref(obs_data_array_t*); -void ___output_dummy_addref(obs_output_t*); -void ___data_item_dummy_addref(obs_data_item_t*); -void ___data_item_release(obs_data_item_t*); -void ___properties_dummy_addref(obs_properties_t*); +inline void ___properties_dummy_addref(obs_properties_t*){} +using OBSPropertiesAutoDestroy = OBSRef; + +#if !defined(OBS_AUTORELEASE) +inline void ___source_dummy_addref(obs_source_t*){} +inline void ___scene_dummy_addref(obs_scene_t*){} +inline void ___sceneitem_dummy_addref(obs_sceneitem_t*){} +inline void ___data_dummy_addref(obs_data_t*){} +inline void ___data_array_dummy_addref(obs_data_array_t*){} +inline void ___output_dummy_addref(obs_output_t*){} +inline void ___encoder_dummy_addref(obs_encoder_t *){} +inline void ___service_dummy_addref(obs_service_t *){} + +inline void ___weak_source_dummy_addref(obs_weak_source_t*){} +inline void ___weak_output_dummy_addref(obs_weak_output_t *){} +inline void ___weak_encoder_dummy_addref(obs_weak_encoder_t *){} +inline void ___weak_service_dummy_addref(obs_weak_service_t *){} using OBSSourceAutoRelease = OBSRef; -using OBSWeakSourceAutoRelease = OBSRef; using OBSSceneAutoRelease = OBSRef; using OBSSceneItemAutoRelease = OBSRef; using OBSDataAutoRelease = OBSRef; using OBSDataArrayAutoRelease = OBSRef; using OBSOutputAutoRelease = OBSRef; -using OBSDataItemAutoRelease = OBSRef; -using OBSPropertiesAutoDestroy = OBSRef; +using OBSEncoderAutoRelease = OBSRef; +using OBSServiceAutoRelease = OBSRef; + +using OBSWeakSourceAutoRelease = OBSRef; +using OBSWeakOutputAutoRelease = OBSRef; +using OBSWeakEncoderAutoRelease = OBSRef; +using OBSWeakServiceAutoRelease = OBSRef; #endif template T* GetCalldataPointer(const calldata_t *data, const char* name) { From 873ad1b167d479b2415c4e2aaa94f2f471809af6 Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Sun, 19 Dec 2021 16:31:31 +0900 Subject: [PATCH 007/128] docs: Document missing `overlay` field --- src/requesthandler/RequestHandler_Inputs.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/requesthandler/RequestHandler_Inputs.cpp b/src/requesthandler/RequestHandler_Inputs.cpp index 21e90744..ca0a0eb5 100644 --- a/src/requesthandler/RequestHandler_Inputs.cpp +++ b/src/requesthandler/RequestHandler_Inputs.cpp @@ -278,8 +278,10 @@ RequestResult RequestHandler::GetInputSettings(const Request& request) /** * Sets the settings of an input. * - * @requestField inputName | String | Name of the input to set the settings of - * @requestField inputSettings | Object | Object of settings to apply + * @requestField inputName | String | Name of the input to set the settings of + * @requestField inputSettings | Object | Object of settings to apply + * @requestField ?overlay | Boolean | True == apply the settings on top of existing ones, + * False == reset the input to its defaults, then apply settings. | true * * @requestType SetInputSettings * @complexity 3 From c3e6bc323a7cec81d6933b22661bd99006a6a98a Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Sun, 19 Dec 2021 17:23:22 +0900 Subject: [PATCH 008/128] Adjust spacing of docs --- src/requesthandler/RequestHandler_Inputs.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/requesthandler/RequestHandler_Inputs.cpp b/src/requesthandler/RequestHandler_Inputs.cpp index ca0a0eb5..3e782bd5 100644 --- a/src/requesthandler/RequestHandler_Inputs.cpp +++ b/src/requesthandler/RequestHandler_Inputs.cpp @@ -280,8 +280,7 @@ RequestResult RequestHandler::GetInputSettings(const Request& request) * * @requestField inputName | String | Name of the input to set the settings of * @requestField inputSettings | Object | Object of settings to apply - * @requestField ?overlay | Boolean | True == apply the settings on top of existing ones, - * False == reset the input to its defaults, then apply settings. | true + * @requestField ?overlay | Boolean | True == apply the settings on top of existing ones, False == reset the input to its defaults, then apply settings. | true * * @requestType SetInputSettings * @complexity 3 From 9749502e8873d623c367574cf69328c63d8809b2 Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Sun, 19 Dec 2021 17:30:58 +0900 Subject: [PATCH 009/128] protocol: Fix error formatting for wrong op codes --- src/websocketserver/WebSocketServer_Protocol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/websocketserver/WebSocketServer_Protocol.cpp b/src/websocketserver/WebSocketServer_Protocol.cpp index 14c60eec..689ef977 100644 --- a/src/websocketserver/WebSocketServer_Protocol.cpp +++ b/src/websocketserver/WebSocketServer_Protocol.cpp @@ -296,7 +296,7 @@ void WebSocketServer::ProcessMessage(SessionPtr session, WebSocketServer::Proces } return; default: ret.closeCode = WebSocketCloseCode::UnknownOpCode; - ret.closeReason = std::string("Unknown OpCode: %s") + std::to_string(opCode); + ret.closeReason = std::string("Unknown OpCode: ") + std::to_string(opCode); return; } } From 6f6fbf84d18ada88b2fb3fd67aba16662e05e077 Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Sun, 19 Dec 2021 17:35:34 +0900 Subject: [PATCH 010/128] ci: Set the minimum MacOS version to 10.13 --- CI/macos/build-plugin-macos.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/CI/macos/build-plugin-macos.sh b/CI/macos/build-plugin-macos.sh index 13c15806..bc6c78ea 100755 --- a/CI/macos/build-plugin-macos.sh +++ b/CI/macos/build-plugin-macos.sh @@ -17,6 +17,7 @@ fi echo "[obs-websocket] Building 'obs-websocket' for macOS." mkdir -p build && cd build cmake .. \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \ -DQTDIR=/tmp/obsdeps \ -DLIBOBS_INCLUDE_DIR=../../obs-studio/libobs \ -DLIBOBS_LIB=../../obs-studio/libobs \ From 71bf9e9021588b954fa5ee9e7ca46a890380f026 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Sun, 19 Dec 2021 10:11:36 +0000 Subject: [PATCH 011/128] docs(ci): Update generated docs - 0c7fda2 [skip ci] --- docs/generated/protocol.json | 8 ++++++++ docs/generated/protocol.md | 1 + 2 files changed, 9 insertions(+) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 3b1faa5f..2638c03f 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -1619,6 +1619,14 @@ "valueRestrictions": null, "valueOptional": false, "valueOptionalBehavior": null + }, + { + "valueName": "overlay", + "valueType": "Boolean", + "valueDescription": "True == apply the settings on top of existing ones, False == reset the input to its defaults, then apply settings.", + "valueRestrictions": null, + "valueOptional": true, + "valueOptionalBehavior": "true" } ], "responseFields": [] diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 428693e2..f03675f9 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -2374,6 +2374,7 @@ Sets the settings of an input. | ---- | :---: | ----------- | :----------------: | ----------------- | | inputName | String | Name of the input to set the settings of | None | N/A | | inputSettings | Object | Object of settings to apply | None | N/A | +| ?overlay | Boolean | True == apply the settings on top of existing ones, False == reset the input to its defaults, then apply settings. | None | true | --- From 82ad3313e83b0c08eb624ba71d124052388b6e8e Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sat, 18 Dec 2021 21:23:12 -0800 Subject: [PATCH 012/128] docs: More docs --- .../RequestHandler_SceneItems.cpp | 234 ++++++++++++++++++ src/requesthandler/RequestHandler_Scenes.cpp | 2 +- src/requesthandler/RequestHandler_Stream.cpp | 50 ++++ 3 files changed, 285 insertions(+), 1 deletion(-) diff --git a/src/requesthandler/RequestHandler_SceneItems.cpp b/src/requesthandler/RequestHandler_SceneItems.cpp index a1f6fcb4..3f612cfc 100644 --- a/src/requesthandler/RequestHandler_SceneItems.cpp +++ b/src/requesthandler/RequestHandler_SceneItems.cpp @@ -19,6 +19,22 @@ with this program. If not, see #include "RequestHandler.h" +/** + * Gets a list of all scene items in a scene. + * + * Scenes only + * + * @requestField sceneName | String | Name of the scene to get the items of + * + * @responseField sceneItems | Array | Array of scene items in the scene + * + * @requestType GetSceneItemList + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::GetSceneItemList(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -33,6 +49,24 @@ RequestResult RequestHandler::GetSceneItemList(const Request& request) return RequestResult::Success(responseData); } +/** + * Basically GetSceneItemList, but for groups. + * + * Using groups at all in OBS is discouraged, as they are very broken under the hood. + * + * Groups only + * + * @requestField sceneName | String | Name of the group to get the items of + * + * @responseField sceneItems | Array | Array of scene items in the group + * + * @requestType GetGroupItemList + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::GetGroupSceneItemList(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -47,6 +81,23 @@ RequestResult RequestHandler::GetGroupSceneItemList(const Request& request) return RequestResult::Success(responseData); } +/** + * Searches a scene for a source, and returns its id. + * + * Scenes and Groups + * + * @requestField sceneName | String | Name of the scene or group to search in + * @requestField sourceName | String | Name of the source to find + * + * @responseField sceneItemId | Number | Numeric ID of the scene item + * + * @requestType GetSceneItemId + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::GetSceneItemId(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -74,6 +125,24 @@ RequestResult RequestHandler::GetSceneItemId(const Request& request) return RequestResult::Success(responseData); } +/** + * Creates a new scene item using a source. + * + * Scenes only + * + * @requestField sceneName | String | Name of the scene to create the new item in + * @requestField sourceName | String | Name of the source to add to the scene + * @requestField ?sceneItemEnabled | Boolean | Enable state to apply to the scene item on creation | True + * + * @responseField sceneItemId | Number | Numeric ID of the scene item + * + * @requestType CreateSceneItem + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::CreateSceneItem(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -108,6 +177,21 @@ RequestResult RequestHandler::CreateSceneItem(const Request& request) return RequestResult::Success(responseData); } +/** + * Removes a scene item from a scene. + * + * Scenes only + * + * @requestField sceneName | String | Name of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * + * @requestType RemoveSceneItem + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::RemoveSceneItem(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -121,6 +205,24 @@ RequestResult RequestHandler::RemoveSceneItem(const Request& request) return RequestResult::Success(); } +/** + * Duplicates a scene item, copying all transform and crop info. + * + * Scenes only + * + * @requestField sceneName | String | Name of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * @requestField ?destinationSceneName | String | Name of the scene to create the duplicated item in | `sceneName` is assumed + * + * @responseField sceneItemId | Number | Numeric ID of the duplicated scene item + * + * @requestType DuplicateSceneItem + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::DuplicateSceneItem(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -165,6 +267,23 @@ RequestResult RequestHandler::DuplicateSceneItem(const Request& request) return RequestResult::Success(responseData); } +/** + * Gets the transform and crop info of a scene item. + * + * Scenes and Groups + * + * @requestField sceneName | String | Name of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * + * @responseField sceneItemTransform | Object | Object containing scene item transform info + * + * @requestType GetSceneItemTransform + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::GetSceneItemTransform(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -179,6 +298,20 @@ RequestResult RequestHandler::GetSceneItemTransform(const Request& request) return RequestResult::Success(responseData); } +/** + * Sets the transform and crop info of a scene item. + * + * @requestField sceneName | String | Name of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * @requestField sceneItemTransform | Object | Object containing scene item transform info to update + * + * @requestType SetSceneItemTransform + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::SetSceneItemTransform(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -317,6 +450,23 @@ RequestResult RequestHandler::SetSceneItemTransform(const Request& request) return RequestResult::Success(); } +/** + * Gets the enable state of a scene item. + * + * Scenes and Groups + * + * @requestField sceneName | String | Name of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * + * @responseField sceneItemEnabled | Boolean | Whether the scene item is enabled. `true` for enabled, `false` for disabled + * + * @requestType GetSceneItemEnabled + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::GetSceneItemEnabled(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -331,6 +481,22 @@ RequestResult RequestHandler::GetSceneItemEnabled(const Request& request) return RequestResult::Success(responseData); } +/** + * Sets the enable state of a scene item. + * + * Scenes and Groups + * + * @requestField sceneName | String | Name of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * @requestField sceneItemEnabled | Boolean | New enable state of the scene item + * + * @requestType SetSceneItemEnabled + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::SetSceneItemEnabled(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -346,6 +512,23 @@ RequestResult RequestHandler::SetSceneItemEnabled(const Request& request) return RequestResult::Success(); } +/** + * Gets the lock state of a scene item. + * + * Scenes and Groups + * + * @requestField sceneName | String | Name of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * + * @responseField sceneItemLocked | Boolean | Whether the scene item is locked. `true` for locked, `false` for unlocked + * + * @requestType GetSceneItemLocked + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::GetSceneItemLocked(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -360,6 +543,22 @@ RequestResult RequestHandler::GetSceneItemLocked(const Request& request) return RequestResult::Success(responseData); } +/** + * Sets the lock state of a scene item. + * + * Scenes and Group + * + * @requestField sceneName | String | Name of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * @requestField sceneItemLocked | Boolean | New lock state of the scene item + * + * @requestType SetSceneItemLocked + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::SetSceneItemLocked(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -375,6 +574,25 @@ RequestResult RequestHandler::SetSceneItemLocked(const Request& request) return RequestResult::Success(); } +/** + * Gets the index position of a scene item in a scene. + * + * An index of 0 is at the bottom of the source list in the UI. + * + * Scenes and Groups + * + * @requestField sceneName | String | Name of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * + * @responseField sceneItemIndex | Number | Index position of the scene item + * + * @requestType GetSceneItemIndex + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::GetSceneItemIndex(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -389,6 +607,22 @@ RequestResult RequestHandler::GetSceneItemIndex(const Request& request) return RequestResult::Success(responseData); } +/** + * Sets the index position of a scene item in a scene. + * + * Scenes and Groups + * + * @requestField sceneName | String | Name of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * @requestField sceneItemIndex | Number | New index position of the scene item | >= 0 + * + * @requestType SetSceneItemIndex + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ RequestResult RequestHandler::SetSceneItemIndex(const Request& request) { RequestStatus::RequestStatus statusCode; diff --git a/src/requesthandler/RequestHandler_Scenes.cpp b/src/requesthandler/RequestHandler_Scenes.cpp index 0f4d78e2..f6a3e013 100644 --- a/src/requesthandler/RequestHandler_Scenes.cpp +++ b/src/requesthandler/RequestHandler_Scenes.cpp @@ -22,9 +22,9 @@ with this program. If not, see /** * Gets an array of all scenes in OBS. * - * @responseField scenes | Array | Array of scenes in OBS * @responseField currentProgramSceneName | String | Current program scene * @responseField currentPreviewSceneName | String | Current preview scene. `null` if not in studio mode + * @responseField scenes | Array | Array of scenes in OBS * * @requestType GetSceneList * @complexity 2 diff --git a/src/requesthandler/RequestHandler_Stream.cpp b/src/requesthandler/RequestHandler_Stream.cpp index 8136dcfb..98c9e60b 100644 --- a/src/requesthandler/RequestHandler_Stream.cpp +++ b/src/requesthandler/RequestHandler_Stream.cpp @@ -19,6 +19,24 @@ with this program. If not, see #include "RequestHandler.h" +/** + * Gets the status of the stream output. + * + * @responseField outputActive | Boolean | Whether the output is active + * @responseField outputReconnecting | Boolean | Whether the output is currently reconnecting + * @responseField outputTimecode | String | Current formatted timecode string for the output + * @responseField outputDuration | Number | Current duration in milliseconds for the output + * @responseField outputBytes | Number | Number of bytes sent by the output + * @responseField outputSkippedFrames | Number | Number of frames skipped by the output's process + * @responseField outputTotalFrames | Number | Total number of frames delivered by the output's process + * + * @requestType GetStreamStatus + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category stream + */ RequestResult RequestHandler::GetStreamStatus(const Request&) { OBSOutputAutoRelease streamOutput = obs_frontend_get_streaming_output(); @@ -37,6 +55,18 @@ RequestResult RequestHandler::GetStreamStatus(const Request&) return RequestResult::Success(responseData); } +/** + * Toggles the status of the stream output. + * + * @responseField outputActive | Boolean | New state of the stream output + * + * @requestType ToggleStream + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category stream + */ RequestResult RequestHandler::ToggleStream(const Request&) { json responseData; @@ -51,6 +81,16 @@ RequestResult RequestHandler::ToggleStream(const Request&) return RequestResult::Success(responseData); } +/** + * Starts the stream output. + * + * @requestType StartStream + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category stream + */ RequestResult RequestHandler::StartStream(const Request&) { if (obs_frontend_streaming_active()) @@ -62,6 +102,16 @@ RequestResult RequestHandler::StartStream(const Request&) return RequestResult::Success(); } +/** + * Stops the stream output. + * + * @requestType StopStream + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category stream + */ RequestResult RequestHandler::StopStream(const Request&) { if (!obs_frontend_streaming_active()) From f66080a0312e4872c5bf10b0cf8710e6e7ed28d5 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sat, 18 Dec 2021 21:40:49 -0800 Subject: [PATCH 013/128] Utils: Split Obs utils into individual files --- CMakeLists.txt | 7 + src/utils/Obs.cpp | 557 --------------------------------- src/utils/Obs.h | 1 + src/utils/Obs_ActionHelper.cpp | 89 ++++++ src/utils/Obs_DataHelper.cpp | 89 ++++++ src/utils/Obs_EnumHelper.cpp | 47 +++ src/utils/Obs_ListHelper.cpp | 222 +++++++++++++ src/utils/Obs_NumberHelper.cpp | 54 ++++ src/utils/Obs_SearchHelper.cpp | 48 +++ src/utils/Obs_StringHelper.cpp | 154 +++++++++ 10 files changed, 711 insertions(+), 557 deletions(-) create mode 100644 src/utils/Obs_ActionHelper.cpp create mode 100644 src/utils/Obs_DataHelper.cpp create mode 100644 src/utils/Obs_EnumHelper.cpp create mode 100644 src/utils/Obs_ListHelper.cpp create mode 100644 src/utils/Obs_NumberHelper.cpp create mode 100644 src/utils/Obs_SearchHelper.cpp create mode 100644 src/utils/Obs_StringHelper.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f65f0ea0..86eead93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,13 @@ set(obs-websocket_SOURCES src/utils/Crypto.cpp src/utils/Json.cpp src/utils/Obs.cpp + src/utils/Obs_StringHelper.cpp + src/utils/Obs_EnumHelper.cpp + src/utils/Obs_NumberHelper.cpp + src/utils/Obs_ListHelper.cpp + src/utils/Obs_DataHelper.cpp + src/utils/Obs_SearchHelper.cpp + src/utils/Obs_ActionHelper.cpp src/utils/ObsVolumeMeter.cpp src/utils/Platform.cpp src/utils/Compat.cpp diff --git a/src/utils/Obs.cpp b/src/utils/Obs.cpp index 3b11ebe9..131e8d22 100644 --- a/src/utils/Obs.cpp +++ b/src/utils/Obs.cpp @@ -17,562 +17,5 @@ You should have received a copy of the GNU General Public License along with this program. If not, see */ -#include -#include -#include -#include -#include -#include - #include "Obs.h" -#include "../obs-websocket.h" #include "../plugin-macros.generated.h" - -#define CASE(x) case x: return #x; - -#define RET_COMPARE(str, x) if (str == #x) return x; - -std::vector ConvertStringArray(char **array) -{ - std::vector ret; - if (!array) - return ret; - - size_t index = 0; - char* value = nullptr; - do { - value = array[index]; - if (value) - ret.push_back(value); - index++; - } while (value); - - return ret; -} - -std::string Utils::Obs::StringHelper::GetObsVersion() -{ - uint32_t version = obs_get_version(); - - uint8_t major, minor, patch; - major = (version >> 24) & 0xFF; - minor = (version >> 16) & 0xFF; - patch = version & 0xFF; - - QString combined = QString("%1.%2.%3").arg(major).arg(minor).arg(patch); - return combined.toStdString(); -} - -std::string Utils::Obs::StringHelper::GetCurrentSceneCollection() -{ - char *sceneCollectionName = obs_frontend_get_current_scene_collection(); - std::string ret = sceneCollectionName; - bfree(sceneCollectionName); - return ret; -} - -std::string Utils::Obs::StringHelper::GetCurrentProfile() -{ - char *profileName = obs_frontend_get_current_profile(); - std::string ret = profileName; - bfree(profileName); - return ret; -} - -std::string Utils::Obs::StringHelper::GetCurrentProfilePath() -{ - char *profilePath = obs_frontend_get_current_profile_path(); - std::string ret = profilePath; - bfree(profilePath); - return ret; -} - -std::string Utils::Obs::StringHelper::GetCurrentRecordOutputPath() -{ - //char *recordOutputPath = obs_frontend_get_current_record_output_path(); - //std::string ret = recordOutputPath; - //bfree(recordOutputPath); - //return ret; - - return ""; -} - -std::string Utils::Obs::StringHelper::GetSourceType(obs_source_t *source) -{ - obs_source_type sourceType = obs_source_get_type(source); - - switch (sourceType) { - default: - CASE(OBS_SOURCE_TYPE_INPUT) - CASE(OBS_SOURCE_TYPE_FILTER) - CASE(OBS_SOURCE_TYPE_TRANSITION) - CASE(OBS_SOURCE_TYPE_SCENE) - } -} - -std::string Utils::Obs::StringHelper::GetInputMonitorType(obs_source_t *input) -{ - obs_monitoring_type monitorType = obs_source_get_monitoring_type(input); - - switch (monitorType) { - default: - CASE(OBS_MONITORING_TYPE_NONE) - CASE(OBS_MONITORING_TYPE_MONITOR_ONLY) - CASE(OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT) - } -} - -std::string Utils::Obs::StringHelper::GetMediaInputState(obs_source_t *input) -{ - obs_media_state mediaState = obs_source_media_get_state(input); - - switch (mediaState) { - default: - CASE(OBS_MEDIA_STATE_NONE) - CASE(OBS_MEDIA_STATE_PLAYING) - CASE(OBS_MEDIA_STATE_OPENING) - CASE(OBS_MEDIA_STATE_BUFFERING) - CASE(OBS_MEDIA_STATE_PAUSED) - CASE(OBS_MEDIA_STATE_STOPPED) - CASE(OBS_MEDIA_STATE_ENDED) - CASE(OBS_MEDIA_STATE_ERROR) - } -} - -std::string Utils::Obs::StringHelper::GetLastReplayBufferFilePath() -{ - OBSOutputAutoRelease output = obs_frontend_get_replay_buffer_output(); - calldata_t cd = {0}; - proc_handler_t *ph = obs_output_get_proc_handler(output); - proc_handler_call(ph, "get_last_replay", &cd); - auto ret = calldata_string(&cd, "path"); - calldata_free(&cd); - return ret; -} - -std::string Utils::Obs::StringHelper::GetSceneItemBoundsType(enum obs_bounds_type type) -{ - switch (type) { - default: - CASE(OBS_BOUNDS_NONE) - CASE(OBS_BOUNDS_STRETCH) - CASE(OBS_BOUNDS_SCALE_INNER) - CASE(OBS_BOUNDS_SCALE_OUTER) - CASE(OBS_BOUNDS_SCALE_TO_WIDTH) - CASE(OBS_BOUNDS_SCALE_TO_HEIGHT) - CASE(OBS_BOUNDS_MAX_ONLY) - } -} - -std::string Utils::Obs::StringHelper::DurationToTimecode(uint64_t ms) -{ - uint64_t secs = ms / 1000ULL; - uint64_t minutes = secs / 60ULL; - - uint64_t hoursPart = minutes / 60ULL; - uint64_t minutesPart = minutes % 60ULL; - uint64_t secsPart = secs % 60ULL; - uint64_t msPart = ms % 1000ULL; - - QString formatted = QString::asprintf("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64 ".%03" PRIu64, hoursPart, minutesPart, secsPart, msPart); - return formatted.toStdString(); -} - -enum obs_bounds_type Utils::Obs::EnumHelper::GetSceneItemBoundsType(std::string boundsType) -{ - RET_COMPARE(boundsType, OBS_BOUNDS_NONE); - RET_COMPARE(boundsType, OBS_BOUNDS_STRETCH); - RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_INNER); - RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_OUTER); - RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_TO_WIDTH); - RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_TO_HEIGHT); - RET_COMPARE(boundsType, OBS_BOUNDS_MAX_ONLY); - - return OBS_BOUNDS_NONE; -} - -enum ObsMediaInputAction Utils::Obs::EnumHelper::GetMediaInputAction(std::string mediaAction) -{ - RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY); - RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE); - RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP); - RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART); - RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT); - RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS); - - return OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE; -} - -uint64_t Utils::Obs::NumberHelper::GetOutputDuration(obs_output_t *output) -{ - if (!output || !obs_output_active(output)) - return 0; - - video_t* video = obs_output_video(output); - uint64_t frameTimeNs = video_output_get_frame_time(video); - int totalFrames = obs_output_get_total_frames(output); - - return util_mul_div64(totalFrames, frameTimeNs, 1000000ULL); -} - -size_t Utils::Obs::NumberHelper::GetSceneCount() -{ - size_t ret; - auto sceneEnumProc = [](void *param, obs_source_t *scene) { - auto ret = reinterpret_cast(param); - - if (obs_source_is_group(scene)) - return true; - - (*ret)++; - return true; - }; - - obs_enum_scenes(sceneEnumProc, &ret); - - return ret; -} - -std::vector Utils::Obs::ListHelper::GetSceneCollectionList() -{ - char** sceneCollections = obs_frontend_get_scene_collections(); - auto ret = ConvertStringArray(sceneCollections); - bfree(sceneCollections); - return ret; -} - -std::vector Utils::Obs::ListHelper::GetProfileList() -{ - char** profiles = obs_frontend_get_profiles(); - auto ret = ConvertStringArray(profiles); - bfree(profiles); - return ret; -} - -std::vector Utils::Obs::ListHelper::GetHotkeyList() -{ - std::vector ret; - - obs_enum_hotkeys([](void* data, obs_hotkey_id, obs_hotkey_t* hotkey) { - auto ret = reinterpret_cast *>(data); - - ret->push_back(hotkey); - - return true; - }, &ret); - - return ret; -} - -std::vector Utils::Obs::ListHelper::GetHotkeyNameList() -{ - auto hotkeys = GetHotkeyList(); - - std::vector ret; - for (auto hotkey : hotkeys) { - ret.emplace_back(obs_hotkey_get_name(hotkey)); - } - - return ret; -} - -std::vector Utils::Obs::ListHelper::GetSceneList() -{ - obs_frontend_source_list sceneList = {}; - obs_frontend_get_scenes(&sceneList); - - std::vector ret; - for (size_t i = 0; i < sceneList.sources.num; i++) { - obs_source_t *scene = sceneList.sources.array[i]; - - if (obs_source_is_group(scene)) - continue; - - json sceneJson; - sceneJson["sceneName"] = obs_source_get_name(scene); - sceneJson["sceneIndex"] = sceneList.sources.num - i - 1; - - 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 Utils::Obs::ListHelper::GetSceneItemList(obs_scene_t *scene, bool basic) -{ - std::pair, bool> enumData; - enumData.second = basic; - - obs_scene_enum_items(scene, [](obs_scene_t*, obs_sceneitem_t* sceneItem, void* param) { - auto enumData = reinterpret_cast, bool>*>(param); - - json item; - item["sceneItemId"] = obs_sceneitem_get_id(sceneItem); - // Should be slightly faster than calling obs_sceneitem_get_order_position() - item["sceneItemIndex"] = enumData->first.size(); - if (!enumData->second) { - OBSSource itemSource = obs_sceneitem_get_source(sceneItem); - item["sourceName"] = obs_source_get_name(itemSource); - item["sourceType"] = StringHelper::GetSourceType(itemSource); - if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_INPUT) - item["inputKind"] = obs_source_get_id(itemSource); - else - item["inputKind"] = nullptr; - if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_SCENE) - item["isGroup"] = obs_source_is_group(itemSource); - else - item["isGroup"] = nullptr; - } - - enumData->first.push_back(item); - - return true; - }, &enumData); - - return enumData.first; -} - -std::vector Utils::Obs::ListHelper::GetTransitionList() -{ - obs_frontend_source_list transitionList = {}; - obs_frontend_get_transitions(&transitionList); - - std::vector ret; - for (size_t i = 0; i < transitionList.sources.num; i++) { - obs_source_t *transition = transitionList.sources.array[i]; - json transitionJson; - transitionJson["transitionName"] = obs_source_get_name(transition); - transitionJson["transitionKind"] = obs_source_get_id(transition); - transitionJson["transitionFixed"] = obs_transition_fixed(transition); - ret.push_back(transitionJson); - } - - obs_frontend_source_list_free(&transitionList); - - return ret; -} - -struct EnumInputInfo { - std::string inputKind; // For searching by input kind - std::vector inputs; -}; - -std::vector Utils::Obs::ListHelper::GetInputList(std::string inputKind) -{ - EnumInputInfo inputInfo; - inputInfo.inputKind = inputKind; - - auto inputEnumProc = [](void *param, obs_source_t *input) { - // Sanity check in case the API changes - if (obs_source_get_type(input) != OBS_SOURCE_TYPE_INPUT) - return true; - - auto inputInfo = reinterpret_cast(param); - - std::string inputKind = obs_source_get_id(input); - - if (!inputInfo->inputKind.empty() && inputInfo->inputKind != inputKind) - return true; - - json inputJson; - inputJson["inputName"] = obs_source_get_name(input); - inputJson["inputKind"] = inputKind; - inputJson["unversionedInputKind"] = obs_source_get_unversioned_id(input); - - inputInfo->inputs.push_back(inputJson); - return true; - }; - // Actually enumerates only public inputs, despite the name - obs_enum_sources(inputEnumProc, &inputInfo); - - return inputInfo.inputs; -} - -std::vector Utils::Obs::ListHelper::GetInputKindList(bool unversioned, bool includeDisabled) -{ - std::vector ret; - - size_t idx = 0; - const char *kind; - const char *unversioned_kind; - while (obs_enum_input_types2(idx++, &kind, &unversioned_kind)) { - uint32_t caps = obs_get_source_output_flags(kind); - - if (!includeDisabled && (caps & OBS_SOURCE_CAP_DISABLED) != 0) - continue; - - if (unversioned) - ret.push_back(unversioned_kind); - else - ret.push_back(kind); - } - - return ret; -} - -json Utils::Obs::DataHelper::GetStats() -{ - json ret; - - config_t* currentProfile = obs_frontend_get_profile_config(); - const char* outputMode = config_get_string(currentProfile, "Output", "Mode"); - const char* recordPath = strcmp(outputMode, "Advanced") ? config_get_string(currentProfile, "SimpleOutput", "FilePath") : config_get_string(currentProfile, "AdvOut", "RecFilePath"); - - video_t* video = obs_get_video(); - - ret["cpuUsage"] = os_cpu_usage_info_query(GetCpuUsageInfo()); - ret["memoryUsage"] = (double)os_get_proc_resident_size() / (1024.0 * 1024.0); - ret["availableDiskSpace"] = (double)os_get_free_disk_space(recordPath) / (1024.0 * 1024.0); - ret["activeFps"] = obs_get_active_fps(); - ret["averageFrameRenderTime"] = (double)obs_get_average_frame_time_ns() / 1000000.0; - ret["renderSkippedFrames"] = obs_get_lagged_frames(); - ret["renderTotalFrames"] = obs_get_total_frames(); - ret["outputSkippedFrames"] = video_output_get_skipped_frames(video); - ret["outputTotalFrames"] = video_output_get_total_frames(video); - - return ret; -} - -json Utils::Obs::DataHelper::GetSceneItemTransform(obs_sceneitem_t *item) -{ - json ret; - - obs_transform_info osi; - obs_sceneitem_crop crop; - obs_sceneitem_get_info(item, &osi); - obs_sceneitem_get_crop(item, &crop); - - OBSSource source = obs_sceneitem_get_source(item); - float sourceWidth = float(obs_source_get_width(source)); - float sourceHeight = float(obs_source_get_height(source)); - - ret["sourceWidth"] = sourceWidth; - ret["sourceHeight"] = sourceHeight; - - ret["positionX"] = osi.pos.x; - ret["positionY"] = osi.pos.y; - - ret["rotation"] = osi.rot; - - ret["scaleX"] = osi.scale.x; - ret["scaleY"] = osi.scale.y; - - ret["width"] = osi.scale.x * sourceWidth; - ret["height"] = osi.scale.y * sourceHeight; - - ret["alignment"] = osi.alignment; - - ret["boundsType"] = StringHelper::GetSceneItemBoundsType(osi.bounds_type); - ret["boundsAlignment"] = osi.bounds_alignment; - ret["boundsWidth"] = osi.bounds.x; - ret["boundsHeight"] = osi.bounds.y; - - ret["cropLeft"] = int(crop.left); - ret["cropRight"] = int(crop.right); - ret["cropTop"] = int(crop.top); - ret["cropBottom"] = int(crop.bottom); - - return ret; -} - -obs_hotkey_t *Utils::Obs::SearchHelper::GetHotkeyByName(std::string name) -{ - if (name.empty()) - return nullptr; - - auto hotkeys = ListHelper::GetHotkeyList(); - - for (auto hotkey : hotkeys) { - if (obs_hotkey_get_name(hotkey) == name) - return hotkey; - } - - return nullptr; -} - -// Increments item ref. Use OBSSceneItemAutoRelease -obs_sceneitem_t *Utils::Obs::SearchHelper::GetSceneItemByName(obs_scene_t *scene, std::string name) -{ - if (name.empty()) - return nullptr; - - // Finds first matching scene item in scene, search starts at index 0 - OBSSceneItem ret = obs_scene_find_source(scene, name.c_str()); - obs_sceneitem_addref(ret); - - return ret; -} - -struct CreateSceneItemData { - obs_source_t *source; // In - bool sceneItemEnabled; // In - obs_transform_info *sceneItemTransform = nullptr; // In - obs_sceneitem_crop *sceneItemCrop = nullptr; // In - OBSSceneItem sceneItem; // Out -}; - -void CreateSceneItemHelper(void *_data, obs_scene_t *scene) -{ - auto *data = reinterpret_cast(_data); - data->sceneItem = obs_scene_add(scene, data->source); - - if (data->sceneItemTransform) - obs_sceneitem_set_info(data->sceneItem, data->sceneItemTransform); - - if (data->sceneItemCrop) - obs_sceneitem_set_crop(data->sceneItem, data->sceneItemCrop); - - obs_sceneitem_set_visible(data->sceneItem, data->sceneItemEnabled); -} - -obs_sceneitem_t *Utils::Obs::ActionHelper::CreateSceneItem(obs_source_t *source, obs_scene_t *scene, bool sceneItemEnabled, obs_transform_info *sceneItemTransform, obs_sceneitem_crop *sceneItemCrop) -{ - // Sanity check for valid scene - if (!(source && scene)) - return nullptr; - - // Create data struct and populate for scene item creation - CreateSceneItemData data; - data.source = source; - data.sceneItemEnabled = sceneItemEnabled; - data.sceneItemTransform = sceneItemTransform; - data.sceneItemCrop = sceneItemCrop; - - // Enter graphics context and create the scene item - obs_enter_graphics(); - obs_scene_atomic_update(scene, CreateSceneItemHelper, &data); - obs_leave_graphics(); - - obs_sceneitem_addref(data.sceneItem); - - return data.sceneItem; -} - -obs_sceneitem_t *Utils::Obs::ActionHelper::CreateInput(std::string inputName, std::string inputKind, obs_data_t *inputSettings, obs_scene_t *scene, bool sceneItemEnabled) -{ - // Create the input - OBSSourceAutoRelease input = obs_source_create(inputKind.c_str(), inputName.c_str(), inputSettings, nullptr); - - // Check that everything was created properly - if (!input) - return nullptr; - - // Apparently not all default input properties actually get applied on creation (smh) - uint32_t flags = obs_source_get_output_flags(input); - if ((flags & OBS_SOURCE_MONITOR_BY_DEFAULT) != 0) - obs_source_set_monitoring_type(input, OBS_MONITORING_TYPE_MONITOR_ONLY); - - // Create a scene item for the input - obs_sceneitem_t *ret = CreateSceneItem(input, scene, sceneItemEnabled); - - // If creation failed, remove the input - if (!ret) - obs_source_remove(input); - - return ret; -} diff --git a/src/utils/Obs.h b/src/utils/Obs.h index f5beecad..e92788ce 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -21,6 +21,7 @@ with this program. If not, see #include #include +#include #include "Json.h" diff --git a/src/utils/Obs_ActionHelper.cpp b/src/utils/Obs_ActionHelper.cpp new file mode 100644 index 00000000..5442219b --- /dev/null +++ b/src/utils/Obs_ActionHelper.cpp @@ -0,0 +1,89 @@ +/* +obs-websocket +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 "Obs.h" +#include "../plugin-macros.generated.h" + +struct CreateSceneItemData { + obs_source_t *source; // In + bool sceneItemEnabled; // In + obs_transform_info *sceneItemTransform = nullptr; // In + obs_sceneitem_crop *sceneItemCrop = nullptr; // In + OBSSceneItem sceneItem; // Out +}; + +void CreateSceneItemHelper(void *_data, obs_scene_t *scene) +{ + auto *data = reinterpret_cast(_data); + data->sceneItem = obs_scene_add(scene, data->source); + + if (data->sceneItemTransform) + obs_sceneitem_set_info(data->sceneItem, data->sceneItemTransform); + + if (data->sceneItemCrop) + obs_sceneitem_set_crop(data->sceneItem, data->sceneItemCrop); + + obs_sceneitem_set_visible(data->sceneItem, data->sceneItemEnabled); +} + +obs_sceneitem_t *Utils::Obs::ActionHelper::CreateSceneItem(obs_source_t *source, obs_scene_t *scene, bool sceneItemEnabled, obs_transform_info *sceneItemTransform, obs_sceneitem_crop *sceneItemCrop) +{ + // Sanity check for valid scene + if (!(source && scene)) + return nullptr; + + // Create data struct and populate for scene item creation + CreateSceneItemData data; + data.source = source; + data.sceneItemEnabled = sceneItemEnabled; + data.sceneItemTransform = sceneItemTransform; + data.sceneItemCrop = sceneItemCrop; + + // Enter graphics context and create the scene item + obs_enter_graphics(); + obs_scene_atomic_update(scene, CreateSceneItemHelper, &data); + obs_leave_graphics(); + + obs_sceneitem_addref(data.sceneItem); + + return data.sceneItem; +} + +obs_sceneitem_t *Utils::Obs::ActionHelper::CreateInput(std::string inputName, std::string inputKind, obs_data_t *inputSettings, obs_scene_t *scene, bool sceneItemEnabled) +{ + // Create the input + OBSSourceAutoRelease input = obs_source_create(inputKind.c_str(), inputName.c_str(), inputSettings, nullptr); + + // Check that everything was created properly + if (!input) + return nullptr; + + // Apparently not all default input properties actually get applied on creation (smh) + uint32_t flags = obs_source_get_output_flags(input); + if ((flags & OBS_SOURCE_MONITOR_BY_DEFAULT) != 0) + obs_source_set_monitoring_type(input, OBS_MONITORING_TYPE_MONITOR_ONLY); + + // Create a scene item for the input + obs_sceneitem_t *ret = CreateSceneItem(input, scene, sceneItemEnabled); + + // If creation failed, remove the input + if (!ret) + obs_source_remove(input); + + return ret; +} diff --git a/src/utils/Obs_DataHelper.cpp b/src/utils/Obs_DataHelper.cpp new file mode 100644 index 00000000..1d5b33e1 --- /dev/null +++ b/src/utils/Obs_DataHelper.cpp @@ -0,0 +1,89 @@ +/* +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 + +#include "Obs.h" +#include "../obs-websocket.h" +#include "../plugin-macros.generated.h" + +json Utils::Obs::DataHelper::GetStats() +{ + json ret; + + config_t* currentProfile = obs_frontend_get_profile_config(); + const char* outputMode = config_get_string(currentProfile, "Output", "Mode"); + const char* recordPath = strcmp(outputMode, "Advanced") ? config_get_string(currentProfile, "SimpleOutput", "FilePath") : config_get_string(currentProfile, "AdvOut", "RecFilePath"); + + video_t* video = obs_get_video(); + + ret["cpuUsage"] = os_cpu_usage_info_query(GetCpuUsageInfo()); + ret["memoryUsage"] = (double)os_get_proc_resident_size() / (1024.0 * 1024.0); + ret["availableDiskSpace"] = (double)os_get_free_disk_space(recordPath) / (1024.0 * 1024.0); + ret["activeFps"] = obs_get_active_fps(); + ret["averageFrameRenderTime"] = (double)obs_get_average_frame_time_ns() / 1000000.0; + ret["renderSkippedFrames"] = obs_get_lagged_frames(); + ret["renderTotalFrames"] = obs_get_total_frames(); + ret["outputSkippedFrames"] = video_output_get_skipped_frames(video); + ret["outputTotalFrames"] = video_output_get_total_frames(video); + + return ret; +} + +json Utils::Obs::DataHelper::GetSceneItemTransform(obs_sceneitem_t *item) +{ + json ret; + + obs_transform_info osi; + obs_sceneitem_crop crop; + obs_sceneitem_get_info(item, &osi); + obs_sceneitem_get_crop(item, &crop); + + OBSSource source = obs_sceneitem_get_source(item); + float sourceWidth = float(obs_source_get_width(source)); + float sourceHeight = float(obs_source_get_height(source)); + + ret["sourceWidth"] = sourceWidth; + ret["sourceHeight"] = sourceHeight; + + ret["positionX"] = osi.pos.x; + ret["positionY"] = osi.pos.y; + + ret["rotation"] = osi.rot; + + ret["scaleX"] = osi.scale.x; + ret["scaleY"] = osi.scale.y; + + ret["width"] = osi.scale.x * sourceWidth; + ret["height"] = osi.scale.y * sourceHeight; + + ret["alignment"] = osi.alignment; + + ret["boundsType"] = StringHelper::GetSceneItemBoundsType(osi.bounds_type); + ret["boundsAlignment"] = osi.bounds_alignment; + ret["boundsWidth"] = osi.bounds.x; + ret["boundsHeight"] = osi.bounds.y; + + ret["cropLeft"] = int(crop.left); + ret["cropRight"] = int(crop.right); + ret["cropTop"] = int(crop.top); + ret["cropBottom"] = int(crop.bottom); + + return ret; +} diff --git a/src/utils/Obs_EnumHelper.cpp b/src/utils/Obs_EnumHelper.cpp new file mode 100644 index 00000000..b0c21aa4 --- /dev/null +++ b/src/utils/Obs_EnumHelper.cpp @@ -0,0 +1,47 @@ +/* +obs-websocket +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 "Obs.h" +#include "../plugin-macros.generated.h" + +#define RET_COMPARE(str, x) if (str == #x) return x; + +enum obs_bounds_type Utils::Obs::EnumHelper::GetSceneItemBoundsType(std::string boundsType) +{ + RET_COMPARE(boundsType, OBS_BOUNDS_NONE); + RET_COMPARE(boundsType, OBS_BOUNDS_STRETCH); + RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_INNER); + RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_OUTER); + RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_TO_WIDTH); + RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_TO_HEIGHT); + RET_COMPARE(boundsType, OBS_BOUNDS_MAX_ONLY); + + return OBS_BOUNDS_NONE; +} + +enum ObsMediaInputAction Utils::Obs::EnumHelper::GetMediaInputAction(std::string mediaAction) +{ + RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY); + RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE); + RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP); + RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART); + RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT); + RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS); + + return OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE; +} diff --git a/src/utils/Obs_ListHelper.cpp b/src/utils/Obs_ListHelper.cpp new file mode 100644 index 00000000..9a40fbd0 --- /dev/null +++ b/src/utils/Obs_ListHelper.cpp @@ -0,0 +1,222 @@ +/* +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 + +#include "Obs.h" +#include "../plugin-macros.generated.h" + +static std::vector ConvertStringArray(char **array) +{ + std::vector ret; + if (!array) + return ret; + + size_t index = 0; + char* value = nullptr; + do { + value = array[index]; + if (value) + ret.push_back(value); + index++; + } while (value); + + return ret; +} + +std::vector Utils::Obs::ListHelper::GetSceneCollectionList() +{ + char** sceneCollections = obs_frontend_get_scene_collections(); + auto ret = ConvertStringArray(sceneCollections); + bfree(sceneCollections); + return ret; +} + +std::vector Utils::Obs::ListHelper::GetProfileList() +{ + char** profiles = obs_frontend_get_profiles(); + auto ret = ConvertStringArray(profiles); + bfree(profiles); + return ret; +} + +std::vector Utils::Obs::ListHelper::GetHotkeyList() +{ + std::vector ret; + + obs_enum_hotkeys([](void* data, obs_hotkey_id, obs_hotkey_t* hotkey) { + auto ret = reinterpret_cast *>(data); + + ret->push_back(hotkey); + + return true; + }, &ret); + + return ret; +} + +std::vector Utils::Obs::ListHelper::GetHotkeyNameList() +{ + auto hotkeys = GetHotkeyList(); + + std::vector ret; + for (auto hotkey : hotkeys) + ret.emplace_back(obs_hotkey_get_name(hotkey)); + + return ret; +} + +std::vector Utils::Obs::ListHelper::GetSceneList() +{ + obs_frontend_source_list sceneList = {}; + obs_frontend_get_scenes(&sceneList); + + std::vector ret; + for (size_t i = 0; i < sceneList.sources.num; i++) { + obs_source_t *scene = sceneList.sources.array[i]; + + if (obs_source_is_group(scene)) + continue; + + json sceneJson; + sceneJson["sceneName"] = obs_source_get_name(scene); + sceneJson["sceneIndex"] = sceneList.sources.num - i - 1; + + 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 Utils::Obs::ListHelper::GetSceneItemList(obs_scene_t *scene, bool basic) +{ + std::pair, bool> enumData; + enumData.second = basic; + + obs_scene_enum_items(scene, [](obs_scene_t*, obs_sceneitem_t* sceneItem, void* param) { + auto enumData = reinterpret_cast, bool>*>(param); + + json item; + item["sceneItemId"] = obs_sceneitem_get_id(sceneItem); + // Should be slightly faster than calling obs_sceneitem_get_order_position() + item["sceneItemIndex"] = enumData->first.size(); + if (!enumData->second) { + OBSSource itemSource = obs_sceneitem_get_source(sceneItem); + item["sourceName"] = obs_source_get_name(itemSource); + item["sourceType"] = StringHelper::GetSourceType(itemSource); + if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_INPUT) + item["inputKind"] = obs_source_get_id(itemSource); + else + item["inputKind"] = nullptr; + if (obs_source_get_type(itemSource) == OBS_SOURCE_TYPE_SCENE) + item["isGroup"] = obs_source_is_group(itemSource); + else + item["isGroup"] = nullptr; + } + + enumData->first.push_back(item); + + return true; + }, &enumData); + + return enumData.first; +} + +std::vector Utils::Obs::ListHelper::GetTransitionList() +{ + obs_frontend_source_list transitionList = {}; + obs_frontend_get_transitions(&transitionList); + + std::vector ret; + for (size_t i = 0; i < transitionList.sources.num; i++) { + obs_source_t *transition = transitionList.sources.array[i]; + json transitionJson; + transitionJson["transitionName"] = obs_source_get_name(transition); + transitionJson["transitionKind"] = obs_source_get_id(transition); + transitionJson["transitionFixed"] = obs_transition_fixed(transition); + ret.push_back(transitionJson); + } + + obs_frontend_source_list_free(&transitionList); + + return ret; +} + +struct EnumInputInfo { + std::string inputKind; // For searching by input kind + std::vector inputs; +}; + +std::vector Utils::Obs::ListHelper::GetInputList(std::string inputKind) +{ + EnumInputInfo inputInfo; + inputInfo.inputKind = inputKind; + + auto inputEnumProc = [](void *param, obs_source_t *input) { + // Sanity check in case the API changes + if (obs_source_get_type(input) != OBS_SOURCE_TYPE_INPUT) + return true; + + auto inputInfo = reinterpret_cast(param); + + std::string inputKind = obs_source_get_id(input); + + if (!inputInfo->inputKind.empty() && inputInfo->inputKind != inputKind) + return true; + + json inputJson; + inputJson["inputName"] = obs_source_get_name(input); + inputJson["inputKind"] = inputKind; + inputJson["unversionedInputKind"] = obs_source_get_unversioned_id(input); + + inputInfo->inputs.push_back(inputJson); + return true; + }; + // Actually enumerates only public inputs, despite the name + obs_enum_sources(inputEnumProc, &inputInfo); + + return inputInfo.inputs; +} + +std::vector Utils::Obs::ListHelper::GetInputKindList(bool unversioned, bool includeDisabled) +{ + std::vector ret; + + size_t idx = 0; + const char *kind; + const char *unversioned_kind; + while (obs_enum_input_types2(idx++, &kind, &unversioned_kind)) { + uint32_t caps = obs_get_source_output_flags(kind); + + if (!includeDisabled && (caps & OBS_SOURCE_CAP_DISABLED) != 0) + continue; + + if (unversioned) + ret.push_back(unversioned_kind); + else + ret.push_back(kind); + } + + return ret; +} diff --git a/src/utils/Obs_NumberHelper.cpp b/src/utils/Obs_NumberHelper.cpp new file mode 100644 index 00000000..a3891231 --- /dev/null +++ b/src/utils/Obs_NumberHelper.cpp @@ -0,0 +1,54 @@ +/* +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 +#include + +#include "Obs.h" +#include "../plugin-macros.generated.h" + +uint64_t Utils::Obs::NumberHelper::GetOutputDuration(obs_output_t *output) +{ + if (!output || !obs_output_active(output)) + return 0; + + video_t* video = obs_output_video(output); + uint64_t frameTimeNs = video_output_get_frame_time(video); + int totalFrames = obs_output_get_total_frames(output); + + return util_mul_div64(totalFrames, frameTimeNs, 1000000ULL); +} + +size_t Utils::Obs::NumberHelper::GetSceneCount() +{ + size_t ret; + auto sceneEnumProc = [](void *param, obs_source_t *scene) { + auto ret = reinterpret_cast(param); + + if (obs_source_is_group(scene)) + return true; + + (*ret)++; + return true; + }; + + obs_enum_scenes(sceneEnumProc, &ret); + + return ret; +} diff --git a/src/utils/Obs_SearchHelper.cpp b/src/utils/Obs_SearchHelper.cpp new file mode 100644 index 00000000..3b3e95ff --- /dev/null +++ b/src/utils/Obs_SearchHelper.cpp @@ -0,0 +1,48 @@ +/* +obs-websocket +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 "Obs.h" +#include "../plugin-macros.generated.h" + +obs_hotkey_t *Utils::Obs::SearchHelper::GetHotkeyByName(std::string name) +{ + if (name.empty()) + return nullptr; + + auto hotkeys = ListHelper::GetHotkeyList(); + + for (auto hotkey : hotkeys) { + if (obs_hotkey_get_name(hotkey) == name) + return hotkey; + } + + return nullptr; +} + +// Increments item ref. Use OBSSceneItemAutoRelease +obs_sceneitem_t *Utils::Obs::SearchHelper::GetSceneItemByName(obs_scene_t *scene, std::string name) +{ + if (name.empty()) + return nullptr; + + // Finds first matching scene item in scene, search starts at index 0 + OBSSceneItem ret = obs_scene_find_source(scene, name.c_str()); + obs_sceneitem_addref(ret); + + return ret; +} diff --git a/src/utils/Obs_StringHelper.cpp b/src/utils/Obs_StringHelper.cpp new file mode 100644 index 00000000..3abf6c50 --- /dev/null +++ b/src/utils/Obs_StringHelper.cpp @@ -0,0 +1,154 @@ +/* +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 +#include + +#include "Obs.h" +#include "../plugin-macros.generated.h" + +#define CASE(x) case x: return #x; + +std::string Utils::Obs::StringHelper::GetObsVersion() +{ + uint32_t version = obs_get_version(); + + uint8_t major, minor, patch; + major = (version >> 24) & 0xFF; + minor = (version >> 16) & 0xFF; + patch = version & 0xFF; + + QString combined = QString("%1.%2.%3").arg(major).arg(minor).arg(patch); + return combined.toStdString(); +} + +std::string Utils::Obs::StringHelper::GetCurrentSceneCollection() +{ + char *sceneCollectionName = obs_frontend_get_current_scene_collection(); + std::string ret = sceneCollectionName; + bfree(sceneCollectionName); + return ret; +} + +std::string Utils::Obs::StringHelper::GetCurrentProfile() +{ + char *profileName = obs_frontend_get_current_profile(); + std::string ret = profileName; + bfree(profileName); + return ret; +} + +std::string Utils::Obs::StringHelper::GetCurrentProfilePath() +{ + char *profilePath = obs_frontend_get_current_profile_path(); + std::string ret = profilePath; + bfree(profilePath); + return ret; +} + +std::string Utils::Obs::StringHelper::GetCurrentRecordOutputPath() +{ + //char *recordOutputPath = obs_frontend_get_current_record_output_path(); + //std::string ret = recordOutputPath; + //bfree(recordOutputPath); + //return ret; + + return ""; +} + +std::string Utils::Obs::StringHelper::GetSourceType(obs_source_t *source) +{ + obs_source_type sourceType = obs_source_get_type(source); + + switch (sourceType) { + default: + CASE(OBS_SOURCE_TYPE_INPUT) + CASE(OBS_SOURCE_TYPE_FILTER) + CASE(OBS_SOURCE_TYPE_TRANSITION) + CASE(OBS_SOURCE_TYPE_SCENE) + } +} + +std::string Utils::Obs::StringHelper::GetInputMonitorType(obs_source_t *input) +{ + obs_monitoring_type monitorType = obs_source_get_monitoring_type(input); + + switch (monitorType) { + default: + CASE(OBS_MONITORING_TYPE_NONE) + CASE(OBS_MONITORING_TYPE_MONITOR_ONLY) + CASE(OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT) + } +} + +std::string Utils::Obs::StringHelper::GetMediaInputState(obs_source_t *input) +{ + obs_media_state mediaState = obs_source_media_get_state(input); + + switch (mediaState) { + default: + CASE(OBS_MEDIA_STATE_NONE) + CASE(OBS_MEDIA_STATE_PLAYING) + CASE(OBS_MEDIA_STATE_OPENING) + CASE(OBS_MEDIA_STATE_BUFFERING) + CASE(OBS_MEDIA_STATE_PAUSED) + CASE(OBS_MEDIA_STATE_STOPPED) + CASE(OBS_MEDIA_STATE_ENDED) + CASE(OBS_MEDIA_STATE_ERROR) + } +} + +std::string Utils::Obs::StringHelper::GetLastReplayBufferFilePath() +{ + OBSOutputAutoRelease output = obs_frontend_get_replay_buffer_output(); + calldata_t cd = {0}; + proc_handler_t *ph = obs_output_get_proc_handler(output); + proc_handler_call(ph, "get_last_replay", &cd); + auto ret = calldata_string(&cd, "path"); + calldata_free(&cd); + return ret; +} + +std::string Utils::Obs::StringHelper::GetSceneItemBoundsType(enum obs_bounds_type type) +{ + switch (type) { + default: + CASE(OBS_BOUNDS_NONE) + CASE(OBS_BOUNDS_STRETCH) + CASE(OBS_BOUNDS_SCALE_INNER) + CASE(OBS_BOUNDS_SCALE_OUTER) + CASE(OBS_BOUNDS_SCALE_TO_WIDTH) + CASE(OBS_BOUNDS_SCALE_TO_HEIGHT) + CASE(OBS_BOUNDS_MAX_ONLY) + } +} + +std::string Utils::Obs::StringHelper::DurationToTimecode(uint64_t ms) +{ + uint64_t secs = ms / 1000ULL; + uint64_t minutes = secs / 60ULL; + + uint64_t hoursPart = minutes / 60ULL; + uint64_t minutesPart = minutes % 60ULL; + uint64_t secsPart = secs % 60ULL; + uint64_t msPart = ms % 1000ULL; + + QString formatted = QString::asprintf("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64 ".%03" PRIu64, hoursPart, minutesPart, secsPart, msPart); + return formatted.toStdString(); +} From 5cd1af426ab4be680fc992b3c7308cb200351434 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sat, 18 Dec 2021 21:50:00 -0800 Subject: [PATCH 014/128] Utils: Rename `DataHelper` to `ObjectHelper` --- CMakeLists.txt | 2 +- src/eventhandler/EventHandler_SceneItems.cpp | 2 +- src/requesthandler/RequestHandler_General.cpp | 2 +- src/requesthandler/RequestHandler_SceneItems.cpp | 2 +- src/utils/Obs.h | 2 +- src/utils/{Obs_DataHelper.cpp => Obs_ObjectHelper.cpp} | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) rename src/utils/{Obs_DataHelper.cpp => Obs_ObjectHelper.cpp} (96%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86eead93..74183b4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,7 +127,7 @@ set(obs-websocket_SOURCES src/utils/Obs_EnumHelper.cpp src/utils/Obs_NumberHelper.cpp src/utils/Obs_ListHelper.cpp - src/utils/Obs_DataHelper.cpp + src/utils/Obs_ObjectHelper.cpp src/utils/Obs_SearchHelper.cpp src/utils/Obs_ActionHelper.cpp src/utils/ObsVolumeMeter.cpp diff --git a/src/eventhandler/EventHandler_SceneItems.cpp b/src/eventhandler/EventHandler_SceneItems.cpp index b811dc22..d570dcef 100644 --- a/src/eventhandler/EventHandler_SceneItems.cpp +++ b/src/eventhandler/EventHandler_SceneItems.cpp @@ -134,6 +134,6 @@ void EventHandler::HandleSceneItemTransformChanged(void *param, calldata_t *data json eventData; eventData["sceneName"] = obs_source_get_name(obs_scene_get_source(scene)); eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem); - eventData["sceneItemTransform"] = Utils::Obs::DataHelper::GetSceneItemTransform(sceneItem); + eventData["sceneItemTransform"] = Utils::Obs::ObjectHelper::GetSceneItemTransform(sceneItem); eventHandler->BroadcastEvent(EventSubscription::SceneItemTransformChanged, "SceneItemTransformChanged", eventData); } diff --git a/src/requesthandler/RequestHandler_General.cpp b/src/requesthandler/RequestHandler_General.cpp index 9e4238ef..ea6afb40 100644 --- a/src/requesthandler/RequestHandler_General.cpp +++ b/src/requesthandler/RequestHandler_General.cpp @@ -84,7 +84,7 @@ RequestResult RequestHandler::GetVersion(const Request&) */ RequestResult RequestHandler::GetStats(const Request&) { - json responseData = Utils::Obs::DataHelper::GetStats(); + json responseData = Utils::Obs::ObjectHelper::GetStats(); responseData["webSocketSessionIncomingMessages"] = _session->IncomingMessages(); responseData["webSocketSessionOutgoingMessages"] = _session->OutgoingMessages(); diff --git a/src/requesthandler/RequestHandler_SceneItems.cpp b/src/requesthandler/RequestHandler_SceneItems.cpp index 3f612cfc..bb6a41b0 100644 --- a/src/requesthandler/RequestHandler_SceneItems.cpp +++ b/src/requesthandler/RequestHandler_SceneItems.cpp @@ -293,7 +293,7 @@ RequestResult RequestHandler::GetSceneItemTransform(const Request& request) return RequestResult::Error(statusCode, comment); json responseData; - responseData["sceneItemTransform"] = Utils::Obs::DataHelper::GetSceneItemTransform(sceneItem); + responseData["sceneItemTransform"] = Utils::Obs::ObjectHelper::GetSceneItemTransform(sceneItem); return RequestResult::Success(responseData); } diff --git a/src/utils/Obs.h b/src/utils/Obs.h index e92788ce..c3e4a410 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -123,7 +123,7 @@ namespace Utils { std::vector GetInputKindList(bool unversioned = false, bool includeDisabled = false); } - namespace DataHelper { + namespace ObjectHelper { json GetStats(); json GetSceneItemTransform(obs_sceneitem_t *item); } diff --git a/src/utils/Obs_DataHelper.cpp b/src/utils/Obs_ObjectHelper.cpp similarity index 96% rename from src/utils/Obs_DataHelper.cpp rename to src/utils/Obs_ObjectHelper.cpp index 1d5b33e1..34077c62 100644 --- a/src/utils/Obs_DataHelper.cpp +++ b/src/utils/Obs_ObjectHelper.cpp @@ -23,7 +23,7 @@ with this program. If not, see #include "../obs-websocket.h" #include "../plugin-macros.generated.h" -json Utils::Obs::DataHelper::GetStats() +json Utils::Obs::ObjectHelper::GetStats() { json ret; @@ -46,7 +46,7 @@ json Utils::Obs::DataHelper::GetStats() return ret; } -json Utils::Obs::DataHelper::GetSceneItemTransform(obs_sceneitem_t *item) +json Utils::Obs::ObjectHelper::GetSceneItemTransform(obs_sceneitem_t *item) { json ret; From 1e6a60f5455ae47e827968e252b84c86c93f8caf Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sat, 18 Dec 2021 21:54:29 -0800 Subject: [PATCH 015/128] Utils: Rename `ListHelper` to `ArrayHelper` --- CMakeLists.txt | 2 +- src/eventhandler/EventHandler_Config.cpp | 4 ++-- src/eventhandler/EventHandler_SceneItems.cpp | 2 +- src/eventhandler/EventHandler_Scenes.cpp | 2 +- src/requesthandler/RequestHandler_Config.cpp | 14 +++++++------- src/requesthandler/RequestHandler_General.cpp | 2 +- src/requesthandler/RequestHandler_Inputs.cpp | 6 +++--- .../RequestHandler_SceneItems.cpp | 4 ++-- src/requesthandler/RequestHandler_Scenes.cpp | 2 +- src/utils/Obs.h | 2 +- ...{Obs_ListHelper.cpp => Obs_ArrayHelper.cpp} | 18 +++++++++--------- src/utils/Obs_SearchHelper.cpp | 2 +- 12 files changed, 30 insertions(+), 30 deletions(-) rename src/utils/{Obs_ListHelper.cpp => Obs_ArrayHelper.cpp} (88%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 74183b4d..81a8ddfe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,7 +126,7 @@ set(obs-websocket_SOURCES src/utils/Obs_StringHelper.cpp src/utils/Obs_EnumHelper.cpp src/utils/Obs_NumberHelper.cpp - src/utils/Obs_ListHelper.cpp + src/utils/Obs_ArrayHelper.cpp src/utils/Obs_ObjectHelper.cpp src/utils/Obs_SearchHelper.cpp src/utils/Obs_ActionHelper.cpp diff --git a/src/eventhandler/EventHandler_Config.cpp b/src/eventhandler/EventHandler_Config.cpp index 8082ecba..d93bc621 100644 --- a/src/eventhandler/EventHandler_Config.cpp +++ b/src/eventhandler/EventHandler_Config.cpp @@ -80,7 +80,7 @@ void EventHandler::HandleCurrentSceneCollectionChanged() void EventHandler::HandleSceneCollectionListChanged() { json eventData; - eventData["sceneCollections"] = Utils::Obs::ListHelper::GetSceneCollectionList(); + eventData["sceneCollections"] = Utils::Obs::ArrayHelper::GetSceneCollectionList(); BroadcastEvent(EventSubscription::Config, "SceneCollectionListChanged", eventData); } @@ -140,6 +140,6 @@ void EventHandler::HandleCurrentProfileChanged() void EventHandler::HandleProfileListChanged() { json eventData; - eventData["profiles"] = Utils::Obs::ListHelper::GetProfileList(); + eventData["profiles"] = Utils::Obs::ArrayHelper::GetProfileList(); BroadcastEvent(EventSubscription::Config, "ProfileListChanged", eventData); } diff --git a/src/eventhandler/EventHandler_SceneItems.cpp b/src/eventhandler/EventHandler_SceneItems.cpp index d570dcef..ca0ed9ab 100644 --- a/src/eventhandler/EventHandler_SceneItems.cpp +++ b/src/eventhandler/EventHandler_SceneItems.cpp @@ -70,7 +70,7 @@ void EventHandler::HandleSceneItemListReindexed(void *param, calldata_t *data) json eventData; eventData["sceneName"] = obs_source_get_name(obs_scene_get_source(scene)); - eventData["sceneItems"] = Utils::Obs::ListHelper::GetSceneItemList(scene, true); + eventData["sceneItems"] = Utils::Obs::ArrayHelper::GetSceneItemList(scene, true); eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemListReindexed", eventData); } diff --git a/src/eventhandler/EventHandler_Scenes.cpp b/src/eventhandler/EventHandler_Scenes.cpp index 05c0f587..d8aee383 100644 --- a/src/eventhandler/EventHandler_Scenes.cpp +++ b/src/eventhandler/EventHandler_Scenes.cpp @@ -68,6 +68,6 @@ void EventHandler::HandleCurrentPreviewSceneChanged() void EventHandler::HandleSceneListChanged() { json eventData; - eventData["scenes"] = Utils::Obs::ListHelper::GetSceneList(); + eventData["scenes"] = Utils::Obs::ArrayHelper::GetSceneList(); BroadcastEvent(EventSubscription::Scenes, "SceneListChanged", eventData); } diff --git a/src/requesthandler/RequestHandler_Config.cpp b/src/requesthandler/RequestHandler_Config.cpp index 0cf7fe87..40e0938a 100644 --- a/src/requesthandler/RequestHandler_Config.cpp +++ b/src/requesthandler/RequestHandler_Config.cpp @@ -124,7 +124,7 @@ RequestResult RequestHandler::GetSceneCollectionList(const Request&) { json responseData; responseData["currentSceneCollectionName"] = Utils::Obs::StringHelper::GetCurrentSceneCollection(); - responseData["sceneCollections"] = Utils::Obs::ListHelper::GetSceneCollectionList(); + responseData["sceneCollections"] = Utils::Obs::ArrayHelper::GetSceneCollectionList(); return RequestResult::Success(responseData); } @@ -151,7 +151,7 @@ RequestResult RequestHandler::SetCurrentSceneCollection(const Request& request) std::string sceneCollectionName = request.RequestData["sceneCollectionName"]; - auto sceneCollections = Utils::Obs::ListHelper::GetSceneCollectionList(); + auto sceneCollections = Utils::Obs::ArrayHelper::GetSceneCollectionList(); if (std::find(sceneCollections.begin(), sceneCollections.end(), sceneCollectionName) == sceneCollections.end()) return RequestResult::Error(RequestStatus::ResourceNotFound); @@ -189,7 +189,7 @@ RequestResult RequestHandler::CreateSceneCollection(const Request& request) std::string sceneCollectionName = request.RequestData["sceneCollectionName"]; - auto sceneCollections = Utils::Obs::ListHelper::GetSceneCollectionList(); + auto sceneCollections = Utils::Obs::ArrayHelper::GetSceneCollectionList(); if (std::find(sceneCollections.begin(), sceneCollections.end(), sceneCollectionName) != sceneCollections.end()) return RequestResult::Error(RequestStatus::ResourceAlreadyExists); @@ -219,7 +219,7 @@ RequestResult RequestHandler::GetProfileList(const Request&) { json responseData; responseData["currentProfileName"] = Utils::Obs::StringHelper::GetCurrentProfile(); - responseData["profiles"] = Utils::Obs::ListHelper::GetProfileList(); + responseData["profiles"] = Utils::Obs::ArrayHelper::GetProfileList(); return RequestResult::Success(responseData); } @@ -244,7 +244,7 @@ RequestResult RequestHandler::SetCurrentProfile(const Request& request) std::string profileName = request.RequestData["profileName"]; - auto profiles = Utils::Obs::ListHelper::GetProfileList(); + auto profiles = Utils::Obs::ArrayHelper::GetProfileList(); if (std::find(profiles.begin(), profiles.end(), profileName) == profiles.end()) return RequestResult::Error(RequestStatus::ResourceNotFound); @@ -280,7 +280,7 @@ RequestResult RequestHandler::CreateProfile(const Request& request) std::string profileName = request.RequestData["profileName"]; - auto profiles = Utils::Obs::ListHelper::GetProfileList(); + auto profiles = Utils::Obs::ArrayHelper::GetProfileList(); if (std::find(profiles.begin(), profiles.end(), profileName) != profiles.end()) return RequestResult::Error(RequestStatus::ResourceAlreadyExists); @@ -311,7 +311,7 @@ RequestResult RequestHandler::RemoveProfile(const Request& request) std::string profileName = request.RequestData["profileName"]; - auto profiles = Utils::Obs::ListHelper::GetProfileList(); + auto profiles = Utils::Obs::ArrayHelper::GetProfileList(); if (std::find(profiles.begin(), profiles.end(), profileName) == profiles.end()) return RequestResult::Error(RequestStatus::ResourceNotFound); diff --git a/src/requesthandler/RequestHandler_General.cpp b/src/requesthandler/RequestHandler_General.cpp index ea6afb40..53852ef5 100644 --- a/src/requesthandler/RequestHandler_General.cpp +++ b/src/requesthandler/RequestHandler_General.cpp @@ -195,7 +195,7 @@ RequestResult RequestHandler::CallVendorRequest(const Request& request) RequestResult RequestHandler::GetHotkeyList(const Request&) { json responseData; - responseData["hotkeys"] = Utils::Obs::ListHelper::GetHotkeyNameList(); + responseData["hotkeys"] = Utils::Obs::ArrayHelper::GetHotkeyNameList(); return RequestResult::Success(responseData); } diff --git a/src/requesthandler/RequestHandler_Inputs.cpp b/src/requesthandler/RequestHandler_Inputs.cpp index 3e782bd5..b29bfe1f 100644 --- a/src/requesthandler/RequestHandler_Inputs.cpp +++ b/src/requesthandler/RequestHandler_Inputs.cpp @@ -47,7 +47,7 @@ RequestResult RequestHandler::GetInputList(const Request& request) } json responseData; - responseData["inputs"] = Utils::Obs::ListHelper::GetInputList(inputKind); + responseData["inputs"] = Utils::Obs::ArrayHelper::GetInputList(inputKind); return RequestResult::Success(responseData); } @@ -79,7 +79,7 @@ RequestResult RequestHandler::GetInputKindList(const Request& request) } json responseData; - responseData["inputKinds"] = Utils::Obs::ListHelper::GetInputKindList(unversioned); + responseData["inputKinds"] = Utils::Obs::ArrayHelper::GetInputKindList(unversioned); return RequestResult::Success(responseData); } @@ -115,7 +115,7 @@ RequestResult RequestHandler::CreateInput(const Request& request) return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A source already exists by that input name."); std::string inputKind = request.RequestData["inputKind"]; - auto kinds = Utils::Obs::ListHelper::GetInputKindList(); + auto kinds = Utils::Obs::ArrayHelper::GetInputKindList(); if (std::find(kinds.begin(), kinds.end(), inputKind) == kinds.end()) return RequestResult::Error(RequestStatus::InvalidInputKind, "Your specified input kind is not supported by OBS. Check that your specified kind is properly versioned and that any necessary plugins are loaded."); diff --git a/src/requesthandler/RequestHandler_SceneItems.cpp b/src/requesthandler/RequestHandler_SceneItems.cpp index bb6a41b0..34f1958e 100644 --- a/src/requesthandler/RequestHandler_SceneItems.cpp +++ b/src/requesthandler/RequestHandler_SceneItems.cpp @@ -44,7 +44,7 @@ RequestResult RequestHandler::GetSceneItemList(const Request& request) return RequestResult::Error(statusCode, comment); json responseData; - responseData["sceneItems"] = Utils::Obs::ListHelper::GetSceneItemList(obs_scene_from_source(scene)); + responseData["sceneItems"] = Utils::Obs::ArrayHelper::GetSceneItemList(obs_scene_from_source(scene)); return RequestResult::Success(responseData); } @@ -76,7 +76,7 @@ RequestResult RequestHandler::GetGroupSceneItemList(const Request& request) return RequestResult::Error(statusCode, comment); json responseData; - responseData["sceneItems"] = Utils::Obs::ListHelper::GetSceneItemList(obs_group_from_source(scene)); + responseData["sceneItems"] = Utils::Obs::ArrayHelper::GetSceneItemList(obs_group_from_source(scene)); return RequestResult::Success(responseData); } diff --git a/src/requesthandler/RequestHandler_Scenes.cpp b/src/requesthandler/RequestHandler_Scenes.cpp index f6a3e013..9481013f 100644 --- a/src/requesthandler/RequestHandler_Scenes.cpp +++ b/src/requesthandler/RequestHandler_Scenes.cpp @@ -49,7 +49,7 @@ RequestResult RequestHandler::GetSceneList(const Request&) else responseData["currentPreviewSceneName"] = nullptr; - responseData["scenes"] = Utils::Obs::ListHelper::GetSceneList(); + responseData["scenes"] = Utils::Obs::ArrayHelper::GetSceneList(); return RequestResult::Success(responseData); } diff --git a/src/utils/Obs.h b/src/utils/Obs.h index c3e4a410..2ce8579e 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -111,7 +111,7 @@ namespace Utils { size_t GetSceneCount(); } - namespace ListHelper { + namespace ArrayHelper { std::vector GetSceneCollectionList(); std::vector GetProfileList(); std::vector GetHotkeyList(); diff --git a/src/utils/Obs_ListHelper.cpp b/src/utils/Obs_ArrayHelper.cpp similarity index 88% rename from src/utils/Obs_ListHelper.cpp rename to src/utils/Obs_ArrayHelper.cpp index 9a40fbd0..4b9317a6 100644 --- a/src/utils/Obs_ListHelper.cpp +++ b/src/utils/Obs_ArrayHelper.cpp @@ -40,7 +40,7 @@ static std::vector ConvertStringArray(char **array) return ret; } -std::vector Utils::Obs::ListHelper::GetSceneCollectionList() +std::vector Utils::Obs::ArrayHelper::GetSceneCollectionList() { char** sceneCollections = obs_frontend_get_scene_collections(); auto ret = ConvertStringArray(sceneCollections); @@ -48,7 +48,7 @@ std::vector Utils::Obs::ListHelper::GetSceneCollectionList() return ret; } -std::vector Utils::Obs::ListHelper::GetProfileList() +std::vector Utils::Obs::ArrayHelper::GetProfileList() { char** profiles = obs_frontend_get_profiles(); auto ret = ConvertStringArray(profiles); @@ -56,7 +56,7 @@ std::vector Utils::Obs::ListHelper::GetProfileList() return ret; } -std::vector Utils::Obs::ListHelper::GetHotkeyList() +std::vector Utils::Obs::ArrayHelper::GetHotkeyList() { std::vector ret; @@ -71,7 +71,7 @@ std::vector Utils::Obs::ListHelper::GetHotkeyList() return ret; } -std::vector Utils::Obs::ListHelper::GetHotkeyNameList() +std::vector Utils::Obs::ArrayHelper::GetHotkeyNameList() { auto hotkeys = GetHotkeyList(); @@ -82,7 +82,7 @@ std::vector Utils::Obs::ListHelper::GetHotkeyNameList() return ret; } -std::vector Utils::Obs::ListHelper::GetSceneList() +std::vector Utils::Obs::ArrayHelper::GetSceneList() { obs_frontend_source_list sceneList = {}; obs_frontend_get_scenes(&sceneList); @@ -109,7 +109,7 @@ std::vector Utils::Obs::ListHelper::GetSceneList() return ret; } -std::vector Utils::Obs::ListHelper::GetSceneItemList(obs_scene_t *scene, bool basic) +std::vector Utils::Obs::ArrayHelper::GetSceneItemList(obs_scene_t *scene, bool basic) { std::pair, bool> enumData; enumData.second = basic; @@ -143,7 +143,7 @@ std::vector Utils::Obs::ListHelper::GetSceneItemList(obs_scene_t *scene, b return enumData.first; } -std::vector Utils::Obs::ListHelper::GetTransitionList() +std::vector Utils::Obs::ArrayHelper::GetTransitionList() { obs_frontend_source_list transitionList = {}; obs_frontend_get_transitions(&transitionList); @@ -168,7 +168,7 @@ struct EnumInputInfo { std::vector inputs; }; -std::vector Utils::Obs::ListHelper::GetInputList(std::string inputKind) +std::vector Utils::Obs::ArrayHelper::GetInputList(std::string inputKind) { EnumInputInfo inputInfo; inputInfo.inputKind = inputKind; @@ -199,7 +199,7 @@ std::vector Utils::Obs::ListHelper::GetInputList(std::string inputKind) return inputInfo.inputs; } -std::vector Utils::Obs::ListHelper::GetInputKindList(bool unversioned, bool includeDisabled) +std::vector Utils::Obs::ArrayHelper::GetInputKindList(bool unversioned, bool includeDisabled) { std::vector ret; diff --git a/src/utils/Obs_SearchHelper.cpp b/src/utils/Obs_SearchHelper.cpp index 3b3e95ff..c01ef21b 100644 --- a/src/utils/Obs_SearchHelper.cpp +++ b/src/utils/Obs_SearchHelper.cpp @@ -24,7 +24,7 @@ obs_hotkey_t *Utils::Obs::SearchHelper::GetHotkeyByName(std::string name) if (name.empty()) return nullptr; - auto hotkeys = ListHelper::GetHotkeyList(); + auto hotkeys = ArrayHelper::GetHotkeyList(); for (auto hotkey : hotkeys) { if (obs_hotkey_get_name(hotkey) == name) From d29b87ffc128ec29b5d1fa8cb4af003a1f3f8a5a Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sat, 18 Dec 2021 22:10:57 -0800 Subject: [PATCH 016/128] EventHandler: Remove unused file --- .../EventHandler_InputVolumeMeters.cpp | 21 ------------------- 1 file changed, 21 deletions(-) delete mode 100644 src/eventhandler/EventHandler_InputVolumeMeters.cpp diff --git a/src/eventhandler/EventHandler_InputVolumeMeters.cpp b/src/eventhandler/EventHandler_InputVolumeMeters.cpp deleted file mode 100644 index 64da0b0c..00000000 --- a/src/eventhandler/EventHandler_InputVolumeMeters.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* -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" - From 4a193d44a1937c4d876abdb33d558e09d1ae0451 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sun, 19 Dec 2021 00:34:18 -0800 Subject: [PATCH 017/128] RequestHandler: Add OutputStartFailed request status --- src/requesthandler/types/RequestStatus.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/requesthandler/types/RequestStatus.h b/src/requesthandler/types/RequestStatus.h index a9537854..671a97ee 100644 --- a/src/requesthandler/types/RequestStatus.h +++ b/src/requesthandler/types/RequestStatus.h @@ -262,6 +262,17 @@ namespace RequestStatus { * @api enums */ StudioModeNotActive = 506, + /** + * Starting the output failed. + * + * @enumIdentifier OutputStartFailed + * @enumValue 507 + * @enumType RequestStatus + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api enums + */ + OutputStartFailed = 507, /** From 2e8622e8d7fd3caffb529991a15718ed76d031ad Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sun, 19 Dec 2021 00:36:56 -0800 Subject: [PATCH 018/128] RequestHandler: Fix IsValid() input parameter --- src/requesthandler/types/RequestBatchExecutionType.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requesthandler/types/RequestBatchExecutionType.h b/src/requesthandler/types/RequestBatchExecutionType.h index 9033387f..d778ee99 100644 --- a/src/requesthandler/types/RequestBatchExecutionType.h +++ b/src/requesthandler/types/RequestBatchExecutionType.h @@ -77,7 +77,7 @@ namespace RequestBatchExecutionType { Parallel = 2, }; - inline bool IsValid(uint8_t executionType) + inline bool IsValid(int executionType) { return executionType >= None && executionType <= Parallel; } From f566ccd76b371aabf4aaf57cb0795ca4607f1b95 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sun, 19 Dec 2021 02:17:48 -0800 Subject: [PATCH 019/128] Utils: Add output state util to utils --- src/eventhandler/EventHandler_Outputs.cpp | 24 +++++------------------ src/utils/Obs.h | 6 ++++-- src/utils/Obs_StringHelper.cpp | 14 +++++++++++++ 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/eventhandler/EventHandler_Outputs.cpp b/src/eventhandler/EventHandler_Outputs.cpp index 19238d75..15195bb9 100644 --- a/src/eventhandler/EventHandler_Outputs.cpp +++ b/src/eventhandler/EventHandler_Outputs.cpp @@ -19,21 +19,7 @@ with this program. If not, see #include "EventHandler.h" -#define CASE(x) case x: return #x; - -std::string GetOutputStateString(ObsOutputState state) { - switch (state) { - default: - CASE(OBS_WEBSOCKET_OUTPUT_STARTING) - CASE(OBS_WEBSOCKET_OUTPUT_STARTED) - CASE(OBS_WEBSOCKET_OUTPUT_STOPPING) - CASE(OBS_WEBSOCKET_OUTPUT_STOPPED) - CASE(OBS_WEBSOCKET_OUTPUT_PAUSED) - CASE(OBS_WEBSOCKET_OUTPUT_RESUMED) - } -} - -bool GetOutputStateActive(ObsOutputState state) { +static bool GetOutputStateActive(ObsOutputState state) { switch(state) { case OBS_WEBSOCKET_OUTPUT_STARTED: case OBS_WEBSOCKET_OUTPUT_RESUMED: @@ -52,7 +38,7 @@ void EventHandler::HandleStreamStateChanged(ObsOutputState state) { json eventData; eventData["outputActive"] = GetOutputStateActive(state); - eventData["outputState"] = GetOutputStateString(state); + eventData["outputState"] = Utils::Obs::StringHelper::GetOutputState(state); BroadcastEvent(EventSubscription::Outputs, "StreamStateChanged", eventData); } @@ -60,7 +46,7 @@ void EventHandler::HandleRecordStateChanged(ObsOutputState state) { json eventData; eventData["outputActive"] = GetOutputStateActive(state); - eventData["outputState"] = GetOutputStateString(state); + eventData["outputState"] = Utils::Obs::StringHelper::GetOutputState(state); BroadcastEvent(EventSubscription::Outputs, "RecordStateChanged", eventData); } @@ -68,7 +54,7 @@ void EventHandler::HandleReplayBufferStateChanged(ObsOutputState state) { json eventData; eventData["outputActive"] = GetOutputStateActive(state); - eventData["outputState"] = GetOutputStateString(state); + eventData["outputState"] = Utils::Obs::StringHelper::GetOutputState(state); BroadcastEvent(EventSubscription::Outputs, "ReplayBufferStateChanged", eventData); } @@ -76,7 +62,7 @@ void EventHandler::HandleVirtualcamStateChanged(ObsOutputState state) { json eventData; eventData["outputActive"] = GetOutputStateActive(state); - eventData["outputState"] = GetOutputStateString(state); + eventData["outputState"] = Utils::Obs::StringHelper::GetOutputState(state); BroadcastEvent(EventSubscription::Outputs, "VirtualcamStateChanged", eventData); } diff --git a/src/utils/Obs.h b/src/utils/Obs.h index 2ce8579e..310892a7 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -66,13 +66,14 @@ template T* GetCalldataPointer(const calldata_t *data, const char* } enum ObsOutputState { + OBS_WEBSOCKET_OUTPUT_UNKNOWN, OBS_WEBSOCKET_OUTPUT_STARTING, OBS_WEBSOCKET_OUTPUT_STARTED, OBS_WEBSOCKET_OUTPUT_STOPPING, OBS_WEBSOCKET_OUTPUT_STOPPED, OBS_WEBSOCKET_OUTPUT_RECONNECTING, OBS_WEBSOCKET_OUTPUT_PAUSED, - OBS_WEBSOCKET_OUTPUT_RESUMED + OBS_WEBSOCKET_OUTPUT_RESUMED, }; enum ObsMediaInputAction { @@ -82,7 +83,7 @@ enum ObsMediaInputAction { OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT, - OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS + OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS, }; namespace Utils { @@ -99,6 +100,7 @@ namespace Utils { std::string GetLastReplayBufferFilePath(); std::string GetSceneItemBoundsType(enum obs_bounds_type type); std::string DurationToTimecode(uint64_t); + std::string GetOutputState(ObsOutputState state); } namespace EnumHelper { diff --git a/src/utils/Obs_StringHelper.cpp b/src/utils/Obs_StringHelper.cpp index 3abf6c50..f437b5b5 100644 --- a/src/utils/Obs_StringHelper.cpp +++ b/src/utils/Obs_StringHelper.cpp @@ -152,3 +152,17 @@ std::string Utils::Obs::StringHelper::DurationToTimecode(uint64_t ms) QString formatted = QString::asprintf("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64 ".%03" PRIu64, hoursPart, minutesPart, secsPart, msPart); return formatted.toStdString(); } + +std::string Utils::Obs::StringHelper::GetOutputState(ObsOutputState state) +{ + switch (state) { + default: + CASE(OBS_WEBSOCKET_OUTPUT_UNKNOWN) + CASE(OBS_WEBSOCKET_OUTPUT_STARTING) + CASE(OBS_WEBSOCKET_OUTPUT_STARTED) + CASE(OBS_WEBSOCKET_OUTPUT_STOPPING) + CASE(OBS_WEBSOCKET_OUTPUT_STOPPED) + CASE(OBS_WEBSOCKET_OUTPUT_PAUSED) + CASE(OBS_WEBSOCKET_OUTPUT_RESUMED) + } +} From a0ad43c7d77b647f6e4fb321e3c2d7648f74da43 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Tue, 21 Dec 2021 09:32:37 +0000 Subject: [PATCH 020/128] docs(ci): Update generated docs - f566ccd [skip ci] --- docs/generated/protocol.json | 582 ++++++++++++++++++++++++++++++++++- docs/generated/protocol.md | 444 +++++++++++++++++++++++++- 2 files changed, 1020 insertions(+), 6 deletions(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 2638c03f..2b9b4ee0 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -341,6 +341,14 @@ "initialVersion": "5.0.0", "enumValue": 506 }, + { + "description": "Starting the output failed.", + "enumIdentifier": "OutputStartFailed", + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "enumValue": 507 + }, { "description": "The resource was not found.\n\nNote: Resources are any kind of object in obs-websocket, like inputs, profiles, outputs, etc.", "enumIdentifier": "ResourceNotFound", @@ -1948,6 +1956,484 @@ ], "responseFields": [] }, + { + "description": "Gets a list of all scene items in a scene.\n\nScenes only", + "requestType": "GetSceneItemList", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene to get the items of", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "sceneItems", + "valueType": "Array", + "valueDescription": "Array of scene items in the scene" + } + ] + }, + { + "description": "Basically GetSceneItemList, but for groups.\n\nUsing groups at all in OBS is discouraged, as they are very broken under the hood.\n\nGroups only", + "requestType": "GetGroupItemList", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the group to get the items of", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "sceneItems", + "valueType": "Array", + "valueDescription": "Array of scene items in the group" + } + ] + }, + { + "description": "Searches a scene for a source, and returns its id.\n\nScenes and Groups", + "requestType": "GetSceneItemId", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene or group to search in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the source to find", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item" + } + ] + }, + { + "description": "Creates a new scene item using a source.\n\nScenes only", + "requestType": "CreateSceneItem", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene to create the new item in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the source to add to the scene", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemEnabled", + "valueType": "Boolean", + "valueDescription": "Enable state to apply to the scene item on creation", + "valueRestrictions": null, + "valueOptional": true, + "valueOptionalBehavior": "True" + } + ], + "responseFields": [ + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item" + } + ] + }, + { + "description": "Removes a scene item from a scene.\n\nScenes only", + "requestType": "RemoveSceneItem", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, + { + "description": "Duplicates a scene item, copying all transform and crop info.\n\nScenes only", + "requestType": "DuplicateSceneItem", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "destinationSceneName", + "valueType": "String", + "valueDescription": "Name of the scene to create the duplicated item in", + "valueRestrictions": null, + "valueOptional": true, + "valueOptionalBehavior": "`sceneName` is assumed" + } + ], + "responseFields": [ + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the duplicated scene item" + } + ] + }, + { + "description": "Gets the transform and crop info of a scene item.\n\nScenes and Groups", + "requestType": "GetSceneItemTransform", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "sceneItemTransform", + "valueType": "Object", + "valueDescription": "Object containing scene item transform info" + } + ] + }, + { + "description": "Sets the transform and crop info of a scene item.", + "requestType": "SetSceneItemTransform", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemTransform", + "valueType": "Object", + "valueDescription": "Object containing scene item transform info to update", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, + { + "description": "Gets the enable state of a scene item.\n\nScenes and Groups", + "requestType": "GetSceneItemEnabled", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "sceneItemEnabled", + "valueType": "Boolean", + "valueDescription": "Whether the scene item is enabled. `true` for enabled, `false` for disabled" + } + ] + }, + { + "description": "Sets the enable state of a scene item.\n\nScenes and Groups", + "requestType": "SetSceneItemEnabled", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemEnabled", + "valueType": "Boolean", + "valueDescription": "New enable state of the scene item", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, + { + "description": "Gets the lock state of a scene item.\n\nScenes and Groups", + "requestType": "GetSceneItemLocked", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "sceneItemLocked", + "valueType": "Boolean", + "valueDescription": "Whether the scene item is locked. `true` for locked, `false` for unlocked" + } + ] + }, + { + "description": "Sets the lock state of a scene item.\n\nScenes and Group", + "requestType": "SetSceneItemLocked", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemLocked", + "valueType": "Boolean", + "valueDescription": "New lock state of the scene item", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, + { + "description": "Gets the index position of a scene item in a scene.\n\nAn index of 0 is at the bottom of the source list in the UI.\n\nScenes and Groups", + "requestType": "GetSceneItemIndex", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "sceneItemIndex", + "valueType": "Number", + "valueDescription": "Index position of the scene item" + } + ] + }, + { + "description": "Sets the index position of a scene item in a scene.\n\nScenes and Groups", + "requestType": "SetSceneItemIndex", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemIndex", + "valueType": "Number", + "valueDescription": "New index position of the scene item", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, { "description": "Gets an array of all scenes in OBS.", "requestType": "GetSceneList", @@ -1958,11 +2444,6 @@ "category": "scenes", "requestFields": [], "responseFields": [ - { - "valueName": "scenes", - "valueType": "Array", - "valueDescription": "Array of scenes in OBS" - }, { "valueName": "currentProgramSceneName", "valueType": "String", @@ -1972,6 +2453,11 @@ "valueName": "currentPreviewSceneName", "valueType": "String", "valueDescription": "Current preview scene. `null` if not in studio mode" + }, + { + "valueName": "scenes", + "valueType": "Array", + "valueDescription": "Array of scenes in OBS" } ] }, @@ -2271,6 +2757,92 @@ "valueDescription": "Base64-encoded screenshot" } ] + }, + { + "description": "Gets the status of the stream output.", + "requestType": "GetStreamStatus", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "stream", + "requestFields": [], + "responseFields": [ + { + "valueName": "outputActive", + "valueType": "Boolean", + "valueDescription": "Whether the output is active" + }, + { + "valueName": "outputReconnecting", + "valueType": "Boolean", + "valueDescription": "Whether the output is currently reconnecting" + }, + { + "valueName": "outputTimecode", + "valueType": "String", + "valueDescription": "Current formatted timecode string for the output" + }, + { + "valueName": "outputDuration", + "valueType": "Number", + "valueDescription": "Current duration in milliseconds for the output" + }, + { + "valueName": "outputBytes", + "valueType": "Number", + "valueDescription": "Number of bytes sent by the output" + }, + { + "valueName": "outputSkippedFrames", + "valueType": "Number", + "valueDescription": "Number of frames skipped by the output's process" + }, + { + "valueName": "outputTotalFrames", + "valueType": "Number", + "valueDescription": "Total number of frames delivered by the output's process" + } + ] + }, + { + "description": "Toggles the status of the stream output.", + "requestType": "ToggleStream", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "stream", + "requestFields": [], + "responseFields": [ + { + "valueName": "outputActive", + "valueType": "Boolean", + "valueDescription": "New state of the stream output" + } + ] + }, + { + "description": "Starts the stream output.", + "requestType": "StartStream", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "stream", + "requestFields": [], + "responseFields": [] + }, + { + "description": "Stops the stream output.", + "requestType": "StopStream", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "stream", + "requestFields": [], + "responseFields": [] } ], "events": [ diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index f03675f9..24d84903 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -436,6 +436,7 @@ These are enumeration declarations, which are referenced throughout obs-websocke - [RequestStatus::OutputDisabled](#requeststatusoutputdisabled) - [RequestStatus::StudioModeActive](#requeststatusstudiomodeactive) - [RequestStatus::StudioModeNotActive](#requeststatusstudiomodenotactive) + - [RequestStatus::OutputStartFailed](#requeststatusoutputstartfailed) - [RequestStatus::ResourceNotFound](#requeststatusresourcenotfound) - [RequestStatus::ResourceAlreadyExists](#requeststatusresourcealreadyexists) - [RequestStatus::InvalidResourceType](#requeststatusinvalidresourcetype) @@ -949,6 +950,16 @@ Studio mode is not active and should be. --- +### RequestStatus::OutputStartFailed + +Starting the output failed. + +- Identifier Value: `507` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + ### RequestStatus::ResourceNotFound The resource was not found. @@ -1446,6 +1457,26 @@ The profile list has changed. - [SetInputAudioMonitorType](#setinputaudiomonitortype) - [GetInputPropertiesListPropertyItems](#getinputpropertieslistpropertyitems) - [PressInputPropertiesButton](#pressinputpropertiesbutton) +- [Scene Items](#scene-items) + - [GetSceneItemList](#getsceneitemlist) + - [GetGroupItemList](#getgroupitemlist) + - [GetSceneItemId](#getsceneitemid) + - [CreateSceneItem](#createsceneitem) + - [RemoveSceneItem](#removesceneitem) + - [DuplicateSceneItem](#duplicatesceneitem) + - [GetSceneItemTransform](#getsceneitemtransform) + - [SetSceneItemTransform](#setsceneitemtransform) + - [GetSceneItemEnabled](#getsceneitemenabled) + - [SetSceneItemEnabled](#setsceneitemenabled) + - [GetSceneItemLocked](#getsceneitemlocked) + - [SetSceneItemLocked](#setsceneitemlocked) + - [GetSceneItemIndex](#getsceneitemindex) + - [SetSceneItemIndex](#setsceneitemindex) +- [Stream](#stream) + - [GetStreamStatus](#getstreamstatus) + - [ToggleStream](#togglestream) + - [StartStream](#startstream) + - [StopStream](#stopstream) @@ -2064,9 +2095,9 @@ Gets an array of all scenes in OBS. | Name | Type | Description | | ---- | :---: | ----------- | -| scenes | Array<Object> | Array of scenes in OBS | | currentProgramSceneName | String | Current program scene | | currentPreviewSceneName | String | Current preview scene. `null` if not in studio mode | +| scenes | Array<Object> | Array of scenes in OBS | --- @@ -2625,3 +2656,414 @@ Note: Use this in cases where there is a button in the properties of an input th | propertyName | String | Name of the button property to press | None | N/A | +## Scene Items + +### GetSceneItemList + +Gets a list of all scene items in a scene. + +Scenes only + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene to get the items of | None | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneItems | Array<Object> | Array of scene items in the scene | + +--- + +### GetGroupItemList + +Basically GetSceneItemList, but for groups. + +Using groups at all in OBS is discouraged, as they are very broken under the hood. + +Groups only + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the group to get the items of | None | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneItems | Array<Object> | Array of scene items in the group | + +--- + +### GetSceneItemId + +Searches a scene for a source, and returns its id. + +Scenes and Groups + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene or group to search in | None | N/A | +| sourceName | String | Name of the source to find | None | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneItemId | Number | Numeric ID of the scene item | + +--- + +### CreateSceneItem + +Creates a new scene item using a source. + +Scenes only + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene to create the new item in | None | N/A | +| sourceName | String | Name of the source to add to the scene | None | N/A | +| ?sceneItemEnabled | Boolean | Enable state to apply to the scene item on creation | None | True | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneItemId | Number | Numeric ID of the scene item | + +--- + +### RemoveSceneItem + +Removes a scene item from a scene. + +Scenes only + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene the item is in | None | N/A | +| sceneItemId | Number | Numeric ID of the scene item | >= 0 | N/A | + +--- + +### DuplicateSceneItem + +Duplicates a scene item, copying all transform and crop info. + +Scenes only + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene the item is in | None | N/A | +| sceneItemId | Number | Numeric ID of the scene item | >= 0 | N/A | +| ?destinationSceneName | String | Name of the scene to create the duplicated item in | None | `sceneName` is assumed | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneItemId | Number | Numeric ID of the duplicated scene item | + +--- + +### GetSceneItemTransform + +Gets the transform and crop info of a scene item. + +Scenes and Groups + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene the item is in | None | N/A | +| sceneItemId | Number | Numeric ID of the scene item | >= 0 | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneItemTransform | Object | Object containing scene item transform info | + +--- + +### SetSceneItemTransform + +Sets the transform and crop info of a scene item. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene the item is in | None | N/A | +| sceneItemId | Number | Numeric ID of the scene item | >= 0 | N/A | +| sceneItemTransform | Object | Object containing scene item transform info to update | None | N/A | + +--- + +### GetSceneItemEnabled + +Gets the enable state of a scene item. + +Scenes and Groups + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene the item is in | None | N/A | +| sceneItemId | Number | Numeric ID of the scene item | >= 0 | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneItemEnabled | Boolean | Whether the scene item is enabled. `true` for enabled, `false` for disabled | + +--- + +### SetSceneItemEnabled + +Sets the enable state of a scene item. + +Scenes and Groups + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene the item is in | None | N/A | +| sceneItemId | Number | Numeric ID of the scene item | >= 0 | N/A | +| sceneItemEnabled | Boolean | New enable state of the scene item | None | N/A | + +--- + +### GetSceneItemLocked + +Gets the lock state of a scene item. + +Scenes and Groups + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene the item is in | None | N/A | +| sceneItemId | Number | Numeric ID of the scene item | >= 0 | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneItemLocked | Boolean | Whether the scene item is locked. `true` for locked, `false` for unlocked | + +--- + +### SetSceneItemLocked + +Sets the lock state of a scene item. + +Scenes and Group + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene the item is in | None | N/A | +| sceneItemId | Number | Numeric ID of the scene item | >= 0 | N/A | +| sceneItemLocked | Boolean | New lock state of the scene item | None | N/A | + +--- + +### GetSceneItemIndex + +Gets the index position of a scene item in a scene. + +An index of 0 is at the bottom of the source list in the UI. + +Scenes and Groups + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene the item is in | None | N/A | +| sceneItemId | Number | Numeric ID of the scene item | >= 0 | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneItemIndex | Number | Index position of the scene item | + +--- + +### SetSceneItemIndex + +Sets the index position of a scene item in a scene. + +Scenes and Groups + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene the item is in | None | N/A | +| sceneItemId | Number | Numeric ID of the scene item | >= 0 | N/A | +| sceneItemIndex | Number | New index position of the scene item | >= 0 | N/A | + + +## Stream + +### GetStreamStatus + +Gets the status of the stream output. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| outputActive | Boolean | Whether the output is active | +| outputReconnecting | Boolean | Whether the output is currently reconnecting | +| outputTimecode | String | Current formatted timecode string for the output | +| outputDuration | Number | Current duration in milliseconds for the output | +| outputBytes | Number | Number of bytes sent by the output | +| outputSkippedFrames | Number | Number of frames skipped by the output's process | +| outputTotalFrames | Number | Total number of frames delivered by the output's process | + +--- + +### ToggleStream + +Toggles the status of the stream output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| outputActive | Boolean | New state of the stream output | + +--- + +### StartStream + +Starts the stream output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + +### StopStream + +Stops the stream output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + From 527a0080027cf8b279ca16b256c61f1ee2141268 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 21 Dec 2021 01:33:16 -0800 Subject: [PATCH 021/128] RequestHandler: Remove OutputStartFailed request status Accidentally pushed this commit when it was for a component which will not be implemented. --- src/requesthandler/types/RequestStatus.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/requesthandler/types/RequestStatus.h b/src/requesthandler/types/RequestStatus.h index 671a97ee..a9537854 100644 --- a/src/requesthandler/types/RequestStatus.h +++ b/src/requesthandler/types/RequestStatus.h @@ -262,17 +262,6 @@ namespace RequestStatus { * @api enums */ StudioModeNotActive = 506, - /** - * Starting the output failed. - * - * @enumIdentifier OutputStartFailed - * @enumValue 507 - * @enumType RequestStatus - * @rpcVersion -1 - * @initialVersion 5.0.0 - * @api enums - */ - OutputStartFailed = 507, /** From a898bacd796dbd229473a95e8f3715c33b67e206 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 21 Dec 2021 01:58:20 -0800 Subject: [PATCH 022/128] Utils: Rename VolumeMeter utils for consistency --- CMakeLists.txt | 6 +++--- src/eventhandler/EventHandler.h | 2 +- src/utils/{ObsVolumeMeter.cpp => Obs_VolumeMeter.cpp} | 4 ++-- src/utils/{ObsVolumeMeter.h => Obs_VolumeMeter.h} | 0 .../{ObsVolumeMeter_Helpers.h => Obs_VolumeMeter_Helpers.h} | 0 src/utils/Utils.h | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) rename src/utils/{ObsVolumeMeter.cpp => Obs_VolumeMeter.cpp} (96%) rename src/utils/{ObsVolumeMeter.h => Obs_VolumeMeter.h} (100%) rename src/utils/{ObsVolumeMeter_Helpers.h => Obs_VolumeMeter_Helpers.h} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 81a8ddfe..e6b89a2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,7 +130,7 @@ set(obs-websocket_SOURCES src/utils/Obs_ObjectHelper.cpp src/utils/Obs_SearchHelper.cpp src/utils/Obs_ActionHelper.cpp - src/utils/ObsVolumeMeter.cpp + src/utils/Obs_VolumeMeter.cpp src/utils/Platform.cpp src/utils/Compat.cpp deps/qr/cpp/QrCode.cpp) @@ -157,8 +157,8 @@ set(obs-websocket_HEADERS src/utils/Crypto.h src/utils/Json.h src/utils/Obs.h - src/utils/ObsVolumeMeter.h - src/utils/ObsVolumeMeter_Helpers.h + src/utils/Obs_VolumeMeter.h + src/utils/Obs_VolumeMeter_Helpers.h src/utils/Platform.h src/utils/Compat.h src/utils/Utils.h diff --git a/src/eventhandler/EventHandler.h b/src/eventhandler/EventHandler.h index 317a2b76..a7a96e07 100644 --- a/src/eventhandler/EventHandler.h +++ b/src/eventhandler/EventHandler.h @@ -27,7 +27,7 @@ with this program. If not, see #include "types/EventSubscription.h" #include "../obs-websocket.h" #include "../utils/Obs.h" -#include "../utils/ObsVolumeMeter.h" +#include "../utils/Obs_VolumeMeter.h" #include "../plugin-macros.generated.h" class EventHandler diff --git a/src/utils/ObsVolumeMeter.cpp b/src/utils/Obs_VolumeMeter.cpp similarity index 96% rename from src/utils/ObsVolumeMeter.cpp rename to src/utils/Obs_VolumeMeter.cpp index e5c9c7db..db683db4 100644 --- a/src/utils/ObsVolumeMeter.cpp +++ b/src/utils/Obs_VolumeMeter.cpp @@ -22,8 +22,8 @@ with this program. If not, see #include #include "Obs.h" -#include "ObsVolumeMeter.h" -#include "ObsVolumeMeter_Helpers.h" +#include "Obs_VolumeMeter.h" +#include "Obs_VolumeMeter_Helpers.h" #include "../obs-websocket.h" Utils::Obs::VolumeMeter::Meter::Meter(obs_source_t *input) : diff --git a/src/utils/ObsVolumeMeter.h b/src/utils/Obs_VolumeMeter.h similarity index 100% rename from src/utils/ObsVolumeMeter.h rename to src/utils/Obs_VolumeMeter.h diff --git a/src/utils/ObsVolumeMeter_Helpers.h b/src/utils/Obs_VolumeMeter_Helpers.h similarity index 100% rename from src/utils/ObsVolumeMeter_Helpers.h rename to src/utils/Obs_VolumeMeter_Helpers.h diff --git a/src/utils/Utils.h b/src/utils/Utils.h index 9a06728c..00a88f3d 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -22,6 +22,6 @@ with this program. If not, see #include "Crypto.h" #include "Json.h" #include "Obs.h" -#include "ObsVolumeMeter.h" +#include "Obs_VolumeMeter.h" #include "Platform.h" #include "Compat.h" From b331f76d4048dead9353a111e40ff17b3318c7f0 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 21 Dec 2021 02:30:18 -0800 Subject: [PATCH 023/128] Utils: Use output path util instead of hacky method We still have to wait for a new OBS version to be released before this will work, but to be fair it was pretty broken in the previous state. --- src/utils/Obs_ObjectHelper.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/utils/Obs_ObjectHelper.cpp b/src/utils/Obs_ObjectHelper.cpp index 34077c62..14714976 100644 --- a/src/utils/Obs_ObjectHelper.cpp +++ b/src/utils/Obs_ObjectHelper.cpp @@ -27,15 +27,13 @@ json Utils::Obs::ObjectHelper::GetStats() { json ret; - config_t* currentProfile = obs_frontend_get_profile_config(); - const char* outputMode = config_get_string(currentProfile, "Output", "Mode"); - const char* recordPath = strcmp(outputMode, "Advanced") ? config_get_string(currentProfile, "SimpleOutput", "FilePath") : config_get_string(currentProfile, "AdvOut", "RecFilePath"); + std::string outputPath = Utils::Obs::StringHelper::GetCurrentRecordOutputPath(); video_t* video = obs_get_video(); ret["cpuUsage"] = os_cpu_usage_info_query(GetCpuUsageInfo()); ret["memoryUsage"] = (double)os_get_proc_resident_size() / (1024.0 * 1024.0); - ret["availableDiskSpace"] = (double)os_get_free_disk_space(recordPath) / (1024.0 * 1024.0); + ret["availableDiskSpace"] = (double)os_get_free_disk_space(outputPath.c_str()) / (1024.0 * 1024.0); ret["activeFps"] = obs_get_active_fps(); ret["averageFrameRenderTime"] = (double)obs_get_average_frame_time_ns() / 1000000.0; ret["renderSkippedFrames"] = obs_get_lagged_frames(); From 66f416236c9e9d793b914edbb3408242b81886f5 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Tue, 21 Dec 2021 11:10:11 +0000 Subject: [PATCH 024/128] docs(ci): Update generated docs - b331f76 [skip ci] --- docs/generated/protocol.json | 8 -------- docs/generated/protocol.md | 11 ----------- 2 files changed, 19 deletions(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 2b9b4ee0..215f68b6 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -341,14 +341,6 @@ "initialVersion": "5.0.0", "enumValue": 506 }, - { - "description": "Starting the output failed.", - "enumIdentifier": "OutputStartFailed", - "rpcVersion": "1", - "deprecated": false, - "initialVersion": "5.0.0", - "enumValue": 507 - }, { "description": "The resource was not found.\n\nNote: Resources are any kind of object in obs-websocket, like inputs, profiles, outputs, etc.", "enumIdentifier": "ResourceNotFound", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 24d84903..0b0fb35b 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -436,7 +436,6 @@ These are enumeration declarations, which are referenced throughout obs-websocke - [RequestStatus::OutputDisabled](#requeststatusoutputdisabled) - [RequestStatus::StudioModeActive](#requeststatusstudiomodeactive) - [RequestStatus::StudioModeNotActive](#requeststatusstudiomodenotactive) - - [RequestStatus::OutputStartFailed](#requeststatusoutputstartfailed) - [RequestStatus::ResourceNotFound](#requeststatusresourcenotfound) - [RequestStatus::ResourceAlreadyExists](#requeststatusresourcealreadyexists) - [RequestStatus::InvalidResourceType](#requeststatusinvalidresourcetype) @@ -950,16 +949,6 @@ Studio mode is not active and should be. --- -### RequestStatus::OutputStartFailed - -Starting the output failed. - -- Identifier Value: `507` -- Latest Supported RPC Version: `1` -- Added in v5.0.0 - ---- - ### RequestStatus::ResourceNotFound The resource was not found. From 91e3f5ee185df719e161487fc2fcec20887fc8e4 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 21 Dec 2021 17:19:08 -0800 Subject: [PATCH 025/128] EventHandler: Remove platform include Already included by obs-websocket.h, but does not have ifdefs protecting strtoll. Better to just remove it. --- src/eventhandler/EventHandler.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/eventhandler/EventHandler.h b/src/eventhandler/EventHandler.h index a7a96e07..657da887 100644 --- a/src/eventhandler/EventHandler.h +++ b/src/eventhandler/EventHandler.h @@ -22,7 +22,6 @@ with this program. If not, see #include #include #include -#include #include "types/EventSubscription.h" #include "../obs-websocket.h" From 0f303504e1311a2ac5526f9054e3ceef780351a6 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 21 Dec 2021 17:52:46 -0800 Subject: [PATCH 026/128] Base: Nitpick cleanup for obs-websocket.cpp --- src/WebSocketApi.cpp | 11 +++++++++-- src/WebSocketApi.h | 4 +++- src/obs-websocket.cpp | 3 ++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/WebSocketApi.cpp b/src/WebSocketApi.cpp index bd5540ba..c7901764 100644 --- a/src/WebSocketApi.cpp +++ b/src/WebSocketApi.cpp @@ -16,8 +16,7 @@ WebSocketApi::Vendor *get_vendor(calldata_t *cd) return static_cast(voidVendor); } -WebSocketApi::WebSocketApi(EventCallback cb) : - _eventCallback(cb) +WebSocketApi::WebSocketApi() { blog_debug("[WebSocketApi::WebSocketApi] Setting up..."); @@ -50,6 +49,11 @@ WebSocketApi::~WebSocketApi() blog_debug("[WebSocketApi::~WebSocketApi] Finished."); } +void WebSocketApi::SetEventCallback(EventCallback cb) +{ + _eventCallback = cb; +} + enum WebSocketApi::RequestReturnCode WebSocketApi::PerformVendorRequest(std::string vendorName, std::string requestType, obs_data_t *requestData, obs_data_t *responseData) { std::shared_lock l(_mutex); @@ -196,6 +200,9 @@ void WebSocketApi::vendor_event_emit_cb(void *priv_data, calldata_t *cd) auto eventData = static_cast(voidEventData); + if (!c->_eventCallback) + RETURN_FAILURE(); + c->_eventCallback(v->_name, eventType, eventData); RETURN_SUCCESS(); diff --git a/src/WebSocketApi.h b/src/WebSocketApi.h index 78d02cea..5c18c678 100644 --- a/src/WebSocketApi.h +++ b/src/WebSocketApi.h @@ -25,9 +25,11 @@ class WebSocketApi { std::map _requests; }; - WebSocketApi(EventCallback cb); + WebSocketApi(); ~WebSocketApi(); + void SetEventCallback(EventCallback cb); + enum RequestReturnCode PerformVendorRequest(std::string vendorName, std::string requestName, obs_data_t *requestData, obs_data_t *responseData); static void get_ph_cb(void *priv_data, calldata_t *cd); diff --git a/src/obs-websocket.cpp b/src/obs-websocket.cpp index 81804c4b..58345e9a 100644 --- a/src/obs-websocket.cpp +++ b/src/obs-websocket.cpp @@ -56,7 +56,8 @@ bool obs_module_load(void) // Initialize event handler before server, as the server configures the event handler. _eventHandler = EventHandlerPtr(new EventHandler()); - _webSocketApi = WebSocketApiPtr(new WebSocketApi(WebSocketApiEventCallback)); + _webSocketApi = WebSocketApiPtr(new WebSocketApi()); + _webSocketApi->SetEventCallback(WebSocketApiEventCallback); _webSocketServer = WebSocketServerPtr(new WebSocketServer()); From 40ff3f6960152b2f3908ce8d1a27a43412200c00 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 21 Dec 2021 18:11:15 -0800 Subject: [PATCH 027/128] Base: More code/comment nitpicks --- src/obs-websocket.cpp | 50 ++++++++++++++++++++++++++----------------- src/obs-websocket.h | 12 +++++------ 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/obs-websocket.cpp b/src/obs-websocket.cpp index 58345e9a..830a2365 100644 --- a/src/obs-websocket.cpp +++ b/src/obs-websocket.cpp @@ -35,12 +35,12 @@ OBS_MODULE_AUTHOR("OBSProject") const char *obs_module_name(void) { return "obs-websocket"; } const char *obs_module_description(void) { return obs_module_text("OBSWebSocket.Plugin.Description"); } +os_cpu_usage_info_t* _cpuUsageInfo; ConfigPtr _config; +EventHandlerPtr _eventHandler; WebSocketApiPtr _webSocketApi; WebSocketServerPtr _webSocketServer; -EventHandlerPtr _eventHandler; SettingsDialog *_settingsDialog = nullptr; -os_cpu_usage_info_t* _cpuUsageInfo; void WebSocketApiEventCallback(std::string vendorName, std::string eventType, obs_data_t *obsEventData); @@ -49,32 +49,35 @@ bool obs_module_load(void) blog(LOG_INFO, "[obs_module_load] you can haz websockets (Version: %s | RPC Version: %d)", OBS_WEBSOCKET_VERSION, OBS_WEBSOCKET_RPC_VERSION); blog(LOG_INFO, "[obs_module_load] Qt version (compile-time): %s | Qt version (run-time): %s", QT_VERSION_STR, qVersion()); - // Create the config object then load the parameters from storage + // Initialize the cpu stats + _cpuUsageInfo = os_cpu_usage_info_start(); + + // Create the config manager then load the parameters from storage _config = ConfigPtr(new Config()); _config->Load(); - // Initialize event handler before server, as the server configures the event handler. + // Initialize the event handler _eventHandler = EventHandlerPtr(new EventHandler()); + // Initialize the plugin/script API _webSocketApi = WebSocketApiPtr(new WebSocketApi()); _webSocketApi->SetEventCallback(WebSocketApiEventCallback); + // Initialize the WebSocket server _webSocketServer = WebSocketServerPtr(new WebSocketServer()); + // Initialize the settings dialog obs_frontend_push_ui_translation(obs_module_get_string); QMainWindow* mainWindow = reinterpret_cast(obs_frontend_get_main_window()); _settingsDialog = new SettingsDialog(mainWindow); obs_frontend_pop_ui_translation(); + // Add the settings dialog to the tools menu const char* menuActionText = obs_module_text("OBSWebSocket.Settings.DialogTitle"); QAction* menuAction = (QAction*)obs_frontend_add_tools_menu_qaction(menuActionText); QObject::connect(menuAction, &QAction::triggered, [] { _settingsDialog->ToggleShowHide(); }); - _cpuUsageInfo = os_cpu_usage_info_start(); - - // Loading finished blog(LOG_INFO, "[obs_module_load] Module loaded."); - return true; } @@ -82,29 +85,46 @@ void obs_module_unload() { blog(LOG_INFO, "[obs_module_unload] Shutting down..."); + // Shutdown the WebSocket server if it is running if (_webSocketServer->IsListening()) { blog_debug("[obs_module_unload] WebSocket server is running. Stopping..."); _webSocketServer->Stop(); } + + // Destroy the WebSocket server _webSocketServer.reset(); - _eventHandler.reset(); - + // Destroy the plugin/script api _webSocketApi.reset(); + // Destroy the event handler + _eventHandler.reset(); + + // Save and destroy the config manager _config->Save(); _config.reset(); + // Destroy the cpu stats os_cpu_usage_info_destroy(_cpuUsageInfo); blog(LOG_INFO, "[obs_module_unload] Finished shutting down."); } +os_cpu_usage_info_t* GetCpuUsageInfo() +{ + return _cpuUsageInfo; +} + ConfigPtr GetConfig() { return _config; } +EventHandlerPtr GetEventHandler() +{ + return _eventHandler; +} + WebSocketApiPtr GetWebSocketApi() { return _webSocketApi; @@ -115,16 +135,6 @@ WebSocketServerPtr GetWebSocketServer() return _webSocketServer; } -EventHandlerPtr GetEventHandler() -{ - return _eventHandler; -} - -os_cpu_usage_info_t* GetCpuUsageInfo() -{ - return _cpuUsageInfo; -} - bool IsDebugEnabled() { return !_config || _config->DebugEnabled; diff --git a/src/obs-websocket.h b/src/obs-websocket.h index c8c7b58f..8e9f5c72 100644 --- a/src/obs-websocket.h +++ b/src/obs-websocket.h @@ -35,23 +35,23 @@ with this program. If not, see class Config; typedef std::shared_ptr ConfigPtr; +class EventHandler; +typedef std::shared_ptr EventHandlerPtr; + class WebSocketApi; typedef std::shared_ptr WebSocketApiPtr; class WebSocketServer; typedef std::shared_ptr WebSocketServerPtr; -class EventHandler; -typedef std::shared_ptr EventHandlerPtr; +os_cpu_usage_info_t* GetCpuUsageInfo(); ConfigPtr GetConfig(); +EventHandlerPtr GetEventHandler(); + WebSocketApiPtr GetWebSocketApi(); WebSocketServerPtr GetWebSocketServer(); -EventHandlerPtr GetEventHandler(); - -os_cpu_usage_info_t* GetCpuUsageInfo(); - bool IsDebugEnabled(); From 714b4db840795c0f796c499294b550e58b17f079 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 22 Dec 2021 15:23:42 -0800 Subject: [PATCH 028/128] deps: Update asio to 1.21.0 --- deps/asio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/asio b/deps/asio index b84e6c16..08a7029c 160000 --- a/deps/asio +++ b/deps/asio @@ -1 +1 @@ -Subproject commit b84e6c16b2ea907dbad94206b7510d85aafc0b42 +Subproject commit 08a7029cb10c911b6fb66fb015217a431206e52c From ad347c4823a943b30efffd9b0f381c0138c75965 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 22 Dec 2021 15:57:57 -0800 Subject: [PATCH 029/128] RequestHandler: Add files for Transitions and Filters --- CMakeLists.txt | 2 ++ src/requesthandler/RequestHandler_Filters.cpp | 20 +++++++++++++++++++ .../RequestHandler_Transitions.cpp | 20 +++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 src/requesthandler/RequestHandler_Filters.cpp create mode 100644 src/requesthandler/RequestHandler_Transitions.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e6b89a2a..4957d2a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,6 +110,8 @@ set(obs-websocket_SOURCES src/requesthandler/RequestHandler_Sources.cpp src/requesthandler/RequestHandler_Scenes.cpp src/requesthandler/RequestHandler_Inputs.cpp + src/requesthandler/RequestHandler_Transitions.cpp + src/requesthandler/RequestHandler_Filters.cpp src/requesthandler/RequestHandler_SceneItems.cpp src/requesthandler/RequestHandler_Stream.cpp src/requesthandler/RequestHandler_Record.cpp diff --git a/src/requesthandler/RequestHandler_Filters.cpp b/src/requesthandler/RequestHandler_Filters.cpp new file mode 100644 index 00000000..b09e414c --- /dev/null +++ b/src/requesthandler/RequestHandler_Filters.cpp @@ -0,0 +1,20 @@ +/* +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" diff --git a/src/requesthandler/RequestHandler_Transitions.cpp b/src/requesthandler/RequestHandler_Transitions.cpp new file mode 100644 index 00000000..b09e414c --- /dev/null +++ b/src/requesthandler/RequestHandler_Transitions.cpp @@ -0,0 +1,20 @@ +/* +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" From 1c6ec1dda278d4e36f24c0c7284a45fb1f649795 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 22 Dec 2021 16:08:39 -0800 Subject: [PATCH 030/128] RequestHandler: Add ResourceNotConfigurable --- src/requesthandler/types/RequestStatus.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/requesthandler/types/RequestStatus.h b/src/requesthandler/types/RequestStatus.h index a9537854..12999bfb 100644 --- a/src/requesthandler/types/RequestStatus.h +++ b/src/requesthandler/types/RequestStatus.h @@ -332,6 +332,19 @@ namespace RequestStatus { * @api enums */ InvalidInputKind = 605, + /** + * The resource does not support being configured. + * + * This is particularly relevant to transitions, where they do not always have changeable settings. + * + * @enumIdentifier ResourceNotConfigurable + * @enumValue 606 + * @enumType RequestStatus + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api enums + */ + ResourceNotConfigurable = 606, /** * Creating the resource failed. From 2302fdd25f1933257128c77f75b6f9cf21f6a926 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 22 Dec 2021 16:27:50 -0800 Subject: [PATCH 031/128] Utils: Fix up transition related utils --- src/utils/Obs.h | 3 +- src/utils/Obs_ArrayHelper.cpp | 53 ++++++++++++++++++++++------------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/utils/Obs.h b/src/utils/Obs.h index 310892a7..6fcf4589 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -120,9 +120,10 @@ namespace Utils { std::vector GetHotkeyNameList(); std::vector GetSceneList(); std::vector GetSceneItemList(obs_scene_t *scene, bool basic = false); - std::vector GetTransitionList(); std::vector GetInputList(std::string inputKind = ""); std::vector GetInputKindList(bool unversioned = false, bool includeDisabled = false); + std::vector GetTransitionKindList(); + std::vector GetSceneTransitionList(); } namespace ObjectHelper { diff --git a/src/utils/Obs_ArrayHelper.cpp b/src/utils/Obs_ArrayHelper.cpp index 4b9317a6..f408fe58 100644 --- a/src/utils/Obs_ArrayHelper.cpp +++ b/src/utils/Obs_ArrayHelper.cpp @@ -143,26 +143,6 @@ std::vector Utils::Obs::ArrayHelper::GetSceneItemList(obs_scene_t *scene, return enumData.first; } -std::vector Utils::Obs::ArrayHelper::GetTransitionList() -{ - obs_frontend_source_list transitionList = {}; - obs_frontend_get_transitions(&transitionList); - - std::vector ret; - for (size_t i = 0; i < transitionList.sources.num; i++) { - obs_source_t *transition = transitionList.sources.array[i]; - json transitionJson; - transitionJson["transitionName"] = obs_source_get_name(transition); - transitionJson["transitionKind"] = obs_source_get_id(transition); - transitionJson["transitionFixed"] = obs_transition_fixed(transition); - ret.push_back(transitionJson); - } - - obs_frontend_source_list_free(&transitionList); - - return ret; -} - struct EnumInputInfo { std::string inputKind; // For searching by input kind std::vector inputs; @@ -220,3 +200,36 @@ std::vector Utils::Obs::ArrayHelper::GetInputKindList(bool unversio return ret; } + +std::vector Utils::Obs::ArrayHelper::GetTransitionKindList() +{ + std::vector ret; + + size_t idx = 0; + const char *kind; + while (obs_enum_transition_types(idx++, &kind)) + ret.emplace_back(kind); + + return ret; +} + +std::vector Utils::Obs::ArrayHelper::GetSceneTransitionList() +{ + obs_frontend_source_list transitionList = {}; + obs_frontend_get_transitions(&transitionList); + + std::vector ret; + for (size_t i = 0; i < transitionList.sources.num; i++) { + obs_source_t *transition = transitionList.sources.array[i]; + json transitionJson; + transitionJson["transitionName"] = obs_source_get_name(transition); + transitionJson["transitionKind"] = obs_source_get_id(transition); + transitionJson["transitionFixed"] = obs_transition_fixed(transition); + transitionJson["transitionConfigurable"] = obs_source_configurable(transition); + ret.push_back(transitionJson); + } + + obs_frontend_source_list_free(&transitionList); + + return ret; +} From e05be4784753500c71b368254a374fb36aac0eee Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 22 Dec 2021 16:28:12 -0800 Subject: [PATCH 032/128] RequestHandler: Add GetTransitionKindList --- src/requesthandler/RequestHandler.cpp | 3 +++ src/requesthandler/RequestHandler.h | 3 +++ src/requesthandler/RequestHandler_Transitions.cpp | 7 +++++++ 3 files changed, 13 insertions(+) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index ee747307..1aa370f7 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -86,6 +86,9 @@ const std::map RequestHandler::_handlerMap {"GetInputPropertiesListPropertyItems", &RequestHandler::GetInputPropertiesListPropertyItems}, {"PressInputPropertiesButton", &RequestHandler::PressInputPropertiesButton}, + // Transitions + {"GetTransitionKindList", &RequestHandler::GetTransitionKindList}, + // Scene Items {"GetSceneItemList", &RequestHandler::GetSceneItemList}, {"GetGroupSceneItemList", &RequestHandler::GetGroupSceneItemList}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 4594a442..82941f0c 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -108,6 +108,9 @@ class RequestHandler { RequestResult GetInputPropertiesListPropertyItems(const Request&); RequestResult PressInputPropertiesButton(const Request&); + // Transitions + RequestResult GetTransitionKindList(const Request&); + // Scene Items RequestResult GetSceneItemList(const Request&); RequestResult GetGroupSceneItemList(const Request&); diff --git a/src/requesthandler/RequestHandler_Transitions.cpp b/src/requesthandler/RequestHandler_Transitions.cpp index b09e414c..b9079194 100644 --- a/src/requesthandler/RequestHandler_Transitions.cpp +++ b/src/requesthandler/RequestHandler_Transitions.cpp @@ -18,3 +18,10 @@ with this program. If not, see */ #include "RequestHandler.h" + +RequestResult RequestHandler::GetTransitionKindList(const Request&) +{ + json responseData; + responseData["transitionKinds"] = Utils::Obs::ArrayHelper::GetTransitionKindList(); + return RequestResult::Success(responseData); +} From 5cbf439f55182d731df324916adb589c6fc79333 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Thu, 23 Dec 2021 01:07:15 -0800 Subject: [PATCH 033/128] Utils: Add GetSceneTransitionByName --- src/utils/Obs.h | 1 + src/utils/Obs_SearchHelper.cpp | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/utils/Obs.h b/src/utils/Obs.h index 6fcf4589..a41511e3 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -133,6 +133,7 @@ namespace Utils { namespace SearchHelper { obs_hotkey_t *GetHotkeyByName(std::string name); + obs_source_t *GetSceneTransitionByName(std::string name); // Increments source ref. Use OBSSourceAutoRelease obs_sceneitem_t *GetSceneItemByName(obs_scene_t *scene, std::string name); // Increments ref. Use OBSSceneItemAutoRelease } diff --git a/src/utils/Obs_SearchHelper.cpp b/src/utils/Obs_SearchHelper.cpp index c01ef21b..c39501f7 100644 --- a/src/utils/Obs_SearchHelper.cpp +++ b/src/utils/Obs_SearchHelper.cpp @@ -34,6 +34,26 @@ obs_hotkey_t *Utils::Obs::SearchHelper::GetHotkeyByName(std::string name) return nullptr; } +// Increments source ref. Use OBSSourceAutoRelease +obs_source_t *Utils::Obs::SearchHelper::GetSceneTransitionByName(std::string name) +{ + obs_frontend_source_list transitionList = {}; + obs_frontend_get_transitions(&transitionList); + + obs_source_t *ret = nullptr; + for (size_t i = 0; i < transitionList.sources.num; i++) { + obs_source_t *transition = transitionList.sources.array[i]; + if (obs_source_get_name(transition) == name) { + ret = obs_source_get_ref(transition); + break; + } + } + + obs_frontend_source_list_free(&transitionList); + + return ret; +} + // Increments item ref. Use OBSSceneItemAutoRelease obs_sceneitem_t *Utils::Obs::SearchHelper::GetSceneItemByName(obs_scene_t *scene, std::string name) { From 14238027cc7621b96adf71d6d4c3ba9f0300399c Mon Sep 17 00:00:00 2001 From: tt2468 Date: Thu, 23 Dec 2021 01:07:27 -0800 Subject: [PATCH 034/128] RequestHandler: More transition requests --- src/requesthandler/RequestHandler.cpp | 3 + src/requesthandler/RequestHandler.h | 3 + .../RequestHandler_Transitions.cpp | 67 +++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 1aa370f7..8bd364e6 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -88,6 +88,9 @@ const std::map RequestHandler::_handlerMap // Transitions {"GetTransitionKindList", &RequestHandler::GetTransitionKindList}, + {"GetSceneTransitionList", &RequestHandler::GetSceneTransitionList}, + {"GetCurrentSceneTransition", &RequestHandler::GetCurrentSceneTransition}, + {"SetCurrentSceneTransition", &RequestHandler::SetCurrentSceneTransition}, // Scene Items {"GetSceneItemList", &RequestHandler::GetSceneItemList}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 82941f0c..30fcfe33 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -110,6 +110,9 @@ class RequestHandler { // Transitions RequestResult GetTransitionKindList(const Request&); + RequestResult GetSceneTransitionList(const Request&); + RequestResult GetCurrentSceneTransition(const Request&); + RequestResult SetCurrentSceneTransition(const Request&); // Scene Items RequestResult GetSceneItemList(const Request&); diff --git a/src/requesthandler/RequestHandler_Transitions.cpp b/src/requesthandler/RequestHandler_Transitions.cpp index b9079194..74f87b8f 100644 --- a/src/requesthandler/RequestHandler_Transitions.cpp +++ b/src/requesthandler/RequestHandler_Transitions.cpp @@ -25,3 +25,70 @@ RequestResult RequestHandler::GetTransitionKindList(const Request&) responseData["transitionKinds"] = Utils::Obs::ArrayHelper::GetTransitionKindList(); return RequestResult::Success(responseData); } + +RequestResult RequestHandler::GetSceneTransitionList(const Request&) +{ + json responseData; + + OBSSourceAutoRelease transition = obs_frontend_get_current_transition(); + if (transition) { + responseData["currentSceneTransitionName"] = obs_source_get_name(transition); + responseData["currentSceneTransitionKind"] = obs_source_get_id(transition); + } else { + responseData["currentSceneTransitionName"] = nullptr; + responseData["currentSceneTransitionKind"] = nullptr; + } + + responseData["transitions"] = Utils::Obs::ArrayHelper::GetSceneTransitionList(); + + return RequestResult::Success(responseData); +} + +RequestResult RequestHandler::GetCurrentSceneTransition(const Request&) +{ + OBSSourceAutoRelease transition = obs_frontend_get_current_transition(); + if (!transition) + return RequestResult::Error(RequestStatus::InvalidResourceState, "OBS does not currently have a scene transition set."); // This should not happen! + + json responseData; + responseData["transitionName"] = obs_source_get_name(transition); + responseData["transitionKind"] = obs_source_get_id(transition); + + if (obs_transition_fixed(transition)) { + responseData["transitionFixed"] = true; + responseData["transitionDuration"] = nullptr; + } else { + responseData["transitionFixed"] = false; + responseData["transitionDuration"] = obs_frontend_get_transition_duration(); + } + + if (obs_source_configurable(transition)) { + responseData["transitionConfigurable"] = true; + OBSDataAutoRelease transitionSettings = obs_source_get_settings(transition); + responseData["transitionSettings"] = Utils::Json::ObsDataToJson(transitionSettings); + } else { + responseData["transitionConfigurable"] = false; + responseData["transitionSettings"] = nullptr; + } + + return RequestResult::Success(responseData); +} + +// Transition names being unique are a UI concept and are not enforced by libobs +RequestResult RequestHandler::SetCurrentSceneTransition(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + if (!request.ValidateString("transitionName", statusCode, comment)) + return RequestResult::Error(statusCode, comment); + + std::string transitionName = request.RequestData["transitionName"]; + + OBSSourceAutoRelease transition = Utils::Obs::SearchHelper::GetSceneTransitionByName(transitionName); + if (!transition) + return RequestResult::Error(RequestStatus::ResourceNotFound, "No scene transition was found by that name."); + + obs_frontend_set_current_transition(transition); + + return RequestResult::Success(); +} From 899888eb6c9ea153a217e04f86f0707fac127cb2 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Thu, 23 Dec 2021 09:07:56 +0000 Subject: [PATCH 035/128] docs(ci): Update generated docs - 1423802 [skip ci] --- docs/generated/protocol.json | 8 ++++++++ docs/generated/protocol.md | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 215f68b6..22fa582a 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -389,6 +389,14 @@ "initialVersion": "5.0.0", "enumValue": 605 }, + { + "description": "The resource does not support being configured.\n\nThis is particularly relevant to transitions, where they do not always have changeable settings.", + "enumIdentifier": "ResourceNotConfigurable", + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "enumValue": 606 + }, { "description": "Creating the resource failed.", "enumIdentifier": "ResourceCreationFailed", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 0b0fb35b..56f55b61 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -442,6 +442,7 @@ These are enumeration declarations, which are referenced throughout obs-websocke - [RequestStatus::NotEnoughResources](#requeststatusnotenoughresources) - [RequestStatus::InvalidResourceState](#requeststatusinvalidresourcestate) - [RequestStatus::InvalidInputKind](#requeststatusinvalidinputkind) + - [RequestStatus::ResourceNotConfigurable](#requeststatusresourcenotconfigurable) - [RequestStatus::ResourceCreationFailed](#requeststatusresourcecreationfailed) - [RequestStatus::ResourceActionFailed](#requeststatusresourceactionfailed) - [RequestStatus::RequestProcessingFailed](#requeststatusrequestprocessingfailed) @@ -1011,6 +1012,18 @@ The specified input (obs_source_t-OBS_SOURCE_TYPE_INPUT) had the wrong kind. --- +### RequestStatus::ResourceNotConfigurable + +The resource does not support being configured. + +This is particularly relevant to transitions, where they do not always have changeable settings. + +- Identifier Value: `606` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + ### RequestStatus::ResourceCreationFailed Creating the resource failed. From 07249da400fc523e879014df69a2f17d6b01d9f2 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Thu, 23 Dec 2021 21:00:11 -0800 Subject: [PATCH 036/128] RequestHandler: More transition requests --- src/requesthandler/RequestHandler.cpp | 3 + src/requesthandler/RequestHandler.h | 3 + .../RequestHandler_Transitions.cpp | 62 +++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 8bd364e6..1da18c91 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -91,6 +91,9 @@ const std::map RequestHandler::_handlerMap {"GetSceneTransitionList", &RequestHandler::GetSceneTransitionList}, {"GetCurrentSceneTransition", &RequestHandler::GetCurrentSceneTransition}, {"SetCurrentSceneTransition", &RequestHandler::SetCurrentSceneTransition}, + {"SetCurrentSceneTransitionDuration", &RequestHandler::SetCurrentSceneTransitionDuration}, + {"SetCurrentSceneTransitionSettings", &RequestHandler::SetCurrentSceneTransitionSettings}, + {"TriggerStudioModeTransition", &RequestHandler::TriggerStudioModeTransition}, // Scene Items {"GetSceneItemList", &RequestHandler::GetSceneItemList}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 30fcfe33..266d89e0 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -113,6 +113,9 @@ class RequestHandler { RequestResult GetSceneTransitionList(const Request&); RequestResult GetCurrentSceneTransition(const Request&); RequestResult SetCurrentSceneTransition(const Request&); + RequestResult SetCurrentSceneTransitionDuration(const Request&); + RequestResult SetCurrentSceneTransitionSettings(const Request&); + RequestResult TriggerStudioModeTransition(const Request&); // Scene Items RequestResult GetSceneItemList(const Request&); diff --git a/src/requesthandler/RequestHandler_Transitions.cpp b/src/requesthandler/RequestHandler_Transitions.cpp index 74f87b8f..42ba3617 100644 --- a/src/requesthandler/RequestHandler_Transitions.cpp +++ b/src/requesthandler/RequestHandler_Transitions.cpp @@ -92,3 +92,65 @@ RequestResult RequestHandler::SetCurrentSceneTransition(const Request& request) return RequestResult::Success(); } + +RequestResult RequestHandler::SetCurrentSceneTransitionDuration(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + if (!request.ValidateNumber("transitionDuration", statusCode, comment, 50, 20000)) + return RequestResult::Error(statusCode, comment); + + int transitionDuration = request.RequestData["transitionDuration"]; + + obs_frontend_set_transition_duration(transitionDuration); + + return RequestResult::Success(); +} + +RequestResult RequestHandler::SetCurrentSceneTransitionSettings(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + if (!request.ValidateObject("transitionSettings", statusCode, comment, true)) + return RequestResult::Error(statusCode, comment); + + OBSSourceAutoRelease transition = obs_frontend_get_current_transition(); + if (!transition) + return RequestResult::Error(RequestStatus::InvalidResourceState, "OBS does not currently have a scene transition set."); // This should not happen! + + if (!obs_source_configurable(transition)) + return RequestResult::Error(RequestStatus::ResourceNotConfigurable, "The current transition does not support custom settings."); + + bool overlay = true; + if (request.Contains("overlay")) { + if (!request.ValidateOptionalBoolean("overlay", statusCode, comment)) + return RequestResult::Error(statusCode, comment); + + overlay = request.RequestData["overlay"]; + } + + OBSDataAutoRelease newSettings = Utils::Json::JsonToObsData(request.RequestData["transitionSettings"]); + if (!newSettings) + return RequestResult::Error(RequestStatus::RequestProcessingFailed, "An internal data conversion operation failed. Please report this!"); + + if (overlay) + obs_source_update(transition, newSettings); + else + obs_source_reset_settings(transition, newSettings); + + obs_source_update_properties(transition); + + return RequestResult::Success(); +} + +RequestResult RequestHandler::TriggerStudioModeTransition(const Request&) +{ + if (!obs_frontend_preview_program_mode_active()) + return RequestResult::Error(RequestStatus::StudioModeNotActive); + + OBSSourceAutoRelease previewScene = obs_frontend_get_current_preview_scene(); + + obs_frontend_set_current_scene(previewScene); + + return RequestResult::Success(); +} From da83de75033a0238637fe551bd795a3f27599418 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sat, 25 Dec 2021 00:57:09 -0800 Subject: [PATCH 037/128] Config: Fix firstload password generation --- src/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Config.cpp b/src/Config.cpp index 2d42d7da..835f2123 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -70,7 +70,7 @@ void Config::Load() // future loads use the override flag. if (FirstLoad) { FirstLoad = false; - if (!ServerPassword.isEmpty()) { + if (ServerPassword.isEmpty()) { blog(LOG_INFO, "[Config::Load] (FirstLoad) Generating new server password."); ServerPassword = QString::fromStdString(Utils::Crypto::GeneratePassword()); } else { From 430e61bef74841a0f783bf457c68b536a9e32229 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Mon, 27 Dec 2021 18:26:38 -0800 Subject: [PATCH 038/128] RequestHandler: Use ValidateScene2 in ValidateSceneItem --- src/requesthandler/rpc/Request.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/requesthandler/rpc/Request.cpp b/src/requesthandler/rpc/Request.cpp index 669a7954..418268e3 100644 --- a/src/requesthandler/rpc/Request.cpp +++ b/src/requesthandler/rpc/Request.cpp @@ -297,22 +297,12 @@ obs_source_t *Request::ValidateInput(const std::string &keyName, RequestStatus:: obs_sceneitem_t *Request::ValidateSceneItem(const std::string &sceneKeyName, const std::string &sceneItemIdKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter) const { - OBSSourceAutoRelease sceneSource = ValidateScene(sceneKeyName, statusCode, comment, filter); - if (!sceneSource) + OBSSceneAutoRelease scene = ValidateScene2(sceneKeyName, statusCode, comment, filter); + if (!scene) return nullptr; if (!ValidateNumber(sceneItemIdKeyName, statusCode, comment, 0)) return nullptr; - - OBSScene scene = obs_scene_from_source(sceneSource); - if (!scene) { - scene = obs_group_from_source(sceneSource); - if (!scene) { // This should never happen - statusCode = RequestStatus::GenericError; - comment = "Somehow the scene was found but the scene object could not be fetched. Please report this to the obs-websocket developers."; - return nullptr; - } - } int64_t sceneItemId = RequestData[sceneItemIdKeyName]; From 0992f74fad7626138c69a8e2acfed2f5c4501849 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Mon, 27 Dec 2021 19:06:57 -0800 Subject: [PATCH 039/128] RequestHandler: Use ValidateScene2 for GetSceneItemId --- src/requesthandler/RequestHandler_SceneItems.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/requesthandler/RequestHandler_SceneItems.cpp b/src/requesthandler/RequestHandler_SceneItems.cpp index 34f1958e..90abd2fc 100644 --- a/src/requesthandler/RequestHandler_SceneItems.cpp +++ b/src/requesthandler/RequestHandler_SceneItems.cpp @@ -102,17 +102,10 @@ RequestResult RequestHandler::GetSceneItemId(const Request& request) { RequestStatus::RequestStatus statusCode; std::string comment; - OBSSourceAutoRelease sceneSource = request.ValidateScene("sceneName", statusCode, comment, OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP); - if (!(sceneSource && request.ValidateString("sourceName", statusCode, comment))) + OBSSceneAutoRelease scene = request.ValidateScene2("sceneName", statusCode, comment, OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP); + if (!(scene && request.ValidateString("sourceName", statusCode, comment))) return RequestResult::Error(statusCode, comment); - OBSScene scene = obs_scene_from_source(sceneSource); - if (!scene) { - scene = obs_group_from_source(sceneSource); - if (!scene) // This should never happen - return RequestResult::Error(RequestStatus::GenericError, "Somehow the scene was found but the scene object could not be fetched. Please report this to the obs-websocket developers."); - } - std::string sourceName = request.RequestData["sourceName"]; OBSSceneItemAutoRelease item = Utils::Obs::SearchHelper::GetSceneItemByName(scene, sourceName); From 86506778ad6c7179b6df9bbd9d83f7be285d7dff Mon Sep 17 00:00:00 2001 From: tt2468 Date: Mon, 27 Dec 2021 19:09:16 -0800 Subject: [PATCH 040/128] RequestHandler: Add Ui category Creates a new category specific to requests controlling the OBS UI. --- CMakeLists.txt | 1 + docs/docs/generate_md.py | 1 + src/requesthandler/RequestHandler_General.cpp | 52 -------------- src/requesthandler/RequestHandler_Ui.cpp | 72 +++++++++++++++++++ 4 files changed, 74 insertions(+), 52 deletions(-) create mode 100644 src/requesthandler/RequestHandler_Ui.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4957d2a3..c859d0a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,6 +116,7 @@ set(obs-websocket_SOURCES src/requesthandler/RequestHandler_Stream.cpp src/requesthandler/RequestHandler_Record.cpp src/requesthandler/RequestHandler_MediaInputs.cpp + src/requesthandler/RequestHandler_Ui.cpp src/requesthandler/rpc/Request.cpp src/requesthandler/rpc/RequestBatchRequest.cpp src/requesthandler/rpc/RequestResult.cpp diff --git a/docs/docs/generate_md.py b/docs/docs/generate_md.py index 539664b9..c75f6318 100644 --- a/docs/docs/generate_md.py +++ b/docs/docs/generate_md.py @@ -25,6 +25,7 @@ categoryOrder = [ 'Stream', 'Record', 'Media Inputs', + 'Ui', 'High-Volume' ] diff --git a/src/requesthandler/RequestHandler_General.cpp b/src/requesthandler/RequestHandler_General.cpp index 53852ef5..97dd1483 100644 --- a/src/requesthandler/RequestHandler_General.cpp +++ b/src/requesthandler/RequestHandler_General.cpp @@ -288,58 +288,6 @@ RequestResult RequestHandler::TriggerHotkeyByKeySequence(const Request& request) return RequestResult::Success(); } -/** - * Gets whether studio is enabled. - * - * @responseField studioModeEnabled | Boolean | Whether studio mode is enabled - * - * @requestType GetStudioModeEnabled - * @complexity 1 - * @rpcVersion -1 - * @initialVersion 5.0.0 - * @category general - * @api requests - */ -RequestResult RequestHandler::GetStudioModeEnabled(const Request&) -{ - json responseData; - responseData["studioModeEnabled"] = obs_frontend_preview_program_mode_active(); - return RequestResult::Success(responseData); -} - -/** - * Enables or disables studio mode - * - * @requestField studioModeEnabled | Boolean | True == Enabled, False == Disabled - * - * @requestType SetStudioModeEnabled - * @complexity 1 - * @rpcVersion -1 - * @initialVersion 5.0.0 - * @category general - * @api requests - */ -RequestResult RequestHandler::SetStudioModeEnabled(const Request& request) -{ - RequestStatus::RequestStatus statusCode; - std::string comment; - if (!request.ValidateBoolean("studioModeEnabled", statusCode, comment)) - return RequestResult::Error(statusCode, comment); - - // Avoid queueing tasks if nothing will change - if (obs_frontend_preview_program_mode_active() != request.RequestData["studioModeEnabled"]) { - // (Bad) Create a boolean then pass it as a reference to the task. Requires `wait` in obs_queue_task() to be true, else undefined behavior - bool studioModeEnabled = request.RequestData["studioModeEnabled"]; - // Queue the task inside of the UI thread to prevent race conditions - obs_queue_task(OBS_TASK_UI, [](void* param) { - auto studioModeEnabled = (bool*)param; - obs_frontend_set_preview_program_mode(*studioModeEnabled); - }, &studioModeEnabled, true); - } - - return RequestResult::Success(); -} - /** * Sleeps for a time duration or number of frames. Only available in request batches with types `SERIAL_REALTIME` or `SERIAL_FRAME`. * diff --git a/src/requesthandler/RequestHandler_Ui.cpp b/src/requesthandler/RequestHandler_Ui.cpp new file mode 100644 index 00000000..4a093591 --- /dev/null +++ b/src/requesthandler/RequestHandler_Ui.cpp @@ -0,0 +1,72 @@ +/* +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 whether studio is enabled. + * + * @responseField studioModeEnabled | Boolean | Whether studio mode is enabled + * + * @requestType GetStudioModeEnabled + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category ui + * @api requests + */ +RequestResult RequestHandler::GetStudioModeEnabled(const Request&) +{ + json responseData; + responseData["studioModeEnabled"] = obs_frontend_preview_program_mode_active(); + return RequestResult::Success(responseData); +} + +/** + * Enables or disables studio mode + * + * @requestField studioModeEnabled | Boolean | True == Enabled, False == Disabled + * + * @requestType SetStudioModeEnabled + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category ui + * @api requests + */ +RequestResult RequestHandler::SetStudioModeEnabled(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + if (!request.ValidateBoolean("studioModeEnabled", statusCode, comment)) + return RequestResult::Error(statusCode, comment); + + // Avoid queueing tasks if nothing will change + if (obs_frontend_preview_program_mode_active() != request.RequestData["studioModeEnabled"]) { + // (Bad) Create a boolean then pass it as a reference to the task. Requires `wait` in obs_queue_task() to be true, else undefined behavior + bool studioModeEnabled = request.RequestData["studioModeEnabled"]; + // Queue the task inside of the UI thread to prevent race conditions + obs_queue_task(OBS_TASK_UI, [](void* param) { + auto studioModeEnabled = (bool*)param; + obs_frontend_set_preview_program_mode(*studioModeEnabled); + }, &studioModeEnabled, true); + } + + return RequestResult::Success(); +} From e2f60b002e0aa0845c88150c06e6dd96e001c5ce Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 28 Dec 2021 16:57:58 -0800 Subject: [PATCH 041/128] RequestHandler: Reorder Ui requests to new category --- src/requesthandler/RequestHandler.cpp | 6 ++++-- src/requesthandler/RequestHandler.h | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 1da18c91..a0c118a4 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -29,8 +29,6 @@ const std::map RequestHandler::_handlerMap {"GetHotkeyList", &RequestHandler::GetHotkeyList}, {"TriggerHotkeyByName", &RequestHandler::TriggerHotkeyByName}, {"TriggerHotkeyByKeySequence", &RequestHandler::TriggerHotkeyByKeySequence}, - {"GetStudioModeEnabled", &RequestHandler::GetStudioModeEnabled}, - {"SetStudioModeEnabled", &RequestHandler::SetStudioModeEnabled}, {"Sleep", &RequestHandler::Sleep}, // Config @@ -132,6 +130,10 @@ const std::map RequestHandler::_handlerMap {"SetMediaInputCursor", &RequestHandler::SetMediaInputCursor}, {"OffsetMediaInputCursor", &RequestHandler::OffsetMediaInputCursor}, {"TriggerMediaInputAction", &RequestHandler::TriggerMediaInputAction}, + + // Ui + {"GetStudioModeEnabled", &RequestHandler::GetStudioModeEnabled}, + {"SetStudioModeEnabled", &RequestHandler::SetStudioModeEnabled}, }; RequestHandler::RequestHandler(SessionPtr session) : diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 266d89e0..19e3fde4 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -51,8 +51,6 @@ class RequestHandler { RequestResult GetHotkeyList(const Request&); RequestResult TriggerHotkeyByName(const Request&); RequestResult TriggerHotkeyByKeySequence(const Request&); - RequestResult GetStudioModeEnabled(const Request&); - RequestResult SetStudioModeEnabled(const Request&); RequestResult Sleep(const Request&); // Config @@ -155,6 +153,10 @@ class RequestHandler { RequestResult OffsetMediaInputCursor(const Request&); RequestResult TriggerMediaInputAction(const Request&); + // Ui + RequestResult GetStudioModeEnabled(const Request&); + RequestResult SetStudioModeEnabled(const Request&); + SessionPtr _session; static const std::map _handlerMap; }; From 851a6f8c5ae384a9b3035d9511f66de3439a9d96 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Wed, 29 Dec 2021 00:58:51 +0000 Subject: [PATCH 042/128] docs(ci): Update generated docs - e2f60b0 [skip ci] --- docs/generated/protocol.json | 74 ++++++++++++++++++------------------ docs/generated/protocol.md | 74 ++++++++++++++++++------------------ 2 files changed, 75 insertions(+), 73 deletions(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 22fa582a..a1d1bc1c 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -1323,43 +1323,6 @@ ], "responseFields": [] }, - { - "description": "Gets whether studio is enabled.", - "requestType": "GetStudioModeEnabled", - "complexity": 1, - "rpcVersion": "1", - "deprecated": false, - "initialVersion": "5.0.0", - "category": "general", - "requestFields": [], - "responseFields": [ - { - "valueName": "studioModeEnabled", - "valueType": "Boolean", - "valueDescription": "Whether studio mode is enabled" - } - ] - }, - { - "description": "Enables or disables studio mode", - "requestType": "SetStudioModeEnabled", - "complexity": 1, - "rpcVersion": "1", - "deprecated": false, - "initialVersion": "5.0.0", - "category": "general", - "requestFields": [ - { - "valueName": "studioModeEnabled", - "valueType": "Boolean", - "valueDescription": "True == Enabled, False == Disabled", - "valueRestrictions": null, - "valueOptional": false, - "valueOptionalBehavior": null - } - ], - "responseFields": [] - }, { "description": "Sleeps for a time duration or number of frames. Only available in request batches with types `SERIAL_REALTIME` or `SERIAL_FRAME`.", "requestType": "Sleep", @@ -2843,6 +2806,43 @@ "category": "stream", "requestFields": [], "responseFields": [] + }, + { + "description": "Gets whether studio is enabled.", + "requestType": "GetStudioModeEnabled", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "ui", + "requestFields": [], + "responseFields": [ + { + "valueName": "studioModeEnabled", + "valueType": "Boolean", + "valueDescription": "Whether studio mode is enabled" + } + ] + }, + { + "description": "Enables or disables studio mode", + "requestType": "SetStudioModeEnabled", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "ui", + "requestFields": [ + { + "valueName": "studioModeEnabled", + "valueType": "Boolean", + "valueDescription": "True == Enabled, False == Disabled", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] } ], "events": [ diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 56f55b61..84f52c2f 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -1407,8 +1407,6 @@ The profile list has changed. - [GetHotkeyList](#gethotkeylist) - [TriggerHotkeyByName](#triggerhotkeybyname) - [TriggerHotkeyByKeySequence](#triggerhotkeybykeysequence) - - [GetStudioModeEnabled](#getstudiomodeenabled) - - [SetStudioModeEnabled](#setstudiomodeenabled) - [Sleep](#sleep) - [Config](#config-1) - [GetPersistentData](#getpersistentdata) @@ -1479,6 +1477,9 @@ The profile list has changed. - [ToggleStream](#togglestream) - [StartStream](#startstream) - [StopStream](#stopstream) +- [Ui](#ui) + - [GetStudioModeEnabled](#getstudiomodeenabled) + - [SetStudioModeEnabled](#setstudiomodeenabled) @@ -1635,40 +1636,6 @@ Triggers a hotkey using a sequence of keys. --- -### GetStudioModeEnabled - -Gets whether studio is enabled. - -- Complexity Rating: `1/5` -- Latest Supported RPC Version: `1` -- Added in v5.0.0 - - -**Response Fields:** - -| Name | Type | Description | -| ---- | :---: | ----------- | -| studioModeEnabled | Boolean | Whether studio mode is enabled | - ---- - -### SetStudioModeEnabled - -Enables or disables studio mode - -- Complexity Rating: `1/5` -- Latest Supported RPC Version: `1` -- Added in v5.0.0 - - -**Request Fields:** - -| Name | Type | Description | Value Restrictions | ?Default Behavior | -| ---- | :---: | ----------- | :----------------: | ----------------- | -| studioModeEnabled | Boolean | True == Enabled, False == Disabled | None | N/A | - ---- - ### Sleep Sleeps for a time duration or number of frames. Only available in request batches with types `SERIAL_REALTIME` or `SERIAL_FRAME`. @@ -3069,3 +3036,38 @@ Stops the stream output. - Added in v5.0.0 +## Ui + +### GetStudioModeEnabled + +Gets whether studio is enabled. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| studioModeEnabled | Boolean | Whether studio mode is enabled | + +--- + +### SetStudioModeEnabled + +Enables or disables studio mode + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| studioModeEnabled | Boolean | True == Enabled, False == Disabled | None | N/A | + + From 4d65c2adeecaff9cd50cac0eb5fabb1a7034557b Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 28 Dec 2021 17:16:41 -0800 Subject: [PATCH 043/128] Utils: Move GetListPropertyItems to utils --- src/requesthandler/RequestHandler_Inputs.cpp | 28 +------------------- src/utils/Obs.h | 1 + src/utils/Obs_ArrayHelper.cpp | 26 ++++++++++++++++++ 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/requesthandler/RequestHandler_Inputs.cpp b/src/requesthandler/RequestHandler_Inputs.cpp index b29bfe1f..a14c0f14 100644 --- a/src/requesthandler/RequestHandler_Inputs.cpp +++ b/src/requesthandler/RequestHandler_Inputs.cpp @@ -616,32 +616,6 @@ RequestResult RequestHandler::SetInputAudioMonitorType(const Request& request) return RequestResult::Success(); } -std::vector GetListPropertyItems(obs_property_t *property) -{ - std::vector ret; - - enum obs_combo_format itemFormat = obs_property_list_format(property); - size_t itemCount = obs_property_list_item_count(property); - - for (size_t i = 0; i < itemCount; i++) { - json itemData; - itemData["itemName"] = obs_property_list_item_name(property, i); - itemData["itemEnabled"] = !obs_property_list_item_disabled(property, i); - if (itemFormat == OBS_COMBO_FORMAT_INT) { - itemData["itemValue"] = obs_property_list_item_int(property, i); - } else if (itemFormat == OBS_COMBO_FORMAT_FLOAT) { - itemData["itemValue"] = obs_property_list_item_float(property, i); - } else if (itemFormat == OBS_COMBO_FORMAT_STRING) { - itemData["itemValue"] = obs_property_list_item_string(property, i); - } else { - itemData["itemValue"] = nullptr; - } - ret.push_back(itemData); - } - - return ret; -} - /** * Gets the items of a list property from an input's properties. * @@ -677,7 +651,7 @@ RequestResult RequestHandler::GetInputPropertiesListPropertyItems(const Request& return RequestResult::Error(RequestStatus::InvalidResourceType, "The property found is not a list."); json responseData; - responseData["propertyItems"] = GetListPropertyItems(property); + responseData["propertyItems"] = Utils::Obs::ArrayHelper::GetListPropertyItems(property); return RequestResult::Success(responseData); } diff --git a/src/utils/Obs.h b/src/utils/Obs.h index a41511e3..943b6b7f 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -122,6 +122,7 @@ namespace Utils { 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); + std::vector GetListPropertyItems(obs_property_t *property); std::vector GetTransitionKindList(); std::vector GetSceneTransitionList(); } diff --git a/src/utils/Obs_ArrayHelper.cpp b/src/utils/Obs_ArrayHelper.cpp index f408fe58..bbd032c3 100644 --- a/src/utils/Obs_ArrayHelper.cpp +++ b/src/utils/Obs_ArrayHelper.cpp @@ -201,6 +201,32 @@ std::vector Utils::Obs::ArrayHelper::GetInputKindList(bool unversio return ret; } +std::vector Utils::Obs::ArrayHelper::GetListPropertyItems(obs_property_t *property) +{ + std::vector ret; + + enum obs_combo_format itemFormat = obs_property_list_format(property); + size_t itemCount = obs_property_list_item_count(property); + + for (size_t i = 0; i < itemCount; i++) { + json itemData; + itemData["itemName"] = obs_property_list_item_name(property, i); + itemData["itemEnabled"] = !obs_property_list_item_disabled(property, i); + if (itemFormat == OBS_COMBO_FORMAT_INT) { + itemData["itemValue"] = obs_property_list_item_int(property, i); + } else if (itemFormat == OBS_COMBO_FORMAT_FLOAT) { + itemData["itemValue"] = obs_property_list_item_float(property, i); + } else if (itemFormat == OBS_COMBO_FORMAT_STRING) { + itemData["itemValue"] = obs_property_list_item_string(property, i); + } else { + itemData["itemValue"] = nullptr; + } + ret.push_back(itemData); + } + + return ret; +} + std::vector Utils::Obs::ArrayHelper::GetTransitionKindList() { std::vector ret; From ec79124b5f0ed5207b1ef06a0ab10f686e722cb4 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 28 Dec 2021 18:11:30 -0800 Subject: [PATCH 044/128] docs: Document transition requests --- .../RequestHandler_Transitions.cpp | 95 ++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/src/requesthandler/RequestHandler_Transitions.cpp b/src/requesthandler/RequestHandler_Transitions.cpp index 42ba3617..108358ee 100644 --- a/src/requesthandler/RequestHandler_Transitions.cpp +++ b/src/requesthandler/RequestHandler_Transitions.cpp @@ -19,6 +19,20 @@ with this program. If not, see #include "RequestHandler.h" +/** + * Gets an array of all available transition kinds. + * + * Similar to `GetInputKindList` + * + * @responseField transitionKinds | Vector | Array of transition kinds + * + * @requestType GetTransitionKindList + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category transitions + */ RequestResult RequestHandler::GetTransitionKindList(const Request&) { json responseData; @@ -26,6 +40,20 @@ RequestResult RequestHandler::GetTransitionKindList(const Request&) return RequestResult::Success(responseData); } +/** + * Gets an array of all scene transitions in OBS. + * + * @responseField currentSceneTransitionName | String | Name of the current scene transition. Can be null + * @responseField currentSceneTransitionKind | String | Kind of the current scene transition. Can be null + * @responseField transitions | Vector | Array of transitions + * + * @requestType GetSceneTransitionList + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category transitions + */ RequestResult RequestHandler::GetSceneTransitionList(const Request&) { json responseData; @@ -44,6 +72,23 @@ RequestResult RequestHandler::GetSceneTransitionList(const Request&) return RequestResult::Success(responseData); } +/** + * Gets information about the current scene transition. + * + * @responseField transitionName | String | Name of the transition + * @responseField transitionKind | String | Kind of the transition + * @responseField transitionFixed | Boolean | Whether the transition uses a fixed (unconfigurable) duration + * @responseField transitionDuration | Number | Configured transition duration in milliseconds. `null` if transition is fixed + * @responseField transitionConfigurable | Boolean | Whether the transition supports being configured + * @responseField transitionSettings | Object | Object of settings for the transition. `null` if transition is not configurable + * + * @requestType GetCurrentSceneTransition + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category transitions + */ RequestResult RequestHandler::GetCurrentSceneTransition(const Request&) { OBSSourceAutoRelease transition = obs_frontend_get_current_transition(); @@ -74,7 +119,20 @@ RequestResult RequestHandler::GetCurrentSceneTransition(const Request&) return RequestResult::Success(responseData); } -// Transition names being unique are a UI concept and are not enforced by libobs +/** + * Sets the current scene transition. + * + * Small note: While the namespace of scene transitions is generally unique, that uniqueness is not a guarantee as it is with other resources like inputs. + * + * @requestField transitionName | String | Name of the transition to make active + * + * @requestType SetCurrentSceneTransition + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category transitions + */ RequestResult RequestHandler::SetCurrentSceneTransition(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -93,6 +151,18 @@ RequestResult RequestHandler::SetCurrentSceneTransition(const Request& request) return RequestResult::Success(); } +/** + * Sets the duration of the current scene transition, if it is not fixed. + * + * @requestField transitionDuration | Number | Duration in milliseconds | >= 50, <= 20000 + * + * @requestType SetCurrentSceneTransitionDuration + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category transitions + */ RequestResult RequestHandler::SetCurrentSceneTransitionDuration(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -107,6 +177,19 @@ RequestResult RequestHandler::SetCurrentSceneTransitionDuration(const Request& r return RequestResult::Success(); } +/** + * Sets the settings of the current scene transition. + * + * @requestField transitionSettings | Object | Settings object to apply to the transition. Can be `{}` + * @requestField ?overlay | Boolean | Whether to overlay over the current settings or replace them | true + * + * @requestType SetCurrentSceneTransitionSettings + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category transitions + */ RequestResult RequestHandler::SetCurrentSceneTransitionSettings(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -143,6 +226,16 @@ RequestResult RequestHandler::SetCurrentSceneTransitionSettings(const Request& r return RequestResult::Success(); } +/** + * Triggers the current scene transition. Same functionality as the `Transition` button in studio mode. + * + * @requestType TriggerStudioModeTransition + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category transitions + */ RequestResult RequestHandler::TriggerStudioModeTransition(const Request&) { if (!obs_frontend_preview_program_mode_active()) From 9385a2449ecc1792f0193ccfd4ee70a810aaa589 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 28 Dec 2021 18:28:04 -0800 Subject: [PATCH 045/128] docs: Document the rest of the undocumented requests --- .../RequestHandler_MediaInputs.cpp | 69 +++++++++++++++ src/requesthandler/RequestHandler_Record.cpp | 88 +++++++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/src/requesthandler/RequestHandler_MediaInputs.cpp b/src/requesthandler/RequestHandler_MediaInputs.cpp index e651ddf7..8df95162 100644 --- a/src/requesthandler/RequestHandler_MediaInputs.cpp +++ b/src/requesthandler/RequestHandler_MediaInputs.cpp @@ -25,6 +25,32 @@ bool IsMediaTimeValid(obs_source_t *input) return mediaState == OBS_MEDIA_STATE_PLAYING || mediaState == OBS_MEDIA_STATE_PAUSED; } +/** + * Gets the status of a media input. + * + * Media States: + * - `OBS_MEDIA_STATE_NONE` + * - `OBS_MEDIA_STATE_PLAYING` + * - `OBS_MEDIA_STATE_OPENING` + * - `OBS_MEDIA_STATE_BUFFERING` + * - `OBS_MEDIA_STATE_PAUSED` + * - `OBS_MEDIA_STATE_STOPPED` + * - `OBS_MEDIA_STATE_ENDED` + * - `OBS_MEDIA_STATE_ERROR` + * + * @requestField inputName | String | Name of the media input + * + * @responseField mediaState | String | State of the media input + * @responseField mediaDuration | Number | Total duration of the playing media in milliseconds. `null` if not playing + * @responseField mediaCursor | Number | Position of the cursor in milliseconds. `null` if not playing + * + * @requestType GetMediaInputStatus + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category media inputs + */ RequestResult RequestHandler::GetMediaInputStatus(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -47,6 +73,21 @@ RequestResult RequestHandler::GetMediaInputStatus(const Request& request) return RequestResult::Success(responseData); } +/** + * Sets the cursor position of a media input. + * + * This request does not perform bounds checking of the cursor position. + * + * @requestField inputName | String | Name of the media input + * @requestField mediaCursor | Number | New cursor position to set | >= 0 + * + * @requestType SetMediaInputCursor + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category media inputs + */ RequestResult RequestHandler::SetMediaInputCursor(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -66,6 +107,21 @@ RequestResult RequestHandler::SetMediaInputCursor(const Request& request) return RequestResult::Success(); } +/** + * Offsets the current cursor position of a media input by the specified value. + * + * This request does not perform bounds checking of the cursor position. + * + * @requestField inputName | String | Name of the media input + * @requestField mediaCursorOffset | Number | Value to offset the current cursor position by | None + * + * @requestType OffsetMediaInputCursor + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category media inputs + */ RequestResult RequestHandler::OffsetMediaInputCursor(const Request& request) { RequestStatus::RequestStatus statusCode; @@ -88,6 +144,19 @@ RequestResult RequestHandler::OffsetMediaInputCursor(const Request& request) return RequestResult::Success(); } +/** + * Triggers an action on a media input. + * + * @requestField inputName | String | Name of the media input + * @requestField mediaAction | String | Identifier of the `ObsMediaInputAction` enum + * + * @requestType TriggerMediaInputAction + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category media inputs + */ RequestResult RequestHandler::TriggerMediaInputAction(const Request& request) { RequestStatus::RequestStatus statusCode; diff --git a/src/requesthandler/RequestHandler_Record.cpp b/src/requesthandler/RequestHandler_Record.cpp index e18071c8..c6e2e21a 100644 --- a/src/requesthandler/RequestHandler_Record.cpp +++ b/src/requesthandler/RequestHandler_Record.cpp @@ -19,6 +19,22 @@ with this program. If not, see #include "RequestHandler.h" +/** + * Gets the status of the record output. + * + * @responseField outputActive | Boolean | Whether the output is active + * @responseField ouputPaused | Boolean | Whether the output is paused + * @responseField outputTimecode | String | Current formatted timecode string for the output + * @responseField outputDuration | Number | Current duration in milliseconds for the output + * @responseField outputBytes | Number | Number of bytes sent by the output + * + * @requestType GetRecordStatus + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category record + */ RequestResult RequestHandler::GetRecordStatus(const Request&) { OBSOutputAutoRelease recordOutput = obs_frontend_get_recording_output(); @@ -35,6 +51,16 @@ RequestResult RequestHandler::GetRecordStatus(const Request&) return RequestResult::Success(responseData); } +/** + * Toggles the status of the record output. + * + * @requestType ToggleRecord + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category record + */ RequestResult RequestHandler::ToggleRecord(const Request&) { json responseData; @@ -49,6 +75,16 @@ RequestResult RequestHandler::ToggleRecord(const Request&) return RequestResult::Success(responseData); } +/** + * Starts the record output. + * + * @requestType StartRecord + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category record + */ RequestResult RequestHandler::StartRecord(const Request&) { if (obs_frontend_recording_active()) @@ -60,6 +96,16 @@ RequestResult RequestHandler::StartRecord(const Request&) return RequestResult::Success(); } +/** + * Stops the record output. + * + * @requestType StopRecord + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category record + */ RequestResult RequestHandler::StopRecord(const Request&) { if (!obs_frontend_recording_active()) @@ -71,6 +117,16 @@ RequestResult RequestHandler::StopRecord(const Request&) return RequestResult::Success(); } +/** + * Toggles pause on the record output. + * + * @requestType ToggleRecordPause + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category record + */ RequestResult RequestHandler::ToggleRecordPause(const Request&) { json responseData; @@ -85,6 +141,16 @@ RequestResult RequestHandler::ToggleRecordPause(const Request&) return RequestResult::Success(responseData); } +/** + * Pauses the record output. + * + * @requestType PauseRecord + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category record + */ RequestResult RequestHandler::PauseRecord(const Request&) { if (obs_frontend_recording_paused()) @@ -96,6 +162,16 @@ RequestResult RequestHandler::PauseRecord(const Request&) return RequestResult::Success(); } +/** + * Resumes the record output. + * + * @requestType ResumeRecord + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category record + */ RequestResult RequestHandler::ResumeRecord(const Request&) { if (!obs_frontend_recording_paused()) @@ -107,6 +183,18 @@ RequestResult RequestHandler::ResumeRecord(const Request&) return RequestResult::Success(); } +/** + * Gets the current directory that the record output is set to. + * + * @responseField recordDirectory | String | Output directory + * + * @requestType GetRecordDirectory + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category record + */ RequestResult RequestHandler::GetRecordDirectory(const Request&) { json responseData; From 964e91bbd78f419e82af74be1baab4b69f753c88 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 28 Dec 2021 18:57:02 -0800 Subject: [PATCH 046/128] docs: Document ObsMediaInputAction --- docs/docs/process_comments.py | 2 +- src/utils/Obs.h | 63 +++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/docs/docs/process_comments.py b/docs/docs/process_comments.py index db52914c..3868eb5e 100644 --- a/docs/docs/process_comments.py +++ b/docs/docs/process_comments.py @@ -122,7 +122,7 @@ for comment in comments_raw: enumValue = field_to_string(comment['enumValue']) enum['enumValue'] = int(enumValue) if enumValue.isdigit() else enumValue else: - enum['enumValue'] = None + enum['enumValue'] = enum['enumIdentifier'] if enumType not in enums_raw: enums_raw[enumType] = {'enumIdentifiers': [enum]} diff --git a/src/utils/Obs.h b/src/utils/Obs.h index 943b6b7f..7a881e1a 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -77,12 +77,75 @@ enum ObsOutputState { }; enum ObsMediaInputAction { + /** + * No action. + * + * @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE + * @enumType ObsMediaInputAction + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE, + /** + * Play the media input. + * + * @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY + * @enumType ObsMediaInputAction + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY, + /** + * Pause the media input. + * + * @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE + * @enumType ObsMediaInputAction + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE, + /** + * Stop the media input. + * + * @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP + * @enumType ObsMediaInputAction + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP, + /** + * Restart the media input. + * + * @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART + * @enumType ObsMediaInputAction + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART, + /** + * Go to the next playlist item. + * + * @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT + * @enumType ObsMediaInputAction + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT, + /** + * Go to the previous playlist item. + * + * @enumIdentifier OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS + * @enumType ObsMediaInputAction + * @rpcVersion 1 + * @initialVersion 5.0.0 + * @api enums + */ OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS, }; From 4835abd9c2b1d66d58596f6afce9d96981daed82 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Wed, 29 Dec 2021 03:04:15 +0000 Subject: [PATCH 047/128] docs(ci): Update generated docs - 964e91b [skip ci] --- docs/generated/protocol.json | 466 +++++++++++++++++++++++++++++++++++ docs/generated/protocol.md | 341 +++++++++++++++++++++++++ 2 files changed, 807 insertions(+) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index a1d1bc1c..f2fdb0b8 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -431,6 +431,67 @@ } ] }, + { + "enumType": "ObsMediaInputAction", + "enumIdentifiers": [ + { + "description": "No action.", + "enumIdentifier": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE" + }, + { + "description": "Play the media input.", + "enumIdentifier": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY" + }, + { + "description": "Pause the media input.", + "enumIdentifier": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE" + }, + { + "description": "Stop the media input.", + "enumIdentifier": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP" + }, + { + "description": "Restart the media input.", + "enumIdentifier": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART" + }, + { + "description": "Go to the next playlist item.", + "enumIdentifier": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT" + }, + { + "description": "Go to the previous playlist item.", + "enumIdentifier": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS", + "rpcVersion": 1, + "deprecated": true, + "initialVersion": "5.0.0", + "enumValue": "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS" + } + ] + }, { "enumType": "WebSocketCloseCode", "enumIdentifiers": [ @@ -1919,6 +1980,246 @@ ], "responseFields": [] }, + { + "description": "Gets the status of a media input.\n\nMedia States:\n- `OBS_MEDIA_STATE_NONE`\n- `OBS_MEDIA_STATE_PLAYING`\n- `OBS_MEDIA_STATE_OPENING`\n- `OBS_MEDIA_STATE_BUFFERING`\n- `OBS_MEDIA_STATE_PAUSED`\n- `OBS_MEDIA_STATE_STOPPED`\n- `OBS_MEDIA_STATE_ENDED`\n- `OBS_MEDIA_STATE_ERROR`", + "requestType": "GetMediaInputStatus", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "media inputs", + "requestFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the media input", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "mediaState", + "valueType": "String", + "valueDescription": "State of the media input" + }, + { + "valueName": "mediaDuration", + "valueType": "Number", + "valueDescription": "Total duration of the playing media in milliseconds. `null` if not playing" + }, + { + "valueName": "mediaCursor", + "valueType": "Number", + "valueDescription": "Position of the cursor in milliseconds. `null` if not playing" + } + ] + }, + { + "description": "Sets the cursor position of a media input.\n\nThis request does not perform bounds checking of the cursor position.", + "requestType": "SetMediaInputCursor", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "media inputs", + "requestFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the media input", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "mediaCursor", + "valueType": "Number", + "valueDescription": "New cursor position to set", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, + { + "description": "Offsets the current cursor position of a media input by the specified value.\n\nThis request does not perform bounds checking of the cursor position.", + "requestType": "OffsetMediaInputCursor", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "media inputs", + "requestFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the media input", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "mediaCursorOffset", + "valueType": "Number", + "valueDescription": "Value to offset the current cursor position by", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, + { + "description": "Triggers an action on a media input.", + "requestType": "TriggerMediaInputAction", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "media inputs", + "requestFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the media input", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "mediaAction", + "valueType": "String", + "valueDescription": "Identifier of the `ObsMediaInputAction` enum", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, + { + "description": "Gets the status of the record output.", + "requestType": "GetRecordStatus", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "record", + "requestFields": [], + "responseFields": [ + { + "valueName": "outputActive", + "valueType": "Boolean", + "valueDescription": "Whether the output is active" + }, + { + "valueName": "ouputPaused", + "valueType": "Boolean", + "valueDescription": "Whether the output is paused" + }, + { + "valueName": "outputTimecode", + "valueType": "String", + "valueDescription": "Current formatted timecode string for the output" + }, + { + "valueName": "outputDuration", + "valueType": "Number", + "valueDescription": "Current duration in milliseconds for the output" + }, + { + "valueName": "outputBytes", + "valueType": "Number", + "valueDescription": "Number of bytes sent by the output" + } + ] + }, + { + "description": "Toggles the status of the record output.", + "requestType": "ToggleRecord", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "record", + "requestFields": [], + "responseFields": [] + }, + { + "description": "Starts the record output.", + "requestType": "StartRecord", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "record", + "requestFields": [], + "responseFields": [] + }, + { + "description": "Stops the record output.", + "requestType": "StopRecord", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "record", + "requestFields": [], + "responseFields": [] + }, + { + "description": "Toggles pause on the record output.", + "requestType": "ToggleRecordPause", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "record", + "requestFields": [], + "responseFields": [] + }, + { + "description": "Pauses the record output.", + "requestType": "PauseRecord", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "record", + "requestFields": [], + "responseFields": [] + }, + { + "description": "Resumes the record output.", + "requestType": "ResumeRecord", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "record", + "requestFields": [], + "responseFields": [] + }, + { + "description": "Gets the current directory that the record output is set to.", + "requestType": "GetRecordDirectory", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "record", + "requestFields": [], + "responseFields": [ + { + "valueName": "recordDirectory", + "valueType": "String", + "valueDescription": "Output directory" + } + ] + }, { "description": "Gets a list of all scene items in a scene.\n\nScenes only", "requestType": "GetSceneItemList", @@ -2807,6 +3108,171 @@ "requestFields": [], "responseFields": [] }, + { + "description": "Gets an array of all available transition kinds.\n\nSimilar to `GetInputKindList`", + "requestType": "GetTransitionKindList", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "transitions", + "requestFields": [], + "responseFields": [ + { + "valueName": "transitionKinds", + "valueType": "Vector", + "valueDescription": "Array of transition kinds" + } + ] + }, + { + "description": "Gets an array of all scene transitions in OBS.", + "requestType": "GetSceneTransitionList", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "transitions", + "requestFields": [], + "responseFields": [ + { + "valueName": "currentSceneTransitionName", + "valueType": "String", + "valueDescription": "Name of the current scene transition. Can be null" + }, + { + "valueName": "currentSceneTransitionKind", + "valueType": "String", + "valueDescription": "Kind of the current scene transition. Can be null" + }, + { + "valueName": "transitions", + "valueType": "Vector", + "valueDescription": "Array of transitions" + } + ] + }, + { + "description": "Gets information about the current scene transition.", + "requestType": "GetCurrentSceneTransition", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "transitions", + "requestFields": [], + "responseFields": [ + { + "valueName": "transitionName", + "valueType": "String", + "valueDescription": "Name of the transition" + }, + { + "valueName": "transitionKind", + "valueType": "String", + "valueDescription": "Kind of the transition" + }, + { + "valueName": "transitionFixed", + "valueType": "Boolean", + "valueDescription": "Whether the transition uses a fixed (unconfigurable) duration" + }, + { + "valueName": "transitionDuration", + "valueType": "Number", + "valueDescription": "Configured transition duration in milliseconds. `null` if transition is fixed" + }, + { + "valueName": "transitionConfigurable", + "valueType": "Boolean", + "valueDescription": "Whether the transition supports being configured" + }, + { + "valueName": "transitionSettings", + "valueType": "Object", + "valueDescription": "Object of settings for the transition. `null` if transition is not configurable" + } + ] + }, + { + "description": "Sets the current scene transition.\n\nSmall note: While the namespace of scene transitions is generally unique, that uniqueness is not a guarantee as it is with other resources like inputs.", + "requestType": "SetCurrentSceneTransition", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "transitions", + "requestFields": [ + { + "valueName": "transitionName", + "valueType": "String", + "valueDescription": "Name of the transition to make active", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, + { + "description": "Sets the duration of the current scene transition, if it is not fixed.", + "requestType": "SetCurrentSceneTransitionDuration", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "transitions", + "requestFields": [ + { + "valueName": "transitionDuration", + "valueType": "Number", + "valueDescription": "Duration in milliseconds", + "valueRestrictions": ">= 50, <= 20000", + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, + { + "description": "Sets the settings of the current scene transition.", + "requestType": "SetCurrentSceneTransitionSettings", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "transitions", + "requestFields": [ + { + "valueName": "transitionSettings", + "valueType": "Object", + "valueDescription": "Settings object to apply to the transition. Can be `{}`", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "overlay", + "valueType": "Boolean", + "valueDescription": "Whether to overlay over the current settings or replace them", + "valueRestrictions": null, + "valueOptional": true, + "valueOptionalBehavior": "true" + } + ], + "responseFields": [] + }, + { + "description": "Triggers the current scene transition. Same functionality as the `Transition` button in studio mode.", + "requestType": "TriggerStudioModeTransition", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "transitions", + "requestFields": [], + "responseFields": [] + }, { "description": "Gets whether studio is enabled.", "requestType": "GetStudioModeEnabled", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 84f52c2f..5a38cf50 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -1457,6 +1457,14 @@ The profile list has changed. - [SetInputAudioMonitorType](#setinputaudiomonitortype) - [GetInputPropertiesListPropertyItems](#getinputpropertieslistpropertyitems) - [PressInputPropertiesButton](#pressinputpropertiesbutton) +- [Transitions](#transitions) + - [GetTransitionKindList](#gettransitionkindlist) + - [GetSceneTransitionList](#getscenetransitionlist) + - [GetCurrentSceneTransition](#getcurrentscenetransition) + - [SetCurrentSceneTransition](#setcurrentscenetransition) + - [SetCurrentSceneTransitionDuration](#setcurrentscenetransitionduration) + - [SetCurrentSceneTransitionSettings](#setcurrentscenetransitionsettings) + - [TriggerStudioModeTransition](#triggerstudiomodetransition) - [Scene Items](#scene-items) - [GetSceneItemList](#getsceneitemlist) - [GetGroupItemList](#getgroupitemlist) @@ -1477,6 +1485,20 @@ The profile list has changed. - [ToggleStream](#togglestream) - [StartStream](#startstream) - [StopStream](#stopstream) +- [Record](#record) + - [GetRecordStatus](#getrecordstatus) + - [ToggleRecord](#togglerecord) + - [StartRecord](#startrecord) + - [StopRecord](#stoprecord) + - [ToggleRecordPause](#togglerecordpause) + - [PauseRecord](#pauserecord) + - [ResumeRecord](#resumerecord) + - [GetRecordDirectory](#getrecorddirectory) +- [Media Inputs](#media-inputs) + - [GetMediaInputStatus](#getmediainputstatus) + - [SetMediaInputCursor](#setmediainputcursor) + - [OffsetMediaInputCursor](#offsetmediainputcursor) + - [TriggerMediaInputAction](#triggermediainputaction) - [Ui](#ui) - [GetStudioModeEnabled](#getstudiomodeenabled) - [SetStudioModeEnabled](#setstudiomodeenabled) @@ -2625,6 +2647,131 @@ Note: Use this in cases where there is a button in the properties of an input th | propertyName | String | Name of the button property to press | None | N/A | +## Transitions + +### GetTransitionKindList + +Gets an array of all available transition kinds. + +Similar to `GetInputKindList` + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| transitionKinds | Vector<String> | Array of transition kinds | + +--- + +### GetSceneTransitionList + +Gets an array of all scene transitions in OBS. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| currentSceneTransitionName | String | Name of the current scene transition. Can be null | +| currentSceneTransitionKind | String | Kind of the current scene transition. Can be null | +| transitions | Vector<Object> | Array of transitions | + +--- + +### GetCurrentSceneTransition + +Gets information about the current scene transition. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| transitionName | String | Name of the transition | +| transitionKind | String | Kind of the transition | +| transitionFixed | Boolean | Whether the transition uses a fixed (unconfigurable) duration | +| transitionDuration | Number | Configured transition duration in milliseconds. `null` if transition is fixed | +| transitionConfigurable | Boolean | Whether the transition supports being configured | +| transitionSettings | Object | Object of settings for the transition. `null` if transition is not configurable | + +--- + +### SetCurrentSceneTransition + +Sets the current scene transition. + +Small note: While the namespace of scene transitions is generally unique, that uniqueness is not a guarantee as it is with other resources like inputs. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| transitionName | String | Name of the transition to make active | None | N/A | + +--- + +### SetCurrentSceneTransitionDuration + +Sets the duration of the current scene transition, if it is not fixed. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| transitionDuration | Number | Duration in milliseconds | >= 50, <= 20000 | N/A | + +--- + +### SetCurrentSceneTransitionSettings + +Sets the settings of the current scene transition. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| transitionSettings | Object | Settings object to apply to the transition. Can be `{}` | None | N/A | +| ?overlay | Boolean | Whether to overlay over the current settings or replace them | None | true | + +--- + +### TriggerStudioModeTransition + +Triggers the current scene transition. Same functionality as the `Transition` button in studio mode. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + ## Scene Items ### GetSceneItemList @@ -3036,6 +3183,200 @@ Stops the stream output. - Added in v5.0.0 +## Record + +### GetRecordStatus + +Gets the status of the record output. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| outputActive | Boolean | Whether the output is active | +| ouputPaused | Boolean | Whether the output is paused | +| outputTimecode | String | Current formatted timecode string for the output | +| outputDuration | Number | Current duration in milliseconds for the output | +| outputBytes | Number | Number of bytes sent by the output | + +--- + +### ToggleRecord + +Toggles the status of the record output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + +### StartRecord + +Starts the record output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + +### StopRecord + +Stops the record output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + +### ToggleRecordPause + +Toggles pause on the record output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + +### PauseRecord + +Pauses the record output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + +### ResumeRecord + +Resumes the record output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + +### GetRecordDirectory + +Gets the current directory that the record output is set to. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| recordDirectory | String | Output directory | + + +## Media Inputs + +### GetMediaInputStatus + +Gets the status of a media input. + +Media States: +- `OBS_MEDIA_STATE_NONE` +- `OBS_MEDIA_STATE_PLAYING` +- `OBS_MEDIA_STATE_OPENING` +- `OBS_MEDIA_STATE_BUFFERING` +- `OBS_MEDIA_STATE_PAUSED` +- `OBS_MEDIA_STATE_STOPPED` +- `OBS_MEDIA_STATE_ENDED` +- `OBS_MEDIA_STATE_ERROR` + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| inputName | String | Name of the media input | None | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| mediaState | String | State of the media input | +| mediaDuration | Number | Total duration of the playing media in milliseconds. `null` if not playing | +| mediaCursor | Number | Position of the cursor in milliseconds. `null` if not playing | + +--- + +### SetMediaInputCursor + +Sets the cursor position of a media input. + +This request does not perform bounds checking of the cursor position. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| inputName | String | Name of the media input | None | N/A | +| mediaCursor | Number | New cursor position to set | >= 0 | N/A | + +--- + +### OffsetMediaInputCursor + +Offsets the current cursor position of a media input by the specified value. + +This request does not perform bounds checking of the cursor position. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| inputName | String | Name of the media input | None | N/A | +| mediaCursorOffset | Number | Value to offset the current cursor position by | None | N/A | + +--- + +### TriggerMediaInputAction + +Triggers an action on a media input. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| inputName | String | Name of the media input | None | N/A | +| mediaAction | String | Identifier of the `ObsMediaInputAction` enum | None | N/A | + + ## Ui ### GetStudioModeEnabled From 1339202c02bee0d3c8dac5a7875433466c6c5bcc Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 28 Dec 2021 22:37:00 -0800 Subject: [PATCH 048/128] docs: Fix Array fields in transition requests --- src/requesthandler/RequestHandler_Transitions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/requesthandler/RequestHandler_Transitions.cpp b/src/requesthandler/RequestHandler_Transitions.cpp index 108358ee..aaa793e7 100644 --- a/src/requesthandler/RequestHandler_Transitions.cpp +++ b/src/requesthandler/RequestHandler_Transitions.cpp @@ -24,7 +24,7 @@ with this program. If not, see * * Similar to `GetInputKindList` * - * @responseField transitionKinds | Vector | Array of transition kinds + * @responseField transitionKinds | Array | Array of transition kinds * * @requestType GetTransitionKindList * @complexity 2 @@ -45,7 +45,7 @@ RequestResult RequestHandler::GetTransitionKindList(const Request&) * * @responseField currentSceneTransitionName | String | Name of the current scene transition. Can be null * @responseField currentSceneTransitionKind | String | Kind of the current scene transition. Can be null - * @responseField transitions | Vector | Array of transitions + * @responseField transitions | Array | Array of transitions * * @requestType GetSceneTransitionList * @complexity 3 From e1cb858d2dfeb39de24da5d9a2d885f16fd877c8 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 28 Dec 2021 22:49:58 -0800 Subject: [PATCH 049/128] Utils: Split monitor type util --- src/utils/Obs.h | 1 + src/utils/Obs_StringHelper.cpp | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/utils/Obs.h b/src/utils/Obs.h index 7a881e1a..76bcebd8 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -158,6 +158,7 @@ namespace Utils { std::string GetCurrentProfilePath(); std::string GetCurrentRecordOutputPath(); std::string GetSourceType(obs_source_t *source); + std::string GetInputMonitorType(enum obs_monitoring_type monitorType); std::string GetInputMonitorType(obs_source_t *input); std::string GetMediaInputState(obs_source_t *input); std::string GetLastReplayBufferFilePath(); diff --git a/src/utils/Obs_StringHelper.cpp b/src/utils/Obs_StringHelper.cpp index f437b5b5..471651ca 100644 --- a/src/utils/Obs_StringHelper.cpp +++ b/src/utils/Obs_StringHelper.cpp @@ -85,10 +85,8 @@ std::string Utils::Obs::StringHelper::GetSourceType(obs_source_t *source) } } -std::string Utils::Obs::StringHelper::GetInputMonitorType(obs_source_t *input) +std::string Utils::Obs::StringHelper::GetInputMonitorType(enum obs_monitoring_type monitorType) { - obs_monitoring_type monitorType = obs_source_get_monitoring_type(input); - switch (monitorType) { default: CASE(OBS_MONITORING_TYPE_NONE) @@ -97,6 +95,13 @@ std::string Utils::Obs::StringHelper::GetInputMonitorType(obs_source_t *input) } } +std::string Utils::Obs::StringHelper::GetInputMonitorType(obs_source_t *input) +{ + obs_monitoring_type monitorType = obs_source_get_monitoring_type(input); + + return GetInputMonitorType(monitorType); +} + std::string Utils::Obs::StringHelper::GetMediaInputState(obs_source_t *input) { obs_media_state mediaState = obs_source_media_get_state(input); From bb2c125601b9bc24b83821a76711003f06c58375 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 28 Dec 2021 22:50:11 -0800 Subject: [PATCH 050/128] Utils: Use atomic in VolumeMeter manager --- src/utils/Obs_VolumeMeter.cpp | 2 -- src/utils/Obs_VolumeMeter.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/utils/Obs_VolumeMeter.cpp b/src/utils/Obs_VolumeMeter.cpp index db683db4..92fbe3cf 100644 --- a/src/utils/Obs_VolumeMeter.cpp +++ b/src/utils/Obs_VolumeMeter.cpp @@ -278,9 +278,7 @@ Utils::Obs::VolumeMeter::Handler::~Handler() signal_handler_disconnect(sh, "source_deactivate", Handler::InputDeactivateCallback, this); if (_running) { - _mutex.lock(); _running = false; - _mutex.unlock(); _cond.notify_all(); } diff --git a/src/utils/Obs_VolumeMeter.h b/src/utils/Obs_VolumeMeter.h index 75e46faf..9058fb2d 100644 --- a/src/utils/Obs_VolumeMeter.h +++ b/src/utils/Obs_VolumeMeter.h @@ -87,7 +87,7 @@ namespace Utils { std::mutex _mutex; std::condition_variable _cond; - bool _running; + std::atomic _running; std::thread _updateThread; void UpdateThread(); From e640ae12183c98e3e10a075a7faded4c7345079a Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 28 Dec 2021 23:45:11 -0800 Subject: [PATCH 051/128] docs: Finish documenting events --- src/eventhandler/EventHandler.cpp | 12 -- src/eventhandler/EventHandler.h | 5 - src/eventhandler/EventHandler_Inputs.cpp | 193 ++++++++++++++++-- src/eventhandler/EventHandler_MediaInputs.cpp | 40 ++++ src/eventhandler/EventHandler_Outputs.cpp | 69 +++++++ src/eventhandler/EventHandler_SceneItems.cpp | 98 ++++++++- src/eventhandler/EventHandler_Scenes.cpp | 83 ++++++++ src/eventhandler/EventHandler_Transitions.cpp | 24 --- 8 files changed, 459 insertions(+), 65 deletions(-) diff --git a/src/eventhandler/EventHandler.cpp b/src/eventhandler/EventHandler.cpp index 12b36733..d5bf3448 100644 --- a/src/eventhandler/EventHandler.cpp +++ b/src/eventhandler/EventHandler.cpp @@ -379,10 +379,6 @@ void EventHandler::SourceCreatedMultiHandler(void *param, calldata_t *data) case OBS_SOURCE_TYPE_INPUT: eventHandler->HandleInputCreated(source); break; - case OBS_SOURCE_TYPE_FILTER: - break; - case OBS_SOURCE_TYPE_TRANSITION: - break; case OBS_SOURCE_TYPE_SCENE: eventHandler->HandleSceneCreated(source); break; @@ -413,10 +409,6 @@ void EventHandler::SourceDestroyedMultiHandler(void *param, calldata_t *data) // We have to call `InputRemoved` with source_destroy because source_removed is not called when an input's last scene item is removed eventHandler->HandleInputRemoved(source); break; - case OBS_SOURCE_TYPE_FILTER: - break; - case OBS_SOURCE_TYPE_TRANSITION: - break; case OBS_SOURCE_TYPE_SCENE: break; default: @@ -438,10 +430,6 @@ void EventHandler::SourceRemovedMultiHandler(void *param, calldata_t *data) switch (obs_source_get_type(source)) { case OBS_SOURCE_TYPE_INPUT: break; - case OBS_SOURCE_TYPE_FILTER: - break; - case OBS_SOURCE_TYPE_TRANSITION: - break; case OBS_SOURCE_TYPE_SCENE: // Scenes emit the `removed` signal when they are removed from OBS, as expected eventHandler->HandleSceneRemoved(source); diff --git a/src/eventhandler/EventHandler.h b/src/eventhandler/EventHandler.h index 657da887..1c08227f 100644 --- a/src/eventhandler/EventHandler.h +++ b/src/eventhandler/EventHandler.h @@ -111,11 +111,6 @@ class EventHandler static void HandleInputAudioTracksChanged(void *param, calldata_t *data); // Direct callback static void HandleInputAudioMonitorTypeChanged(void *param, calldata_t *data); // Direct callback - // Transitions - void HandleTransitionCreated(obs_source_t *source); - void HandleTransitionRemoved(obs_source_t *source); - void HandleTransitionNameChanged(obs_source_t *source, std::string oldTransitionName, std::string transitionName); - // Outputs void HandleStreamStateChanged(ObsOutputState state); void HandleRecordStateChanged(ObsOutputState state); diff --git a/src/eventhandler/EventHandler_Inputs.cpp b/src/eventhandler/EventHandler_Inputs.cpp index c827c697..a4b0c2af 100644 --- a/src/eventhandler/EventHandler_Inputs.cpp +++ b/src/eventhandler/EventHandler_Inputs.cpp @@ -19,6 +19,23 @@ with this program. If not, see #include "EventHandler.h" +/** + * An input has been created. + * + * @dataField inputName | String | Name of the input + * @dataField inputKind | String | The kind of the input + * @dataField unversionedInputKind | String | The unversioned kind of input (aka no `_v2` stuff) + * @dataField inputSettings | Object | The settings configured to the input when it was created + * @dataField defaultInputSettings | Object | The default settings for the input + * + * @eventType InputCreated + * @eventSubscription Inputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category inputs + */ void EventHandler::HandleInputCreated(obs_source_t *source) { std::string inputKind = obs_source_get_id(source); @@ -34,6 +51,19 @@ void EventHandler::HandleInputCreated(obs_source_t *source) BroadcastEvent(EventSubscription::Inputs, "InputCreated", eventData); } +/** + * An input has been removed. + * + * @dataField inputName | String | Name of the input + * + * @eventType InputRemoved + * @eventSubscription Inputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category inputs + */ void EventHandler::HandleInputRemoved(obs_source_t *source) { json eventData; @@ -41,6 +71,20 @@ void EventHandler::HandleInputRemoved(obs_source_t *source) BroadcastEvent(EventSubscription::Inputs, "InputRemoved", eventData); } +/** + * The name of an input has changed. + * + * @dataField oldInputName | String | Old name of the input + * @dataField inputName | String | New name of the input + * + * @eventType InputNameChanged + * @eventSubscription Inputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category inputs + */ void EventHandler::HandleInputNameChanged(obs_source_t *, std::string oldInputName, std::string inputName) { json eventData; @@ -49,13 +93,22 @@ void EventHandler::HandleInputNameChanged(obs_source_t *, std::string oldInputNa BroadcastEvent(EventSubscription::Inputs, "InputNameChanged", eventData); } -void EventHandler::HandleInputVolumeMeters(std::vector inputs) -{ - json eventData; - eventData["inputs"] = inputs; - BroadcastEvent(EventSubscription::InputVolumeMeters, "InputVolumeMeters", eventData); -} - +/** + * An input's active state has changed. + * + * When an input is active, it means it's being shown by the program feed. + * + * @dataField inputName | String | Name of the input + * @dataField videoActive | Boolean | Whether the input is active + * + * @eventType InputActiveStateChanged + * @eventSubscription InputActiveStateChanged + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category inputs + */ void EventHandler::HandleInputActiveStateChanged(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -76,6 +129,22 @@ void EventHandler::HandleInputActiveStateChanged(void *param, calldata_t *data) eventHandler->BroadcastEvent(EventSubscription::InputActiveStateChanged, "InputActiveStateChanged", eventData); } +/** + * An input's show state has changed. + * + * When an input is showing, it means it's being shown by the preview or a dialog. + * + * @dataField inputName | String | Name of the input + * @dataField videoShowing | Boolean | Whether the input is showing + * + * @eventType InputShowStateChanged + * @eventSubscription InputShowStateChanged + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category inputs + */ void EventHandler::HandleInputShowStateChanged(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -96,6 +165,20 @@ void EventHandler::HandleInputShowStateChanged(void *param, calldata_t *data) eventHandler->BroadcastEvent(EventSubscription::InputShowStateChanged, "InputShowStateChanged", eventData); } +/** + * An input's mute state has changed. + * + * @dataField inputName | String | Name of the input + * @dataField inputMuted | Boolean | Whether the input is muted + * + * @eventType InputMuteStateChanged + * @eventSubscription Inputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category inputs + */ void EventHandler::HandleInputMuteStateChanged(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -113,6 +196,21 @@ void EventHandler::HandleInputMuteStateChanged(void *param, calldata_t *data) eventHandler->BroadcastEvent(EventSubscription::Inputs, "InputMuteStateChanged", eventData); } +/** + * An input's volume level has changed. + * + * @dataField inputName | String | Name of the input + * @dataField inputVolumeMul | Number | New volume level in multimap + * @dataField inputVolumeDb | Number | New volume level in dB + * + * @eventType InputVolumeChanged + * @eventSubscription Inputs + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category inputs + */ void EventHandler::HandleInputVolumeChanged(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -138,6 +236,20 @@ void EventHandler::HandleInputVolumeChanged(void *param, calldata_t *data) eventHandler->BroadcastEvent(EventSubscription::Inputs, "InputVolumeChanged", eventData); } +/** + * The sync offset of an input has changed. + * + * @dataField inputName | String | Name of the input + * @dataField inputAudioSyncOffset | Number | New sync offset in milliseconds + * + * @eventType InputAudioSyncOffsetChanged + * @eventSubscription Inputs + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category inputs + */ void EventHandler::HandleInputAudioSyncOffsetChanged(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -157,6 +269,20 @@ void EventHandler::HandleInputAudioSyncOffsetChanged(void *param, calldata_t *da eventHandler->BroadcastEvent(EventSubscription::Inputs, "InputAudioSyncOffsetChanged", eventData); } +/** + * The audio tracks of an input have changed. + * + * @dataField inputName | String | Name of the input + * @dataField inputAudioTracks | Array | Array of audio tracks along with their associated enable states + * + * @eventType InputAudioTracksChanged + * @eventSubscription Inputs + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category inputs + */ void EventHandler::HandleInputAudioTracksChanged(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -181,6 +307,25 @@ void EventHandler::HandleInputAudioTracksChanged(void *param, calldata_t *data) eventHandler->BroadcastEvent(EventSubscription::Inputs, "InputAudioTracksChanged", eventData); } +/** + * The monitor type of an input has changed. + * + * Available types are: + * - `OBS_MONITORING_TYPE_NONE` + * - `OBS_MONITORING_TYPE_MONITOR_ONLY` + * - `OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT` + * + * @dataField inputName | String | Name of the input + * @dataField monitorType | String | New monitor type of the input + * + * @eventType InputAudioMonitorTypeChanged + * @eventSubscription Inputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category inputs + */ void EventHandler::HandleInputAudioMonitorTypeChanged(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -194,22 +339,30 @@ void EventHandler::HandleInputAudioMonitorTypeChanged(void *param, calldata_t *d enum obs_monitoring_type monitorType = (obs_monitoring_type)calldata_int(data, "type"); - std::string monitorTypeString; - switch (monitorType) { - default: - case OBS_MONITORING_TYPE_NONE: - monitorTypeString = "OBS_WEBSOCKET_MONITOR_TYPE_NONE"; - break; - case OBS_MONITORING_TYPE_MONITOR_ONLY: - monitorTypeString = "OBS_WEBSOCKET_MONITOR_TYPE_MONITOR_ONLY"; - break; - case OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT: - monitorTypeString = "OBS_WEBSOCKET_MONITOR_TYPE_MONITOR_AND_OUTPUT"; - break; - } + std::string monitorTypeString = Utils::Obs::StringHelper::GetInputMonitorType(monitorType); json eventData; eventData["inputName"] = obs_source_get_name(source); eventData["monitorType"] = monitorTypeString; eventHandler->BroadcastEvent(EventSubscription::Inputs, "InputAudioMonitorTypeChanged", eventData); } + +/** + * A high-volume event providing volume levels of all active inputs every 50 milliseconds. + * + * @dataField inputs | Array | Array of active inputs with their associated volume levels + * + * @eventType InputVolumeMeters + * @eventSubscription InputVolumeMeters + * @complexity 4 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category inputs + */ +void EventHandler::HandleInputVolumeMeters(std::vector inputs) +{ + json eventData; + eventData["inputs"] = inputs; + BroadcastEvent(EventSubscription::InputVolumeMeters, "InputVolumeMeters", eventData); +} diff --git a/src/eventhandler/EventHandler_MediaInputs.cpp b/src/eventhandler/EventHandler_MediaInputs.cpp index 146a8c8c..7bd0cb54 100644 --- a/src/eventhandler/EventHandler_MediaInputs.cpp +++ b/src/eventhandler/EventHandler_MediaInputs.cpp @@ -117,6 +117,19 @@ void EventHandler::SourceMediaPreviousMultiHandler(void *param, calldata_t *data eventHandler->HandleMediaInputActionTriggered(source, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS); } +/** + * A media input has started playing. + * + * @dataField inputName | String | Name of the input + * + * @eventType MediaInputPlaybackStarted + * @eventSubscription MediaInputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category media inputs + */ void EventHandler::HandleMediaInputPlaybackStarted(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -133,6 +146,19 @@ void EventHandler::HandleMediaInputPlaybackStarted(void *param, calldata_t *data eventHandler->BroadcastEvent(EventSubscription::MediaInputs, "MediaInputPlaybackStarted", eventData); } +/** + * A media input has finished playing. + * + * @dataField inputName | String | Name of the input + * + * @eventType MediaInputPlaybackEnded + * @eventSubscription MediaInputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category media inputs + */ void EventHandler::HandleMediaInputPlaybackEnded(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -149,6 +175,20 @@ void EventHandler::HandleMediaInputPlaybackEnded(void *param, calldata_t *data) eventHandler->BroadcastEvent(EventSubscription::MediaInputs, "MediaInputPlaybackEnded", eventData); } +/** + * An action has been performed on an input. + * + * @dataField inputName | String | Name of the input + * @dataField mediaAction | String | Action performed on the input. See `ObsMediaInputAction` enum + * + * @eventType MediaInputActionTriggered + * @eventSubscription MediaInputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category media inputs + */ void EventHandler::HandleMediaInputActionTriggered(obs_source_t *source, ObsMediaInputAction action) { json eventData; diff --git a/src/eventhandler/EventHandler_Outputs.cpp b/src/eventhandler/EventHandler_Outputs.cpp index 15195bb9..bf9acfb6 100644 --- a/src/eventhandler/EventHandler_Outputs.cpp +++ b/src/eventhandler/EventHandler_Outputs.cpp @@ -34,6 +34,20 @@ static bool GetOutputStateActive(ObsOutputState state) { } } +/** + * The state of the stream output has changed. + * + * @dataField outputActive | Boolean | Whether the output is active + * @dataField outputState | String | The specific state of the output + * + * @eventType StreamStateChanged + * @eventSubscription Outputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category outputs + */ void EventHandler::HandleStreamStateChanged(ObsOutputState state) { json eventData; @@ -42,6 +56,20 @@ void EventHandler::HandleStreamStateChanged(ObsOutputState state) BroadcastEvent(EventSubscription::Outputs, "StreamStateChanged", eventData); } +/** + * The state of the record output has changed. + * + * @dataField outputActive | Boolean | Whether the output is active + * @dataField outputState | String | The specific state of the output + * + * @eventType RecordStateChanged + * @eventSubscription Outputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category outputs + */ void EventHandler::HandleRecordStateChanged(ObsOutputState state) { json eventData; @@ -50,6 +78,20 @@ void EventHandler::HandleRecordStateChanged(ObsOutputState state) BroadcastEvent(EventSubscription::Outputs, "RecordStateChanged", eventData); } +/** + * The state of the replay buffer output has changed. + * + * @dataField outputActive | Boolean | Whether the output is active + * @dataField outputState | String | The specific state of the output + * + * @eventType ReplayBufferStateChanged + * @eventSubscription Outputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category outputs + */ void EventHandler::HandleReplayBufferStateChanged(ObsOutputState state) { json eventData; @@ -58,6 +100,20 @@ void EventHandler::HandleReplayBufferStateChanged(ObsOutputState state) BroadcastEvent(EventSubscription::Outputs, "ReplayBufferStateChanged", eventData); } +/** + * The state of the virtualcam output has changed. + * + * @dataField outputActive | Boolean | Whether the output is active + * @dataField outputState | String | The specific state of the output + * + * @eventType VirtualcamStateChanged + * @eventSubscription Outputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category outputs + */ void EventHandler::HandleVirtualcamStateChanged(ObsOutputState state) { json eventData; @@ -66,6 +122,19 @@ void EventHandler::HandleVirtualcamStateChanged(ObsOutputState state) BroadcastEvent(EventSubscription::Outputs, "VirtualcamStateChanged", eventData); } +/** + * The replay buffer has been saved. + * + * @dataField savedReplayPath | String | Path of the saved replay file + * + * @eventType ReplayBufferSaved + * @eventSubscription Outputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category outputs + */ void EventHandler::HandleReplayBufferSaved() { json eventData; diff --git a/src/eventhandler/EventHandler_SceneItems.cpp b/src/eventhandler/EventHandler_SceneItems.cpp index ca0ed9ab..60b78e04 100644 --- a/src/eventhandler/EventHandler_SceneItems.cpp +++ b/src/eventhandler/EventHandler_SceneItems.cpp @@ -19,6 +19,22 @@ with this program. If not, see #include "EventHandler.h" +/** + * A scene item has been created. + * + * @dataField sceneName | String | Name of the scene the item was added to + * @dataField sourceName | String | Name of the underlying source (input/scene) + * @dataField sceneItemId | Number | Numeric ID of the scene item + * @dataField sceneItemIndex | Number | Index position of the item + * + * @eventType SceneItemCreated + * @eventSubscription SceneItems + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category scene items + */ void EventHandler::HandleSceneItemCreated(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -33,13 +49,29 @@ void EventHandler::HandleSceneItemCreated(void *param, calldata_t *data) json eventData; eventData["sceneName"] = obs_source_get_name(obs_scene_get_source(scene)); - eventData["inputName"] = obs_source_get_name(obs_sceneitem_get_source(sceneItem)); + eventData["sourceName"] = obs_source_get_name(obs_sceneitem_get_source(sceneItem)); eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem); eventData["sceneItemIndex"] = obs_sceneitem_get_order_position(sceneItem); eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemCreated", eventData); } -// Will not be emitted if an item is removed due to the parent scene being removed. +/** + * A scene item has been removed. + * + * This event is not emitted when the scene the item is in is removed. + * + * @dataField sceneName | String | Name of the scene the item was removed from + * @dataField sourceName | String | Name of the underlying source (input/scene) + * @dataField sceneItemId | Number | Numeric ID of the scene item + * + * @eventType SceneItemRemoved + * @eventSubscription SceneItems + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category scene items + */ void EventHandler::HandleSceneItemRemoved(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -54,12 +86,25 @@ void EventHandler::HandleSceneItemRemoved(void *param, calldata_t *data) json eventData; eventData["sceneName"] = obs_source_get_name(obs_scene_get_source(scene)); - eventData["inputName"] = obs_source_get_name(obs_sceneitem_get_source(sceneItem)); + eventData["sourceName"] = obs_source_get_name(obs_sceneitem_get_source(sceneItem)); eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem); - eventData["sceneItemIndex"] = obs_sceneitem_get_order_position(sceneItem); eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemRemoved", eventData); } +/** + * A scene's item list has been reindexed. + * + * @dataField sceneName | String | Name of the scene + * @dataField sceneItems | Array | Array of scene item objects + * + * @eventType SceneItemListReindexed + * @eventSubscription SceneItems + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category scene items + */ void EventHandler::HandleSceneItemListReindexed(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -74,6 +119,21 @@ void EventHandler::HandleSceneItemListReindexed(void *param, calldata_t *data) eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemListReindexed", eventData); } +/** + * A scene item's enable state has changed. + * + * @dataField sceneName | String | Name of the scene the item is in + * @dataField sceneItemId | Number | Numeric ID of the scene item + * @dataField sceneItemEnabled | Boolean | Whether the scene item is enabled (visible) + * + * @eventType SceneItemEnableStateChanged + * @eventSubscription SceneItems + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category scene items + */ void EventHandler::HandleSceneItemEnableStateChanged(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -95,6 +155,21 @@ void EventHandler::HandleSceneItemEnableStateChanged(void *param, calldata_t *da eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemEnableStateChanged", eventData); } +/** + * A scene item's lock state has changed. + * + * @dataField sceneName | String | Name of the scene the item is in + * @dataField sceneItemId | Number | Numeric ID of the scene item + * @dataField sceneItemEnabled | Boolean | Whether the scene item is locked + * + * @eventType SceneItemLockStateChanged + * @eventSubscription SceneItems + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category scene items + */ void EventHandler::HandleSceneItemLockStateChanged(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); @@ -116,6 +191,21 @@ void EventHandler::HandleSceneItemLockStateChanged(void *param, calldata_t *data eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemLockStateChanged", eventData); } +/** + * The transform/crop of a scene item has changed. + * + * @dataField sceneName | String | The name of the scene the item is in + * @dataField sceneItemId | Number | Numeric ID of the scene item + * @dataField sceneItemTransform | Object | New transform/crop info of the scene item + * + * @eventType SceneItemTransformChanged + * @eventSubscription SceneItemTransformChanged + * @complexity 4 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category scene items + */ void EventHandler::HandleSceneItemTransformChanged(void *param, calldata_t *data) { auto eventHandler = reinterpret_cast(param); diff --git a/src/eventhandler/EventHandler_Scenes.cpp b/src/eventhandler/EventHandler_Scenes.cpp index d8aee383..8ab1f812 100644 --- a/src/eventhandler/EventHandler_Scenes.cpp +++ b/src/eventhandler/EventHandler_Scenes.cpp @@ -19,6 +19,20 @@ with this program. If not, see #include "EventHandler.h" +/** + * A new scene has been created. + * + * @dataField sceneName | String | Name of the new scene + * @dataField isGroup | Boolean | Whether the new scene is a group + * + * @eventType SceneCreated + * @eventSubscription Scenes + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category scenes + */ void EventHandler::HandleSceneCreated(obs_source_t *source) { json eventData; @@ -27,6 +41,20 @@ void EventHandler::HandleSceneCreated(obs_source_t *source) BroadcastEvent(EventSubscription::Scenes, "SceneCreated", eventData); } +/** + * A scene has been removed. + * + * @dataField sceneName | String | Name of the removed scene + * @dataField isGroup | Boolean | Whether the scene was a group + * + * @eventType SceneRemoved + * @eventSubscription Scenes + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category scenes + */ void EventHandler::HandleSceneRemoved(obs_source_t *source) { json eventData; @@ -35,6 +63,20 @@ void EventHandler::HandleSceneRemoved(obs_source_t *source) BroadcastEvent(EventSubscription::Scenes, "SceneRemoved", eventData); } +/** + * The name of a scene has changed. + * + * @dataField oldSceneName | String | Old name of the scene + * @dataField sceneName | String | New name of the scene + * + * @eventType SceneNameChanged + * @eventSubscription Scenes + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category scenes + */ void EventHandler::HandleSceneNameChanged(obs_source_t *, std::string oldSceneName, std::string sceneName) { json eventData; @@ -43,6 +85,19 @@ void EventHandler::HandleSceneNameChanged(obs_source_t *, std::string oldSceneNa BroadcastEvent(EventSubscription::Scenes, "SceneNameChanged", eventData); } +/** + * The current program scene has changed. + * + * @dataField sceneName | String | Name of the scene that was switched to + * + * @eventType CurrentSceneChanged + * @eventSubscription Scenes + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category scenes + */ void EventHandler::HandleCurrentSceneChanged() { OBSSourceAutoRelease currentScene = obs_frontend_get_current_scene(); @@ -52,6 +107,19 @@ void EventHandler::HandleCurrentSceneChanged() BroadcastEvent(EventSubscription::Scenes, "CurrentSceneChanged", eventData); } +/** + * The current preview scene has changed. + * + * @dataField sceneName | String | Name of the scene that was switched to + * + * @eventType CurrentPreviewSceneChanged + * @eventSubscription Scenes + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category scenes + */ void EventHandler::HandleCurrentPreviewSceneChanged() { OBSSourceAutoRelease currentPreviewScene = obs_frontend_get_current_preview_scene(); @@ -65,6 +133,21 @@ void EventHandler::HandleCurrentPreviewSceneChanged() BroadcastEvent(EventSubscription::Scenes, "CurrentPreviewSceneChanged", eventData); } +/** + * The list of scenes has changed. + * + * TODO: Make OBS fire this event when scenes are reordered. + * + * @dataField scenes | Array | Updated array of scenes + * + * @eventType SceneListChanged + * @eventSubscription Scenes + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category scenes + */ void EventHandler::HandleSceneListChanged() { json eventData; diff --git a/src/eventhandler/EventHandler_Transitions.cpp b/src/eventhandler/EventHandler_Transitions.cpp index 2ae8d85c..6e0f4c11 100644 --- a/src/eventhandler/EventHandler_Transitions.cpp +++ b/src/eventhandler/EventHandler_Transitions.cpp @@ -18,27 +18,3 @@ with this program. If not, see */ #include "EventHandler.h" - -void EventHandler::HandleTransitionCreated(obs_source_t *source) -{ - json eventData; - eventData["transitionName"] = obs_source_get_name(source); - eventData["transitionKind"] = obs_source_get_id(source); - eventData["transitionFixed"] = obs_transition_fixed(source); - BroadcastEvent(EventSubscription::Transitions, "TransitionCreated", eventData); -} - -void EventHandler::HandleTransitionRemoved(obs_source_t *source) -{ - json eventData; - eventData["transitionName"] = obs_source_get_name(source); - BroadcastEvent(EventSubscription::Transitions, "TransitionRemoved", eventData); -} - -void EventHandler::HandleTransitionNameChanged(obs_source_t *, std::string oldTransitionName, std::string transitionName) -{ - json eventData; - eventData["oldTransitionName"] = oldTransitionName; - eventData["transitionName"] = transitionName; - BroadcastEvent(EventSubscription::Transitions, "TransitionNameChanged", eventData); -} From af217c05f1bcedd54145d98308f9cd8f689e68a4 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 28 Dec 2021 23:53:58 -0800 Subject: [PATCH 052/128] EventHandler: [BREAKING] Rename CurrentSceneChanged to CurrentProgramSceneChanged Now matches the requests --- src/eventhandler/EventHandler.cpp | 2 +- src/eventhandler/EventHandler.h | 2 +- src/eventhandler/EventHandler_Scenes.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/eventhandler/EventHandler.cpp b/src/eventhandler/EventHandler.cpp index d5bf3448..5979e5b9 100644 --- a/src/eventhandler/EventHandler.cpp +++ b/src/eventhandler/EventHandler.cpp @@ -285,7 +285,7 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_ // Scenes case OBS_FRONTEND_EVENT_SCENE_CHANGED: - eventHandler->HandleCurrentSceneChanged(); + eventHandler->HandleCurrentProgramSceneChanged(); break; case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED: eventHandler->HandleCurrentPreviewSceneChanged(); diff --git a/src/eventhandler/EventHandler.h b/src/eventhandler/EventHandler.h index 1c08227f..98fec117 100644 --- a/src/eventhandler/EventHandler.h +++ b/src/eventhandler/EventHandler.h @@ -94,7 +94,7 @@ class EventHandler void HandleSceneCreated(obs_source_t *source); void HandleSceneRemoved(obs_source_t *source); void HandleSceneNameChanged(obs_source_t *source, std::string oldSceneName, std::string sceneName); - void HandleCurrentSceneChanged(); + void HandleCurrentProgramSceneChanged(); void HandleCurrentPreviewSceneChanged(); void HandleSceneListChanged(); diff --git a/src/eventhandler/EventHandler_Scenes.cpp b/src/eventhandler/EventHandler_Scenes.cpp index 8ab1f812..aca61e5a 100644 --- a/src/eventhandler/EventHandler_Scenes.cpp +++ b/src/eventhandler/EventHandler_Scenes.cpp @@ -90,7 +90,7 @@ void EventHandler::HandleSceneNameChanged(obs_source_t *, std::string oldSceneNa * * @dataField sceneName | String | Name of the scene that was switched to * - * @eventType CurrentSceneChanged + * @eventType CurrentProgramSceneChanged * @eventSubscription Scenes * @complexity 1 * @rpcVersion -1 @@ -98,13 +98,13 @@ void EventHandler::HandleSceneNameChanged(obs_source_t *, std::string oldSceneNa * @api events * @category scenes */ -void EventHandler::HandleCurrentSceneChanged() +void EventHandler::HandleCurrentProgramSceneChanged() { OBSSourceAutoRelease currentScene = obs_frontend_get_current_scene(); json eventData; eventData["sceneName"] = obs_source_get_name(currentScene); - BroadcastEvent(EventSubscription::Scenes, "CurrentSceneChanged", eventData); + BroadcastEvent(EventSubscription::Scenes, "CurrentProgramSceneChanged", eventData); } /** From 5c16a11ba8c835f2273f725a8ce8d6ee14e6ccf3 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Wed, 29 Dec 2021 07:54:48 +0000 Subject: [PATCH 053/128] docs(ci): Update generated docs - af217c0 [skip ci] --- docs/generated/protocol.json | 696 ++++++++++++++++++++++++++++++++++- docs/generated/protocol.md | 616 ++++++++++++++++++++++++++++++- 2 files changed, 1304 insertions(+), 8 deletions(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index f2fdb0b8..7a04a6de 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -3120,7 +3120,7 @@ "responseFields": [ { "valueName": "transitionKinds", - "valueType": "Vector", + "valueType": "Array", "valueDescription": "Array of transition kinds" } ] @@ -3147,7 +3147,7 @@ }, { "valueName": "transitions", - "valueType": "Vector", + "valueType": "Array", "valueDescription": "Array of transitions" } ] @@ -3442,6 +3442,698 @@ } ] }, + { + "description": "An input has been created.", + "eventType": "InputCreated", + "eventSubscription": "Inputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "dataFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input" + }, + { + "valueName": "inputKind", + "valueType": "String", + "valueDescription": "The kind of the input" + }, + { + "valueName": "unversionedInputKind", + "valueType": "String", + "valueDescription": "The unversioned kind of input (aka no `_v2` stuff)" + }, + { + "valueName": "inputSettings", + "valueType": "Object", + "valueDescription": "The settings configured to the input when it was created" + }, + { + "valueName": "defaultInputSettings", + "valueType": "Object", + "valueDescription": "The default settings for the input" + } + ] + }, + { + "description": "An input has been removed.", + "eventType": "InputRemoved", + "eventSubscription": "Inputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "dataFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input" + } + ] + }, + { + "description": "The name of an input has changed.", + "eventType": "InputNameChanged", + "eventSubscription": "Inputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "dataFields": [ + { + "valueName": "oldInputName", + "valueType": "String", + "valueDescription": "Old name of the input" + }, + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "New name of the input" + } + ] + }, + { + "description": "An input's active state has changed.\n\nWhen an input is active, it means it's being shown by the program feed.", + "eventType": "InputActiveStateChanged", + "eventSubscription": "InputActiveStateChanged", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "dataFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input" + }, + { + "valueName": "videoActive", + "valueType": "Boolean", + "valueDescription": "Whether the input is active" + } + ] + }, + { + "description": "An input's show state has changed.\n\nWhen an input is showing, it means it's being shown by the preview or a dialog.", + "eventType": "InputShowStateChanged", + "eventSubscription": "InputShowStateChanged", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "dataFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input" + }, + { + "valueName": "videoShowing", + "valueType": "Boolean", + "valueDescription": "Whether the input is showing" + } + ] + }, + { + "description": "An input's mute state has changed.", + "eventType": "InputMuteStateChanged", + "eventSubscription": "Inputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "dataFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input" + }, + { + "valueName": "inputMuted", + "valueType": "Boolean", + "valueDescription": "Whether the input is muted" + } + ] + }, + { + "description": "An input's volume level has changed.", + "eventType": "InputVolumeChanged", + "eventSubscription": "Inputs", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "dataFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input" + }, + { + "valueName": "inputVolumeMul", + "valueType": "Number", + "valueDescription": "New volume level in multimap" + }, + { + "valueName": "inputVolumeDb", + "valueType": "Number", + "valueDescription": "New volume level in dB" + } + ] + }, + { + "description": "The sync offset of an input has changed.", + "eventType": "InputAudioSyncOffsetChanged", + "eventSubscription": "Inputs", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "dataFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input" + }, + { + "valueName": "inputAudioSyncOffset", + "valueType": "Number", + "valueDescription": "New sync offset in milliseconds" + } + ] + }, + { + "description": "The audio tracks of an input have changed.", + "eventType": "InputAudioTracksChanged", + "eventSubscription": "Inputs", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "dataFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input" + }, + { + "valueName": "inputAudioTracks", + "valueType": "Array", + "valueDescription": "Array of audio tracks along with their associated enable states" + } + ] + }, + { + "description": "The monitor type of an input has changed.\n\nAvailable types are:\n- `OBS_MONITORING_TYPE_NONE`\n- `OBS_MONITORING_TYPE_MONITOR_ONLY`\n- `OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT`", + "eventType": "InputAudioMonitorTypeChanged", + "eventSubscription": "Inputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "dataFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input" + }, + { + "valueName": "monitorType", + "valueType": "String", + "valueDescription": "New monitor type of the input" + } + ] + }, + { + "description": "A high-volume event providing volume levels of all active inputs every 50 milliseconds.", + "eventType": "InputVolumeMeters", + "eventSubscription": "InputVolumeMeters", + "complexity": 4, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "dataFields": [ + { + "valueName": "inputs", + "valueType": "Array", + "valueDescription": "Array of active inputs with their associated volume levels" + } + ] + }, + { + "description": "A media input has started playing.", + "eventType": "MediaInputPlaybackStarted", + "eventSubscription": "MediaInputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "media inputs", + "dataFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input" + } + ] + }, + { + "description": "A media input has finished playing.", + "eventType": "MediaInputPlaybackEnded", + "eventSubscription": "MediaInputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "media inputs", + "dataFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input" + } + ] + }, + { + "description": "An action has been performed on an input.", + "eventType": "MediaInputActionTriggered", + "eventSubscription": "MediaInputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "media inputs", + "dataFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input" + }, + { + "valueName": "mediaAction", + "valueType": "String", + "valueDescription": "Action performed on the input. See `ObsMediaInputAction` enum" + } + ] + }, + { + "description": "The state of the stream output has changed.", + "eventType": "StreamStateChanged", + "eventSubscription": "Outputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "dataFields": [ + { + "valueName": "outputActive", + "valueType": "Boolean", + "valueDescription": "Whether the output is active" + }, + { + "valueName": "outputState", + "valueType": "String", + "valueDescription": "The specific state of the output" + } + ] + }, + { + "description": "The state of the record output has changed.", + "eventType": "RecordStateChanged", + "eventSubscription": "Outputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "dataFields": [ + { + "valueName": "outputActive", + "valueType": "Boolean", + "valueDescription": "Whether the output is active" + }, + { + "valueName": "outputState", + "valueType": "String", + "valueDescription": "The specific state of the output" + } + ] + }, + { + "description": "The state of the replay buffer output has changed.", + "eventType": "ReplayBufferStateChanged", + "eventSubscription": "Outputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "dataFields": [ + { + "valueName": "outputActive", + "valueType": "Boolean", + "valueDescription": "Whether the output is active" + }, + { + "valueName": "outputState", + "valueType": "String", + "valueDescription": "The specific state of the output" + } + ] + }, + { + "description": "The state of the virtualcam output has changed.", + "eventType": "VirtualcamStateChanged", + "eventSubscription": "Outputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "dataFields": [ + { + "valueName": "outputActive", + "valueType": "Boolean", + "valueDescription": "Whether the output is active" + }, + { + "valueName": "outputState", + "valueType": "String", + "valueDescription": "The specific state of the output" + } + ] + }, + { + "description": "The replay buffer has been saved.", + "eventType": "ReplayBufferSaved", + "eventSubscription": "Outputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "dataFields": [ + { + "valueName": "savedReplayPath", + "valueType": "String", + "valueDescription": "Path of the saved replay file" + } + ] + }, + { + "description": "A scene item has been created.", + "eventType": "SceneItemCreated", + "eventSubscription": "SceneItems", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "dataFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item was added to" + }, + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the underlying source (input/scene)" + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item" + }, + { + "valueName": "sceneItemIndex", + "valueType": "Number", + "valueDescription": "Index position of the item" + } + ] + }, + { + "description": "A scene item has been removed.\n\nThis event is not emitted when the scene the item is in is removed.", + "eventType": "SceneItemRemoved", + "eventSubscription": "SceneItems", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "dataFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item was removed from" + }, + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the underlying source (input/scene)" + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item" + } + ] + }, + { + "description": "A scene's item list has been reindexed.", + "eventType": "SceneItemListReindexed", + "eventSubscription": "SceneItems", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "dataFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene" + }, + { + "valueName": "sceneItems", + "valueType": "Array", + "valueDescription": "Array of scene item objects" + } + ] + }, + { + "description": "A scene item's enable state has changed.", + "eventType": "SceneItemEnableStateChanged", + "eventSubscription": "SceneItems", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "dataFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in" + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item" + }, + { + "valueName": "sceneItemEnabled", + "valueType": "Boolean", + "valueDescription": "Whether the scene item is enabled (visible)" + } + ] + }, + { + "description": "A scene item's lock state has changed.", + "eventType": "SceneItemLockStateChanged", + "eventSubscription": "SceneItems", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "dataFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in" + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item" + }, + { + "valueName": "sceneItemEnabled", + "valueType": "Boolean", + "valueDescription": "Whether the scene item is locked" + } + ] + }, + { + "description": "The transform/crop of a scene item has changed.", + "eventType": "SceneItemTransformChanged", + "eventSubscription": "SceneItemTransformChanged", + "complexity": 4, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "dataFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "The name of the scene the item is in" + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item" + }, + { + "valueName": "sceneItemTransform", + "valueType": "Object", + "valueDescription": "New transform/crop info of the scene item" + } + ] + }, + { + "description": "A new scene has been created.", + "eventType": "SceneCreated", + "eventSubscription": "Scenes", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scenes", + "dataFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the new scene" + }, + { + "valueName": "isGroup", + "valueType": "Boolean", + "valueDescription": "Whether the new scene is a group" + } + ] + }, + { + "description": "A scene has been removed.", + "eventType": "SceneRemoved", + "eventSubscription": "Scenes", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scenes", + "dataFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the removed scene" + }, + { + "valueName": "isGroup", + "valueType": "Boolean", + "valueDescription": "Whether the scene was a group" + } + ] + }, + { + "description": "The name of a scene has changed.", + "eventType": "SceneNameChanged", + "eventSubscription": "Scenes", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scenes", + "dataFields": [ + { + "valueName": "oldSceneName", + "valueType": "String", + "valueDescription": "Old name of the scene" + }, + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "New name of the scene" + } + ] + }, + { + "description": "The current program scene has changed.", + "eventType": "CurrentProgramSceneChanged", + "eventSubscription": "Scenes", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scenes", + "dataFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene that was switched to" + } + ] + }, + { + "description": "The current preview scene has changed.", + "eventType": "CurrentPreviewSceneChanged", + "eventSubscription": "Scenes", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scenes", + "dataFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene that was switched to" + } + ] + }, + { + "description": "The list of scenes has changed.\n\nTODO: Make OBS fire this event when scenes are reordered.", + "eventType": "SceneListChanged", + "eventSubscription": "Scenes", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scenes", + "dataFields": [ + { + "valueName": "scenes", + "valueType": "Array", + "valueDescription": "Updated array of scenes" + } + ] + }, { "description": "An event has been emitted from a vendor.\n\nA vendor is a unique name registered by a third-party plugin or script, which allows for custom requests and events to be added to obs-websocket.\nIf a plugin or script implements vendor requests or events, documentation is expected to be provided with them.", "eventType": "VendorEvent", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 5a38cf50..58e9632e 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -1238,6 +1238,42 @@ Subscription value to receive the `SceneItemTransformChanged` high-volume event. - [CurrentProfileChanging](#currentprofilechanging) - [CurrentProfileChanged](#currentprofilechanged) - [ProfileListChanged](#profilelistchanged) +- [Scenes](#scenes) + - [SceneCreated](#scenecreated) + - [SceneRemoved](#sceneremoved) + - [SceneNameChanged](#scenenamechanged) + - [CurrentProgramSceneChanged](#currentprogramscenechanged) + - [CurrentPreviewSceneChanged](#currentpreviewscenechanged) + - [SceneListChanged](#scenelistchanged) +- [Inputs](#inputs) + - [InputCreated](#inputcreated) + - [InputRemoved](#inputremoved) + - [InputNameChanged](#inputnamechanged) + - [InputActiveStateChanged](#inputactivestatechanged) + - [InputShowStateChanged](#inputshowstatechanged) + - [InputMuteStateChanged](#inputmutestatechanged) + - [InputVolumeChanged](#inputvolumechanged) + - [InputAudioSyncOffsetChanged](#inputaudiosyncoffsetchanged) + - [InputAudioTracksChanged](#inputaudiotrackschanged) + - [InputAudioMonitorTypeChanged](#inputaudiomonitortypechanged) + - [InputVolumeMeters](#inputvolumemeters) +- [Scene Items](#scene-items) + - [SceneItemCreated](#sceneitemcreated) + - [SceneItemRemoved](#sceneitemremoved) + - [SceneItemListReindexed](#sceneitemlistreindexed) + - [SceneItemEnableStateChanged](#sceneitemenablestatechanged) + - [SceneItemLockStateChanged](#sceneitemlockstatechanged) + - [SceneItemTransformChanged](#sceneitemtransformchanged) +- [Outputs](#outputs) + - [StreamStateChanged](#streamstatechanged) + - [RecordStateChanged](#recordstatechanged) + - [ReplayBufferStateChanged](#replaybufferstatechanged) + - [VirtualcamStateChanged](#virtualcamstatechanged) + - [ReplayBufferSaved](#replaybuffersaved) +- [Media Inputs](#media-inputs) + - [MediaInputPlaybackStarted](#mediainputplaybackstarted) + - [MediaInputPlaybackEnded](#mediainputplaybackended) + - [MediaInputActionTriggered](#mediainputactiontriggered) ## General @@ -1394,6 +1430,574 @@ The profile list has changed. | Name | Type | Description | | ---- | :---: | ----------- | | profiles | Array<String> | Updated list of profiles | +## Scenes + +### SceneCreated + +A new scene has been created. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneName | String | Name of the new scene | +| isGroup | Boolean | Whether the new scene is a group | + +--- + +### SceneRemoved + +A scene has been removed. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneName | String | Name of the removed scene | +| isGroup | Boolean | Whether the scene was a group | + +--- + +### SceneNameChanged + +The name of a scene has changed. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| oldSceneName | String | Old name of the scene | +| sceneName | String | New name of the scene | + +--- + +### CurrentProgramSceneChanged + +The current program scene has changed. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneName | String | Name of the scene that was switched to | + +--- + +### CurrentPreviewSceneChanged + +The current preview scene has changed. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneName | String | Name of the scene that was switched to | + +--- + +### SceneListChanged + +The list of scenes has changed. + +TODO: Make OBS fire this event when scenes are reordered. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| scenes | Array<Object> | Updated array of scenes | +## Inputs + +### InputCreated + +An input has been created. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputName | String | Name of the input | +| inputKind | String | The kind of the input | +| unversionedInputKind | String | The unversioned kind of input (aka no `_v2` stuff) | +| inputSettings | Object | The settings configured to the input when it was created | +| defaultInputSettings | Object | The default settings for the input | + +--- + +### InputRemoved + +An input has been removed. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputName | String | Name of the input | + +--- + +### InputNameChanged + +The name of an input has changed. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| oldInputName | String | Old name of the input | +| inputName | String | New name of the input | + +--- + +### InputActiveStateChanged + +An input's active state has changed. + +When an input is active, it means it's being shown by the program feed. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputName | String | Name of the input | +| videoActive | Boolean | Whether the input is active | + +--- + +### InputShowStateChanged + +An input's show state has changed. + +When an input is showing, it means it's being shown by the preview or a dialog. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputName | String | Name of the input | +| videoShowing | Boolean | Whether the input is showing | + +--- + +### InputMuteStateChanged + +An input's mute state has changed. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputName | String | Name of the input | +| inputMuted | Boolean | Whether the input is muted | + +--- + +### InputVolumeChanged + +An input's volume level has changed. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputName | String | Name of the input | +| inputVolumeMul | Number | New volume level in multimap | +| inputVolumeDb | Number | New volume level in dB | + +--- + +### InputAudioSyncOffsetChanged + +The sync offset of an input has changed. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputName | String | Name of the input | +| inputAudioSyncOffset | Number | New sync offset in milliseconds | + +--- + +### InputAudioTracksChanged + +The audio tracks of an input have changed. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputName | String | Name of the input | +| inputAudioTracks | Array<Boolean> | Array of audio tracks along with their associated enable states | + +--- + +### InputAudioMonitorTypeChanged + +The monitor type of an input has changed. + +Available types are: +- `OBS_MONITORING_TYPE_NONE` +- `OBS_MONITORING_TYPE_MONITOR_ONLY` +- `OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT` + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputName | String | Name of the input | +| monitorType | String | New monitor type of the input | + +--- + +### InputVolumeMeters + +A high-volume event providing volume levels of all active inputs every 50 milliseconds. + +- Complexity Rating: `4/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputs | Array<Object> | Array of active inputs with their associated volume levels | +## Scene Items + +### SceneItemCreated + +A scene item has been created. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneName | String | Name of the scene the item was added to | +| sourceName | String | Name of the underlying source (input/scene) | +| sceneItemId | Number | Numeric ID of the scene item | +| sceneItemIndex | Number | Index position of the item | + +--- + +### SceneItemRemoved + +A scene item has been removed. + +This event is not emitted when the scene the item is in is removed. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneName | String | Name of the scene the item was removed from | +| sourceName | String | Name of the underlying source (input/scene) | +| sceneItemId | Number | Numeric ID of the scene item | + +--- + +### SceneItemListReindexed + +A scene's item list has been reindexed. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneName | String | Name of the scene | +| sceneItems | Array<Object> | Array of scene item objects | + +--- + +### SceneItemEnableStateChanged + +A scene item's enable state has changed. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneName | String | Name of the scene the item is in | +| sceneItemId | Number | Numeric ID of the scene item | +| sceneItemEnabled | Boolean | Whether the scene item is enabled (visible) | + +--- + +### SceneItemLockStateChanged + +A scene item's lock state has changed. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneName | String | Name of the scene the item is in | +| sceneItemId | Number | Numeric ID of the scene item | +| sceneItemEnabled | Boolean | Whether the scene item is locked | + +--- + +### SceneItemTransformChanged + +The transform/crop of a scene item has changed. + +- Complexity Rating: `4/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneName | String | The name of the scene the item is in | +| sceneItemId | Number | Numeric ID of the scene item | +| sceneItemTransform | Object | New transform/crop info of the scene item | +## Outputs + +### StreamStateChanged + +The state of the stream output has changed. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| outputActive | Boolean | Whether the output is active | +| outputState | String | The specific state of the output | + +--- + +### RecordStateChanged + +The state of the record output has changed. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| outputActive | Boolean | Whether the output is active | +| outputState | String | The specific state of the output | + +--- + +### ReplayBufferStateChanged + +The state of the replay buffer output has changed. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| outputActive | Boolean | Whether the output is active | +| outputState | String | The specific state of the output | + +--- + +### VirtualcamStateChanged + +The state of the virtualcam output has changed. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| outputActive | Boolean | Whether the output is active | +| outputState | String | The specific state of the output | + +--- + +### ReplayBufferSaved + +The replay buffer has been saved. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| savedReplayPath | String | Path of the saved replay file | +## Media Inputs + +### MediaInputPlaybackStarted + +A media input has started playing. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputName | String | Name of the input | + +--- + +### MediaInputPlaybackEnded + +A media input has finished playing. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputName | String | Name of the input | + +--- + +### MediaInputActionTriggered + +An action has been performed on an input. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputName | String | Name of the input | +| mediaAction | String | Action performed on the input. See `ObsMediaInputAction` enum | # Requests @@ -1428,7 +2032,7 @@ The profile list has changed. - [GetSourceActive](#getsourceactive) - [GetSourceScreenshot](#getsourcescreenshot) - [SaveSourceScreenshot](#savesourcescreenshot) -- [Scenes](#scenes) +- [Scenes](#scenes-1) - [GetSceneList](#getscenelist) - [GetCurrentProgramScene](#getcurrentprogramscene) - [SetCurrentProgramScene](#setcurrentprogramscene) @@ -1437,7 +2041,7 @@ The profile list has changed. - [CreateScene](#createscene) - [RemoveScene](#removescene) - [SetSceneName](#setscenename) -- [Inputs](#inputs) +- [Inputs](#inputs-1) - [GetInputList](#getinputlist) - [GetInputKindList](#getinputkindlist) - [CreateInput](#createinput) @@ -1465,7 +2069,7 @@ The profile list has changed. - [SetCurrentSceneTransitionDuration](#setcurrentscenetransitionduration) - [SetCurrentSceneTransitionSettings](#setcurrentscenetransitionsettings) - [TriggerStudioModeTransition](#triggerstudiomodetransition) -- [Scene Items](#scene-items) +- [Scene Items](#scene-items-1) - [GetSceneItemList](#getsceneitemlist) - [GetGroupItemList](#getgroupitemlist) - [GetSceneItemId](#getsceneitemid) @@ -1494,7 +2098,7 @@ The profile list has changed. - [PauseRecord](#pauserecord) - [ResumeRecord](#resumerecord) - [GetRecordDirectory](#getrecorddirectory) -- [Media Inputs](#media-inputs) +- [Media Inputs](#media-inputs-1) - [GetMediaInputStatus](#getmediainputstatus) - [SetMediaInputCursor](#setmediainputcursor) - [OffsetMediaInputCursor](#offsetmediainputcursor) @@ -2664,7 +3268,7 @@ Similar to `GetInputKindList` | Name | Type | Description | | ---- | :---: | ----------- | -| transitionKinds | Vector<String> | Array of transition kinds | +| transitionKinds | Array<String> | Array of transition kinds | --- @@ -2683,7 +3287,7 @@ Gets an array of all scene transitions in OBS. | ---- | :---: | ----------- | | currentSceneTransitionName | String | Name of the current scene transition. Can be null | | currentSceneTransitionKind | String | Kind of the current scene transition. Can be null | -| transitions | Vector<Object> | Array of transitions | +| transitions | Array<Object> | Array of transitions | --- From f8263caa0341c0f0ea34b4af6783fcdf9aba308f Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 29 Dec 2021 00:23:30 -0800 Subject: [PATCH 054/128] RequestHandler: Add code comment to RemoveSceneItem --- src/requesthandler/RequestHandler_SceneItems.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/requesthandler/RequestHandler_SceneItems.cpp b/src/requesthandler/RequestHandler_SceneItems.cpp index 90abd2fc..50ea294a 100644 --- a/src/requesthandler/RequestHandler_SceneItems.cpp +++ b/src/requesthandler/RequestHandler_SceneItems.cpp @@ -193,6 +193,7 @@ RequestResult RequestHandler::RemoveSceneItem(const Request& request) if (!sceneItem) return RequestResult::Error(statusCode, comment); + // Makes the UI log `User Removed source '[source]' from scene '(null)'`. This is not a problem, just a side effect. obs_sceneitem_remove(sceneItem); return RequestResult::Success(); From 0939273abf3a3241a036ff32a05241be386544a6 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 29 Dec 2021 00:31:43 -0800 Subject: [PATCH 055/128] EventSubscription: Add `Ui` category --- src/eventhandler/types/EventSubscription.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/eventhandler/types/EventSubscription.h b/src/eventhandler/types/EventSubscription.h index 242b8023..0951745f 100644 --- a/src/eventhandler/types/EventSubscription.h +++ b/src/eventhandler/types/EventSubscription.h @@ -130,7 +130,6 @@ namespace EventSubscription { * @initialVersion 5.0.0 * @api enums */ - // Receive events in the `MediaInputs` category MediaInputs = (1 << 8), /** * Subscription value to receive the `VendorEvent` event. @@ -142,9 +141,19 @@ namespace EventSubscription { * @initialVersion 5.0.0 * @api enums */ - // Receive events from external OBS plugins and scripts Vendors = (1 << 9), /** + * Subscription value to receive events in the `Ui` category. + * + * @enumIdentifier Ui + * @enumValue (1 << 10) + * @enumType EventSubscription + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api enums + */ + Ui = (1 << 10), + /** * Helper to receive all non-high-volume events. * * @enumIdentifier All @@ -154,8 +163,7 @@ namespace EventSubscription { * @initialVersion 5.0.0 * @api enums */ - // Receive all event categories (exclude high-volume) - All = (General | Config | Scenes | Inputs | Transitions | Filters | Outputs | SceneItems | MediaInputs | Vendors), + All = (General | Config | Scenes | Inputs | Transitions | Filters | Outputs | SceneItems | MediaInputs | Ui | Vendors), /** * Subscription value to receive the `InputVolumeMeters` high-volume event. * @@ -166,7 +174,6 @@ namespace EventSubscription { * @initialVersion 5.0.0 * @api enums */ - // InputVolumeMeters event (high-volume) InputVolumeMeters = (1 << 16), /** * Subscription value to receive the `InputActiveStateChanged` high-volume event. @@ -178,7 +185,6 @@ namespace EventSubscription { * @initialVersion 5.0.0 * @api enums */ - // InputActiveStateChanged event (high-volume) InputActiveStateChanged = (1 << 17), /** * Subscription value to receive the `InputShowStateChanged` high-volume event. @@ -190,7 +196,6 @@ namespace EventSubscription { * @initialVersion 5.0.0 * @api enums */ - // InputShowStateChanged event (high-volume) InputShowStateChanged = (1 << 18), /** * Subscription value to receive the `SceneItemTransformChanged` high-volume event. @@ -202,7 +207,6 @@ namespace EventSubscription { * @initialVersion 5.0.0 * @api enums */ - // SceneItemTransformChanged event (high-volume) SceneItemTransformChanged = (1 << 19), }; } From 732d5af50c2781092ec4db0ba77a60802ef6c8d0 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 29 Dec 2021 00:34:25 -0800 Subject: [PATCH 056/128] EventHandler: Add Ui category --- CMakeLists.txt | 1 + src/eventhandler/EventHandler_General.cpp | 20 ------------ src/eventhandler/EventHandler_Ui.cpp | 40 +++++++++++++++++++++++ 3 files changed, 41 insertions(+), 20 deletions(-) create mode 100644 src/eventhandler/EventHandler_Ui.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c859d0a7..40d9e633 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,7 @@ set(obs-websocket_SOURCES src/eventhandler/EventHandler_Outputs.cpp src/eventhandler/EventHandler_SceneItems.cpp src/eventhandler/EventHandler_MediaInputs.cpp + src/eventhandler/EventHandler_Ui.cpp src/requesthandler/RequestHandler.cpp src/requesthandler/RequestBatchHandler.cpp src/requesthandler/RequestHandler_General.cpp diff --git a/src/eventhandler/EventHandler_General.cpp b/src/eventhandler/EventHandler_General.cpp index db1ee8ea..ad46e4e9 100644 --- a/src/eventhandler/EventHandler_General.cpp +++ b/src/eventhandler/EventHandler_General.cpp @@ -34,23 +34,3 @@ void EventHandler::HandleExitStarted() { BroadcastEvent(EventSubscription::General, "ExitStarted"); } - -/** - * Studio mode has been enabled or disabled. - * - * @dataField studioModeEnabled | Boolean | True == Enabled, False == Disabled - * - * @eventType StudioModeStateChanged - * @eventSubscription General - * @complexity 1 - * @rpcVersion -1 - * @initialVersion 5.0.0 - * @category general - * @api events - */ -void EventHandler::HandleStudioModeStateChanged(bool enabled) -{ - json eventData; - eventData["studioModeEnabled"] = enabled; - BroadcastEvent(EventSubscription::General, "StudioModeStateChanged", eventData); -} diff --git a/src/eventhandler/EventHandler_Ui.cpp b/src/eventhandler/EventHandler_Ui.cpp new file mode 100644 index 00000000..633baf8a --- /dev/null +++ b/src/eventhandler/EventHandler_Ui.cpp @@ -0,0 +1,40 @@ +/* +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" + +/** + * Studio mode has been enabled or disabled. + * + * @dataField studioModeEnabled | Boolean | True == Enabled, False == Disabled + * + * @eventType StudioModeStateChanged + * @eventSubscription Ui + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category ui + * @api events + */ +void EventHandler::HandleStudioModeStateChanged(bool enabled) +{ + json eventData; + eventData["studioModeEnabled"] = enabled; + BroadcastEvent(EventSubscription::Ui, "StudioModeStateChanged", eventData); +} From 707ac3f7e3dbc5c4648225d84f97737936e0e424 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 29 Dec 2021 00:51:50 -0800 Subject: [PATCH 057/128] docs: Increase complexity of G/SetProfileParameter --- src/requesthandler/RequestHandler_Config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/requesthandler/RequestHandler_Config.cpp b/src/requesthandler/RequestHandler_Config.cpp index 40e0938a..6925986f 100644 --- a/src/requesthandler/RequestHandler_Config.cpp +++ b/src/requesthandler/RequestHandler_Config.cpp @@ -334,7 +334,7 @@ RequestResult RequestHandler::RemoveProfile(const Request& request) * @responseField defaultParameterValue | String | Default value associated with the parameter. `null` if no default * * @requestType GetProfileParameter - * @complexity 3 + * @complexity 4 * @rpcVersion -1 * @initialVersion 5.0.0 * @category config @@ -378,7 +378,7 @@ RequestResult RequestHandler::GetProfileParameter(const Request& request) * @requestField parameterValue | String | Value of the parameter to set. Use `null` to delete * * @requestType SetProfileParameter - * @complexity 3 + * @complexity 4 * @rpcVersion -1 * @initialVersion 5.0.0 * @category config From 389cbd854cbfa32a68635df3909b5ff988dcda20 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Wed, 29 Dec 2021 08:54:22 +0000 Subject: [PATCH 058/128] docs(ci): Update generated docs - 707ac3f [skip ci] --- docs/generated/protocol.json | 46 ++++++++++++++++++------------- docs/generated/protocol.md | 53 ++++++++++++++++++++++-------------- 2 files changed, 59 insertions(+), 40 deletions(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 7a04a6de..ce6c1fd7 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -91,6 +91,14 @@ "initialVersion": "5.0.0", "enumValue": "(1 << 9)" }, + { + "description": "Subscription value to receive events in the `Ui` category.", + "enumIdentifier": "Ui", + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "enumValue": "(1 << 10)" + }, { "description": "Helper to receive all non-high-volume events.", "enumIdentifier": "All", @@ -897,7 +905,7 @@ { "description": "Gets a parameter from the current profile's configuration.", "requestType": "GetProfileParameter", - "complexity": 3, + "complexity": 4, "rpcVersion": "1", "deprecated": false, "initialVersion": "5.0.0", @@ -936,7 +944,7 @@ { "description": "Sets the value of a parameter in the current profile's configuration.", "requestType": "SetProfileParameter", - "complexity": 3, + "complexity": 4, "rpcVersion": "1", "deprecated": false, "initialVersion": "5.0.0", @@ -3425,23 +3433,6 @@ "category": "general", "dataFields": [] }, - { - "description": "Studio mode has been enabled or disabled.", - "eventType": "StudioModeStateChanged", - "eventSubscription": "General", - "complexity": 1, - "rpcVersion": "1", - "deprecated": false, - "initialVersion": "5.0.0", - "category": "general", - "dataFields": [ - { - "valueName": "studioModeEnabled", - "valueType": "Boolean", - "valueDescription": "True == Enabled, False == Disabled" - } - ] - }, { "description": "An input has been created.", "eventType": "InputCreated", @@ -4134,6 +4125,23 @@ } ] }, + { + "description": "Studio mode has been enabled or disabled.", + "eventType": "StudioModeStateChanged", + "eventSubscription": "Ui", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "ui", + "dataFields": [ + { + "valueName": "studioModeEnabled", + "valueType": "Boolean", + "valueDescription": "True == Enabled, False == Disabled" + } + ] + }, { "description": "An event has been emitted from a vendor.\n\nA vendor is a unique name registered by a third-party plugin or script, which allows for custom requests and events to be added to obs-websocket.\nIf a plugin or script implements vendor requests or events, documentation is expected to be provided with them.", "eventType": "VendorEvent", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 58e9632e..ac8d03ac 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -459,6 +459,7 @@ These are enumeration declarations, which are referenced throughout obs-websocke - [EventSubscription::SceneItems](#eventsubscriptionsceneitems) - [EventSubscription::MediaInputs](#eventsubscriptionmediainputs) - [EventSubscription::Vendors](#eventsubscriptionvendors) + - [EventSubscription::Ui](#eventsubscriptionui) - [EventSubscription::All](#eventsubscriptionall) - [EventSubscription::InputVolumeMeters](#eventsubscriptioninputvolumemeters) - [EventSubscription::InputActiveStateChanged](#eventsubscriptioninputactivestatechanged) @@ -1175,6 +1176,16 @@ Subscription value to receive the `VendorEvent` event. --- +### EventSubscription::Ui + +Subscription value to receive events in the `Ui` category. + +- Identifier Value: `(1 << 10)` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + ### EventSubscription::All Helper to receive all non-high-volume events. @@ -1229,7 +1240,6 @@ Subscription value to receive the `SceneItemTransformChanged` high-volume event. ### Events Table of Contents - [General](#general) - [ExitStarted](#exitstarted) - - [StudioModeStateChanged](#studiomodestatechanged) - [VendorEvent](#vendorevent) - [Config](#config) - [CurrentSceneCollectionChanging](#currentscenecollectionchanging) @@ -1274,6 +1284,8 @@ Subscription value to receive the `SceneItemTransformChanged` high-volume event. - [MediaInputPlaybackStarted](#mediainputplaybackstarted) - [MediaInputPlaybackEnded](#mediainputplaybackended) - [MediaInputActionTriggered](#mediainputactiontriggered) +- [Ui](#ui) + - [StudioModeStateChanged](#studiomodestatechanged) ## General @@ -1288,23 +1300,6 @@ OBS has begun the shutdown process. --- -### StudioModeStateChanged - -Studio mode has been enabled or disabled. - -- Complexity Rating: `1/5` -- Latest Supported RPC Version: `1` -- Added in v5.0.0 - - -**Data Fields:** - -| Name | Type | Description | -| ---- | :---: | ----------- | -| studioModeEnabled | Boolean | True == Enabled, False == Disabled | - ---- - ### VendorEvent An event has been emitted from a vendor. @@ -1998,6 +1993,22 @@ An action has been performed on an input. | ---- | :---: | ----------- | | inputName | String | Name of the input | | mediaAction | String | Action performed on the input. See `ObsMediaInputAction` enum | +## Ui + +### StudioModeStateChanged + +Studio mode has been enabled or disabled. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| studioModeEnabled | Boolean | True == Enabled, False == Disabled | # Requests @@ -2103,7 +2114,7 @@ An action has been performed on an input. - [SetMediaInputCursor](#setmediainputcursor) - [OffsetMediaInputCursor](#offsetmediainputcursor) - [TriggerMediaInputAction](#triggermediainputaction) -- [Ui](#ui) +- [Ui](#ui-1) - [GetStudioModeEnabled](#getstudiomodeenabled) - [SetStudioModeEnabled](#setstudiomodeenabled) @@ -2454,7 +2465,7 @@ Removes a profile. If the current profile is chosen, it will change to a differe Gets a parameter from the current profile's configuration. -- Complexity Rating: `3/5` +- Complexity Rating: `4/5` - Latest Supported RPC Version: `1` - Added in v5.0.0 @@ -2480,7 +2491,7 @@ Gets a parameter from the current profile's configuration. Sets the value of a parameter in the current profile's configuration. -- Complexity Rating: `3/5` +- Complexity Rating: `4/5` - Latest Supported RPC Version: `1` - Added in v5.0.0 From 38157579a6d96712eb98d2f525837d259c4f8af4 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 17 Nov 2021 00:33:23 -0800 Subject: [PATCH 059/128] Requests: Enable GetRecordDirectory --- deps/asio | 2 +- src/requesthandler/RequestHandler.cpp | 2 +- src/utils/Obs_StringHelper.cpp | 10 ++++------ 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/deps/asio b/deps/asio index 08a7029c..b84e6c16 160000 --- a/deps/asio +++ b/deps/asio @@ -1 +1 @@ -Subproject commit 08a7029cb10c911b6fb66fb015217a431206e52c +Subproject commit b84e6c16b2ea907dbad94206b7510d85aafc0b42 diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index a0c118a4..340389fa 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -123,7 +123,7 @@ const std::map RequestHandler::_handlerMap {"ToggleRecordPause", &RequestHandler::ToggleRecordPause}, {"PauseRecord", &RequestHandler::PauseRecord}, {"ResumeRecord", &RequestHandler::ResumeRecord}, - //{"GetRecordDirectory", &RequestHandler::GetRecordDirectory}, + {"GetRecordDirectory", &RequestHandler::GetRecordDirectory}, // Media Inputs {"GetMediaInputStatus", &RequestHandler::GetMediaInputStatus}, diff --git a/src/utils/Obs_StringHelper.cpp b/src/utils/Obs_StringHelper.cpp index 471651ca..8b552abb 100644 --- a/src/utils/Obs_StringHelper.cpp +++ b/src/utils/Obs_StringHelper.cpp @@ -64,12 +64,10 @@ std::string Utils::Obs::StringHelper::GetCurrentProfilePath() std::string Utils::Obs::StringHelper::GetCurrentRecordOutputPath() { - //char *recordOutputPath = obs_frontend_get_current_record_output_path(); - //std::string ret = recordOutputPath; - //bfree(recordOutputPath); - //return ret; - - return ""; + char *recordOutputPath = obs_frontend_get_current_record_output_path(); + std::string ret = recordOutputPath; + bfree(recordOutputPath); + return ret; } std::string Utils::Obs::StringHelper::GetSourceType(obs_source_t *source) From 947450ce4e8884679664ada94d68232264534d20 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 17 Nov 2021 03:18:21 -0800 Subject: [PATCH 060/128] Revert "Revert "Events: Re-enable *Changing events"" This reverts commit c60d09246c635de9b84648cd5a6146fe7938bb2c. --- src/eventhandler/EventHandler.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/eventhandler/EventHandler.cpp b/src/eventhandler/EventHandler.cpp index 5979e5b9..8470e633 100644 --- a/src/eventhandler/EventHandler.cpp +++ b/src/eventhandler/EventHandler.cpp @@ -264,18 +264,18 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_ break; // Config - //case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING: - // eventHandler->HandleCurrentSceneCollectionChanging(); - // break; + case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING: + eventHandler->HandleCurrentSceneCollectionChanging(); + break; case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED: eventHandler->HandleCurrentSceneCollectionChanged(); break; case OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED: eventHandler->HandleSceneCollectionListChanged(); break; - //case OBS_FRONTEND_EVENT_PROFILE_CHANGING: - // eventHandler->HandleCurrentProfileChanging(); - // break; + case OBS_FRONTEND_EVENT_PROFILE_CHANGING: + eventHandler->HandleCurrentProfileChanging(); + break; case OBS_FRONTEND_EVENT_PROFILE_CHANGED: eventHandler->HandleCurrentProfileChanged(); break; From 1f1a8926b180aa0beb7ab21e02e28b600b4f7358 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 17 Nov 2021 13:48:38 -0800 Subject: [PATCH 061/128] Requests: Enable RemoveInput --- src/requesthandler/RequestHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 340389fa..f3c21599 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -67,7 +67,7 @@ const std::map RequestHandler::_handlerMap {"GetInputList", &RequestHandler::GetInputList}, {"GetInputKindList", &RequestHandler::GetInputKindList}, {"CreateInput", &RequestHandler::CreateInput}, - //{"RemoveInput", &RequestHandler::RemoveInput}, // Disabled for now. Pending obs-studio#5276 + {"RemoveInput", &RequestHandler::RemoveInput}, {"SetInputName", &RequestHandler::SetInputName}, {"GetInputDefaultSettings", &RequestHandler::GetInputDefaultSettings}, {"GetInputSettings", &RequestHandler::GetInputSettings}, From 05aba45809271bd44275c5904e87369c1e80878f Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sat, 20 Nov 2021 02:37:18 -0800 Subject: [PATCH 062/128] Base: Remove old ifdefs It was a very cool method to save our precious std::strtoll method, but will no longer be needed on the next OBS release. --- src/obs-websocket.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/obs-websocket.h b/src/obs-websocket.h index 8e9f5c72..bec761be 100644 --- a/src/obs-websocket.h +++ b/src/obs-websocket.h @@ -21,13 +21,7 @@ with this program. If not, see #include #include -#ifdef _MSC_VER - #pragma push_macro("strtoll") -#endif #include -#ifdef _MSC_VER - #pragma pop_macro("strtoll") -#endif #include "utils/Obs.h" #include "plugin-macros.generated.h" From 444685c89da579fd9d47f127b4016eedcc1057dc Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 29 Dec 2021 20:45:20 -0800 Subject: [PATCH 063/128] Utils: Reenable check for valid input in volumemeter --- src/utils/Obs_VolumeMeter.cpp | 707 ++++++++++++++-------------- src/utils/Obs_VolumeMeter.h | 198 ++++---- src/utils/Obs_VolumeMeter_Helpers.h | 4 +- 3 files changed, 454 insertions(+), 455 deletions(-) diff --git a/src/utils/Obs_VolumeMeter.cpp b/src/utils/Obs_VolumeMeter.cpp index 92fbe3cf..9fa75eec 100644 --- a/src/utils/Obs_VolumeMeter.cpp +++ b/src/utils/Obs_VolumeMeter.cpp @@ -1,354 +1,353 @@ -/* -obs-websocket -Copyright (C) 2014 by Leonhard Oelke -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 -#include - -#include "Obs.h" -#include "Obs_VolumeMeter.h" -#include "Obs_VolumeMeter_Helpers.h" -#include "../obs-websocket.h" - -Utils::Obs::VolumeMeter::Meter::Meter(obs_source_t *input) : - PeakMeterType(SAMPLE_PEAK_METER), - _input(obs_source_get_weak_source(input)), - _channels(0), - _lastUpdate(0), - _volume(obs_source_get_volume(input)) -{ - signal_handler_t *sh = obs_source_get_signal_handler(input); - signal_handler_connect(sh, "volume", Meter::InputVolumeCallback, this); - - obs_source_add_audio_capture_callback(input, Meter::InputAudioCaptureCallback, this); - - blog_debug("[Utils::Obs::VolumeMeter::Meter::Meter] Meter created for input: %s", obs_source_get_name(input)); -} - -Utils::Obs::VolumeMeter::Meter::~Meter() -{ - OBSSourceAutoRelease input = obs_weak_source_get_source(_input); - if (!input) { - blog(LOG_WARNING, "[Utils::Obs::VolumeMeter::Meter::~Meter] Failed to get strong reference to input. Has it been destroyed?"); - return; - } - - signal_handler_t *sh = obs_source_get_signal_handler(input); - signal_handler_disconnect(sh, "volume", Meter::InputVolumeCallback, this); - - obs_source_remove_audio_capture_callback(input, Meter::InputAudioCaptureCallback, this); - - blog_debug("[Utils::Obs::VolumeMeter::Meter::~Meter] Meter destroyed for input: %s", obs_source_get_name(input)); -} - -bool Utils::Obs::VolumeMeter::Meter::InputValid() -{ - // return !obs_weak_source_expired(_input); - return true; -} - -json Utils::Obs::VolumeMeter::Meter::GetMeterData() -{ - json ret; - - OBSSourceAutoRelease input = obs_weak_source_get_source(_input); - if (!input) { - blog(LOG_WARNING, "[Utils::Obs::VolumeMeter::Meter::GetMeterData] Failed to get strong reference to input. Has it been destroyed?"); - return ret; - } - - std::vector> levels; - const float volume = _muted ? 0.0f : _volume.load(); - - std::unique_lock l(_mutex); - - if (_lastUpdate != 0 && (os_gettime_ns() - _lastUpdate) * 0.000000001 > 0.3) - ResetAudioLevels(); - - for (int channel = 0; channel < _channels; channel++) { - std::vector level; - level.push_back(_magnitude[channel] * volume); - level.push_back(_peak[channel] * volume); - level.push_back(_peak[channel]); - - levels.push_back(level); - } - l.unlock(); - - ret["inputName"] = obs_source_get_name(input); - ret["inputLevelsMul"] = levels; - - return ret; -} - -// MUST HOLD LOCK -void Utils::Obs::VolumeMeter::Meter::ResetAudioLevels() -{ - _lastUpdate = 0; - for (int channelNumber = 0; channelNumber < MAX_AUDIO_CHANNELS; channelNumber++) { - _magnitude[channelNumber] = 0; - _peak[channelNumber] = 0; - } -} - -// MUST HOLD LOCK -void Utils::Obs::VolumeMeter::Meter::ProcessAudioChannels(const struct audio_data *data) -{ - int channels = 0; - for (int i = 0; i < MAX_AV_PLANES; i++) { - if (data->data[i]) - channels++; - } - - bool channelsChanged = _channels != channels; - _channels = std::clamp(channels, 0, MAX_AUDIO_CHANNELS); - - if (channelsChanged) - ResetAudioLevels(); -} - -// MUST HOLD LOCK -void Utils::Obs::VolumeMeter::Meter::ProcessPeak(const struct audio_data *data) -{ - size_t sampleCount = data->frames; - int channelNumber = 0; - - for (int planeNumber = 0; channelNumber < _channels; planeNumber++) { - float *samples = (float*)data->data[planeNumber]; - if (!samples) - continue; - - if (((uintptr_t)samples & 0xf) > 0) { - _peak[channelNumber] = 1.0f; - channelNumber++; - continue; - } - - __m128 previousSamples = _mm_loadu_ps(_previousSamples[channelNumber]); - - float peak; - switch (PeakMeterType) { - default: - case SAMPLE_PEAK_METER: - peak = GetSamplePeak(previousSamples, samples, sampleCount); - break; - case TRUE_PEAK_METER: - peak = GetTruePeak(previousSamples, samples, sampleCount); - break; - } - - switch (sampleCount) { - case 0: - break; - case 1: - _previousSamples[channelNumber][0] = _previousSamples[channelNumber][1]; - _previousSamples[channelNumber][1] = _previousSamples[channelNumber][2]; - _previousSamples[channelNumber][2] = _previousSamples[channelNumber][3]; - _previousSamples[channelNumber][3] = samples[sampleCount - 1]; - break; - case 2: - _previousSamples[channelNumber][0] = _previousSamples[channelNumber][2]; - _previousSamples[channelNumber][1] = _previousSamples[channelNumber][3]; - _previousSamples[channelNumber][2] = samples[sampleCount - 2]; - _previousSamples[channelNumber][3] = samples[sampleCount - 1]; - break; - case 3: - _previousSamples[channelNumber][0] = _previousSamples[channelNumber][3]; - _previousSamples[channelNumber][1] = samples[sampleCount - 3]; - _previousSamples[channelNumber][2] = samples[sampleCount - 2]; - _previousSamples[channelNumber][3] = samples[sampleCount - 1]; - break; - default: - _previousSamples[channelNumber][0] = samples[sampleCount - 4]; - _previousSamples[channelNumber][1] = samples[sampleCount - 3]; - _previousSamples[channelNumber][2] = samples[sampleCount - 2]; - _previousSamples[channelNumber][3] = samples[sampleCount - 1]; - } - - _peak[channelNumber] = peak; - - channelNumber++; - } - - for (; channelNumber < MAX_AUDIO_CHANNELS; channelNumber++) - _peak[channelNumber] = 0.0; -} - -// MUST HOLD LOCK -void Utils::Obs::VolumeMeter::Meter::ProcessMagnitude(const struct audio_data *data) -{ - size_t sampleCount = data->frames; - - int channelNumber = 0; - for (int planeNumber = 0; channelNumber < _channels; planeNumber++) { - float *samples = (float*)data->data[planeNumber]; - if (!samples) - continue; - - float sum = 0.0; - for (size_t i = 0; i < sampleCount; i++) { - float sample = samples[i]; - sum += sample * sample; - } - - _magnitude[channelNumber] = std::sqrt(sum / sampleCount); - - channelNumber++; - } -} - -void Utils::Obs::VolumeMeter::Meter::InputAudioCaptureCallback(void *priv_data, obs_source_t *, const struct audio_data *data, bool muted) -{ - auto c = static_cast(priv_data); - - std::unique_lock l(c->_mutex); - - c->_muted = muted; - c->ProcessAudioChannels(data); - c->ProcessPeak(data); - c->ProcessMagnitude(data); - - c->_lastUpdate = os_gettime_ns(); -} - -void Utils::Obs::VolumeMeter::Meter::InputVolumeCallback(void *priv_data, calldata_t *cd) -{ - auto c = static_cast(priv_data); - - c->_volume = (float)calldata_float(cd, "volume"); -} - -Utils::Obs::VolumeMeter::Handler::Handler(UpdateCallback cb, uint64_t updatePeriod) : - _updateCallback(cb), - _updatePeriod(updatePeriod), - _running(false) -{ - signal_handler_t *sh = obs_get_signal_handler(); - if (!sh) - return; - - auto enumProc = [](void *priv_data, obs_source_t *input) { - auto c = static_cast(priv_data); - - if (!obs_source_active(input)) - return true; - - uint32_t flags = obs_source_get_output_flags(input); - if ((flags & OBS_SOURCE_AUDIO) == 0) - return true; - - c->_meters.emplace_back(std::move(new Meter(input))); - - return true; - }; - obs_enum_sources(enumProc, this); - - signal_handler_connect(sh, "source_activate", Handler::InputActivateCallback, this); - signal_handler_connect(sh, "source_deactivate", Handler::InputDeactivateCallback, this); - - _running = true; - _updateThread = std::thread(&Handler::UpdateThread, this); - - blog_debug("[Utils::Obs::VolumeMeter::Handler::Handler] Handler created."); -} - -Utils::Obs::VolumeMeter::Handler::~Handler() -{ - signal_handler_t *sh = obs_get_signal_handler(); - if (!sh) - return; - - signal_handler_disconnect(sh, "source_activate", Handler::InputActivateCallback, this); - signal_handler_disconnect(sh, "source_deactivate", Handler::InputDeactivateCallback, this); - - if (_running) { - _running = false; - _cond.notify_all(); - } - - if (_updateThread.joinable()) - _updateThread.join(); - - blog_debug("[Utils::Obs::VolumeMeter::Handler::~Handler] Handler destroyed."); -} - -void Utils::Obs::VolumeMeter::Handler::UpdateThread() -{ - blog_debug("[Utils::Obs::VolumeMeter::Handler::UpdateThread] Thread started."); - while (_running) { - { - std::unique_lock l(_mutex); - if (_cond.wait_for(l, std::chrono::milliseconds(_updatePeriod), [this]{ return !_running; })) - break; - } - - std::vector inputs; - std::unique_lock l(_meterMutex); - for (auto &meter : _meters) { - if (meter->InputValid()) - inputs.push_back(meter->GetMeterData()); - } - l.unlock(); - - if (_updateCallback) - _updateCallback(inputs); - } - blog_debug("[Utils::Obs::VolumeMeter::Handler::UpdateThread] Thread stopped."); -} - -void Utils::Obs::VolumeMeter::Handler::InputActivateCallback(void *priv_data, calldata_t *cd) -{ - auto c = static_cast(priv_data); - - obs_source_t *input = GetCalldataPointer(cd, "source"); - if (!input) - return; - - if (obs_source_get_type(input) != OBS_SOURCE_TYPE_INPUT) - return; - - uint32_t flags = obs_source_get_output_flags(input); - if ((flags & OBS_SOURCE_AUDIO) == 0) - return; - - std::unique_lock l(c->_meterMutex); - c->_meters.emplace_back(std::move(new Meter(input))); -} - -void Utils::Obs::VolumeMeter::Handler::InputDeactivateCallback(void *priv_data, calldata_t *cd) -{ - auto c = static_cast(priv_data); - - obs_source_t *input = GetCalldataPointer(cd, "source"); - if (!input) - return; - - if (obs_source_get_type(input) != OBS_SOURCE_TYPE_INPUT) - return; - - // Don't ask me why, but using std::remove_if segfaults trying this. - std::unique_lock l(c->_meterMutex); - std::vector::iterator iter; - for (iter = c->_meters.begin(); iter != c->_meters.end();) { - if (obs_weak_source_references_source(iter->get()->GetWeakInput(), input)) - iter = c->_meters.erase(iter); - else - ++iter; - } -} +/* +obs-websocket +Copyright (C) 2014 by Leonhard Oelke +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 +#include + +#include "Obs.h" +#include "Obs_VolumeMeter.h" +#include "Obs_VolumeMeter_Helpers.h" +#include "../obs-websocket.h" + +Utils::Obs::VolumeMeter::Meter::Meter(obs_source_t *input) : + PeakMeterType(SAMPLE_PEAK_METER), + _input(obs_source_get_weak_source(input)), + _channels(0), + _lastUpdate(0), + _volume(obs_source_get_volume(input)) +{ + signal_handler_t *sh = obs_source_get_signal_handler(input); + signal_handler_connect(sh, "volume", Meter::InputVolumeCallback, this); + + obs_source_add_audio_capture_callback(input, Meter::InputAudioCaptureCallback, this); + + blog_debug("[Utils::Obs::VolumeMeter::Meter::Meter] Meter created for input: %s", obs_source_get_name(input)); +} + +Utils::Obs::VolumeMeter::Meter::~Meter() +{ + OBSSourceAutoRelease input = obs_weak_source_get_source(_input); + if (!input) { + blog(LOG_WARNING, "[Utils::Obs::VolumeMeter::Meter::~Meter] Failed to get strong reference to input. Has it been destroyed?"); + return; + } + + signal_handler_t *sh = obs_source_get_signal_handler(input); + signal_handler_disconnect(sh, "volume", Meter::InputVolumeCallback, this); + + obs_source_remove_audio_capture_callback(input, Meter::InputAudioCaptureCallback, this); + + blog_debug("[Utils::Obs::VolumeMeter::Meter::~Meter] Meter destroyed for input: %s", obs_source_get_name(input)); +} + +bool Utils::Obs::VolumeMeter::Meter::InputValid() +{ + return !obs_weak_source_expired(_input); +} + +json Utils::Obs::VolumeMeter::Meter::GetMeterData() +{ + json ret; + + OBSSourceAutoRelease input = obs_weak_source_get_source(_input); + if (!input) { + blog(LOG_WARNING, "[Utils::Obs::VolumeMeter::Meter::GetMeterData] Failed to get strong reference to input. Has it been destroyed?"); + return ret; + } + + std::vector> levels; + const float volume = _muted ? 0.0f : _volume.load(); + + std::unique_lock l(_mutex); + + if (_lastUpdate != 0 && (os_gettime_ns() - _lastUpdate) * 0.000000001 > 0.3) + ResetAudioLevels(); + + for (int channel = 0; channel < _channels; channel++) { + std::vector level; + level.push_back(_magnitude[channel] * volume); + level.push_back(_peak[channel] * volume); + level.push_back(_peak[channel]); + + levels.push_back(level); + } + l.unlock(); + + ret["inputName"] = obs_source_get_name(input); + ret["inputLevelsMul"] = levels; + + return ret; +} + +// MUST HOLD LOCK +void Utils::Obs::VolumeMeter::Meter::ResetAudioLevels() +{ + _lastUpdate = 0; + for (int channelNumber = 0; channelNumber < MAX_AUDIO_CHANNELS; channelNumber++) { + _magnitude[channelNumber] = 0; + _peak[channelNumber] = 0; + } +} + +// MUST HOLD LOCK +void Utils::Obs::VolumeMeter::Meter::ProcessAudioChannels(const struct audio_data *data) +{ + int channels = 0; + for (int i = 0; i < MAX_AV_PLANES; i++) { + if (data->data[i]) + channels++; + } + + bool channelsChanged = _channels != channels; + _channels = std::clamp(channels, 0, MAX_AUDIO_CHANNELS); + + if (channelsChanged) + ResetAudioLevels(); +} + +// MUST HOLD LOCK +void Utils::Obs::VolumeMeter::Meter::ProcessPeak(const struct audio_data *data) +{ + size_t sampleCount = data->frames; + int channelNumber = 0; + + for (int planeNumber = 0; channelNumber < _channels; planeNumber++) { + float *samples = (float*)data->data[planeNumber]; + if (!samples) + continue; + + if (((uintptr_t)samples & 0xf) > 0) { + _peak[channelNumber] = 1.0f; + channelNumber++; + continue; + } + + __m128 previousSamples = _mm_loadu_ps(_previousSamples[channelNumber]); + + float peak; + switch (PeakMeterType) { + default: + case SAMPLE_PEAK_METER: + peak = GetSamplePeak(previousSamples, samples, sampleCount); + break; + case TRUE_PEAK_METER: + peak = GetTruePeak(previousSamples, samples, sampleCount); + break; + } + + switch (sampleCount) { + case 0: + break; + case 1: + _previousSamples[channelNumber][0] = _previousSamples[channelNumber][1]; + _previousSamples[channelNumber][1] = _previousSamples[channelNumber][2]; + _previousSamples[channelNumber][2] = _previousSamples[channelNumber][3]; + _previousSamples[channelNumber][3] = samples[sampleCount - 1]; + break; + case 2: + _previousSamples[channelNumber][0] = _previousSamples[channelNumber][2]; + _previousSamples[channelNumber][1] = _previousSamples[channelNumber][3]; + _previousSamples[channelNumber][2] = samples[sampleCount - 2]; + _previousSamples[channelNumber][3] = samples[sampleCount - 1]; + break; + case 3: + _previousSamples[channelNumber][0] = _previousSamples[channelNumber][3]; + _previousSamples[channelNumber][1] = samples[sampleCount - 3]; + _previousSamples[channelNumber][2] = samples[sampleCount - 2]; + _previousSamples[channelNumber][3] = samples[sampleCount - 1]; + break; + default: + _previousSamples[channelNumber][0] = samples[sampleCount - 4]; + _previousSamples[channelNumber][1] = samples[sampleCount - 3]; + _previousSamples[channelNumber][2] = samples[sampleCount - 2]; + _previousSamples[channelNumber][3] = samples[sampleCount - 1]; + } + + _peak[channelNumber] = peak; + + channelNumber++; + } + + for (; channelNumber < MAX_AUDIO_CHANNELS; channelNumber++) + _peak[channelNumber] = 0.0; +} + +// MUST HOLD LOCK +void Utils::Obs::VolumeMeter::Meter::ProcessMagnitude(const struct audio_data *data) +{ + size_t sampleCount = data->frames; + + int channelNumber = 0; + for (int planeNumber = 0; channelNumber < _channels; planeNumber++) { + float *samples = (float*)data->data[planeNumber]; + if (!samples) + continue; + + float sum = 0.0; + for (size_t i = 0; i < sampleCount; i++) { + float sample = samples[i]; + sum += sample * sample; + } + + _magnitude[channelNumber] = std::sqrt(sum / sampleCount); + + channelNumber++; + } +} + +void Utils::Obs::VolumeMeter::Meter::InputAudioCaptureCallback(void *priv_data, obs_source_t *, const struct audio_data *data, bool muted) +{ + auto c = static_cast(priv_data); + + std::unique_lock l(c->_mutex); + + c->_muted = muted; + c->ProcessAudioChannels(data); + c->ProcessPeak(data); + c->ProcessMagnitude(data); + + c->_lastUpdate = os_gettime_ns(); +} + +void Utils::Obs::VolumeMeter::Meter::InputVolumeCallback(void *priv_data, calldata_t *cd) +{ + auto c = static_cast(priv_data); + + c->_volume = (float)calldata_float(cd, "volume"); +} + +Utils::Obs::VolumeMeter::Handler::Handler(UpdateCallback cb, uint64_t updatePeriod) : + _updateCallback(cb), + _updatePeriod(updatePeriod), + _running(false) +{ + signal_handler_t *sh = obs_get_signal_handler(); + if (!sh) + return; + + auto enumProc = [](void *priv_data, obs_source_t *input) { + auto c = static_cast(priv_data); + + if (!obs_source_active(input)) + return true; + + uint32_t flags = obs_source_get_output_flags(input); + if ((flags & OBS_SOURCE_AUDIO) == 0) + return true; + + c->_meters.emplace_back(std::move(new Meter(input))); + + return true; + }; + obs_enum_sources(enumProc, this); + + signal_handler_connect(sh, "source_activate", Handler::InputActivateCallback, this); + signal_handler_connect(sh, "source_deactivate", Handler::InputDeactivateCallback, this); + + _running = true; + _updateThread = std::thread(&Handler::UpdateThread, this); + + blog_debug("[Utils::Obs::VolumeMeter::Handler::Handler] Handler created."); +} + +Utils::Obs::VolumeMeter::Handler::~Handler() +{ + signal_handler_t *sh = obs_get_signal_handler(); + if (!sh) + return; + + signal_handler_disconnect(sh, "source_activate", Handler::InputActivateCallback, this); + signal_handler_disconnect(sh, "source_deactivate", Handler::InputDeactivateCallback, this); + + if (_running) { + _running = false; + _cond.notify_all(); + } + + if (_updateThread.joinable()) + _updateThread.join(); + + blog_debug("[Utils::Obs::VolumeMeter::Handler::~Handler] Handler destroyed."); +} + +void Utils::Obs::VolumeMeter::Handler::UpdateThread() +{ + blog_debug("[Utils::Obs::VolumeMeter::Handler::UpdateThread] Thread started."); + while (_running) { + { + std::unique_lock l(_mutex); + if (_cond.wait_for(l, std::chrono::milliseconds(_updatePeriod), [this]{ return !_running; })) + break; + } + + std::vector inputs; + std::unique_lock l(_meterMutex); + for (auto &meter : _meters) { + if (meter->InputValid()) + inputs.push_back(meter->GetMeterData()); + } + l.unlock(); + + if (_updateCallback) + _updateCallback(inputs); + } + blog_debug("[Utils::Obs::VolumeMeter::Handler::UpdateThread] Thread stopped."); +} + +void Utils::Obs::VolumeMeter::Handler::InputActivateCallback(void *priv_data, calldata_t *cd) +{ + auto c = static_cast(priv_data); + + obs_source_t *input = GetCalldataPointer(cd, "source"); + if (!input) + return; + + if (obs_source_get_type(input) != OBS_SOURCE_TYPE_INPUT) + return; + + uint32_t flags = obs_source_get_output_flags(input); + if ((flags & OBS_SOURCE_AUDIO) == 0) + return; + + std::unique_lock l(c->_meterMutex); + c->_meters.emplace_back(std::move(new Meter(input))); +} + +void Utils::Obs::VolumeMeter::Handler::InputDeactivateCallback(void *priv_data, calldata_t *cd) +{ + auto c = static_cast(priv_data); + + obs_source_t *input = GetCalldataPointer(cd, "source"); + if (!input) + return; + + if (obs_source_get_type(input) != OBS_SOURCE_TYPE_INPUT) + return; + + // Don't ask me why, but using std::remove_if segfaults trying this. + std::unique_lock l(c->_meterMutex); + std::vector::iterator iter; + for (iter = c->_meters.begin(); iter != c->_meters.end();) { + if (obs_weak_source_references_source(iter->get()->GetWeakInput(), input)) + iter = c->_meters.erase(iter); + else + ++iter; + } +} diff --git a/src/utils/Obs_VolumeMeter.h b/src/utils/Obs_VolumeMeter.h index 9058fb2d..e2b20a6e 100644 --- a/src/utils/Obs_VolumeMeter.h +++ b/src/utils/Obs_VolumeMeter.h @@ -1,99 +1,99 @@ -/* -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 -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "Obs.h" -#include "Json.h" - -namespace Utils { - namespace Obs { - namespace VolumeMeter { - // Some code copied from https://github.com/obsproject/obs-studio/blob/master/libobs/obs-audio-controls.c - // Keeps a running tally of the current audio levels, for a specific input - class Meter { - public: - Meter(obs_source_t *input); - ~Meter(); - - bool InputValid(); - obs_weak_source_t *GetWeakInput() { return _input; } - json GetMeterData(); - - std::atomic PeakMeterType; - - private: - OBSWeakSourceAutoRelease _input; - - // All values in mul - std::mutex _mutex; - bool _muted; - int _channels; - float _magnitude[MAX_AUDIO_CHANNELS]; - float _peak[MAX_AUDIO_CHANNELS]; - float _previousSamples[MAX_AUDIO_CHANNELS][4]; - - std::atomic _lastUpdate; - std::atomic _volume; - - void ResetAudioLevels(); - void ProcessAudioChannels(const struct audio_data *data); - void ProcessPeak(const struct audio_data *data); - void ProcessMagnitude(const struct audio_data *data); - - static void InputAudioCaptureCallback(void *priv_data, obs_source_t *source, const struct audio_data *data, bool muted); - static void InputVolumeCallback(void *priv_data, calldata_t *cd); - }; - - // Maintains an array of active inputs - class Handler { - typedef std::function)> UpdateCallback; - typedef std::unique_ptr MeterPtr; - - public: - Handler(UpdateCallback cb, uint64_t updatePeriod = 50); - ~Handler(); - - private: - UpdateCallback _updateCallback; - - std::mutex _meterMutex; - std::vector _meters; - uint64_t _updatePeriod; - - std::mutex _mutex; - std::condition_variable _cond; - std::atomic _running; - std::thread _updateThread; - - void UpdateThread(); - static void InputActivateCallback(void *priv_data, calldata_t *cd); - static void InputDeactivateCallback(void *priv_data, calldata_t *cd); - }; - } - } -} +/* +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 +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "Obs.h" +#include "Json.h" + +namespace Utils { + namespace Obs { + namespace VolumeMeter { + // Some code copied from https://github.com/obsproject/obs-studio/blob/master/libobs/obs-audio-controls.c + // Keeps a running tally of the current audio levels, for a specific input + class Meter { + public: + Meter(obs_source_t *input); + ~Meter(); + + bool InputValid(); + obs_weak_source_t *GetWeakInput() { return _input; } + json GetMeterData(); + + std::atomic PeakMeterType; + + private: + OBSWeakSourceAutoRelease _input; + + // All values in mul + std::mutex _mutex; + bool _muted; + int _channels; + float _magnitude[MAX_AUDIO_CHANNELS]; + float _peak[MAX_AUDIO_CHANNELS]; + float _previousSamples[MAX_AUDIO_CHANNELS][4]; + + std::atomic _lastUpdate; + std::atomic _volume; + + void ResetAudioLevels(); + void ProcessAudioChannels(const struct audio_data *data); + void ProcessPeak(const struct audio_data *data); + void ProcessMagnitude(const struct audio_data *data); + + static void InputAudioCaptureCallback(void *priv_data, obs_source_t *source, const struct audio_data *data, bool muted); + static void InputVolumeCallback(void *priv_data, calldata_t *cd); + }; + + // Maintains an array of active inputs + class Handler { + typedef std::function)> UpdateCallback; + typedef std::unique_ptr MeterPtr; + + public: + Handler(UpdateCallback cb, uint64_t updatePeriod = 50); + ~Handler(); + + private: + UpdateCallback _updateCallback; + + std::mutex _meterMutex; + std::vector _meters; + uint64_t _updatePeriod; + + std::mutex _mutex; + std::condition_variable _cond; + std::atomic _running; + std::thread _updateThread; + + void UpdateThread(); + static void InputActivateCallback(void *priv_data, calldata_t *cd); + static void InputDeactivateCallback(void *priv_data, calldata_t *cd); + }; + } + } +} diff --git a/src/utils/Obs_VolumeMeter_Helpers.h b/src/utils/Obs_VolumeMeter_Helpers.h index e69bfc6f..7af42ac3 100644 --- a/src/utils/Obs_VolumeMeter_Helpers.h +++ b/src/utils/Obs_VolumeMeter_Helpers.h @@ -56,7 +56,7 @@ with this program. If not, see r = fmaxf(r, x4_mem[3]); \ } while (false) -float GetSamplePeak(__m128 previousSamples, const float *samples, size_t sampleCount) +static float GetSamplePeak(__m128 previousSamples, const float *samples, size_t sampleCount) { __m128 peak = previousSamples; for (size_t i = 0; (i + 3) < sampleCount; i += 4) { @@ -69,7 +69,7 @@ float GetSamplePeak(__m128 previousSamples, const float *samples, size_t sampleC return ret; } -float GetTruePeak(__m128 previousSamples, const float *samples, size_t sampleCount) +static float GetTruePeak(__m128 previousSamples, const float *samples, size_t sampleCount) { const __m128 m3 = _mm_set_ps(-0.155915f, 0.935489f, 0.233872f, -0.103943f); const __m128 m1 = _mm_set_ps(-0.216236f, 0.756827f, 0.504551f, -0.189207f); From 3b2369ae97528fbc113fec404e55566f046c457b Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sun, 21 Nov 2021 03:22:39 -0800 Subject: [PATCH 064/128] Requests: Add support check for SetInputAudioMonitorType --- src/requesthandler/RequestHandler_Inputs.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/requesthandler/RequestHandler_Inputs.cpp b/src/requesthandler/RequestHandler_Inputs.cpp index a14c0f14..f65a3c07 100644 --- a/src/requesthandler/RequestHandler_Inputs.cpp +++ b/src/requesthandler/RequestHandler_Inputs.cpp @@ -600,6 +600,9 @@ RequestResult RequestHandler::SetInputAudioMonitorType(const Request& request) if (!(input && request.ValidateString("monitorType", statusCode, comment))) return RequestResult::Error(statusCode, comment); + if (!obs_audio_monitoring_available()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "Audio monitoring is not available on this platform."); + enum obs_monitoring_type monitorType; std::string monitorTypeString = request.RequestData["monitorType"]; if (monitorTypeString == "OBS_MONITORING_TYPE_NONE") From a94ac2402771f1f2fb6663ceeca19da0453d51ad Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 28 Dec 2021 17:01:39 -0800 Subject: [PATCH 065/128] RequestHandler: Add input open dialog requests Adds - `OpenInputPropertiesDialog` - `OpenInputFiltersDialog` - `OpenInputInteractDialog` --- src/requesthandler/RequestHandler.cpp | 3 + src/requesthandler/RequestHandler.h | 3 + src/requesthandler/RequestHandler_Ui.cpp | 78 ++++++++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index f3c21599..02fddd62 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -134,6 +134,9 @@ const std::map RequestHandler::_handlerMap // Ui {"GetStudioModeEnabled", &RequestHandler::GetStudioModeEnabled}, {"SetStudioModeEnabled", &RequestHandler::SetStudioModeEnabled}, + {"OpenInputPropertiesDialog", &RequestHandler::OpenInputPropertiesDialog}, + {"OpenInputFiltersDialog", &RequestHandler::OpenInputFiltersDialog}, + {"OpenInputInteractDialog", &RequestHandler::OpenInputInteractDialog}, }; RequestHandler::RequestHandler(SessionPtr session) : diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 19e3fde4..c918ae16 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -156,6 +156,9 @@ class RequestHandler { // Ui RequestResult GetStudioModeEnabled(const Request&); RequestResult SetStudioModeEnabled(const Request&); + RequestResult OpenInputPropertiesDialog(const Request&); + RequestResult OpenInputFiltersDialog(const Request&); + RequestResult OpenInputInteractDialog(const Request&); SessionPtr _session; static const std::map _handlerMap; diff --git a/src/requesthandler/RequestHandler_Ui.cpp b/src/requesthandler/RequestHandler_Ui.cpp index 4a093591..12fa5d04 100644 --- a/src/requesthandler/RequestHandler_Ui.cpp +++ b/src/requesthandler/RequestHandler_Ui.cpp @@ -70,3 +70,81 @@ RequestResult RequestHandler::SetStudioModeEnabled(const Request& request) return RequestResult::Success(); } + +/** + * Opens the properties dialog of an input. + * + * @requestField inputName | String | Name of the input to open the dialog of + * + * @requestType OpenInputPropertiesDialog + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category ui + * @api requests + */ +RequestResult RequestHandler::OpenInputPropertiesDialog(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment); + if (!input) + return RequestResult::Error(statusCode, comment); + + obs_frontend_open_source_properties(input); + + return RequestResult::Success(); +} + +/** + * Opens the filters dialog of an input. + * + * @requestField inputName | String | Name of the input to open the dialog of + * + * @requestType OpenInputFiltersDialog + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category ui + * @api requests + */ +RequestResult RequestHandler::OpenInputFiltersDialog(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment); + if (!input) + return RequestResult::Error(statusCode, comment); + + obs_frontend_open_source_filters(input); + + return RequestResult::Success(); +} + +/** + * Opens the interact dialog of an input. + * + * @requestField inputName | String | Name of the input to open the dialog of + * + * @requestType OpenInputInteractDialog + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category ui + * @api requests + */ +RequestResult RequestHandler::OpenInputInteractDialog(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment); + if (!input) + return RequestResult::Error(statusCode, comment); + + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_INTERACTION)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support interaction."); + + obs_frontend_open_source_interaction(input); + + return RequestResult::Success(); +} From 1ed095de48667a9cce9a3825cfea374158744625 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 28 Dec 2021 17:36:41 -0800 Subject: [PATCH 066/128] EventHandler: Add `InputAudioBalanceChanged` --- src/eventhandler/EventHandler.cpp | 2 ++ src/eventhandler/EventHandler.h | 1 + src/eventhandler/EventHandler_Inputs.cpp | 33 ++++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/src/eventhandler/EventHandler.cpp b/src/eventhandler/EventHandler.cpp index 8470e633..b012fc1b 100644 --- a/src/eventhandler/EventHandler.cpp +++ b/src/eventhandler/EventHandler.cpp @@ -134,6 +134,7 @@ void EventHandler::ConnectSourceSignals(obs_source_t *source) // Applies to inpu signal_handler_connect(sh, "hide", HandleInputShowStateChanged, this); signal_handler_connect(sh, "mute", HandleInputMuteStateChanged, this); signal_handler_connect(sh, "volume", HandleInputVolumeChanged, this); + signal_handler_connect(sh, "audio_balance", HandleInputAudioBalanceChanged, this); signal_handler_connect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this); signal_handler_connect(sh, "audio_mixers", HandleInputAudioTracksChanged, this); //signal_handler_connect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this); @@ -174,6 +175,7 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source) signal_handler_disconnect(sh, "hide", HandleInputShowStateChanged, this); signal_handler_disconnect(sh, "mute", HandleInputMuteStateChanged, this); signal_handler_disconnect(sh, "volume", HandleInputVolumeChanged, this); + signal_handler_disconnect(sh, "audio_balance", HandleInputAudioBalanceChanged, this); signal_handler_disconnect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this); signal_handler_disconnect(sh, "audio_mixers", HandleInputAudioTracksChanged, this); //signal_handler_disconnect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this); diff --git a/src/eventhandler/EventHandler.h b/src/eventhandler/EventHandler.h index 98fec117..bdd1cde8 100644 --- a/src/eventhandler/EventHandler.h +++ b/src/eventhandler/EventHandler.h @@ -107,6 +107,7 @@ class EventHandler static void HandleInputShowStateChanged(void *param, calldata_t *data); // Direct callback static void HandleInputMuteStateChanged(void *param, calldata_t *data); // Direct callback static void HandleInputVolumeChanged(void *param, calldata_t *data); // Direct callback + static void HandleInputAudioBalanceChanged(void *param, calldata_t *data); // Direct callback static void HandleInputAudioSyncOffsetChanged(void *param, calldata_t *data); // Direct callback static void HandleInputAudioTracksChanged(void *param, calldata_t *data); // Direct callback static void HandleInputAudioMonitorTypeChanged(void *param, calldata_t *data); // Direct callback diff --git a/src/eventhandler/EventHandler_Inputs.cpp b/src/eventhandler/EventHandler_Inputs.cpp index a4b0c2af..7d937939 100644 --- a/src/eventhandler/EventHandler_Inputs.cpp +++ b/src/eventhandler/EventHandler_Inputs.cpp @@ -236,6 +236,39 @@ void EventHandler::HandleInputVolumeChanged(void *param, calldata_t *data) eventHandler->BroadcastEvent(EventSubscription::Inputs, "InputVolumeChanged", eventData); } +/** + * The audio balance value of an input has changed. + * + * @dataField inputName | String | Name of the affected input + * @dataField inputAudioBalance | Number | New audio balance value of the input + * + * @eventType InputAudioBalanceChanged + * @eventSubscription Inputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category inputs + * @api events + */ +void EventHandler::HandleInputAudioBalanceChanged(void *param, calldata_t *data) +{ + auto eventHandler = reinterpret_cast(param); + + obs_source_t *source = GetCalldataPointer(data, "source"); + if (!source) + return; + + if (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT) + return; + + float inputAudioBalance = (float)calldata_float(data, "balance"); + + json eventData; + eventData["inputName"] = obs_source_get_name(source); + eventData["inputAudioBalance"] = inputAudioBalance; + eventHandler->BroadcastEvent(EventSubscription::Inputs, "InputAudioBalanceChanged", eventData); +} + /** * The sync offset of an input has changed. * From 9113ff90213f73aed2d511951be2f56fedc1a9cd Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 28 Dec 2021 17:46:46 -0800 Subject: [PATCH 067/128] RequestHandler: Add audio balance requests --- src/requesthandler/RequestHandler.cpp | 2 + src/requesthandler/RequestHandler.h | 2 + src/requesthandler/RequestHandler_Inputs.cpp | 55 ++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index f3c21599..ca8c54f1 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -77,6 +77,8 @@ const std::map RequestHandler::_handlerMap {"ToggleInputMute", &RequestHandler::ToggleInputMute}, {"GetInputVolume", &RequestHandler::GetInputVolume}, {"SetInputVolume", &RequestHandler::SetInputVolume}, + {"GetInputAudioBalance", &RequestHandler::GetInputAudioBalance}, + {"SetInputAudioBalance", &RequestHandler::SetInputAudioBalance}, {"GetInputAudioSyncOffset", &RequestHandler::GetInputAudioSyncOffset}, {"SetInputAudioSyncOffset", &RequestHandler::SetInputAudioSyncOffset}, {"GetInputAudioMonitorType", &RequestHandler::GetInputAudioMonitorType}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 19e3fde4..410b6b56 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -99,6 +99,8 @@ class RequestHandler { RequestResult ToggleInputMute(const Request&); RequestResult GetInputVolume(const Request&); RequestResult SetInputVolume(const Request&); + RequestResult GetInputAudioBalance(const Request&); + RequestResult SetInputAudioBalance(const Request&); RequestResult GetInputAudioSyncOffset(const Request&); RequestResult SetInputAudioSyncOffset(const Request&); RequestResult GetInputAudioMonitorType(const Request&); diff --git a/src/requesthandler/RequestHandler_Inputs.cpp b/src/requesthandler/RequestHandler_Inputs.cpp index f65a3c07..d7018bc9 100644 --- a/src/requesthandler/RequestHandler_Inputs.cpp +++ b/src/requesthandler/RequestHandler_Inputs.cpp @@ -488,6 +488,61 @@ RequestResult RequestHandler::SetInputVolume(const Request& request) return RequestResult::Success(); } +/** + * Gets the audio balance of an input. + * + * @requestField inputName | String | Name of the input to get the audio balance of + * + * @responseField inputAudioBalance | Number | Audio balance value from 0.0-1.0 + * + * @requestType GetInputAudioBalance + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category inputs + */ +RequestResult RequestHandler::GetInputAudioBalance(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment); + if (!input) + return RequestResult::Error(statusCode, comment); + + json responseData; + responseData["inputAudioBalance"] = obs_source_get_balance_value(input); + + return RequestResult::Success(responseData); +} + +/** + * Sets the audio balance of an input. + * + * @requestField inputName | String | Name of the input to set the audio balance of + * @requestField inputAudioBalance | Number | New audio balance value | >= 0.0, <= 1.0 + * + * @requestType SetInputAudioBalance + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category inputs + */ +RequestResult RequestHandler::SetInputAudioBalance(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment); + if (!(input && request.ValidateNumber("inputAudioBalance", statusCode, comment, 0.0, 1.0))) + return RequestResult::Error(statusCode, comment); + + float inputAudioBalance = request.RequestData["inputAudioBalance"]; + obs_source_set_balance_value(input, inputAudioBalance); + + return RequestResult::Success(); +} + /** * Gets the audio sync offset of an input. * From 85f65952bd13db40c87dd0fd486fc8395f7e4938 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 29 Dec 2021 01:05:30 -0800 Subject: [PATCH 068/128] Base: Update issue template --- .github/ISSUE_TEMPLATE/bug_report.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 839c9545..f4067645 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -69,8 +69,8 @@ body: label: obs-websocket Version description: What version of obs-websocket are you using? options: + - 5.0.0-alpha3 - 5.0.0-alpha2 - - 5.0.0-alpha1 - 4.9.1 - 4.9.0 - Git From 31997db509af867c956c18f8c4323fd05462c344 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 29 Dec 2021 21:05:28 -0800 Subject: [PATCH 069/128] EventHandler: Uncomment audio_monitoring signal --- src/eventhandler/EventHandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/eventhandler/EventHandler.cpp b/src/eventhandler/EventHandler.cpp index 8470e633..19a48b6c 100644 --- a/src/eventhandler/EventHandler.cpp +++ b/src/eventhandler/EventHandler.cpp @@ -136,7 +136,7 @@ void EventHandler::ConnectSourceSignals(obs_source_t *source) // Applies to inpu signal_handler_connect(sh, "volume", HandleInputVolumeChanged, this); signal_handler_connect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this); signal_handler_connect(sh, "audio_mixers", HandleInputAudioTracksChanged, this); - //signal_handler_connect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this); + signal_handler_connect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this); if (sourceType == OBS_SOURCE_TYPE_INPUT) { signal_handler_connect(sh, "media_started", HandleMediaInputPlaybackStarted, this); @@ -176,7 +176,7 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source) signal_handler_disconnect(sh, "volume", HandleInputVolumeChanged, this); signal_handler_disconnect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this); signal_handler_disconnect(sh, "audio_mixers", HandleInputAudioTracksChanged, this); - //signal_handler_disconnect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this); + signal_handler_disconnect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this); signal_handler_disconnect(sh, "media_started", HandleMediaInputPlaybackStarted, this); signal_handler_disconnect(sh, "media_ended", HandleMediaInputPlaybackEnded, this); signal_handler_disconnect(sh, "media_pause", SourceMediaPauseMultiHandler, this); From 3a96b585ce25e113b69c382ca07eb995d8937e9c Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Thu, 30 Dec 2021 05:09:00 +0000 Subject: [PATCH 070/128] docs(ci): Update generated docs - 12c6527 [skip ci] --- docs/generated/protocol.json | 60 ++++++++++++++++++++++++++++++++++++ docs/generated/protocol.md | 54 ++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index ce6c1fd7..99aa2630 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -3317,6 +3317,66 @@ } ], "responseFields": [] + }, + { + "description": "Opens the properties dialog of an input.", + "requestType": "OpenInputPropertiesDialog", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "ui", + "requestFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input to open the dialog of", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, + { + "description": "Opens the filters dialog of an input.", + "requestType": "OpenInputFiltersDialog", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "ui", + "requestFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input to open the dialog of", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, + { + "description": "Opens the interact dialog of an input.", + "requestType": "OpenInputInteractDialog", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "ui", + "requestFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input to open the dialog of", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] } ], "events": [ diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index ac8d03ac..fbf3e9e5 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -2117,6 +2117,9 @@ Studio mode has been enabled or disabled. - [Ui](#ui-1) - [GetStudioModeEnabled](#getstudiomodeenabled) - [SetStudioModeEnabled](#setstudiomodeenabled) + - [OpenInputPropertiesDialog](#openinputpropertiesdialog) + - [OpenInputFiltersDialog](#openinputfiltersdialog) + - [OpenInputInteractDialog](#openinputinteractdialog) @@ -4026,4 +4029,55 @@ Enables or disables studio mode | ---- | :---: | ----------- | :----------------: | ----------------- | | studioModeEnabled | Boolean | True == Enabled, False == Disabled | None | N/A | +--- + +### OpenInputPropertiesDialog + +Opens the properties dialog of an input. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| inputName | String | Name of the input to open the dialog of | None | N/A | + +--- + +### OpenInputFiltersDialog + +Opens the filters dialog of an input. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| inputName | String | Name of the input to open the dialog of | None | N/A | + +--- + +### OpenInputInteractDialog + +Opens the interact dialog of an input. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| inputName | String | Name of the input to open the dialog of | None | N/A | + From 6291cb153262b1fc98b3045eeec7a3472f101052 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Thu, 30 Dec 2021 05:12:42 +0000 Subject: [PATCH 071/128] docs(ci): Update generated docs - a90dafb [skip ci] --- docs/generated/protocol.json | 76 ++++++++++++++++++++++++++++++++++++ docs/generated/protocol.md | 63 ++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 99aa2630..303c1891 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -1818,6 +1818,60 @@ ], "responseFields": [] }, + { + "description": "Gets the audio balance of an input.", + "requestType": "GetInputAudioBalance", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "requestFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input to get the audio balance of", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "inputAudioBalance", + "valueType": "Number", + "valueDescription": "Audio balance value from 0.0-1.0" + } + ] + }, + { + "description": "Sets the audio balance of an input.", + "requestType": "SetInputAudioBalance", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "requestFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input to set the audio balance of", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "inputAudioBalance", + "valueType": "Number", + "valueDescription": "New audio balance value", + "valueRestrictions": ">= 0.0, <= 1.0", + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, { "description": "Gets the audio sync offset of an input.\n\nNote: The audio sync offset can be negative too!", "requestType": "GetInputAudioSyncOffset", @@ -3662,6 +3716,28 @@ } ] }, + { + "description": "The audio balance value of an input has changed.", + "eventType": "InputAudioBalanceChanged", + "eventSubscription": "Inputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "dataFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the affected input" + }, + { + "valueName": "inputAudioBalance", + "valueType": "Number", + "valueDescription": "New audio balance value of the input" + } + ] + }, { "description": "The sync offset of an input has changed.", "eventType": "InputAudioSyncOffsetChanged", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index fbf3e9e5..330b8460 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -1263,6 +1263,7 @@ Subscription value to receive the `SceneItemTransformChanged` high-volume event. - [InputShowStateChanged](#inputshowstatechanged) - [InputMuteStateChanged](#inputmutestatechanged) - [InputVolumeChanged](#inputvolumechanged) + - [InputAudioBalanceChanged](#inputaudiobalancechanged) - [InputAudioSyncOffsetChanged](#inputaudiosyncoffsetchanged) - [InputAudioTracksChanged](#inputaudiotrackschanged) - [InputAudioMonitorTypeChanged](#inputaudiomonitortypechanged) @@ -1666,6 +1667,24 @@ An input's volume level has changed. --- +### InputAudioBalanceChanged + +The audio balance value of an input has changed. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputName | String | Name of the affected input | +| inputAudioBalance | Number | New audio balance value of the input | + +--- + ### InputAudioSyncOffsetChanged The sync offset of an input has changed. @@ -2066,6 +2085,8 @@ Studio mode has been enabled or disabled. - [ToggleInputMute](#toggleinputmute) - [GetInputVolume](#getinputvolume) - [SetInputVolume](#setinputvolume) + - [GetInputAudioBalance](#getinputaudiobalance) + - [SetInputAudioBalance](#setinputaudiobalance) - [GetInputAudioSyncOffset](#getinputaudiosyncoffset) - [SetInputAudioSyncOffset](#setinputaudiosyncoffset) - [GetInputAudioMonitorType](#getinputaudiomonitortype) @@ -3128,6 +3149,48 @@ Sets the volume setting of an input. --- +### GetInputAudioBalance + +Gets the audio balance of an input. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| inputName | String | Name of the input to get the audio balance of | None | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputAudioBalance | Number | Audio balance value from 0.0-1.0 | + +--- + +### SetInputAudioBalance + +Sets the audio balance of an input. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| inputName | String | Name of the input to set the audio balance of | None | N/A | +| inputAudioBalance | Number | New audio balance value | >= 0.0, <= 1.0 | N/A | + +--- + ### GetInputAudioSyncOffset Gets the audio sync offset of an input. From 4a2654d0955108f771b7a332c0a388f719c4c100 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Thu, 30 Dec 2021 00:12:41 -0800 Subject: [PATCH 072/128] RequestHandler: Add GetGroupList --- src/requesthandler/RequestHandler.cpp | 1 + src/requesthandler/RequestHandler.h | 1 + src/requesthandler/RequestHandler_Scenes.cpp | 25 +++++++++++++++++++- src/utils/Obs.h | 1 + src/utils/Obs_ArrayHelper.cpp | 23 +++++++++++++++--- 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 44b8f1d7..27822995 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -55,6 +55,7 @@ const std::map RequestHandler::_handlerMap // Scenes {"GetSceneList", &RequestHandler::GetSceneList}, + {"GetGroupList", &RequestHandler::GetGroupList}, {"GetCurrentProgramScene", &RequestHandler::GetCurrentProgramScene}, {"SetCurrentProgramScene", &RequestHandler::SetCurrentProgramScene}, {"GetCurrentPreviewScene", &RequestHandler::GetCurrentPreviewScene}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 0a040918..fd11952a 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -77,6 +77,7 @@ class RequestHandler { // Scenes RequestResult GetSceneList(const Request&); + RequestResult GetGroupList(const Request&); RequestResult GetCurrentProgramScene(const Request&); RequestResult SetCurrentProgramScene(const Request&); RequestResult GetCurrentPreviewScene(const Request&); diff --git a/src/requesthandler/RequestHandler_Scenes.cpp b/src/requesthandler/RequestHandler_Scenes.cpp index 9481013f..a972306f 100644 --- a/src/requesthandler/RequestHandler_Scenes.cpp +++ b/src/requesthandler/RequestHandler_Scenes.cpp @@ -24,7 +24,7 @@ with this program. If not, see * * @responseField currentProgramSceneName | String | Current program scene * @responseField currentPreviewSceneName | String | Current preview scene. `null` if not in studio mode - * @responseField scenes | Array | Array of scenes in OBS + * @responseField scenes | Array | Array of scenes * * @requestType GetSceneList * @complexity 2 @@ -54,6 +54,29 @@ RequestResult RequestHandler::GetSceneList(const Request&) return RequestResult::Success(responseData); } +/** + * Gets an array of all groups in OBS. + * + * Groups in OBS are actually scenes, but renamed and modified. In obs-websocket, we treat them as scenes where we can. + * + * @responseField groups | Array | Array of group names + * + * @requestType GetGroupList + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scenes + */ +RequestResult RequestHandler::GetGroupList(const Request&) +{ + json responseData; + + responseData["groups"] = Utils::Obs::ArrayHelper::GetGroupList(); + + return RequestResult::Success(responseData); +} + /** * Gets the current program scene. * diff --git a/src/utils/Obs.h b/src/utils/Obs.h index 76bcebd8..97fe1894 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -183,6 +183,7 @@ namespace Utils { std::vector GetHotkeyList(); std::vector GetHotkeyNameList(); std::vector GetSceneList(); + std::vector GetGroupList(); 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 bbd032c3..1ac16263 100644 --- a/src/utils/Obs_ArrayHelper.cpp +++ b/src/utils/Obs_ArrayHelper.cpp @@ -91,9 +91,6 @@ std::vector Utils::Obs::ArrayHelper::GetSceneList() for (size_t i = 0; i < sceneList.sources.num; i++) { obs_source_t *scene = sceneList.sources.array[i]; - if (obs_source_is_group(scene)) - continue; - json sceneJson; sceneJson["sceneName"] = obs_source_get_name(scene); sceneJson["sceneIndex"] = sceneList.sources.num - i - 1; @@ -109,6 +106,26 @@ std::vector Utils::Obs::ArrayHelper::GetSceneList() return ret; } +std::vector Utils::Obs::ArrayHelper::GetGroupList() +{ + std::vector ret; + + auto cb = [](void *priv_data, obs_source_t *scene) { + auto ret = static_cast*>(priv_data); + + if (!obs_source_is_group(scene)) + return true; + + ret->emplace_back(obs_source_get_name(scene)); + + return true; + }; + + obs_enum_scenes(cb, &ret); + + return ret; +} + std::vector Utils::Obs::ArrayHelper::GetSceneItemList(obs_scene_t *scene, bool basic) { std::pair, bool> enumData; From e43ebde7944cc1f4c30646528bba80de215db3ad Mon Sep 17 00:00:00 2001 From: tt2468 Date: Thu, 30 Dec 2021 00:21:29 -0800 Subject: [PATCH 073/128] Base: Use static_cast in place of reinterpret_cast static_cast is a much safer cast method --- src/eventhandler/EventHandler.cpp | 18 +++++++++--------- src/eventhandler/EventHandler_Inputs.cpp | 16 ++++++++-------- src/eventhandler/EventHandler_MediaInputs.cpp | 16 ++++++++-------- src/eventhandler/EventHandler_SceneItems.cpp | 12 ++++++------ src/obs-websocket.cpp | 2 +- src/requesthandler/RequestBatchHandler.cpp | 2 +- src/requesthandler/RequestHandler_Config.cpp | 10 +++++----- src/utils/Obs.h | 2 +- src/utils/Obs_ActionHelper.cpp | 2 +- src/utils/Obs_ArrayHelper.cpp | 6 +++--- src/utils/Obs_NumberHelper.cpp | 2 +- src/utils/Platform.cpp | 4 ++-- 12 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/eventhandler/EventHandler.cpp b/src/eventhandler/EventHandler.cpp index bace24ab..c3dcfd9c 100644 --- a/src/eventhandler/EventHandler.cpp +++ b/src/eventhandler/EventHandler.cpp @@ -199,7 +199,7 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source) void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_data) { - auto eventHandler = reinterpret_cast(private_data); + auto eventHandler = static_cast(private_data); if (!eventHandler->_obsLoaded.load()) { if (event == OBS_FRONTEND_EVENT_FINISHED_LOADING) { @@ -210,14 +210,14 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_ // In the case that plugins become hotloadable, this will have to go back into `EventHandler::EventHandler()` // Enumerate inputs and connect each one obs_enum_sources([](void* param, obs_source_t* source) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); eventHandler->ConnectSourceSignals(source); return true; }, private_data); // Enumerate scenes and connect each one obs_enum_scenes([](void* param, obs_source_t* source) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); eventHandler->ConnectSourceSignals(source); return true; }, private_data); @@ -243,14 +243,14 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_ // In the case that plugins become hotloadable, this will have to go back into `EventHandler::~EventHandler()` // Enumerate inputs and disconnect each one obs_enum_sources([](void* param, obs_source_t* source) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); eventHandler->DisconnectSourceSignals(source); return true; }, private_data); // Enumerate scenes and disconnect each one obs_enum_scenes([](void* param, obs_source_t* source) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); eventHandler->DisconnectSourceSignals(source); return true; }, private_data); @@ -365,7 +365,7 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_ // Only called for creation of a public source void EventHandler::SourceCreatedMultiHandler(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); // Don't react to signals until OBS has finished loading if (!eventHandler->_obsLoaded.load()) @@ -392,7 +392,7 @@ void EventHandler::SourceCreatedMultiHandler(void *param, calldata_t *data) // Only called for destruction of a public source void EventHandler::SourceDestroyedMultiHandler(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); // We can't use any smart types here because releasing the source will cause infinite recursion obs_source_t *source = GetCalldataPointer(data, "source"); @@ -420,7 +420,7 @@ void EventHandler::SourceDestroyedMultiHandler(void *param, calldata_t *data) void EventHandler::SourceRemovedMultiHandler(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); if (!eventHandler->_obsLoaded.load()) return; @@ -443,7 +443,7 @@ void EventHandler::SourceRemovedMultiHandler(void *param, calldata_t *data) void EventHandler::SourceRenamedMultiHandler(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); if (!eventHandler->_obsLoaded.load()) return; diff --git a/src/eventhandler/EventHandler_Inputs.cpp b/src/eventhandler/EventHandler_Inputs.cpp index 7d937939..af3654eb 100644 --- a/src/eventhandler/EventHandler_Inputs.cpp +++ b/src/eventhandler/EventHandler_Inputs.cpp @@ -111,7 +111,7 @@ void EventHandler::HandleInputNameChanged(obs_source_t *, std::string oldInputNa */ void EventHandler::HandleInputActiveStateChanged(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); if (!eventHandler->_inputActiveStateChangedRef.load()) return; @@ -147,7 +147,7 @@ void EventHandler::HandleInputActiveStateChanged(void *param, calldata_t *data) */ void EventHandler::HandleInputShowStateChanged(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); if (!eventHandler->_inputShowStateChangedRef.load()) return; @@ -181,7 +181,7 @@ void EventHandler::HandleInputShowStateChanged(void *param, calldata_t *data) */ void EventHandler::HandleInputMuteStateChanged(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) @@ -213,7 +213,7 @@ void EventHandler::HandleInputMuteStateChanged(void *param, calldata_t *data) */ void EventHandler::HandleInputVolumeChanged(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) @@ -252,7 +252,7 @@ void EventHandler::HandleInputVolumeChanged(void *param, calldata_t *data) */ void EventHandler::HandleInputAudioBalanceChanged(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) @@ -285,7 +285,7 @@ void EventHandler::HandleInputAudioBalanceChanged(void *param, calldata_t *data) */ void EventHandler::HandleInputAudioSyncOffsetChanged(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) @@ -318,7 +318,7 @@ void EventHandler::HandleInputAudioSyncOffsetChanged(void *param, calldata_t *da */ void EventHandler::HandleInputAudioTracksChanged(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) @@ -361,7 +361,7 @@ void EventHandler::HandleInputAudioTracksChanged(void *param, calldata_t *data) */ void EventHandler::HandleInputAudioMonitorTypeChanged(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) diff --git a/src/eventhandler/EventHandler_MediaInputs.cpp b/src/eventhandler/EventHandler_MediaInputs.cpp index 7bd0cb54..faa000c6 100644 --- a/src/eventhandler/EventHandler_MediaInputs.cpp +++ b/src/eventhandler/EventHandler_MediaInputs.cpp @@ -35,7 +35,7 @@ std::string GetMediaInputActionString(ObsMediaInputAction action) { void EventHandler::SourceMediaPauseMultiHandler(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) @@ -49,7 +49,7 @@ void EventHandler::SourceMediaPauseMultiHandler(void *param, calldata_t *data) void EventHandler::SourceMediaPlayMultiHandler(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) @@ -63,7 +63,7 @@ void EventHandler::SourceMediaPlayMultiHandler(void *param, calldata_t *data) void EventHandler::SourceMediaRestartMultiHandler(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) @@ -77,7 +77,7 @@ void EventHandler::SourceMediaRestartMultiHandler(void *param, calldata_t *data) void EventHandler::SourceMediaStopMultiHandler(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) @@ -91,7 +91,7 @@ void EventHandler::SourceMediaStopMultiHandler(void *param, calldata_t *data) void EventHandler::SourceMediaNextMultiHandler(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) @@ -105,7 +105,7 @@ void EventHandler::SourceMediaNextMultiHandler(void *param, calldata_t *data) void EventHandler::SourceMediaPreviousMultiHandler(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) @@ -132,7 +132,7 @@ void EventHandler::SourceMediaPreviousMultiHandler(void *param, calldata_t *data */ void EventHandler::HandleMediaInputPlaybackStarted(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) @@ -161,7 +161,7 @@ void EventHandler::HandleMediaInputPlaybackStarted(void *param, calldata_t *data */ void EventHandler::HandleMediaInputPlaybackEnded(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_source_t *source = GetCalldataPointer(data, "source"); if (!source) diff --git a/src/eventhandler/EventHandler_SceneItems.cpp b/src/eventhandler/EventHandler_SceneItems.cpp index 60b78e04..bac56c4d 100644 --- a/src/eventhandler/EventHandler_SceneItems.cpp +++ b/src/eventhandler/EventHandler_SceneItems.cpp @@ -37,7 +37,7 @@ with this program. If not, see */ void EventHandler::HandleSceneItemCreated(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_scene_t *scene = GetCalldataPointer(data, "scene"); if (!scene) @@ -74,7 +74,7 @@ void EventHandler::HandleSceneItemCreated(void *param, calldata_t *data) */ void EventHandler::HandleSceneItemRemoved(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_scene_t *scene = GetCalldataPointer(data, "scene"); if (!scene) @@ -107,7 +107,7 @@ void EventHandler::HandleSceneItemRemoved(void *param, calldata_t *data) */ void EventHandler::HandleSceneItemListReindexed(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_scene_t *scene = GetCalldataPointer(data, "scene"); if (!scene) @@ -136,7 +136,7 @@ void EventHandler::HandleSceneItemListReindexed(void *param, calldata_t *data) */ void EventHandler::HandleSceneItemEnableStateChanged(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_scene_t *scene = GetCalldataPointer(data, "scene"); if (!scene) @@ -172,7 +172,7 @@ void EventHandler::HandleSceneItemEnableStateChanged(void *param, calldata_t *da */ void EventHandler::HandleSceneItemLockStateChanged(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); obs_scene_t *scene = GetCalldataPointer(data, "scene"); if (!scene) @@ -208,7 +208,7 @@ void EventHandler::HandleSceneItemLockStateChanged(void *param, calldata_t *data */ void EventHandler::HandleSceneItemTransformChanged(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(param); + auto eventHandler = static_cast(param); if (!eventHandler->_sceneItemTransformChangedRef.load()) return; diff --git a/src/obs-websocket.cpp b/src/obs-websocket.cpp index 830a2365..e257780d 100644 --- a/src/obs-websocket.cpp +++ b/src/obs-websocket.cpp @@ -68,7 +68,7 @@ bool obs_module_load(void) // Initialize the settings dialog obs_frontend_push_ui_translation(obs_module_get_string); - QMainWindow* mainWindow = reinterpret_cast(obs_frontend_get_main_window()); + QMainWindow* mainWindow = static_cast(obs_frontend_get_main_window()); _settingsDialog = new SettingsDialog(mainWindow); obs_frontend_pop_ui_translation(); diff --git a/src/requesthandler/RequestBatchHandler.cpp b/src/requesthandler/RequestBatchHandler.cpp index 82f8453a..4d3f3383 100644 --- a/src/requesthandler/RequestBatchHandler.cpp +++ b/src/requesthandler/RequestBatchHandler.cpp @@ -109,7 +109,7 @@ static void ObsTickCallback(void *param, float) { ScopeProfiler prof{"obs_websocket_request_batch_frame_tick"}; - auto serialFrameBatch = reinterpret_cast(param); + auto serialFrameBatch = static_cast(param); // Increment frame count serialFrameBatch->frameCount++; diff --git a/src/requesthandler/RequestHandler_Config.cpp b/src/requesthandler/RequestHandler_Config.cpp index 6925986f..86d92f7e 100644 --- a/src/requesthandler/RequestHandler_Config.cpp +++ b/src/requesthandler/RequestHandler_Config.cpp @@ -159,7 +159,7 @@ RequestResult RequestHandler::SetCurrentSceneCollection(const Request& request) // Avoid queueing tasks if nothing will change if (currentSceneCollectionName != sceneCollectionName) { obs_queue_task(OBS_TASK_UI, [](void* param) { - obs_frontend_set_current_scene_collection(reinterpret_cast(param)); + obs_frontend_set_current_scene_collection(static_cast(param)); }, (void*)sceneCollectionName.c_str(), true); } @@ -193,7 +193,7 @@ RequestResult RequestHandler::CreateSceneCollection(const Request& request) if (std::find(sceneCollections.begin(), sceneCollections.end(), sceneCollectionName) != sceneCollections.end()) return RequestResult::Error(RequestStatus::ResourceAlreadyExists); - QMainWindow* mainWindow = reinterpret_cast(obs_frontend_get_main_window()); + QMainWindow* mainWindow = static_cast(obs_frontend_get_main_window()); bool success = false; QMetaObject::invokeMethod(mainWindow, "AddSceneCollection", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, success), Q_ARG(bool, true), Q_ARG(QString, QString::fromStdString(sceneCollectionName))); if (!success) @@ -252,7 +252,7 @@ RequestResult RequestHandler::SetCurrentProfile(const Request& request) // Avoid queueing tasks if nothing will change if (currentProfileName != profileName) { obs_queue_task(OBS_TASK_UI, [](void* param) { - obs_frontend_set_current_profile(reinterpret_cast(param)); + obs_frontend_set_current_profile(static_cast(param)); }, (void*)profileName.c_str(), true); } @@ -284,7 +284,7 @@ RequestResult RequestHandler::CreateProfile(const Request& request) if (std::find(profiles.begin(), profiles.end(), profileName) != profiles.end()) return RequestResult::Error(RequestStatus::ResourceAlreadyExists); - QMainWindow* mainWindow = reinterpret_cast(obs_frontend_get_main_window()); + QMainWindow* mainWindow = static_cast(obs_frontend_get_main_window()); QMetaObject::invokeMethod(mainWindow, "NewProfile", Qt::BlockingQueuedConnection, Q_ARG(QString, QString::fromStdString(profileName))); return RequestResult::Success(); @@ -318,7 +318,7 @@ RequestResult RequestHandler::RemoveProfile(const Request& request) if (profiles.size() < 2) return RequestResult::Error(RequestStatus::NotEnoughResources); - QMainWindow* mainWindow = reinterpret_cast(obs_frontend_get_main_window()); + QMainWindow* mainWindow = static_cast(obs_frontend_get_main_window()); QMetaObject::invokeMethod(mainWindow, "DeleteProfile", Qt::BlockingQueuedConnection, Q_ARG(QString, QString::fromStdString(profileName))); return RequestResult::Success(); diff --git a/src/utils/Obs.h b/src/utils/Obs.h index 97fe1894..460d3113 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -62,7 +62,7 @@ using OBSWeakServiceAutoRelease = OBSRef T* GetCalldataPointer(const calldata_t *data, const char* name) { void *ptr = nullptr; calldata_get_ptr(data, name, &ptr); - return reinterpret_cast(ptr); + return static_cast(ptr); } enum ObsOutputState { diff --git a/src/utils/Obs_ActionHelper.cpp b/src/utils/Obs_ActionHelper.cpp index 5442219b..407f374e 100644 --- a/src/utils/Obs_ActionHelper.cpp +++ b/src/utils/Obs_ActionHelper.cpp @@ -29,7 +29,7 @@ struct CreateSceneItemData { void CreateSceneItemHelper(void *_data, obs_scene_t *scene) { - auto *data = reinterpret_cast(_data); + auto *data = static_cast(_data); data->sceneItem = obs_scene_add(scene, data->source); if (data->sceneItemTransform) diff --git a/src/utils/Obs_ArrayHelper.cpp b/src/utils/Obs_ArrayHelper.cpp index 1ac16263..997512c1 100644 --- a/src/utils/Obs_ArrayHelper.cpp +++ b/src/utils/Obs_ArrayHelper.cpp @@ -61,7 +61,7 @@ std::vector Utils::Obs::ArrayHelper::GetHotkeyList() std::vector ret; obs_enum_hotkeys([](void* data, obs_hotkey_id, obs_hotkey_t* hotkey) { - auto ret = reinterpret_cast *>(data); + auto ret = static_cast *>(data); ret->push_back(hotkey); @@ -132,7 +132,7 @@ std::vector Utils::Obs::ArrayHelper::GetSceneItemList(obs_scene_t *scene, enumData.second = basic; obs_scene_enum_items(scene, [](obs_scene_t*, obs_sceneitem_t* sceneItem, void* param) { - auto enumData = reinterpret_cast, bool>*>(param); + auto enumData = static_cast, bool>*>(param); json item; item["sceneItemId"] = obs_sceneitem_get_id(sceneItem); @@ -175,7 +175,7 @@ std::vector Utils::Obs::ArrayHelper::GetInputList(std::string inputKind) if (obs_source_get_type(input) != OBS_SOURCE_TYPE_INPUT) return true; - auto inputInfo = reinterpret_cast(param); + auto inputInfo = static_cast(param); std::string inputKind = obs_source_get_id(input); diff --git a/src/utils/Obs_NumberHelper.cpp b/src/utils/Obs_NumberHelper.cpp index a3891231..e7c22c9b 100644 --- a/src/utils/Obs_NumberHelper.cpp +++ b/src/utils/Obs_NumberHelper.cpp @@ -39,7 +39,7 @@ size_t Utils::Obs::NumberHelper::GetSceneCount() { size_t ret; auto sceneEnumProc = [](void *param, obs_source_t *scene) { - auto ret = reinterpret_cast(param); + auto ret = static_cast(param); if (obs_source_is_group(scene)) return true; diff --git a/src/utils/Platform.cpp b/src/utils/Platform.cpp index 6f01fb26..41becdf4 100644 --- a/src/utils/Platform.cpp +++ b/src/utils/Platform.cpp @@ -111,9 +111,9 @@ void Utils::Platform::SendTrayNotification(QSystemTrayIcon::MessageIcon icon, QS obs_queue_task(OBS_TASK_UI, [](void* param) { void *systemTrayPtr = obs_frontend_get_system_tray(); - auto systemTray = reinterpret_cast(systemTrayPtr); + auto systemTray = static_cast(systemTrayPtr); - auto notification = reinterpret_cast(param); + auto notification = static_cast(param); systemTray->showMessage(notification->title, notification->body, notification->icon); delete notification; }, (void*)notification, false); From 00dd8d782110b2ea1ee299fe7b85572606e64c57 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Thu, 30 Dec 2021 01:15:54 -0800 Subject: [PATCH 074/128] lib: Add version define --- lib/obs-websocket-api.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/obs-websocket-api.h b/lib/obs-websocket-api.h index 5607038a..ccaa187f 100644 --- a/lib/obs-websocket-api.h +++ b/lib/obs-websocket-api.h @@ -22,6 +22,8 @@ with this program. If not, see #include +#define OBS_WEBSOCKET_API_VERSION 1 + #ifdef __cplusplus extern "C" { #endif From e6761cf286a62b8bffdbd50bbdd27d89c9f0616c Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Thu, 30 Dec 2021 09:19:59 +0000 Subject: [PATCH 075/128] docs(ci): Update generated docs - 00dd8d7 [skip ci] --- docs/generated/protocol.json | 19 ++++++++++++++++++- docs/generated/protocol.md | 22 +++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 303c1891..5ca2d0ff 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -2783,7 +2783,24 @@ { "valueName": "scenes", "valueType": "Array", - "valueDescription": "Array of scenes in OBS" + "valueDescription": "Array of scenes" + } + ] + }, + { + "description": "Gets an array of all groups in OBS.\n\nGroups in OBS are actually scenes, but renamed and modified. In obs-websocket, we treat them as scenes where we can.", + "requestType": "GetGroupList", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scenes", + "requestFields": [], + "responseFields": [ + { + "valueName": "groups", + "valueType": "Array", + "valueDescription": "Array of group names" } ] }, diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 330b8460..23b70108 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -2064,6 +2064,7 @@ Studio mode has been enabled or disabled. - [SaveSourceScreenshot](#savesourcescreenshot) - [Scenes](#scenes-1) - [GetSceneList](#getscenelist) + - [GetGroupList](#getgrouplist) - [GetCurrentProgramScene](#getcurrentprogramscene) - [SetCurrentProgramScene](#setcurrentprogramscene) - [GetCurrentPreviewScene](#getcurrentpreviewscene) @@ -2727,7 +2728,26 @@ Gets an array of all scenes in OBS. | ---- | :---: | ----------- | | currentProgramSceneName | String | Current program scene | | currentPreviewSceneName | String | Current preview scene. `null` if not in studio mode | -| scenes | Array<Object> | Array of scenes in OBS | +| scenes | Array<Object> | Array of scenes | + +--- + +### GetGroupList + +Gets an array of all groups in OBS. + +Groups in OBS are actually scenes, but renamed and modified. In obs-websocket, we treat them as scenes where we can. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| groups | Array<String> | Array of group names | --- From 6d216e041288cabdfaf547a92e8455da026ce37f Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 31 Dec 2021 14:04:31 -0800 Subject: [PATCH 076/128] docs: Fix docs of InputAudioTracksChanged --- src/eventhandler/EventHandler_Inputs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/eventhandler/EventHandler_Inputs.cpp b/src/eventhandler/EventHandler_Inputs.cpp index af3654eb..2a2050fb 100644 --- a/src/eventhandler/EventHandler_Inputs.cpp +++ b/src/eventhandler/EventHandler_Inputs.cpp @@ -305,8 +305,8 @@ void EventHandler::HandleInputAudioSyncOffsetChanged(void *param, calldata_t *da /** * The audio tracks of an input have changed. * - * @dataField inputName | String | Name of the input - * @dataField inputAudioTracks | Array | Array of audio tracks along with their associated enable states + * @dataField inputName | String | Name of the input + * @dataField inputAudioTracks | Object | Object of audio tracks along with their associated enable states * * @eventType InputAudioTracksChanged * @eventSubscription Inputs From 702f88cea86ce400e4a50663cea5e8a1ca1bab33 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 31 Dec 2021 14:07:59 -0800 Subject: [PATCH 077/128] requesthandler: Add GetInputAudioTracks --- src/requesthandler/RequestHandler.cpp | 1 + src/requesthandler/RequestHandler.h | 1 + src/requesthandler/RequestHandler_Inputs.cpp | 71 ++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 27822995..df43364a 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -84,6 +84,7 @@ const std::map RequestHandler::_handlerMap {"SetInputAudioSyncOffset", &RequestHandler::SetInputAudioSyncOffset}, {"GetInputAudioMonitorType", &RequestHandler::GetInputAudioMonitorType}, {"SetInputAudioMonitorType", &RequestHandler::SetInputAudioMonitorType}, + {"GetInputAudioTracks", &RequestHandler::GetInputAudioTracks}, {"GetInputPropertiesListPropertyItems", &RequestHandler::GetInputPropertiesListPropertyItems}, {"PressInputPropertiesButton", &RequestHandler::PressInputPropertiesButton}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index fd11952a..e18bb3ee 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -106,6 +106,7 @@ class RequestHandler { RequestResult SetInputAudioSyncOffset(const Request&); RequestResult GetInputAudioMonitorType(const Request&); RequestResult SetInputAudioMonitorType(const Request&); + RequestResult GetInputAudioTracks(const Request&); RequestResult GetInputPropertiesListPropertyItems(const Request&); RequestResult PressInputPropertiesButton(const Request&); diff --git a/src/requesthandler/RequestHandler_Inputs.cpp b/src/requesthandler/RequestHandler_Inputs.cpp index d7018bc9..75c1d03f 100644 --- a/src/requesthandler/RequestHandler_Inputs.cpp +++ b/src/requesthandler/RequestHandler_Inputs.cpp @@ -346,6 +346,9 @@ RequestResult RequestHandler::GetInputMute(const Request& request) if (!input) return RequestResult::Error(statusCode, comment); + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio."); + json responseData; responseData["inputMuted"] = obs_source_muted(input); return RequestResult::Success(responseData); @@ -372,6 +375,9 @@ RequestResult RequestHandler::SetInputMute(const Request& request) if (!(input && request.ValidateBoolean("inputMuted", statusCode, comment))) return RequestResult::Error(statusCode, comment); + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio."); + obs_source_set_muted(input, request.RequestData["inputMuted"]); return RequestResult::Success(); @@ -399,6 +405,9 @@ RequestResult RequestHandler::ToggleInputMute(const Request& request) if (!input) return RequestResult::Error(statusCode, comment); + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio."); + bool inputMuted = !obs_source_muted(input); obs_source_set_muted(input, inputMuted); @@ -430,6 +439,9 @@ RequestResult RequestHandler::GetInputVolume(const Request& request) if (!input) return RequestResult::Error(statusCode, comment); + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio."); + float inputVolumeMul = obs_source_get_volume(input); float inputVolumeDb = obs_mul_to_db(inputVolumeMul); if (inputVolumeDb == -INFINITY) @@ -463,6 +475,9 @@ RequestResult RequestHandler::SetInputVolume(const Request& request) if (!input) return RequestResult::Error(statusCode, comment); + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio."); + bool hasMul = request.Contains("inputVolumeMul"); if (hasMul && !request.ValidateOptionalNumber("inputVolumeMul", statusCode, comment, 0, 20)) return RequestResult::Error(statusCode, comment); @@ -510,6 +525,9 @@ RequestResult RequestHandler::GetInputAudioBalance(const Request& request) if (!input) return RequestResult::Error(statusCode, comment); + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio."); + json responseData; responseData["inputAudioBalance"] = obs_source_get_balance_value(input); @@ -537,6 +555,9 @@ RequestResult RequestHandler::SetInputAudioBalance(const Request& request) if (!(input && request.ValidateNumber("inputAudioBalance", statusCode, comment, 0.0, 1.0))) return RequestResult::Error(statusCode, comment); + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio."); + float inputAudioBalance = request.RequestData["inputAudioBalance"]; obs_source_set_balance_value(input, inputAudioBalance); @@ -567,6 +588,9 @@ RequestResult RequestHandler::GetInputAudioSyncOffset(const Request& request) if (!input) return RequestResult::Error(statusCode, comment); + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio."); + json responseData; // Offset is stored in nanoseconds in OBS. responseData["inputAudioSyncOffset"] = obs_source_get_sync_offset(input) / 1000000; @@ -595,6 +619,9 @@ RequestResult RequestHandler::SetInputAudioSyncOffset(const Request& request) if (!(input && request.ValidateNumber("inputAudioSyncOffset", statusCode, comment, -950, 20000))) return RequestResult::Error(statusCode, comment); + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio."); + int64_t syncOffset = request.RequestData["inputAudioSyncOffset"]; obs_source_set_sync_offset(input, syncOffset * 1000000); @@ -628,6 +655,9 @@ RequestResult RequestHandler::GetInputAudioMonitorType(const Request& request) if (!input) return RequestResult::Error(statusCode, comment); + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio."); + json responseData; responseData["monitorType"] = Utils::Obs::StringHelper::GetInputMonitorType(input); @@ -655,6 +685,9 @@ RequestResult RequestHandler::SetInputAudioMonitorType(const Request& request) if (!(input && request.ValidateString("monitorType", statusCode, comment))) return RequestResult::Error(statusCode, comment); + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio."); + if (!obs_audio_monitoring_available()) return RequestResult::Error(RequestStatus::InvalidResourceState, "Audio monitoring is not available on this platform."); @@ -674,6 +707,44 @@ RequestResult RequestHandler::SetInputAudioMonitorType(const Request& request) return RequestResult::Success(); } +/** + * Gets the enable state of all audio tracks of an input. + * + * @requestField inputName | String | Name of the input + * + * @responseField inputAudioTracks | Object | Object of audio tracks and associated enable states + * + * @requestType GetInputAudioTracks + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category inputs + */ +RequestResult RequestHandler::GetInputAudioTracks(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment); + if (!input) + return RequestResult::Error(statusCode, comment); + + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio."); + + long long tracks = obs_source_get_audio_mixers(input); + + json inputAudioTracks; + for (long long i = 0; i < MAX_AUDIO_MIXES; i++) { + inputAudioTracks[std::to_string(i + 1)] = (bool)((tracks >> i) & 1); + } + + json responseData; + responseData["inputAudioTracks"] = inputAudioTracks; + + return RequestResult::Success(responseData); +} + /** * Gets the items of a list property from an input's properties. * From 02bcc0ac1b4be8d99ed6455a24b9b4b405a2038f Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Fri, 31 Dec 2021 22:08:43 +0000 Subject: [PATCH 078/128] docs(ci): Update generated docs - 702f88c [skip ci] --- docs/generated/protocol.json | 30 ++++++++++++++++++++++++++++-- docs/generated/protocol.md | 27 ++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 5ca2d0ff..98693497 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -1980,6 +1980,32 @@ ], "responseFields": [] }, + { + "description": "Gets the enable state of all audio tracks of an input.", + "requestType": "GetInputAudioTracks", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "requestFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "inputAudioTracks", + "valueType": "Object", + "valueDescription": "Object of audio tracks and associated enable states" + } + ] + }, { "description": "Gets the items of a list property from an input's properties.\n\nNote: Use this in cases where an input provides a dynamic, selectable list of items. For example, display capture, where it provides a list of available displays.", "requestType": "GetInputPropertiesListPropertyItems", @@ -3794,8 +3820,8 @@ }, { "valueName": "inputAudioTracks", - "valueType": "Array", - "valueDescription": "Array of audio tracks along with their associated enable states" + "valueType": "Object", + "valueDescription": "Object of audio tracks along with their associated enable states" } ] }, diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 23b70108..e76e8d6e 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -1717,7 +1717,7 @@ The audio tracks of an input have changed. | Name | Type | Description | | ---- | :---: | ----------- | | inputName | String | Name of the input | -| inputAudioTracks | Array<Boolean> | Array of audio tracks along with their associated enable states | +| inputAudioTracks | Object | Object of audio tracks along with their associated enable states | --- @@ -2092,6 +2092,7 @@ Studio mode has been enabled or disabled. - [SetInputAudioSyncOffset](#setinputaudiosyncoffset) - [GetInputAudioMonitorType](#getinputaudiomonitortype) - [SetInputAudioMonitorType](#setinputaudiomonitortype) + - [GetInputAudioTracks](#getinputaudiotracks) - [GetInputPropertiesListPropertyItems](#getinputpropertieslistpropertyitems) - [PressInputPropertiesButton](#pressinputpropertiesbutton) - [Transitions](#transitions) @@ -3302,6 +3303,30 @@ Sets the audio monitor type of an input. --- +### GetInputAudioTracks + +Gets the enable state of all audio tracks of an input. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| inputName | String | Name of the input | None | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| inputAudioTracks | Object | Object of audio tracks and associated enable states | + +--- + ### GetInputPropertiesListPropertyItems Gets the items of a list property from an input's properties. From e451a8d6b06d1d9dfa32016bcb10cfad6471f579 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 31 Dec 2021 14:19:19 -0800 Subject: [PATCH 079/128] requesthandler: Use unordered_map for request table Shaves like 0.0005ms off of request time, but still worth noting. --- src/requesthandler/RequestHandler.cpp | 2 +- src/requesthandler/RequestHandler.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index df43364a..ea78ecda 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -19,7 +19,7 @@ with this program. If not, see #include "RequestHandler.h" -const std::map RequestHandler::_handlerMap +const std::unordered_map RequestHandler::_handlerMap { // General {"GetVersion", &RequestHandler::GetVersion}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index e18bb3ee..e1e1def5 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -19,7 +19,7 @@ with this program. If not, see #pragma once -#include +#include #include #include @@ -165,5 +165,5 @@ class RequestHandler { RequestResult OpenInputInteractDialog(const Request&); SessionPtr _session; - static const std::map _handlerMap; + static const std::unordered_map _handlerMap; }; From 35c8a87def8c4492a9e0efae4770d549628130b5 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 31 Dec 2021 14:21:33 -0800 Subject: [PATCH 080/128] requesthandler: Profile requests if PLUGIN_TESTS is enabled --- src/requesthandler/RequestHandler.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index ea78ecda..5bcdc488 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -17,6 +17,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see */ +#ifdef PLUGIN_TESTS +#include +#endif + #include "RequestHandler.h" const std::unordered_map RequestHandler::_handlerMap @@ -150,6 +154,10 @@ RequestHandler::RequestHandler(SessionPtr session) : RequestResult RequestHandler::ProcessRequest(const Request& request) { +#ifdef PLUGIN_TESTS + ScopeProfiler prof{"obs_websocket_request_processing"}; +#endif + if (!request.RequestData.is_object() && !request.RequestData.is_null()) return RequestResult::Error(RequestStatus::InvalidRequestFieldType, "Your request data is not an object."); From 043444cad58c8efdcea755d21f981f505627ebe8 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 31 Dec 2021 14:26:57 -0800 Subject: [PATCH 081/128] workflows: Enable plugin tests on nightly linux builds --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 50e63703..d6fdce27 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -316,7 +316,7 @@ jobs: if [ "${{ env.GIT_TAG }}" ] ; then \ cmake -DLIBOBS_INCLUDE_DIR=${{ github.workspace }}/obs-studio/libobs -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=TRUE -DOBS_WEBSOCKET_VERSION_SUFFIX="${{ env.CMAKE_VERSION_SUFFIX }}" -DCMAKE_BUILD_TYPE=Release .. ; \ else \ - cmake -DLIBOBS_INCLUDE_DIR=${{ github.workspace }}/obs-studio/libobs -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=TRUE -DOBS_WEBSOCKET_VERSION_SUFFIX="${{ env.CMAKE_VERSION_SUFFIX }}" .. ; \ + cmake -DLIBOBS_INCLUDE_DIR=${{ github.workspace }}/obs-studio/libobs -DCMAKE_INSTALL_PREFIX=/usr -DUSE_UBUNTU_FIX=TRUE -DOBS_WEBSOCKET_VERSION_SUFFIX="${{ env.CMAKE_VERSION_SUFFIX }}" -DPLUGIN_TESTS=TRUE .. ; \ fi - name: 'Build obs-websocket' working-directory: ${{ github.workspace }}/obs-websocket From 506a9167c390bb1f81d0d8beddb24e1970d292e0 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 31 Dec 2021 15:26:38 -0800 Subject: [PATCH 082/128] requesthandler: Add SetInputAudioTracks --- src/requesthandler/RequestHandler.cpp | 1 + src/requesthandler/RequestHandler.h | 1 + src/requesthandler/RequestHandler_Inputs.cpp | 53 +++++++++++++++++++- src/utils/Json.cpp | 4 +- src/utils/Json.h | 5 +- 5 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 5bcdc488..fa70c6e0 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -89,6 +89,7 @@ const std::unordered_map RequestHandler::_han {"GetInputAudioMonitorType", &RequestHandler::GetInputAudioMonitorType}, {"SetInputAudioMonitorType", &RequestHandler::SetInputAudioMonitorType}, {"GetInputAudioTracks", &RequestHandler::GetInputAudioTracks}, + {"SetInputAudioTracks", &RequestHandler::SetInputAudioTracks}, {"GetInputPropertiesListPropertyItems", &RequestHandler::GetInputPropertiesListPropertyItems}, {"PressInputPropertiesButton", &RequestHandler::PressInputPropertiesButton}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index e1e1def5..6807af4d 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -107,6 +107,7 @@ class RequestHandler { RequestResult GetInputAudioMonitorType(const Request&); RequestResult SetInputAudioMonitorType(const Request&); RequestResult GetInputAudioTracks(const Request&); + RequestResult SetInputAudioTracks(const Request&); RequestResult GetInputPropertiesListPropertyItems(const Request&); RequestResult PressInputPropertiesButton(const Request&); diff --git a/src/requesthandler/RequestHandler_Inputs.cpp b/src/requesthandler/RequestHandler_Inputs.cpp index 75c1d03f..d8bf11e0 100644 --- a/src/requesthandler/RequestHandler_Inputs.cpp +++ b/src/requesthandler/RequestHandler_Inputs.cpp @@ -715,7 +715,7 @@ RequestResult RequestHandler::SetInputAudioMonitorType(const Request& request) * @responseField inputAudioTracks | Object | Object of audio tracks and associated enable states * * @requestType GetInputAudioTracks - * @complexity 3 + * @complexity 2 * @rpcVersion -1 * @initialVersion 5.0.0 * @api requests @@ -745,6 +745,57 @@ RequestResult RequestHandler::GetInputAudioTracks(const Request& request) return RequestResult::Success(responseData); } +/** + * Sets the enable state of audio tracks of an input. + * + * @requestField inputName | String | Name of the input + * @requestField inputAudioTracks | Object | Track settings to apply + * + * @requestType SetInputAudioTracks + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category inputs + */ +RequestResult RequestHandler::SetInputAudioTracks(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSourceAutoRelease input = request.ValidateInput("inputName", statusCode, comment); + if (!input || !request.ValidateObject("inputAudioTracks", statusCode, comment)) + return RequestResult::Error(statusCode, comment); + + if (!(obs_source_get_output_flags(input) & OBS_SOURCE_AUDIO)) + return RequestResult::Error(RequestStatus::InvalidResourceState, "The specified input does not support audio."); + + json inputAudioTracks = request.RequestData["inputAudioTracks"]; + + long long mixers = obs_source_get_audio_mixers(input); + + for (long long i = 0; i < MAX_AUDIO_MIXES; i++) { + std::string track = std::to_string(i + 1); + + if (!Utils::Json::Contains(inputAudioTracks, track)) + continue; + + if (!inputAudioTracks[track].is_boolean()) + return RequestResult::Error(RequestStatus::InvalidRequestFieldType, "The value of one of your tracks is not a boolean."); + + bool enabled = inputAudioTracks[track]; + + if (enabled) + mixers |= (1 << i); + else + mixers &= ~(1 << i); + } + + // Decided that checking if tracks have actually changed is unnecessary + obs_source_set_audio_mixers(input, mixers); + + return RequestResult::Success(); +} + /** * Gets the items of a list property from an input's properties. * diff --git a/src/utils/Json.cpp b/src/utils/Json.cpp index 65a0c7c0..114f3afe 100644 --- a/src/utils/Json.cpp +++ b/src/utils/Json.cpp @@ -21,7 +21,7 @@ with this program. If not, see #include "Platform.h" #include "../plugin-macros.generated.h" -bool Utils::Json::JsonArrayIsValidObsArray(json j) +bool Utils::Json::JsonArrayIsValidObsArray(const json &j) { for (auto it : j) { if (!it.is_object()) @@ -191,7 +191,7 @@ bool Utils::Json::GetJsonFileContent(std::string fileName, json &content) return true; } -bool Utils::Json::SetJsonFileContent(std::string fileName, json content, bool createNew) +bool Utils::Json::SetJsonFileContent(std::string fileName, const json &content, bool createNew) { std::string textContent = content.dump(2); return Utils::Platform::SetTextFileContent(fileName, textContent, createNew); diff --git a/src/utils/Json.h b/src/utils/Json.h index 1f6aaef8..f2b88f2b 100644 --- a/src/utils/Json.h +++ b/src/utils/Json.h @@ -27,10 +27,11 @@ using json = nlohmann::json; namespace Utils { namespace Json { - bool JsonArrayIsValidObsArray(json j); + bool JsonArrayIsValidObsArray(const json &j); obs_data_t *JsonToObsData(json j); json ObsDataToJson(obs_data_t *d, bool includeDefault = false); bool GetJsonFileContent(std::string fileName, json &content); - bool SetJsonFileContent(std::string fileName, json content, bool createNew = true); + bool SetJsonFileContent(std::string fileName, const json &content, bool createNew = true); + static inline bool Contains(const json &j, std::string key) { return j.contains(key) && !j[key].is_null(); } } } From c0308d6ce1639f894ed6d71a95ad4fcc31cafc5d Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Fri, 31 Dec 2021 23:27:15 +0000 Subject: [PATCH 083/128] docs(ci): Update generated docs - 506a916 [skip ci] --- docs/generated/protocol.json | 30 +++++++++++++++++++++++++++++- docs/generated/protocol.md | 21 ++++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 98693497..f652f29e 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -1983,7 +1983,7 @@ { "description": "Gets the enable state of all audio tracks of an input.", "requestType": "GetInputAudioTracks", - "complexity": 3, + "complexity": 2, "rpcVersion": "1", "deprecated": false, "initialVersion": "5.0.0", @@ -2006,6 +2006,34 @@ } ] }, + { + "description": "Sets the enable state of audio tracks of an input.", + "requestType": "SetInputAudioTracks", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "requestFields": [ + { + "valueName": "inputName", + "valueType": "String", + "valueDescription": "Name of the input", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "inputAudioTracks", + "valueType": "Object", + "valueDescription": "Track settings to apply", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, { "description": "Gets the items of a list property from an input's properties.\n\nNote: Use this in cases where an input provides a dynamic, selectable list of items. For example, display capture, where it provides a list of available displays.", "requestType": "GetInputPropertiesListPropertyItems", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index e76e8d6e..dca81e7c 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -2093,6 +2093,7 @@ Studio mode has been enabled or disabled. - [GetInputAudioMonitorType](#getinputaudiomonitortype) - [SetInputAudioMonitorType](#setinputaudiomonitortype) - [GetInputAudioTracks](#getinputaudiotracks) + - [SetInputAudioTracks](#setinputaudiotracks) - [GetInputPropertiesListPropertyItems](#getinputpropertieslistpropertyitems) - [PressInputPropertiesButton](#pressinputpropertiesbutton) - [Transitions](#transitions) @@ -3307,7 +3308,7 @@ Sets the audio monitor type of an input. Gets the enable state of all audio tracks of an input. -- Complexity Rating: `3/5` +- Complexity Rating: `2/5` - Latest Supported RPC Version: `1` - Added in v5.0.0 @@ -3327,6 +3328,24 @@ Gets the enable state of all audio tracks of an input. --- +### SetInputAudioTracks + +Sets the enable state of audio tracks of an input. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| inputName | String | Name of the input | None | N/A | +| inputAudioTracks | Object | Track settings to apply | None | N/A | + +--- + ### GetInputPropertiesListPropertyItems Gets the items of a list property from an input's properties. From 24e43d027640dd25c83bf704a24b23667ff137f2 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 31 Dec 2021 16:49:18 -0800 Subject: [PATCH 084/128] requesthandler: Add GetSpecialInputs --- src/requesthandler/RequestHandler.cpp | 1 + src/requesthandler/RequestHandler.h | 1 + src/requesthandler/RequestHandler_Inputs.cpp | 37 ++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index fa70c6e0..b200fd9c 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -71,6 +71,7 @@ const std::unordered_map RequestHandler::_han // Inputs {"GetInputList", &RequestHandler::GetInputList}, {"GetInputKindList", &RequestHandler::GetInputKindList}, + {"GetSpecialInputs", &RequestHandler::GetSpecialInputs}, {"CreateInput", &RequestHandler::CreateInput}, {"RemoveInput", &RequestHandler::RemoveInput}, {"SetInputName", &RequestHandler::SetInputName}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 6807af4d..d108feb0 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -89,6 +89,7 @@ class RequestHandler { // Inputs RequestResult GetInputList(const Request&); RequestResult GetInputKindList(const Request&); + RequestResult GetSpecialInputs(const Request&); RequestResult CreateInput(const Request&); RequestResult RemoveInput(const Request&); RequestResult SetInputName(const Request&); diff --git a/src/requesthandler/RequestHandler_Inputs.cpp b/src/requesthandler/RequestHandler_Inputs.cpp index d8bf11e0..a1a90e1a 100644 --- a/src/requesthandler/RequestHandler_Inputs.cpp +++ b/src/requesthandler/RequestHandler_Inputs.cpp @@ -83,6 +83,43 @@ RequestResult RequestHandler::GetInputKindList(const Request& request) return RequestResult::Success(responseData); } +/** + * Gets the names of all special inputs. + * + * @responseField desktop1 | String | Name of the Desktop Audio input + * @responseField desktop2 | String | Name of the Desktop Audio 2 input + * @responseField mic1 | String | Name of the Mic/Auxiliary Audio input + * @responseField mic2 | String | Name of the Mic/Auxiliary Audio 2 input + * @responseField mic3 | String | Name of the Mic/Auxiliary Audio 3 input + * @responseField mic4 | String | Name of the Mic/Auxiliary Audio 4 input + * + * @requestType GetSpecialInputs + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category inputs + */ +RequestResult RequestHandler::GetSpecialInputs(const Request&) +{ + json responseData; + + std::vector channels = {"desktop1", "desktop2", "mic1", "mic2", "mic3", "mic4"}; + + size_t channelId = 1; + for (auto &channel : channels) { + OBSSourceAutoRelease input = obs_get_output_source(channelId); + if (!input) + responseData[channel] = nullptr; + else + responseData[channel] = obs_source_get_name(input); + + channelId++; + } + + return RequestResult::Success(responseData); +} + /** * Creates a new input, adding it as a scene item to the specified scene. * From fe646207311b89681de20b8cda189d8fb90fce79 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 31 Dec 2021 18:05:05 -0800 Subject: [PATCH 085/128] requesthandler: Add scene item blend mode requests --- src/requesthandler/RequestHandler.cpp | 2 + src/requesthandler/RequestHandler.h | 2 + .../RequestHandler_SceneItems.cpp | 80 +++++++++++++++++++ src/utils/Obs.h | 2 + src/utils/Obs_EnumHelper.cpp | 39 ++++++--- src/utils/Obs_StringHelper.cpp | 14 ++++ 6 files changed, 126 insertions(+), 13 deletions(-) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index b200fd9c..26818a4c 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -118,6 +118,8 @@ const std::unordered_map RequestHandler::_han {"SetSceneItemLocked", &RequestHandler::SetSceneItemLocked}, {"GetSceneItemIndex", &RequestHandler::GetSceneItemIndex}, {"SetSceneItemIndex", &RequestHandler::SetSceneItemIndex}, + {"GetSceneItemBlendMode", &RequestHandler::GetSceneItemBlendMode}, + {"SetSceneItemBlendMode", &RequestHandler::SetSceneItemBlendMode}, // Stream {"GetStreamStatus", &RequestHandler::GetStreamStatus}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index d108feb0..d411f59b 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -136,6 +136,8 @@ class RequestHandler { RequestResult SetSceneItemLocked(const Request&); RequestResult GetSceneItemIndex(const Request&); RequestResult SetSceneItemIndex(const Request&); + RequestResult GetSceneItemBlendMode(const Request&); + RequestResult SetSceneItemBlendMode(const Request&); // Stream RequestResult GetStreamStatus(const Request&); diff --git a/src/requesthandler/RequestHandler_SceneItems.cpp b/src/requesthandler/RequestHandler_SceneItems.cpp index 50ea294a..c47621f9 100644 --- a/src/requesthandler/RequestHandler_SceneItems.cpp +++ b/src/requesthandler/RequestHandler_SceneItems.cpp @@ -631,3 +631,83 @@ RequestResult RequestHandler::SetSceneItemIndex(const Request& request) return RequestResult::Success(); } + +/** + * Gets the blend mode of a scene item. + * + * Blend modes: + * + * - `OBS_BLEND_NORMAL` + * - `OBS_BLEND_ADDITIVE` + * - `OBS_BLEND_SUBTRACT` + * - `OBS_BLEND_SCREEN` + * - `OBS_BLEND_MULTIPLY` + * - `OBS_BLEND_LIGHTEN` + * - `OBS_BLEND_DARKEN` + * + * Scenes and Groups + * + * @requestField sceneName | String | Name of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * + * @responseField sceneItemBlendMode | String | Current blend mode + * + * @requestType GetSceneItemBlendMode + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ +RequestResult RequestHandler::GetSceneItemBlendMode(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSceneItemAutoRelease sceneItem = request.ValidateSceneItem("sceneName", "sceneItemId", statusCode, comment, OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP); + if (!sceneItem) + return RequestResult::Error(statusCode, comment); + + auto blendMode = obs_sceneitem_get_blending_mode(sceneItem); + + json responseData; + responseData["sceneItemBlendMode"] = Utils::Obs::StringHelper::GetSceneItemBlendMode(blendMode); + + return RequestResult::Success(responseData); +} + + + +/** + * Sets the blend mode of a scene item. + * + * Scenes and Groups + * + * @requestField sceneName | String | Name of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * @requestField sceneItemBlendMode | String | New blend mode + * + * @requestType SetSceneItemBlendMode + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scene items + */ +RequestResult RequestHandler::SetSceneItemBlendMode(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSceneItemAutoRelease sceneItem = request.ValidateSceneItem("sceneName", "sceneItemId", statusCode, comment, OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP); + if (!(sceneItem && request.ValidateString("sceneItemBlendMode", statusCode, comment))) + return RequestResult::Error(statusCode, comment); + + std::string blendModeString = request.RequestData["sceneItemBlendMode"]; + + auto blendMode = Utils::Obs::EnumHelper::GetSceneItemBlendMode(blendModeString); + if (blendMode == OBS_BLEND_NORMAL && blendModeString != "OBS_BLEND_NORMAL") + return RequestResult::Error(RequestStatus::InvalidRequestField, "The field sceneItemBlendMode has an invalid value."); + + obs_sceneitem_set_blending_mode(sceneItem, blendMode); + + return RequestResult::Success(); +} diff --git a/src/utils/Obs.h b/src/utils/Obs.h index 460d3113..fb5e0899 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -163,6 +163,7 @@ namespace Utils { std::string GetMediaInputState(obs_source_t *input); std::string GetLastReplayBufferFilePath(); std::string GetSceneItemBoundsType(enum obs_bounds_type type); + std::string GetSceneItemBlendMode(enum obs_blending_type mode); std::string DurationToTimecode(uint64_t); std::string GetOutputState(ObsOutputState state); } @@ -170,6 +171,7 @@ namespace Utils { namespace EnumHelper { enum obs_bounds_type GetSceneItemBoundsType(std::string boundsType); enum ObsMediaInputAction GetMediaInputAction(std::string mediaAction); + enum obs_blending_type GetSceneItemBlendMode(std::string mode); } namespace NumberHelper { diff --git a/src/utils/Obs_EnumHelper.cpp b/src/utils/Obs_EnumHelper.cpp index b0c21aa4..887c33d1 100644 --- a/src/utils/Obs_EnumHelper.cpp +++ b/src/utils/Obs_EnumHelper.cpp @@ -23,25 +23,38 @@ with this program. If not, see enum obs_bounds_type Utils::Obs::EnumHelper::GetSceneItemBoundsType(std::string boundsType) { - RET_COMPARE(boundsType, OBS_BOUNDS_NONE); - RET_COMPARE(boundsType, OBS_BOUNDS_STRETCH); - RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_INNER); - RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_OUTER); - RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_TO_WIDTH); - RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_TO_HEIGHT); - RET_COMPARE(boundsType, OBS_BOUNDS_MAX_ONLY); + RET_COMPARE(boundsType, OBS_BOUNDS_NONE) + RET_COMPARE(boundsType, OBS_BOUNDS_STRETCH) + RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_INNER) + RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_OUTER) + RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_TO_WIDTH) + RET_COMPARE(boundsType, OBS_BOUNDS_SCALE_TO_HEIGHT) + RET_COMPARE(boundsType, OBS_BOUNDS_MAX_ONLY) return OBS_BOUNDS_NONE; } enum ObsMediaInputAction Utils::Obs::EnumHelper::GetMediaInputAction(std::string mediaAction) { - RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY); - RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE); - RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP); - RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART); - RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT); - RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS); + RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY) + RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE) + RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP) + RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART) + RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT) + RET_COMPARE(mediaAction, OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS) return OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE; } + +enum obs_blending_type Utils::Obs::EnumHelper::GetSceneItemBlendMode(std::string mode) +{ + RET_COMPARE(mode, OBS_BLEND_NORMAL) + RET_COMPARE(mode, OBS_BLEND_ADDITIVE) + RET_COMPARE(mode, OBS_BLEND_SUBTRACT) + RET_COMPARE(mode, OBS_BLEND_SCREEN) + RET_COMPARE(mode, OBS_BLEND_MULTIPLY) + RET_COMPARE(mode, OBS_BLEND_LIGHTEN) + RET_COMPARE(mode, OBS_BLEND_DARKEN) + + return OBS_BLEND_NORMAL; +} diff --git a/src/utils/Obs_StringHelper.cpp b/src/utils/Obs_StringHelper.cpp index 8b552abb..ef040bf1 100644 --- a/src/utils/Obs_StringHelper.cpp +++ b/src/utils/Obs_StringHelper.cpp @@ -142,6 +142,20 @@ std::string Utils::Obs::StringHelper::GetSceneItemBoundsType(enum obs_bounds_typ } } +std::string Utils::Obs::StringHelper::GetSceneItemBlendMode(enum obs_blending_type mode) +{ + switch (mode) { + default: + CASE(OBS_BLEND_NORMAL) + CASE(OBS_BLEND_ADDITIVE) + CASE(OBS_BLEND_SUBTRACT) + CASE(OBS_BLEND_SCREEN) + CASE(OBS_BLEND_MULTIPLY) + CASE(OBS_BLEND_LIGHTEN) + CASE(OBS_BLEND_DARKEN) + } +} + std::string Utils::Obs::StringHelper::DurationToTimecode(uint64_t ms) { uint64_t secs = ms / 1000ULL; From 8f2d266decfed1c5095718238aeb917a581fbff2 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Sat, 1 Jan 2022 02:06:35 +0000 Subject: [PATCH 086/128] docs(ci): Update generated docs - fe64620 [skip ci] --- docs/generated/protocol.json | 112 +++++++++++++++++++++++++++++++++++ docs/generated/protocol.md | 83 ++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index f652f29e..8139e7c7 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -1472,6 +1472,48 @@ } ] }, + { + "description": "Gets the names of all special inputs.", + "requestType": "GetSpecialInputs", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "inputs", + "requestFields": [], + "responseFields": [ + { + "valueName": "desktop1", + "valueType": "String", + "valueDescription": "Name of the Desktop Audio input" + }, + { + "valueName": "desktop2", + "valueType": "String", + "valueDescription": "Name of the Desktop Audio 2 input" + }, + { + "valueName": "mic1", + "valueType": "String", + "valueDescription": "Name of the Mic/Auxiliary Audio input" + }, + { + "valueName": "mic2", + "valueType": "String", + "valueDescription": "Name of the Mic/Auxiliary Audio 2 input" + }, + { + "valueName": "mic3", + "valueType": "String", + "valueDescription": "Name of the Mic/Auxiliary Audio 3 input" + }, + { + "valueName": "mic4", + "valueType": "String", + "valueDescription": "Name of the Mic/Auxiliary Audio 4 input" + } + ] + }, { "description": "Creates a new input, adding it as a scene item to the specified scene.", "requestType": "CreateInput", @@ -2814,6 +2856,76 @@ ], "responseFields": [] }, + { + "description": "Gets the blend mode of a scene item.\n\nBlend modes:\n\n- `OBS_BLEND_NORMAL`\n- `OBS_BLEND_ADDITIVE`\n- `OBS_BLEND_SUBTRACT`\n- `OBS_BLEND_SCREEN`\n- `OBS_BLEND_MULTIPLY`\n- `OBS_BLEND_LIGHTEN`\n- `OBS_BLEND_DARKEN`\n\nScenes and Groups", + "requestType": "GetSceneItemBlendMode", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "sceneItemBlendMode", + "valueType": "String", + "valueDescription": "Current blend mode" + } + ] + }, + { + "description": "Sets the blend mode of a scene item.\n\nScenes and Groups", + "requestType": "SetSceneItemBlendMode", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "sceneItemBlendMode", + "valueType": "String", + "valueDescription": "New blend mode", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, { "description": "Gets an array of all scenes in OBS.", "requestType": "GetSceneList", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index dca81e7c..273e2364 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -2075,6 +2075,7 @@ Studio mode has been enabled or disabled. - [Inputs](#inputs-1) - [GetInputList](#getinputlist) - [GetInputKindList](#getinputkindlist) + - [GetSpecialInputs](#getspecialinputs) - [CreateInput](#createinput) - [RemoveInput](#removeinput) - [SetInputName](#setinputname) @@ -2119,6 +2120,8 @@ Studio mode has been enabled or disabled. - [SetSceneItemLocked](#setsceneitemlocked) - [GetSceneItemIndex](#getsceneitemindex) - [SetSceneItemIndex](#setsceneitemindex) + - [GetSceneItemBlendMode](#getsceneitemblendmode) + - [SetSceneItemBlendMode](#setsceneitemblendmode) - [Stream](#stream) - [GetStreamStatus](#getstreamstatus) - [ToggleStream](#togglestream) @@ -2926,6 +2929,28 @@ Gets an array of all available input kinds in OBS. --- +### GetSpecialInputs + +Gets the names of all special inputs. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| desktop1 | String | Name of the Desktop Audio input | +| desktop2 | String | Name of the Desktop Audio 2 input | +| mic1 | String | Name of the Mic/Auxiliary Audio input | +| mic2 | String | Name of the Mic/Auxiliary Audio 2 input | +| mic3 | String | Name of the Mic/Auxiliary Audio 3 input | +| mic4 | String | Name of the Mic/Auxiliary Audio 4 input | + +--- + ### CreateInput Creates a new input, adding it as a scene item to the specified scene. @@ -3866,6 +3891,64 @@ Scenes and Groups | sceneItemId | Number | Numeric ID of the scene item | >= 0 | N/A | | sceneItemIndex | Number | New index position of the scene item | >= 0 | N/A | +--- + +### GetSceneItemBlendMode + +Gets the blend mode of a scene item. + +Blend modes: + +- `OBS_BLEND_NORMAL` +- `OBS_BLEND_ADDITIVE` +- `OBS_BLEND_SUBTRACT` +- `OBS_BLEND_SCREEN` +- `OBS_BLEND_MULTIPLY` +- `OBS_BLEND_LIGHTEN` +- `OBS_BLEND_DARKEN` + +Scenes and Groups + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene the item is in | None | N/A | +| sceneItemId | Number | Numeric ID of the scene item | >= 0 | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneItemBlendMode | String | Current blend mode | + +--- + +### SetSceneItemBlendMode + +Sets the blend mode of a scene item. + +Scenes and Groups + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene the item is in | None | N/A | +| sceneItemId | Number | Numeric ID of the scene item | >= 0 | N/A | +| sceneItemBlendMode | String | New blend mode | None | N/A | + ## Stream From 6a2d5968adf76f6acc3631bd77c282b2da27cb87 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sat, 1 Jan 2022 17:43:26 -0800 Subject: [PATCH 087/128] requesthandler: Add private source settings get/set requests It was requested via Discord to be able to modify the private settings of any private source, since that functionality is used by some client software to store stateful data. As private settings are in territory that no normal user should ever tread into, these requests will be left undocumented. --- src/requesthandler/RequestHandler.cpp | 2 ++ src/requesthandler/RequestHandler.h | 2 ++ .../RequestHandler_SceneItems.cpp | 2 -- src/requesthandler/RequestHandler_Sources.cpp | 36 +++++++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 26818a4c..e3ba574a 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -56,6 +56,8 @@ const std::unordered_map RequestHandler::_han {"GetSourceActive", &RequestHandler::GetSourceActive}, {"GetSourceScreenshot", &RequestHandler::GetSourceScreenshot}, {"SaveSourceScreenshot", &RequestHandler::SaveSourceScreenshot}, + {"GetSourcePrivateSettings", &RequestHandler::GetSourcePrivateSettings}, + {"SetSourcePrivateSettings", &RequestHandler::SetSourcePrivateSettings}, // Scenes {"GetSceneList", &RequestHandler::GetSceneList}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index d411f59b..40967ca0 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -74,6 +74,8 @@ class RequestHandler { RequestResult GetSourceActive(const Request&); RequestResult GetSourceScreenshot(const Request&); RequestResult SaveSourceScreenshot(const Request&); + RequestResult GetSourcePrivateSettings(const Request&); + RequestResult SetSourcePrivateSettings(const Request&); // Scenes RequestResult GetSceneList(const Request&); diff --git a/src/requesthandler/RequestHandler_SceneItems.cpp b/src/requesthandler/RequestHandler_SceneItems.cpp index c47621f9..4f25c7b2 100644 --- a/src/requesthandler/RequestHandler_SceneItems.cpp +++ b/src/requesthandler/RequestHandler_SceneItems.cpp @@ -675,8 +675,6 @@ RequestResult RequestHandler::GetSceneItemBlendMode(const Request& request) return RequestResult::Success(responseData); } - - /** * Sets the blend mode of a scene item. * diff --git a/src/requesthandler/RequestHandler_Sources.cpp b/src/requesthandler/RequestHandler_Sources.cpp index 53bee7ef..584a4143 100644 --- a/src/requesthandler/RequestHandler_Sources.cpp +++ b/src/requesthandler/RequestHandler_Sources.cpp @@ -312,3 +312,39 @@ RequestResult RequestHandler::SaveSourceScreenshot(const Request& request) return RequestResult::Success(); } + +// Intentionally undocumented +RequestResult RequestHandler::GetSourcePrivateSettings(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment); + if (!source) + return RequestResult::Error(statusCode, comment); + + OBSDataAutoRelease privateSettings = obs_source_get_private_settings(source); + + json responseData; + responseData["sourceSettings"] = Utils::Json::ObsDataToJson(privateSettings); + + return RequestResult::Success(responseData); +} + +// Intentionally undocumented +RequestResult RequestHandler::SetSourcePrivateSettings(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment); + if (!source || !request.ValidateObject("sourceSettings", statusCode, comment)) + return RequestResult::Error(statusCode, comment); + + OBSDataAutoRelease privateSettings = obs_source_get_private_settings(source); + + OBSDataAutoRelease newSettings = Utils::Json::JsonToObsData(request.RequestData["sourceSettings"]); + + // Always overlays to prevent destroying internal source data unintentionally + obs_data_apply(privateSettings, newSettings); + + return RequestResult::Success(); +} From 6035294339e7f5106a2ac63719e94c35b1166acf Mon Sep 17 00:00:00 2001 From: tt2468 Date: Mon, 3 Jan 2022 13:54:27 -0800 Subject: [PATCH 088/128] requesthandler: Add GetSourceFilter --- src/requesthandler/RequestHandler.cpp | 3 ++ src/requesthandler/RequestHandler.h | 3 ++ src/requesthandler/RequestHandler_Filters.cpp | 37 +++++++++++++++++++ src/requesthandler/rpc/Request.cpp | 21 +++++++++++ src/requesthandler/rpc/Request.h | 7 ++++ src/utils/Obs.h | 1 + src/utils/Obs_NumberHelper.cpp | 25 +++++++++++++ 7 files changed, 97 insertions(+) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index e3ba574a..b93cf69e 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -105,6 +105,9 @@ const std::unordered_map RequestHandler::_han {"SetCurrentSceneTransitionSettings", &RequestHandler::SetCurrentSceneTransitionSettings}, {"TriggerStudioModeTransition", &RequestHandler::TriggerStudioModeTransition}, + // Filters + {"GetSourceFilter", &RequestHandler::GetSourceFilter}, + // Scene Items {"GetSceneItemList", &RequestHandler::GetSceneItemList}, {"GetGroupSceneItemList", &RequestHandler::GetGroupSceneItemList}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 40967ca0..7e920d19 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -123,6 +123,9 @@ class RequestHandler { RequestResult SetCurrentSceneTransitionSettings(const Request&); RequestResult TriggerStudioModeTransition(const Request&); + // Filters + RequestResult GetSourceFilter(const Request&); + // Scene Items RequestResult GetSceneItemList(const Request&); RequestResult GetGroupSceneItemList(const Request&); diff --git a/src/requesthandler/RequestHandler_Filters.cpp b/src/requesthandler/RequestHandler_Filters.cpp index b09e414c..7bb6e0e0 100644 --- a/src/requesthandler/RequestHandler_Filters.cpp +++ b/src/requesthandler/RequestHandler_Filters.cpp @@ -18,3 +18,40 @@ with this program. If not, see */ #include "RequestHandler.h" + +/** + * Gets the info for a specific source filter. + * + * @requestField sourceName | String | Name of the source + * @requestField filterName | String | Name of the filter + * + * @responseField filterEnabled | Boolean | Whether the filter is enabled + * @responseField filterIndex | Number | Index of the filter in the list, beginning at 0 + * @responseField filterKind | String | The kind of filter + * @responseField filterSettings | Object | Settings object associated with the filter + * + * @requestType GetSourceFilter + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category filters + */ +RequestResult RequestHandler::GetSourceFilter(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); + if (!pair.filter) + return RequestResult::Error(statusCode, comment); + + json responseData; + responseData["filterEnabled"] = obs_source_enabled(pair.filter); + responseData["filterIndex"] = Utils::Obs::NumberHelper::GetSourceFilterIndex(pair.source, pair.filter); // Todo: Use `GetSourceFilterlist` to select this filter maybe + responseData["filterKind"] = obs_source_get_id(pair.filter); + + OBSDataAutoRelease filterSettings = obs_source_get_settings(pair.filter); + responseData["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings); + + return RequestResult::Success(responseData); +} diff --git a/src/requesthandler/rpc/Request.cpp b/src/requesthandler/rpc/Request.cpp index 418268e3..cd55abeb 100644 --- a/src/requesthandler/rpc/Request.cpp +++ b/src/requesthandler/rpc/Request.cpp @@ -295,6 +295,27 @@ obs_source_t *Request::ValidateInput(const std::string &keyName, RequestStatus:: return ret; } +FilterPair Request::ValidateFilter(const std::string &sourceKeyName, const std::string &filterKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const +{ + obs_source_t *source = ValidateSource(sourceKeyName, statusCode, comment); + if (!source) + return FilterPair{source, nullptr}; + + if (!ValidateString(filterKeyName, statusCode, comment)) + return FilterPair{source, nullptr}; + + std::string filterName = RequestData[filterKeyName]; + + obs_source_t *filter = obs_source_get_filter_by_name(source, filterName.c_str()); + if (!filter) { + statusCode = RequestStatus::ResourceNotFound; + comment = std::string("No filter was found in the source `") + RequestData[sourceKeyName].get() + "` with the name `" + filterName + "`."; + return FilterPair{source, nullptr}; + } + + return FilterPair{source, filter}; +} + obs_sceneitem_t *Request::ValidateSceneItem(const std::string &sceneKeyName, const std::string &sceneItemIdKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter) const { OBSSceneAutoRelease scene = ValidateScene2(sceneKeyName, statusCode, comment, filter); diff --git a/src/requesthandler/rpc/Request.h b/src/requesthandler/rpc/Request.h index 03f6fb21..0f44308b 100644 --- a/src/requesthandler/rpc/Request.h +++ b/src/requesthandler/rpc/Request.h @@ -29,6 +29,12 @@ enum ObsWebSocketSceneFilter { OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP, }; +// We return filters as a pair because `obs_filter_get_parent()` is apparently volatile +struct FilterPair { + OBSSourceAutoRelease source; + OBSSourceAutoRelease filter; +}; + struct Request { Request(const std::string &requestType, const json &requestData = nullptr, const RequestBatchExecutionType::RequestBatchExecutionType executionType = RequestBatchExecutionType::None); @@ -53,6 +59,7 @@ struct Request obs_source_t *ValidateScene(const std::string &keyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter = OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY) const; obs_scene_t *ValidateScene2(const std::string &keyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter = OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY) const; obs_source_t *ValidateInput(const std::string &keyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const; + FilterPair ValidateFilter(const std::string &sourceKeyName, const std::string &filterKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment) const; obs_sceneitem_t *ValidateSceneItem(const std::string &sceneKeyName, const std::string &sceneItemIdKeyName, RequestStatus::RequestStatus &statusCode, std::string &comment, const ObsWebSocketSceneFilter filter = OBS_WEBSOCKET_SCENE_FILTER_SCENE_ONLY) const; std::string RequestType; diff --git a/src/utils/Obs.h b/src/utils/Obs.h index fb5e0899..f0d1baff 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -177,6 +177,7 @@ namespace Utils { namespace NumberHelper { uint64_t GetOutputDuration(obs_output_t *output); size_t GetSceneCount(); + size_t GetSourceFilterIndex(obs_source_t *source, obs_source_t *filter); } namespace ArrayHelper { diff --git a/src/utils/Obs_NumberHelper.cpp b/src/utils/Obs_NumberHelper.cpp index e7c22c9b..a510c783 100644 --- a/src/utils/Obs_NumberHelper.cpp +++ b/src/utils/Obs_NumberHelper.cpp @@ -52,3 +52,28 @@ size_t Utils::Obs::NumberHelper::GetSceneCount() return ret; } + +size_t Utils::Obs::NumberHelper::GetSourceFilterIndex(obs_source_t *source, obs_source_t *filter) +{ + struct FilterSearch { + obs_source_t *filter; + bool found; + size_t index; + }; + + auto search = [](obs_source_t *, obs_source_t *filter, void *priv_data) { + auto filterSearch = static_cast(priv_data); + + if (filter == filterSearch->filter) + filterSearch->found = true; + + if (!filterSearch->found) + filterSearch->index++; + }; + + FilterSearch filterSearch = {filter, 0, 0}; + + obs_source_enum_filters(source, search, &filterSearch); + + return filterSearch.index; +} From db9f4b24df6aedc30be9fb0a9437ac0ac5bca008 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Mon, 3 Jan 2022 21:54:54 +0000 Subject: [PATCH 089/128] docs(ci): Update generated docs - 6035294 [skip ci] --- docs/generated/protocol.json | 49 ++++++++++++++++++++++++++++++++++++ docs/generated/protocol.md | 31 +++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 8139e7c7..e02d88b3 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -1129,6 +1129,55 @@ ], "responseFields": [] }, + { + "description": "Gets the info for a specific source filter.", + "requestType": "GetSourceFilter", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "filters", + "requestFields": [ + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the source", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "filterName", + "valueType": "String", + "valueDescription": "Name of the filter", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "filterEnabled", + "valueType": "Boolean", + "valueDescription": "Whether the filter is enabled" + }, + { + "valueName": "filterIndex", + "valueType": "Number", + "valueDescription": "Index of the filter in the list, beginning at 0" + }, + { + "valueName": "filterKind", + "valueType": "String", + "valueDescription": "The kind of filter" + }, + { + "valueName": "filterSettings", + "valueType": "Object", + "valueDescription": "Settings object associated with the filter" + } + ] + }, { "description": "Gets data about the current plugin and RPC version.", "requestType": "GetVersion", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 273e2364..af13f0c4 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -2105,6 +2105,8 @@ Studio mode has been enabled or disabled. - [SetCurrentSceneTransitionDuration](#setcurrentscenetransitionduration) - [SetCurrentSceneTransitionSettings](#setcurrentscenetransitionsettings) - [TriggerStudioModeTransition](#triggerstudiomodetransition) +- [Filters](#filters) + - [GetSourceFilter](#getsourcefilter) - [Scene Items](#scene-items-1) - [GetSceneItemList](#getsceneitemlist) - [GetGroupItemList](#getgroupitemlist) @@ -3542,6 +3544,35 @@ Triggers the current scene transition. Same functionality as the `Transition` bu - Added in v5.0.0 +## Filters + +### GetSourceFilter + +Gets the info for a specific source filter. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sourceName | String | Name of the source | None | N/A | +| filterName | String | Name of the filter | None | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| filterEnabled | Boolean | Whether the filter is enabled | +| filterIndex | Number | Index of the filter in the list, beginning at 0 | +| filterKind | String | The kind of filter | +| filterSettings | Object | Settings object associated with the filter | + + ## Scene Items ### GetSceneItemList From 9f7beb1c0d9f425e37b200c353c2df0a7fb90737 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 4 Jan 2022 00:42:09 -0800 Subject: [PATCH 090/128] deps: Downgrade asio to 1.12.1 Even though we statically link ASIO, it has issues with the kqueue_reactor() on macos segfaulting when other plugins using different ASIO versions are installed. So that means we're stuck using 1.12.1 until we can find some kind of fix for the crash issue. --- deps/asio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/asio b/deps/asio index b84e6c16..b73dc1d2 160000 --- a/deps/asio +++ b/deps/asio @@ -1 +1 @@ -Subproject commit b84e6c16b2ea907dbad94206b7510d85aafc0b42 +Subproject commit b73dc1d2c0ecb9452a87c26544d7f71e24342df6 From dea0fcd5617af131e3abdd6b0ad73d5f63258c0f Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 7 Jan 2022 23:00:14 -0800 Subject: [PATCH 091/128] Base: Add logging for compile time ASIO version --- src/obs-websocket.cpp | 1 + src/websocketserver/WebSocketServer.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/obs-websocket.cpp b/src/obs-websocket.cpp index e257780d..64396051 100644 --- a/src/obs-websocket.cpp +++ b/src/obs-websocket.cpp @@ -48,6 +48,7 @@ bool obs_module_load(void) { blog(LOG_INFO, "[obs_module_load] you can haz websockets (Version: %s | RPC Version: %d)", OBS_WEBSOCKET_VERSION, OBS_WEBSOCKET_RPC_VERSION); blog(LOG_INFO, "[obs_module_load] Qt version (compile-time): %s | Qt version (run-time): %s", QT_VERSION_STR, qVersion()); + blog(LOG_INFO, "[obs_module_load] Linked ASIO Version: %d", ASIO_VERSION); // Initialize the cpu stats _cpuUsageInfo = os_cpu_usage_info_start(); diff --git a/src/websocketserver/WebSocketServer.h b/src/websocketserver/WebSocketServer.h index a8a2feec..9052c793 100644 --- a/src/websocketserver/WebSocketServer.h +++ b/src/websocketserver/WebSocketServer.h @@ -23,6 +23,7 @@ with this program. If not, see #include #include #include +#include #include #include From 873eadec05542e687bd2b64c0aa9cbe9a29e1203 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sat, 8 Jan 2022 22:13:53 -0800 Subject: [PATCH 092/128] requesthandler: Fix documentation of dB value input Max dB value is 26dB, not -26dB. --- src/requesthandler/RequestHandler_Inputs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requesthandler/RequestHandler_Inputs.cpp b/src/requesthandler/RequestHandler_Inputs.cpp index a1a90e1a..3ec5d076 100644 --- a/src/requesthandler/RequestHandler_Inputs.cpp +++ b/src/requesthandler/RequestHandler_Inputs.cpp @@ -495,7 +495,7 @@ RequestResult RequestHandler::GetInputVolume(const Request& request) * * @requestField inputName | String | Name of the input to set the volume of * @requestField ?inputVolumeMul | Number | Volume setting in mul | >= 0, <= 20 | `inputVolumeDb` should be specified - * @requestField ?inputVolumeDb | Number | Volume setting in dB | >= -100, <= -26 | `inputVolumeMul` should be specified + * @requestField ?inputVolumeDb | Number | Volume setting in dB | >= -100, <= 26 | `inputVolumeMul` should be specified * * @requestType SetInputVolume * @complexity 3 From 63dfed1cf97e3aff4d1eabcafefa93466b1f46f4 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Sun, 9 Jan 2022 06:14:13 +0000 Subject: [PATCH 093/128] docs(ci): Update generated docs - 873eade [skip ci] --- docs/generated/protocol.json | 2 +- docs/generated/protocol.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index e02d88b3..263ca6be 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -1902,7 +1902,7 @@ "valueName": "inputVolumeDb", "valueType": "Number", "valueDescription": "Volume setting in dB", - "valueRestrictions": ">= -100, <= -26", + "valueRestrictions": ">= -100, <= 26", "valueOptional": true, "valueOptionalBehavior": "`inputVolumeMul` should be specified" } diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index af13f0c4..d50d8fbf 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -3194,7 +3194,7 @@ Sets the volume setting of an input. | ---- | :---: | ----------- | :----------------: | ----------------- | | inputName | String | Name of the input to set the volume of | None | N/A | | ?inputVolumeMul | Number | Volume setting in mul | >= 0, <= 20 | `inputVolumeDb` should be specified | -| ?inputVolumeDb | Number | Volume setting in dB | >= -100, <= -26 | `inputVolumeMul` should be specified | +| ?inputVolumeDb | Number | Volume setting in dB | >= -100, <= 26 | `inputVolumeMul` should be specified | --- From ae906bb2838a14de103ba7f9270a9a72ae7d1da8 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Tue, 18 Jan 2022 19:23:06 -0800 Subject: [PATCH 094/128] RequestHandler: Add VirtualCam requests --- CMakeLists.txt | 1 + src/requesthandler/RequestHandler.cpp | 6 + src/requesthandler/RequestHandler.h | 6 + src/requesthandler/RequestHandler_Outputs.cpp | 126 ++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 src/requesthandler/RequestHandler_Outputs.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 40d9e633..83b00ea6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,6 +114,7 @@ set(obs-websocket_SOURCES src/requesthandler/RequestHandler_Transitions.cpp src/requesthandler/RequestHandler_Filters.cpp src/requesthandler/RequestHandler_SceneItems.cpp + src/requesthandler/RequestHandler_Outputs.cpp src/requesthandler/RequestHandler_Stream.cpp src/requesthandler/RequestHandler_Record.cpp src/requesthandler/RequestHandler_MediaInputs.cpp diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index b93cf69e..9a03cec7 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -126,6 +126,12 @@ const std::unordered_map RequestHandler::_han {"GetSceneItemBlendMode", &RequestHandler::GetSceneItemBlendMode}, {"SetSceneItemBlendMode", &RequestHandler::SetSceneItemBlendMode}, + // Outputs + {"GetVirtualCamStatus", &RequestHandler::GetVirtualCamStatus}, + {"ToggleVirtualCam", &RequestHandler::ToggleVirtualCam}, + {"StartVirtualCam", &RequestHandler::StartVirtualCam}, + {"StopVirtualCam", &RequestHandler::StopVirtualCam}, + // Stream {"GetStreamStatus", &RequestHandler::GetStreamStatus}, {"ToggleStream", &RequestHandler::ToggleStream}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 7e920d19..6f34759b 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -144,6 +144,12 @@ class RequestHandler { RequestResult GetSceneItemBlendMode(const Request&); RequestResult SetSceneItemBlendMode(const Request&); + // Outputs + RequestResult GetVirtualCamStatus(const Request&); + RequestResult ToggleVirtualCam(const Request&); + RequestResult StartVirtualCam(const Request&); + RequestResult StopVirtualCam(const Request&); + // Stream RequestResult GetStreamStatus(const Request&); RequestResult ToggleStream(const Request&); diff --git a/src/requesthandler/RequestHandler_Outputs.cpp b/src/requesthandler/RequestHandler_Outputs.cpp new file mode 100644 index 00000000..d7c4d493 --- /dev/null +++ b/src/requesthandler/RequestHandler_Outputs.cpp @@ -0,0 +1,126 @@ +/* +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" + +static bool VirtualCamAvailable() +{ + OBSDataAutoRelease privateData = obs_get_private_data(); + if (!privateData) + return false; + + return obs_data_get_bool(privateData, "vcamEnabled"); +} + +/** + * Gets the status of the virtualcam output. + * + * @responseField outputActive | Boolean | Whether the output is active + * + * @requestType GetVirtualCamStatus + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category outputs + * @api requests + */ +RequestResult RequestHandler::GetVirtualCamStatus(const Request&) +{ + if (!VirtualCamAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "VirtualCam is not available."); + + json responseData; + responseData["outputActive"] = obs_frontend_virtualcam_active(); + return RequestResult::Success(responseData); +} + +/** + * Toggles the state of the virtualcam output. + * + * @responseField outputActive | Boolean | Whether the output is active + * + * @requestType ToggleVirtualCam + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category outputs + * @api requests + */ +RequestResult RequestHandler::ToggleVirtualCam(const Request&) +{ + if (!VirtualCamAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "VirtualCam is not available."); + + bool outputActive = obs_frontend_virtualcam_active(); + + if (outputActive) + obs_frontend_stop_virtualcam(); + else + obs_frontend_start_virtualcam(); + + json responseData; + responseData["outputActive"] = !outputActive; + return RequestResult::Success(responseData); +} + +/** + * Starts the virtualcam output. + * + * @requestType StartVirtualCam + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category outputs + */ +RequestResult RequestHandler::StartVirtualCam(const Request&) +{ + if (!VirtualCamAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "VirtualCam is not available."); + + if (obs_frontend_virtualcam_active()) + return RequestResult::Error(RequestStatus::OutputRunning); + + obs_frontend_start_virtualcam(); + + return RequestResult::Success(); +} + +/** + * Stops the virtualcam output. + * + * @requestType StopVirtualCam + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category outputs + */ +RequestResult RequestHandler::StopVirtualCam(const Request&) +{ + if (!VirtualCamAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "VirtualCam is not available."); + + if (!obs_frontend_virtualcam_active()) + return RequestResult::Error(RequestStatus::OutputNotRunning); + + obs_frontend_stop_virtualcam(); + + return RequestResult::Success(); +} From bc0b4999442361e5d94b431364bbe70e29b7f3fb Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Wed, 19 Jan 2022 03:24:00 +0000 Subject: [PATCH 095/128] docs(ci): Update generated docs - ae906bb [skip ci] --- docs/generated/protocol.json | 56 +++++++++++++++++++++++++++++++++ docs/generated/protocol.md | 60 ++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 263ca6be..dbd01e68 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -2307,6 +2307,62 @@ ], "responseFields": [] }, + { + "description": "Gets the status of the virtualcam output.", + "requestType": "GetVirtualCamStatus", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "requestFields": [], + "responseFields": [ + { + "valueName": "outputActive", + "valueType": "Boolean", + "valueDescription": "Whether the output is active" + } + ] + }, + { + "description": "Toggles the state of the virtualcam output.", + "requestType": "ToggleVirtualCam", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "requestFields": [], + "responseFields": [ + { + "valueName": "outputActive", + "valueType": "Boolean", + "valueDescription": "Whether the output is active" + } + ] + }, + { + "description": "Starts the virtualcam output.", + "requestType": "StartVirtualCam", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "requestFields": [], + "responseFields": [] + }, + { + "description": "Stops the virtualcam output.", + "requestType": "StopVirtualCam", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "requestFields": [], + "responseFields": [] + }, { "description": "Gets the status of the record output.", "requestType": "GetRecordStatus", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index d50d8fbf..0f260782 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -2124,6 +2124,11 @@ Studio mode has been enabled or disabled. - [SetSceneItemIndex](#setsceneitemindex) - [GetSceneItemBlendMode](#getsceneitemblendmode) - [SetSceneItemBlendMode](#setsceneitemblendmode) +- [Outputs](#outputs-1) + - [GetVirtualCamStatus](#getvirtualcamstatus) + - [ToggleVirtualCam](#togglevirtualcam) + - [StartVirtualCam](#startvirtualcam) + - [StopVirtualCam](#stopvirtualcam) - [Stream](#stream) - [GetStreamStatus](#getstreamstatus) - [ToggleStream](#togglestream) @@ -3981,6 +3986,61 @@ Scenes and Groups | sceneItemBlendMode | String | New blend mode | None | N/A | +## Outputs + +### GetVirtualCamStatus + +Gets the status of the virtualcam output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| outputActive | Boolean | Whether the output is active | + +--- + +### ToggleVirtualCam + +Toggles the state of the virtualcam output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| outputActive | Boolean | Whether the output is active | + +--- + +### StartVirtualCam + +Starts the virtualcam output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + +### StopVirtualCam + +Stops the virtualcam output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + ## Stream ### GetStreamStatus From 1844f85e1fb986bcd12354c26c419e2c0217c56d Mon Sep 17 00:00:00 2001 From: Brendan Allan Date: Wed, 22 Dec 2021 11:25:25 +0800 Subject: [PATCH 096/128] CI: Add MacOS CI Add MacOS CI for `master` Co-authored-by: tt2468 --- .github/workflows/main.yml | 250 ++++++++++++++++++++++--- CI/macos/Brewfile | 5 - CI/macos/build-plugin-macos.sh | 27 --- CI/macos/install-build-obs-macos.sh | 39 ---- CI/macos/install-dependencies-macos.sh | 57 ------ CI/macos/obs-websocket.pkgproj | 2 +- CI/macos/package-plugin-macos.sh | 93 --------- 7 files changed, 221 insertions(+), 252 deletions(-) delete mode 100644 CI/macos/Brewfile delete mode 100755 CI/macos/build-plugin-macos.sh delete mode 100755 CI/macos/install-build-obs-macos.sh delete mode 100755 CI/macos/install-dependencies-macos.sh delete mode 100755 CI/macos/package-plugin-macos.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d6fdce27..d8e27ccd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,11 +1,11 @@ -name: "CI Multiplatform Build" +name: 'CI Multiplatform Build' on: push: paths-ignore: - 'docs/**' branches: - - master + - '*' tags: - '[45].[0-9]+.[0-9]+*' pull_request: @@ -25,8 +25,8 @@ jobs: QT_VERSION: '5.15.2' WINDOWS_DEPS_CACHE_VERSION: '1' # Change whenever updating Qt dependency URL, in order to force a cache reset WINDOWS_DEPS_VERSION: '2019' - CMAKE_GENERATOR: "Visual Studio 16 2019" - CMAKE_SYSTEM_VERSION: "10.0" + CMAKE_GENERATOR: 'Visual Studio 16 2019' + CMAKE_SYSTEM_VERSION: '10.0' steps: - name: 'Add msbuild to PATH' uses: microsoft/setup-msbuild@v1.0.2 @@ -35,20 +35,20 @@ jobs: with: path: ${{ github.workspace }}/obs-websocket submodules: 'recursive' - - name: 'Checkout OBS-Studio' + - name: 'Checkout OBS Studio' uses: actions/checkout@v2 with: repository: obsproject/obs-studio path: ${{ github.workspace }}/obs-studio submodules: 'recursive' - - name: 'Get OBS-Studio Git Info' + - name: 'Get OBS Studio Git Info' shell: bash working-directory: ${{ github.workspace }}/obs-studio run: | git fetch --prune --unshallow echo "OBS_GIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV echo "OBS_GIT_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV - - name: 'Checkout last OBS-Studio release (${{ env.OBS_GIT_TAG }})' + - name: 'Checkout last OBS Studio release (${{ env.OBS_GIT_TAG }})' shell: bash working-directory: ${{ github.workspace }}/obs-studio run: | @@ -78,8 +78,6 @@ jobs: with: path: Qt_${{ env.QT_VERSION }}.7z key: 'qtdep-${{ env.QT_CACHE_VERSION }} | ${{ runner.os }}' - restore-keys: | - qtdep-${{ env.QT_CACHE_VERSION }} | ${{ runner.os }} - name: 'Download Prerequisite: Qt' if: steps.qtcache.outputs.cache-hit != 'true' run: | @@ -87,20 +85,18 @@ jobs: - name: 'Extract Prerequisite: Qt' run: | 7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}\cmbuild\QT" - - name: 'Restore Cached OBS-Studio Dependencies' + - name: 'Restore Cached OBS Studio Dependencies' id: obscache uses: actions/cache@v2 with: path: ${{ github.workspace }}\cmbuild\deps\** key: 'obsdep-${{ env.WINDOWS_DEPS_CACHE_VERSION }} | ${{ runner.os }}' - restore-keys: | - obsdep-${{ env.WINDOWS_DEPS_CACHE_VERSION }} | ${{ runner.os }} - - name: 'Install Prerequisite: Pre-built OBS-Studio dependencies' + - name: 'Install Prerequisite: Pre-built OBS Studio dependencies' if: steps.obscache.outputs.cache-hit != 'true' run: | curl -kLO https://cdn-fastly.obsproject.com/downloads/dependencies${{ env.WINDOWS_DEPS_VERSION }}.zip -f --retry 5 -C - 7z x dependencies${{ env.WINDOWS_DEPS_VERSION }}.zip -o"${{ github.workspace }}\cmbuild\deps" - - name: 'Restore OBS-Studio 32-bit Build v${{ env.OBS_GIT_TAG }} from Cache' + - name: 'Restore OBS Studio 32-bit Build v${{ env.OBS_GIT_TAG }} from Cache' id: build-cache-obs-32 uses: actions/cache@v2 env: @@ -108,22 +104,20 @@ jobs: with: path: ${{ github.workspace }}/obs-studio/build32 key: ${{ runner.os }}-${{ env.CACHE_NAME }}-${{ env.OBS_GIT_TAG }} - restore-keys: | - ${{ runner.os }}-${{ env.CACHE_NAME }}- - - name: 'Configure OBS-Studio 32-bit' + - name: 'Configure OBS Studio 32-bit' if: steps.build-cache-obs-32.outputs.cache-hit != 'true' working-directory: ${{ github.workspace }}/obs-studio run: | if(!(Test-Path -Path ".\build32")){New-Item -ItemType directory -Path .\build32} cd .\build32 cmake -G "${{ env.CMAKE_GENERATOR }}" -A Win32 -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DQTDIR="${{ github.workspace }}\cmbuild\QT\${{ env.QT_VERSION }}\msvc2019" -DDepsPath="${{ github.workspace }}\cmbuild\deps\win32" -DCOPIED_DEPENDENCIES=NO -DCOPY_DEPENDENCIES=YES -DBUILD_BROWSER=OFF .. - - name: 'Build OBS-Studio 32-bit' + - name: 'Build OBS Studio 32-bit' if: steps.build-cache-obs-32.outputs.cache-hit != 'true' working-directory: ${{ github.workspace }}/obs-studio run: | msbuild /m /p:Configuration=RelWithDebInfo .\build32\libobs\libobs.vcxproj msbuild /m /p:Configuration=RelWithDebInfo .\build32\UI\obs-frontend-api\obs-frontend-api.vcxproj - - name: 'Restore OBS-Studio 64-bit Build v${{ env.OBS_GIT_TAG }} from Cache' + - name: 'Restore OBS Studio 64-bit Build v${{ env.OBS_GIT_TAG }} from Cache' id: build-cache-obs-64 uses: actions/cache@v1 env: @@ -131,16 +125,14 @@ jobs: with: path: ${{ github.workspace }}/obs-studio/build64 key: ${{ runner.os }}-${{ env.CACHE_NAME }}-${{ env.OBS_GIT_TAG }} - restore-keys: | - ${{ runner.os }}-${{ env.CACHE_NAME }}- - - name: 'Configure OBS-Studio 64-bit' + - name: 'Configure OBS Studio 64-bit' if: steps.build-cache-obs-64.outputs.cache-hit != 'true' working-directory: ${{ github.workspace }}/obs-studio run: | if(!(Test-Path -Path ".\build64")){New-Item -ItemType directory -Path .\build64} cd .\build64 cmake -G "${{ env.CMAKE_GENERATOR }}" -A x64 -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DQTDIR="${{ github.workspace }}\cmbuild\QT\${{ env.QT_VERSION }}\msvc2019_64" -DDepsPath="${{ github.workspace }}\cmbuild\deps\win64" -DCOPIED_DEPENDENCIES=NO -DCOPY_DEPENDENCIES=YES -DBUILD_BROWSER=OFF .. - - name: 'Build OBS-Studio 64-bit' + - name: 'Build OBS Studio 64-bit' if: steps.build-cache-obs-64.outputs.cache-hit != 'true' working-directory: ${{ github.workspace }}/obs-studio run: | @@ -188,7 +180,7 @@ jobs: name: 'obs-websocket-${{ env.PACKAGE_VERSION }}-Windows-Installer' path: ${{ github.workspace }}/obs-websocket/package/*.exe ubuntu64: - name: "Linux/Ubuntu 64-bit" + name: 'Linux/Ubuntu 64-bit' runs-on: [ubuntu-latest] if: contains(github.event.head_commit.message, '[skip ci]') != true steps: @@ -197,20 +189,20 @@ jobs: with: path: ${{ github.workspace }}/obs-websocket submodules: 'recursive' - - name: 'Checkout OBS-Studio' + - name: 'Checkout OBS Studio' uses: actions/checkout@v2 with: repository: obsproject/obs-studio path: ${{ github.workspace }}/obs-studio submodules: 'recursive' - - name: 'Get OBS-Studio Git Info' + - name: 'Get OBS Studio Git Info' shell: bash working-directory: ${{ github.workspace }}/obs-studio run: | git fetch --prune --unshallow echo "OBS_GIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV echo "OBS_GIT_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV - - name: 'Checkout last OBS-Studio release (${{ env.OBS_GIT_TAG }})' + - name: 'Checkout last OBS Studio release (${{ env.OBS_GIT_TAG }})' shell: bash working-directory: ${{ github.workspace }}/obs-studio run: | @@ -284,21 +276,21 @@ jobs: libx11-xcb-dev \ libxcb1-dev \ libxss-dev \ - - name: 'Configure OBS-Studio' + - name: 'Configure OBS Studio' working-directory: ${{ github.workspace }}/obs-studio shell: bash run: | mkdir ./build cd ./build cmake -DDISABLE_PLUGINS=YES -DENABLE_SCRIPTING=NO -DUNIX_STRUCTURE=YES -DCMAKE_INSTALL_PREFIX=/usr .. - - name: 'Build OBS-Studio' + - name: 'Build OBS Studio' working-directory: ${{ github.workspace }}/obs-studio shell: bash run: | set -e cd ./build make -j4 libobs obs-frontend-api - - name: 'Install OBS-Studio' + - name: 'Install OBS Studio' working-directory: ${{ github.workspace }}/obs-studio shell: bash run: | @@ -355,3 +347,201 @@ jobs: with: name: 'obs-websocket-${{ env.PACKAGE_VERSION }}-Ubuntu64' path: '${{ github.workspace }}/obs-websocket/package/*.deb' + macOS: + name: 'macOS 64-bit' + runs-on: [macos-latest] + if: contains(github.event.head_commit.message, '[skip ci]') != true + env: + MACOS_DEPS_VERSION: '2022-01-01' + MACOS_DEPS_CACHE_VERSION: '2' # Change whenever updating dependencies version, in order to force a cache reset + steps: + - name: 'Checkout obs-websocket' + uses: actions/checkout@v2 + with: + path: ${{ github.workspace }}/obs-websocket + submodules: 'recursive' + - name: 'Checkout OBS Studio' + uses: actions/checkout@v2 + with: + repository: obsproject/obs-studio + path: ${{ github.workspace }}/obs-studio + submodules: 'recursive' + - name: 'Install Prerequisite: Binary/Installer Signing Certificate' + uses: apple-actions/import-codesign-certs@v1 + with: + p12-file-base64: ${{ secrets.MACOS_SIGNING_CERT }} + p12-password: ${{ secrets.MACOS_SIGNING_CERT_PASSWORD }} + - name: 'Get OBS Studio Git Info' + shell: bash + working-directory: ${{ github.workspace }}/obs-studio + run: | + git fetch --prune --unshallow + echo "OBS_GIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + echo "OBS_GIT_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV + - name: 'Checkout last OBS Studio release (${{ env.OBS_GIT_TAG }})' + shell: bash + working-directory: ${{ github.workspace }}/obs-studio + run: | + git checkout ${{ env.OBS_GIT_TAG }} + git submodule update + - name: 'Get obs-websocket git info' + shell: bash + working-directory: ${{ github.workspace }}/obs-websocket + run: | + git fetch --prune --unshallow + GIT_HASH=$(git rev-parse --short HEAD) + echo "GIT_HASH=$GIT_HASH" >> $GITHUB_ENV + GIT_TAG=$(git describe --exact-match --tags --abbrev=0) || GIT_TAG="" + echo "GIT_TAG=$GIT_TAG" >> $GITHUB_ENV + if [ "$GIT_TAG" ] ; then \ + VERSION="$GIT_TAG" \ + VERSION_SUFFIX=$(echo "$GIT_TAG" | cut -c6-20) ; \ + else \ + VERSION="$GIT_HASH-git" \ + VERSION_SUFFIX="-$GIT_HASH-git" ; \ + fi + echo "PACKAGE_VERSION=$VERSION" >> $GITHUB_ENV + echo "CMAKE_VERSION_SUFFIX=$VERSION_SUFFIX" >> $GITHUB_ENV + - name: 'Install Packages' + shell: bash + run: | + curl -L -O http://s.sudre.free.fr/Software/files/Packages.dmg + sudo hdiutil attach ./Packages.dmg + sudo installer -pkg /Volumes/Packages\ 1.2.9/Install\ Packages.pkg -target / + - name: 'Restore Cached Qt & OBS Studio dependencies' + id: deps-cache + uses: actions/cache@v2 + with: + path: ${{ github.workspace }}/obsdeps/** + key: 'deps-cache-${{ env.MACOS_DEPS_CACHE_VERSION }} | ${{ runner.os }}' + - name: 'Install Prerequisite: Qt + OBS Studio dependencies' + if: steps.deps-cache.outputs.cache-hit != 'true' + shell: bash + run: | + mkdir -p obsdeps + curl -L -O https://github.com/obsproject/obs-deps/releases/download/${{ env.MACOS_DEPS_VERSION }}/macos-deps-qt-${{ env.MACOS_DEPS_VERSION }}-universal.tar.xz + tar -xf macos-deps-qt-${{ env.MACOS_DEPS_VERSION }}-universal.tar.xz -C "./obsdeps" + curl -L -O https://github.com/obsproject/obs-deps/releases/download/${{ env.MACOS_DEPS_VERSION }}/macos-deps-${{ env.MACOS_DEPS_VERSION }}-universal.tar.xz + tar -xf macos-deps-${{ env.MACOS_DEPS_VERSION }}-universal.tar.xz -C "./obsdeps" + - run: xattr -r -d com.apple.quarantine ./obsdeps + shell: bash + - name: 'Configue OBS Studio' + if: steps.cache-obs-build.outputs.cache-hit != 'true' + working-directory: ${{ github.workspace }}/obs-studio + shell: bash + run: | + mkdir -p ./build + cd ./build + cmake .. \ + -DQTDIR=${{ github.workspace }}/obsdeps \ + -DDepsPath=${{ github.workspace }}/obsdeps \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \ + -DDISABLE_PLUGINS=true \ + -DENABLE_SCRIPTING=0 \ + -DCMAKE_PREFIX_PATH=${{ github.workspace }}/obsdeps/lib/cmake + - name: 'Build OBS Studio' + if: steps.cache-obs-build.outputs.cache-hit != 'true' + working-directory: ${{ github.workspace }}/obs-studio/build + shell: bash + run: | + set -e + make -j4 libobs obs-frontend-api + - name: 'Configure obs-websocket' + working-directory: ${{ github.workspace }}/obs-websocket + shell: bash + run: | + mkdir -p build + cd build + cmake .. \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \ + -DQTDIR=${{ github.workspace }}/obsdeps \ + -DLIBOBS_INCLUDE_DIR=${{ github.workspace }}/obs-studio/libobs \ + -DLIBOBS_LIB=${{ github.workspace }}/obs-studio/libobs \ + -DOBS_FRONTEND_LIB="${{ github.workspace }}/obs-studio/build/UI/obs-frontend-api/libobs-frontend-api.dylib" \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_INSTALL_PREFIX=/usr + - name: 'Build obs-websocket' + working-directory: ${{ github.workspace }}/obs-websocket/build + shell: bash + run: | + set -e + make -j4 + - name: 'Relink Qt' + shell: bash + working-directory: ${{ github.workspace }}/obs-websocket/build + run: | + install_name_tool \ + -change /tmp/obsdeps/lib/QtWidgets.framework/Versions/5/QtWidgets \ + @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets \ + -change /tmp/obsdeps/lib/QtGui.framework/Versions/5/QtGui \ + @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui \ + -change /tmp/obsdeps/lib/QtCore.framework/Versions/5/QtCore \ + @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore \ + -change /tmp/obsdeps/lib/QtNetwork.framework/Versions/5/QtNetwork \ + @executable_path/../Frameworks/QtNetwork.framework/Versions/5/QtNetwork \ + -change /tmp/obsdeps/lib/QtSvg.framework/Versions/5/QtSvg \ + @executable_path/../Frameworks/QtSvg.framework/Versions/5/QtSvg \ + ./obs-websocket.so + - name: 'Sign plugin binary' + shell: bash + working-directory: ${{ github.workspace }}/obs-websocket/build + run: | + codesign --sign "${{ secrets.MACOS_SIGNING_IDENTITY }}" ./obs-websocket.so + - name: 'Set PR Artifact Filename' + shell: bash + run: | + echo "MACOS_FILENAME=obs-websocket-${{ env.PACKAGE_VERSION }}-macOS.pkg" >> $GITHUB_ENV + echo "MACOS_FILENAME_UNSIGNED=obs-websocket-${{ env.PACKAGE_VERSION }}-macOS-Unsigned.pkg" >> $GITHUB_ENV + - name: 'Package ${{ env.MACOS_FILENAME_UNSIGNED }}' + if: success() + working-directory: ${{ github.workspace }}/obs-websocket + shell: bash + run: | + packagesbuild ./CI/macos/obs-websocket.pkgproj + mv ./release/obs-websocket.pkg ./release/${{ env.MACOS_FILENAME_UNSIGNED }} + - name: 'Sign plugin package' + if: ${{ env.GIT_TAG != '' }} + shell: bash + working-directory: ${{ github.workspace }}/obs-websocket + run: | + productsign \ + --sign "${{ secrets.MACOS_SIGNING_IDENTITY }}" \ + ./release/${{ env.MACOS_FILENAME_UNSIGNED }} \ + ./release/${{ env.MACOS_FILENAME }} + rm ./release/${{ env.MACOS_FILENAME_UNSIGNED }} + - name: 'Notarize package' + if: ${{ env.GIT_TAG != '' }} + shell: bash + working-directory: ${{ github.workspace }}/obs-websocket + run: | + zip -r ./release/${{ env.MACOS_FILENAME }}.zip ./release/${{ env.MACOS_FILENAME }} + UPLOAD_RESULT=$(xcrun altool --notarize-app \ + --primary-bundle-id "com.obsproject.obs-websocket" \ + --username "${{ secrets.MACOS_NOTARIZATION_USERNAME }}" \ + --password "${{ secrets.MACOS_NOTARIZATION_PASSWORD }}" \ + --asc-provider "${{ secrets.ASC_PROVIDER_SHORTNAME }}" \ + --file "./release/${{ env.MACOS_FILENAME }}.zip") + + rm ./release/${{ env.MACOS_FILENAME }}.zip + + REQUEST_UUID=$(echo $UPLOAD_RESULT | awk -F ' = ' '/RequestUUID/ {print $2}') + + # Pieces of code borrowed from rednoah/notarized-app + while sleep 30 && date; do + CHECK_RESULT=$(xcrun altool \ + --notarization-info "$REQUEST_UUID" \ + --username "${{ secrets.MACOS_NOTARIZATION_USERNAME }}" \ + --password "${{ secrets.MACOS_NOTARIZATION_PASSWORD }}" \ + --asc-provider "${{ secrets.ASC_PROVIDER_SHORTNAME }}") + + if ! grep -q "Status: in progress" <<< "$CHECK_RESULT"; then + xcrun stapler staple ./release/${{ env.MACOS_FILENAME }} + break + fi + done + - name: 'Publish Packages' + if: success() + uses: actions/upload-artifact@v2-preview + with: + name: 'obs-websocket-${{ env.PACKAGE_VERSION }}-macOS' + path: '${{ github.workspace }}/obs-websocket/release/*.pkg' diff --git a/CI/macos/Brewfile b/CI/macos/Brewfile deleted file mode 100644 index 923af906..00000000 --- a/CI/macos/Brewfile +++ /dev/null @@ -1,5 +0,0 @@ -brew "jack" -brew "speexdsp" -brew "cmake" -brew "freetype" -brew "fdk-aac" diff --git a/CI/macos/build-plugin-macos.sh b/CI/macos/build-plugin-macos.sh deleted file mode 100755 index bc6c78ea..00000000 --- a/CI/macos/build-plugin-macos.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -OSTYPE=$(uname) - -if [ "${OSTYPE}" != "Darwin" ]; then - echo "[obs-websocket - Error] macOS build script can be run on Darwin-type OS only." - exit 1 -fi - -HAS_CMAKE=$(type cmake 2>/dev/null) - -if [ "${HAS_CMAKE}" = "" ]; then - echo "[obs-websocket - Error] CMake not installed - please run 'install-dependencies-macos.sh' first." - exit 1 -fi - -echo "[obs-websocket] Building 'obs-websocket' for macOS." -mkdir -p build && cd build -cmake .. \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \ - -DQTDIR=/tmp/obsdeps \ - -DLIBOBS_INCLUDE_DIR=../../obs-studio/libobs \ - -DLIBOBS_LIB=../../obs-studio/libobs \ - -DOBS_FRONTEND_LIB="$(pwd)/../../obs-studio/build/UI/obs-frontend-api/libobs-frontend-api.dylib" \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DCMAKE_INSTALL_PREFIX=/usr \ -&& make -j4 diff --git a/CI/macos/install-build-obs-macos.sh b/CI/macos/install-build-obs-macos.sh deleted file mode 100755 index 580c1dfd..00000000 --- a/CI/macos/install-build-obs-macos.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh - -OSTYPE=$(uname) - -if [ "${OSTYPE}" != "Darwin" ]; then - echo "[obs-websocket - Error] macOS obs-studio build script can be run on Darwin-type OS only." - exit 1 -fi - -HAS_CMAKE=$(type cmake 2>/dev/null) -HAS_GIT=$(type git 2>/dev/null) - -if [ "${HAS_CMAKE}" = "" ]; then - echo "[obs-websocket - Error] CMake not installed - please run 'install-dependencies-macos.sh' first." - exit 1 -fi - -if [ "${HAS_GIT}" = "" ]; then - echo "[obs-websocket - Error] Git not installed - please install Xcode developer tools or via Homebrew." - exit 1 -fi - -# Build obs-studio -cd .. -echo "[obs-websocket] Cloning obs-studio from GitHub.." -git clone https://github.com/obsproject/obs-studio -cd obs-studio -OBSLatestTag=$(git describe --tags --abbrev=0) -git checkout $OBSLatestTag -mkdir build && cd build -echo "[obs-websocket] Building obs-studio.." -cmake .. \ - -DQTDIR=/tmp/obsdeps \ - -DDepsPath=/tmp/obsdeps \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \ - -DDISABLE_PLUGINS=true \ - -DENABLE_SCRIPTING=0 \ - -DCMAKE_PREFIX_PATH=/tmp/obsdeps/lib/cmake \ -&& make -j4 diff --git a/CI/macos/install-dependencies-macos.sh b/CI/macos/install-dependencies-macos.sh deleted file mode 100755 index 8c734b8a..00000000 --- a/CI/macos/install-dependencies-macos.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh - -OSTYPE=$(uname) - -if [ "${OSTYPE}" != "Darwin" ]; then - echo "[obs-websocket - Error] macOS install dependencies script can be run on Darwin-type OS only." - exit 1 -fi - -HAS_BREW=$(type brew 2>/dev/null) - -if [ "${HAS_BREW}" = "" ]; then - echo "[obs-websocket - Error] Please install Homebrew (https://www.brew.sh/) to build obs-websocket on macOS." - exit 1 -fi - -# OBS Studio Brew Deps -echo "[obs-websocket] Updating Homebrew.." -brew update >/dev/null -echo "[obs-websocket] Checking installed Homebrew formulas.." - -if [ -d /usr/local/opt/openssl@1.0.2t ]; then - brew uninstall openssl@1.0.2t - brew untap local/openssl -fi - -if [ -d /usr/local/opt/python@2.7.17 ]; then - brew uninstall python@2.7.17 - brew untap local/python2 -fi - -brew bundle --file ./CI/macos/Brewfile - -# Fetch and install Packages app -# =!= NOTICE =!= -# Installs a LaunchDaemon under /Library/LaunchDaemons/fr.whitebox.packages.build.dispatcher.plist -# =!= NOTICE =!= - -HAS_PACKAGES=$(type packagesbuild 2>/dev/null) - -if [ "${HAS_PACKAGES}" = "" ]; then - echo "[obs-websocket] Installing Packaging app (might require password due to 'sudo').." - curl -L -O http://s.sudre.free.fr/Software/files/Packages.dmg - sudo hdiutil attach ./Packages.dmg - sudo installer -pkg /Volumes/Packages\ 1.2.9/Install\ Packages.pkg -target / -fi - -# OBS Deps -echo "[obs-websocket] Installing obs-websocket dependency 'OBS Deps ${OBS_DEPS_VERSION}'.." -wget --quiet --retry-connrefused --waitretry=1 https://github.com/obsproject/obs-deps/releases/download/${OBS_DEPS_VERSION}/macos-deps-${OBS_DEPS_VERSION}.tar.gz -tar -xf ./macos-deps-${OBS_DEPS_VERSION}.tar.gz -C /tmp - -# Qt deps -echo "[obs-websocket] Installing obs-websocket dependency 'Qt ${QT_VERSION}'.." -curl -L -O https://github.com/obsproject/obs-deps/releases/download/${OBS_DEPS_VERSION}/macos-qt-${QT_VERSION}-${OBS_DEPS_VERSION}.tar.gz -tar -xf ./macos-qt-${QT_VERSION}-${OBS_DEPS_VERSION}.tar.gz -C "/tmp" -xattr -r -d com.apple.quarantine /tmp/obsdeps \ No newline at end of file diff --git a/CI/macos/obs-websocket.pkgproj b/CI/macos/obs-websocket.pkgproj index 328b60ff..d38b3a2e 100644 --- a/CI/macos/obs-websocket.pkgproj +++ b/CI/macos/obs-websocket.pkgproj @@ -514,7 +514,7 @@ CONCLUSION_ACTION 0 IDENTIFIER - fr.palakis.obs-websocket + com.obsproject.obs-websocket OVERWRITE_PERMISSIONS VERSION diff --git a/CI/macos/package-plugin-macos.sh b/CI/macos/package-plugin-macos.sh deleted file mode 100755 index 917585d1..00000000 --- a/CI/macos/package-plugin-macos.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/bash - -set -e - -OSTYPE=$(uname) - -if [ "${OSTYPE}" != "Darwin" ]; then - echo "[obs-websocket - Error] macOS package script can be run on Darwin-type OS only." - exit 1 -fi - -echo "[obs-websocket] Preparing package build" - -GIT_HASH=$(git rev-parse --short HEAD) -GIT_BRANCH_OR_TAG=$(git name-rev --name-only HEAD | awk -F/ '{print $NF}') - -VERSION="$GIT_HASH-$GIT_BRANCH_OR_TAG" - -FILENAME_UNSIGNED="obs-websocket-$VERSION-Unsigned.pkg" -FILENAME="obs-websocket-$VERSION.pkg" - -echo "[obs-websocket] Modifying obs-websocket.so linking" -install_name_tool \ - -change /tmp/obsdeps/lib/QtWidgets.framework/Versions/5/QtWidgets \ - @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets \ - -change /tmp/obsdeps/lib/QtGui.framework/Versions/5/QtGui \ - @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui \ - -change /tmp/obsdeps/lib/QtCore.framework/Versions/5/QtCore \ - @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore \ - -change /tmp/obsdeps/lib/QtNetwork.framework/Versions/5/QtNetwork \ - @executable_path/../Frameworks/QtNetwork.framework/Versions/5/QtNetwork \ - -change /tmp/obsdeps/lib/QtSvg.framework/Versions/5/QtSvg \ - @executable_path/../Frameworks/QtSvg.framework/Versions/5/QtSvg \ - ./build/obs-websocket.so - -# Check if replacement worked -echo "[obs-websocket] Dependencies for obs-websocket" -otool -L ./build/obs-websocket.so - -if [[ "$RELEASE_MODE" == "True" ]]; then - echo "[obs-websocket] Signing plugin binary: obs-websocket.so" - codesign --sign "$CODE_SIGNING_IDENTITY" ./build/obs-websocket.so -else - echo "[obs-websocket] Skipped plugin codesigning" -fi - -echo "[obs-websocket] Actual package build" -packagesbuild ./CI/macos/obs-websocket.pkgproj - -echo "[obs-websocket] Renaming obs-websocket.pkg to $FILENAME" -mv ./release/obs-websocket.pkg ./release/$FILENAME_UNSIGNED - -if [[ "$RELEASE_MODE" == "True" ]]; then - echo "[obs-websocket] Signing installer: $FILENAME" - productsign \ - --sign "$INSTALLER_SIGNING_IDENTITY" \ - ./release/$FILENAME_UNSIGNED \ - ./release/$FILENAME - rm ./release/$FILENAME_UNSIGNED - - echo "[obs-websocket] Submitting installer $FILENAME for notarization" - zip -r ./release/$FILENAME.zip ./release/$FILENAME - UPLOAD_RESULT=$(xcrun altool \ - --notarize-app \ - --primary-bundle-id "fr.palakis.obs-websocket" \ - --username "$AC_USERNAME" \ - --password "$AC_PASSWORD" \ - --asc-provider "$AC_PROVIDER_SHORTNAME" \ - --file "./release/$FILENAME.zip") - rm ./release/$FILENAME.zip - - REQUEST_UUID=$(echo $UPLOAD_RESULT | awk -F ' = ' '/RequestUUID/ {print $2}') - echo "Request UUID: $REQUEST_UUID" - - echo "[obs-websocket] Wait for notarization result" - # Pieces of code borrowed from rednoah/notarized-app - while sleep 30 && date; do - CHECK_RESULT=$(xcrun altool \ - --notarization-info "$REQUEST_UUID" \ - --username "$AC_USERNAME" \ - --password "$AC_PASSWORD" \ - --asc-provider "$AC_PROVIDER_SHORTNAME") - echo $CHECK_RESULT - - if ! grep -q "Status: in progress" <<< "$CHECK_RESULT"; then - echo "[obs-websocket] Staple ticket to installer: $FILENAME" - xcrun stapler staple ./release/$FILENAME - break - fi - done -else - echo "[obs-websocket] Skipped installer codesigning and notarization" -fi From 13c7b83c34eb67b2ee80af05071d81f10d0d2997 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 26 Jan 2022 17:40:45 -0800 Subject: [PATCH 097/128] requesthandler: Fix compiler warnings with latest OBS master OBS has deprecated the `_addref` functions, so the new norm is to use `_get_ref`. --- src/requesthandler/RequestHandler_SceneItems.cpp | 5 +++-- src/requesthandler/rpc/Request.cpp | 8 ++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/requesthandler/RequestHandler_SceneItems.cpp b/src/requesthandler/RequestHandler_SceneItems.cpp index 4f25c7b2..78e72f59 100644 --- a/src/requesthandler/RequestHandler_SceneItems.cpp +++ b/src/requesthandler/RequestHandler_SceneItems.cpp @@ -232,8 +232,9 @@ RequestResult RequestHandler::DuplicateSceneItem(const Request& request) if (!destinationScene) return RequestResult::Error(statusCode, comment); } else { - destinationScene = obs_sceneitem_get_scene(sceneItem); - obs_scene_addref(destinationScene); + destinationScene = obs_scene_get_ref(obs_sceneitem_get_scene(sceneItem)); + if (!destinationScene) + return RequestResult::Error(RequestStatus::RequestProcessingFailed, "Internal error: Failed to get ref for scene of scene item."); } if (obs_sceneitem_is_group(sceneItem) && obs_sceneitem_get_scene(sceneItem) == destinationScene) { diff --git a/src/requesthandler/rpc/Request.cpp b/src/requesthandler/rpc/Request.cpp index cd55abeb..3458347b 100644 --- a/src/requesthandler/rpc/Request.cpp +++ b/src/requesthandler/rpc/Request.cpp @@ -264,18 +264,14 @@ obs_scene_t *Request::ValidateScene2(const std::string &keyName, RequestStatus:: comment = "The specified source is not a scene. (Is group)"; return nullptr; } - OBSScene ret = obs_group_from_source(sceneSource); - obs_scene_addref(ret); - return ret; + return obs_scene_get_ref(obs_group_from_source(sceneSource)); } else { if (filter == OBS_WEBSOCKET_SCENE_FILTER_GROUP_ONLY) { statusCode = RequestStatus::InvalidResourceType; comment = "The specified source is not a group. (Is scene)"; return nullptr; } - OBSScene ret = obs_scene_from_source(sceneSource); - obs_scene_addref(ret); - return ret; + return obs_scene_get_ref(obs_scene_from_source(sceneSource)); } } From 38d78596cee8ac8c3206457135899cd1e8daa53a Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 26 Jan 2022 21:19:10 -0800 Subject: [PATCH 098/128] requesthandler: Add replay buffer requests --- src/requesthandler/RequestHandler.cpp | 6 + src/requesthandler/RequestHandler.h | 6 + src/requesthandler/RequestHandler_Outputs.cpp | 151 ++++++++++++++++++ src/utils/Obs_StringHelper.cpp | 11 +- 4 files changed, 172 insertions(+), 2 deletions(-) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 9a03cec7..ca1275ab 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -131,6 +131,12 @@ const std::unordered_map RequestHandler::_han {"ToggleVirtualCam", &RequestHandler::ToggleVirtualCam}, {"StartVirtualCam", &RequestHandler::StartVirtualCam}, {"StopVirtualCam", &RequestHandler::StopVirtualCam}, + {"GetReplayBufferStatus", &RequestHandler::GetReplayBufferStatus}, + {"ToggleReplayBuffer", &RequestHandler::ToggleReplayBuffer}, + {"StartReplayBuffer", &RequestHandler::StartReplayBuffer}, + {"StopReplayBuffer", &RequestHandler::StopReplayBuffer}, + {"SaveReplayBuffer", &RequestHandler::SaveReplayBuffer}, + {"GetLastReplayBufferReplay", &RequestHandler::GetLastReplayBufferReplay}, // Stream {"GetStreamStatus", &RequestHandler::GetStreamStatus}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 6f34759b..2e5927de 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -149,6 +149,12 @@ class RequestHandler { RequestResult ToggleVirtualCam(const Request&); RequestResult StartVirtualCam(const Request&); RequestResult StopVirtualCam(const Request&); + RequestResult GetReplayBufferStatus(const Request&); + RequestResult ToggleReplayBuffer(const Request&); + RequestResult StartReplayBuffer(const Request&); + RequestResult StopReplayBuffer(const Request&); + RequestResult SaveReplayBuffer(const Request&); + RequestResult GetLastReplayBufferReplay(const Request&); // Stream RequestResult GetStreamStatus(const Request&); diff --git a/src/requesthandler/RequestHandler_Outputs.cpp b/src/requesthandler/RequestHandler_Outputs.cpp index d7c4d493..d85f839a 100644 --- a/src/requesthandler/RequestHandler_Outputs.cpp +++ b/src/requesthandler/RequestHandler_Outputs.cpp @@ -28,6 +28,12 @@ static bool VirtualCamAvailable() return obs_data_get_bool(privateData, "vcamEnabled"); } +static bool ReplayBufferAvailable() +{ + OBSOutputAutoRelease output = obs_frontend_get_replay_buffer_output(); + return output != nullptr; +} + /** * Gets the status of the virtualcam output. * @@ -124,3 +130,148 @@ RequestResult RequestHandler::StopVirtualCam(const Request&) return RequestResult::Success(); } + +/** + * Gets the status of the replay buffer output. + * + * @responseField outputActive | Boolean | Whether the output is active + * + * @requestType GetReplayBufferStatus + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category outputs + * @api requests + */ +RequestResult RequestHandler::GetReplayBufferStatus(const Request&) +{ + if (!ReplayBufferAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available."); + + json responseData; + responseData["outputActive"] = obs_frontend_replay_buffer_active(); + return RequestResult::Success(responseData); +} + +/** + * Toggles the state of the replay buffer output. + * + * @responseField outputActive | Boolean | Whether the output is active + * + * @requestType ToggleReplayBuffer + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category outputs + * @api requests + */ +RequestResult RequestHandler::ToggleReplayBuffer(const Request&) +{ + if (!ReplayBufferAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available."); + + bool outputActive = obs_frontend_replay_buffer_active(); + + if (outputActive) + obs_frontend_replay_buffer_stop(); + else + obs_frontend_replay_buffer_start(); + + json responseData; + responseData["outputActive"] = !outputActive; + return RequestResult::Success(responseData); +} + +/** + * Starts the replay buffer output. + * + * @requestType StartReplayBuffer + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category outputs + */ +RequestResult RequestHandler::StartReplayBuffer(const Request&) +{ + if (!ReplayBufferAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available."); + + if (obs_frontend_replay_buffer_active()) + return RequestResult::Error(RequestStatus::OutputRunning); + + obs_frontend_replay_buffer_start(); + + return RequestResult::Success(); +} + +/** + * Stops the replay buffer output. + * + * @requestType StopReplayBuffer + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category outputs + */ +RequestResult RequestHandler::StopReplayBuffer(const Request&) +{ + if (!ReplayBufferAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available."); + + if (!obs_frontend_replay_buffer_active()) + return RequestResult::Error(RequestStatus::OutputNotRunning); + + obs_frontend_replay_buffer_stop(); + + return RequestResult::Success(); +} + +/** + * Saves the contents of the replay buffer output. + * + * @requestType SaveReplayBuffer + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category outputs + */ +RequestResult RequestHandler::SaveReplayBuffer(const Request&) +{ + if (!ReplayBufferAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available."); + + if (!obs_frontend_replay_buffer_active()) + return RequestResult::Error(RequestStatus::OutputNotRunning); + + obs_frontend_replay_buffer_save(); + + return RequestResult::Success(); +} + +/** + * Gets the filename of the last replay buffer save file. + * + * @responseField savedReplayPath | String | File path + * + * @requestType GetLastReplayBufferReplay + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category outputs + */ +RequestResult RequestHandler::GetLastReplayBufferReplay(const Request&) +{ + if (!ReplayBufferAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available."); + + if (!obs_frontend_replay_buffer_active()) + return RequestResult::Error(RequestStatus::OutputNotRunning); + + json responseData; + responseData["savedReplayPath"] = Utils::Obs::StringHelper::GetLastReplayBufferFilePath(); + return RequestResult::Success(responseData); +} diff --git a/src/utils/Obs_StringHelper.cpp b/src/utils/Obs_StringHelper.cpp index ef040bf1..c5e1bc07 100644 --- a/src/utils/Obs_StringHelper.cpp +++ b/src/utils/Obs_StringHelper.cpp @@ -120,12 +120,19 @@ std::string Utils::Obs::StringHelper::GetMediaInputState(obs_source_t *input) std::string Utils::Obs::StringHelper::GetLastReplayBufferFilePath() { OBSOutputAutoRelease output = obs_frontend_get_replay_buffer_output(); + if (!output) + return ""; + calldata_t cd = {0}; proc_handler_t *ph = obs_output_get_proc_handler(output); proc_handler_call(ph, "get_last_replay", &cd); - auto ret = calldata_string(&cd, "path"); + const char *savedReplayPath = calldata_string(&cd, "path"); calldata_free(&cd); - return ret; + + if (!savedReplayPath) + return ""; + + return savedReplayPath; } std::string Utils::Obs::StringHelper::GetSceneItemBoundsType(enum obs_bounds_type type) From 96a2fd8c253912f2b89447411278ebf1b8e04247 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Thu, 27 Jan 2022 05:34:40 +0000 Subject: [PATCH 099/128] docs(ci): Update generated docs - 38d7859 [skip ci] --- docs/generated/protocol.json | 84 ++++++++++++++++++++++++++++++++++ docs/generated/protocol.md | 87 ++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index dbd01e68..cd8faa48 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -2363,6 +2363,90 @@ "requestFields": [], "responseFields": [] }, + { + "description": "Gets the status of the replay buffer output.", + "requestType": "GetReplayBufferStatus", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "requestFields": [], + "responseFields": [ + { + "valueName": "outputActive", + "valueType": "Boolean", + "valueDescription": "Whether the output is active" + } + ] + }, + { + "description": "Toggles the state of the replay buffer output.", + "requestType": "ToggleReplayBuffer", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "requestFields": [], + "responseFields": [ + { + "valueName": "outputActive", + "valueType": "Boolean", + "valueDescription": "Whether the output is active" + } + ] + }, + { + "description": "Starts the replay buffer output.", + "requestType": "StartReplayBuffer", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "requestFields": [], + "responseFields": [] + }, + { + "description": "Stops the replay buffer output.", + "requestType": "StopReplayBuffer", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "requestFields": [], + "responseFields": [] + }, + { + "description": "Saves the contents of the replay buffer output.", + "requestType": "SaveReplayBuffer", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "requestFields": [], + "responseFields": [] + }, + { + "description": "Gets the filename of the last replay buffer save file.", + "requestType": "GetLastReplayBufferReplay", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "outputs", + "requestFields": [], + "responseFields": [ + { + "valueName": "savedReplayPath", + "valueType": "String", + "valueDescription": "File path" + } + ] + }, { "description": "Gets the status of the record output.", "requestType": "GetRecordStatus", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 0f260782..8ed573eb 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -2129,6 +2129,12 @@ Studio mode has been enabled or disabled. - [ToggleVirtualCam](#togglevirtualcam) - [StartVirtualCam](#startvirtualcam) - [StopVirtualCam](#stopvirtualcam) + - [GetReplayBufferStatus](#getreplaybufferstatus) + - [ToggleReplayBuffer](#togglereplaybuffer) + - [StartReplayBuffer](#startreplaybuffer) + - [StopReplayBuffer](#stopreplaybuffer) + - [SaveReplayBuffer](#savereplaybuffer) + - [GetLastReplayBufferReplay](#getlastreplaybufferreplay) - [Stream](#stream) - [GetStreamStatus](#getstreamstatus) - [ToggleStream](#togglestream) @@ -4040,6 +4046,87 @@ Stops the virtualcam output. - Latest Supported RPC Version: `1` - Added in v5.0.0 +--- + +### GetReplayBufferStatus + +Gets the status of the replay buffer output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| outputActive | Boolean | Whether the output is active | + +--- + +### ToggleReplayBuffer + +Toggles the state of the replay buffer output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| outputActive | Boolean | Whether the output is active | + +--- + +### StartReplayBuffer + +Starts the replay buffer output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + +### StopReplayBuffer + +Stops the replay buffer output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + +### SaveReplayBuffer + +Saves the contents of the replay buffer output. + +- Complexity Rating: `1/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + +### GetLastReplayBufferReplay + +Gets the filename of the last replay buffer save file. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| savedReplayPath | String | File path | + ## Stream From 3e2984fd7a3ad51a969e56ca725744a811d1c9ba Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 28 Jan 2022 15:33:28 -0800 Subject: [PATCH 100/128] eventhandler: Add SceneItemSelected event So I didn't think anyone actually used this, but I was wrong. So I'm adding it again. --- src/eventhandler/EventHandler.cpp | 2 ++ src/eventhandler/EventHandler.h | 1 + src/eventhandler/EventHandler_SceneItems.cpp | 32 ++++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/src/eventhandler/EventHandler.cpp b/src/eventhandler/EventHandler.cpp index c3dcfd9c..ee79c18a 100644 --- a/src/eventhandler/EventHandler.cpp +++ b/src/eventhandler/EventHandler.cpp @@ -157,6 +157,7 @@ void EventHandler::ConnectSourceSignals(obs_source_t *source) // Applies to inpu signal_handler_connect(sh, "reorder", HandleSceneItemListReindexed, this); signal_handler_connect(sh, "item_visible", HandleSceneItemEnableStateChanged, this); signal_handler_connect(sh, "item_locked", HandleSceneItemLockStateChanged, this); + signal_handler_connect(sh, "item_select", HandleSceneItemSelected, this); signal_handler_connect(sh, "item_transform", HandleSceneItemTransformChanged, this); } } @@ -194,6 +195,7 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source) signal_handler_disconnect(sh, "reorder", HandleSceneItemListReindexed, this); signal_handler_disconnect(sh, "item_visible", HandleSceneItemEnableStateChanged, this); signal_handler_disconnect(sh, "item_locked", HandleSceneItemLockStateChanged, this); + signal_handler_disconnect(sh, "item_select", HandleSceneItemSelected, this); signal_handler_disconnect(sh, "item_transform", HandleSceneItemTransformChanged, this); } diff --git a/src/eventhandler/EventHandler.h b/src/eventhandler/EventHandler.h index bdd1cde8..6200dc95 100644 --- a/src/eventhandler/EventHandler.h +++ b/src/eventhandler/EventHandler.h @@ -125,6 +125,7 @@ class EventHandler static void HandleSceneItemListReindexed(void *param, calldata_t *data); // Direct callback static void HandleSceneItemEnableStateChanged(void *param, calldata_t *data); // Direct callback static void HandleSceneItemLockStateChanged(void *param, calldata_t *data); // Direct callback + static void HandleSceneItemSelected(void *param, calldata_t *data); // Direct callback static void HandleSceneItemTransformChanged(void *param, calldata_t *data); // Direct callback // Media Inputs diff --git a/src/eventhandler/EventHandler_SceneItems.cpp b/src/eventhandler/EventHandler_SceneItems.cpp index bac56c4d..9b5e2b6f 100644 --- a/src/eventhandler/EventHandler_SceneItems.cpp +++ b/src/eventhandler/EventHandler_SceneItems.cpp @@ -191,6 +191,38 @@ void EventHandler::HandleSceneItemLockStateChanged(void *param, calldata_t *data eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemLockStateChanged", eventData); } +/** + * A scene item has been selected in the Ui. + * + * @dataField sceneName | String | Name of the scene the item is in + * @dataField sceneItemId | Number | Numeric ID of the scene item + * + * @eventType SceneItemSelected + * @eventSubscription SceneItems + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category scene items + */ +void EventHandler::HandleSceneItemSelected(void *param, calldata_t *data) +{ + auto eventHandler = static_cast(param); + + obs_scene_t *scene = GetCalldataPointer(data, "scene"); + if (!scene) + return; + + obs_sceneitem_t *sceneItem = GetCalldataPointer(data, "item"); + if (!sceneItem) + return; + + json eventData; + eventData["sceneName"] = obs_source_get_name(obs_scene_get_source(scene)); + eventData["sceneItemId"] = obs_sceneitem_get_id(sceneItem); + eventHandler->BroadcastEvent(EventSubscription::SceneItems, "SceneItemSelected", eventData); +} + /** * The transform/crop of a scene item has changed. * From 14227237d7e5299bb45f0d04e701129b58063c13 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 28 Jan 2022 15:38:08 -0800 Subject: [PATCH 101/128] Base: [BREAKING] Update default WebSocket port to 4455 Our original strategy of relying on clients to simply detect the protocol version and use the correct one was optimistic at best, and it has been realized during the transition process from 4.x to 5.x that sharing 4444 is not practical. As such, we'll be using 4455 in the future for 5.x. If you are a client developer, we suggest continuing to maintain appropriate protocol version detection and support, as the WebSocket port is at the end of the day simply a suggestion. --- README.md | 6 +++--- src/Config.cpp | 2 +- src/forms/SettingsDialog.ui | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 207360f6..2f37d2ee 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ It is **highly recommended** to protect obs-websocket with a password against un - Automate scene switching with a third-party program (e.g. : auto-pilot, foot pedal, ...) ### Client software -- (No known clients supporting 5.0.0 at the moment. Send a message in Discord if you have one!) +- (No known clients supporting 5.0.0 at the moment. Ping us in the Discord if you have one!) ### Client libraries (for developers) @@ -35,10 +35,10 @@ Here's a list of available language APIs for obs-websocket: - Python 3.7+ (Asyncio): [simpleobsws](https://github.com/IRLToolkit/simpleobsws/tree/master) by IRLToolkit - Rust: [obws](https://github.com/dnaka91/obws/tree/v5-api) by dnaka91 -The server is a typical Websockets server running by default on port 4444 (the port number can be changed in the Settings dialog under `Tools`). +The 5.x server is a typical WebSocket server running by default on port 4455 (the port number can be changed in the Settings dialog under `Tools`). The protocol we use is documented in [PROTOCOL.md](docs/generated/protocol.md). -We'd like to know what you're building with or for obs-websocket. If you do something in this fashion, feel free to drop a message in `#project-showoff` in the [discord server!](https://discord.gg/WBaSQ3A) +We'd like to know what you're building with obs-websocket! If you do something in this fashion, feel free to drop a message in `#project-showoff` in the [discord server!](https://discord.gg/WBaSQ3A) ## Contributors diff --git a/src/Config.cpp b/src/Config.cpp index 835f2123..5c45b2dd 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -41,7 +41,7 @@ Config::Config() : PasswordOverridden(false), FirstLoad(true), ServerEnabled(true), - ServerPort(4444), + ServerPort(4455), DebugEnabled(false), AlertsEnabled(false), AuthRequired(true), diff --git a/src/forms/SettingsDialog.ui b/src/forms/SettingsDialog.ui index c790e17f..567b3a53 100644 --- a/src/forms/SettingsDialog.ui +++ b/src/forms/SettingsDialog.ui @@ -151,7 +151,7 @@ 65534 - 4444 + 4455 From 5cbc1019ff8581a9e249438a8033b4d1182845cb Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Fri, 28 Jan 2022 23:56:23 +0000 Subject: [PATCH 102/128] docs(ci): Update generated docs - 1422723 [skip ci] --- docs/generated/protocol.json | 22 ++++++++++++++++++++++ docs/generated/protocol.md | 19 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index cd8faa48..bcb6b37b 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -4489,6 +4489,28 @@ } ] }, + { + "description": "A scene item has been selected in the Ui.", + "eventType": "SceneItemSelected", + "eventSubscription": "SceneItems", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scene items", + "dataFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene the item is in" + }, + { + "valueName": "sceneItemId", + "valueType": "Number", + "valueDescription": "Numeric ID of the scene item" + } + ] + }, { "description": "The transform/crop of a scene item has changed.", "eventType": "SceneItemTransformChanged", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 8ed573eb..7c7f66e4 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -1274,6 +1274,7 @@ Subscription value to receive the `SceneItemTransformChanged` high-volume event. - [SceneItemListReindexed](#sceneitemlistreindexed) - [SceneItemEnableStateChanged](#sceneitemenablestatechanged) - [SceneItemLockStateChanged](#sceneitemlockstatechanged) + - [SceneItemSelected](#sceneitemselected) - [SceneItemTransformChanged](#sceneitemtransformchanged) - [Outputs](#outputs) - [StreamStateChanged](#streamstatechanged) @@ -1857,6 +1858,24 @@ A scene item's lock state has changed. --- +### SceneItemSelected + +A scene item has been selected in the Ui. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sceneName | String | Name of the scene the item is in | +| sceneItemId | Number | Numeric ID of the scene item | + +--- + ### SceneItemTransformChanged The transform/crop of a scene item has changed. From 931a1630ce716a4b83517069fbf43ab59e66ef11 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 28 Jan 2022 16:07:23 -0800 Subject: [PATCH 103/128] README: Update link to workflow --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f37d2ee..87dfd285 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ WebSocket API for OBS Studio. -[![CI Multiplatform Build](https://github.com/obsproject/obs-websocket/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/obs-websocket/obs-websocket/actions/workflows/main.yml) +[![CI Multiplatform Build](https://github.com/obsproject/obs-websocket/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/obsproject/obs-websocket/actions/workflows/main.yml) [![Discord](https://img.shields.io/discord/715691013825364120.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/WBaSQ3A) [![Financial Contributors on Open Collective](https://opencollective.com/obs-websocket-dev/all/badge.svg?label=financial+contributors)](https://opencollective.com/obs-websocket-dev) From d2ddde3229d557b0d4d1dcf59f580d33c872d6f4 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 28 Jan 2022 16:56:21 -0800 Subject: [PATCH 104/128] eventhandler: Add a few transition events --- src/eventhandler/EventHandler.cpp | 2 + src/eventhandler/EventHandler.h | 4 ++ src/eventhandler/EventHandler_Transitions.cpp | 42 +++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/src/eventhandler/EventHandler.cpp b/src/eventhandler/EventHandler.cpp index ee79c18a..1ac8f9f3 100644 --- a/src/eventhandler/EventHandler.cpp +++ b/src/eventhandler/EventHandler.cpp @@ -300,10 +300,12 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_ // Transitions case OBS_FRONTEND_EVENT_TRANSITION_CHANGED: + eventHandler->HandleCurrentSceneTransitionChanged(); break; case OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED: break; case OBS_FRONTEND_EVENT_TRANSITION_DURATION_CHANGED: + eventHandler->HandleCurrentSceneTransitionDurationChanged(); break; // Outputs diff --git a/src/eventhandler/EventHandler.h b/src/eventhandler/EventHandler.h index 6200dc95..7049864e 100644 --- a/src/eventhandler/EventHandler.h +++ b/src/eventhandler/EventHandler.h @@ -112,6 +112,10 @@ class EventHandler static void HandleInputAudioTracksChanged(void *param, calldata_t *data); // Direct callback static void HandleInputAudioMonitorTypeChanged(void *param, calldata_t *data); // Direct callback + // Transitions + void HandleCurrentSceneTransitionChanged(); + void HandleCurrentSceneTransitionDurationChanged(); + // Outputs void HandleStreamStateChanged(ObsOutputState state); void HandleRecordStateChanged(ObsOutputState state); diff --git a/src/eventhandler/EventHandler_Transitions.cpp b/src/eventhandler/EventHandler_Transitions.cpp index 6e0f4c11..860d5cc6 100644 --- a/src/eventhandler/EventHandler_Transitions.cpp +++ b/src/eventhandler/EventHandler_Transitions.cpp @@ -18,3 +18,45 @@ with this program. If not, see */ #include "EventHandler.h" + +/** + * The current scene transition has changed. + * + * @dataField transitionName | String | Name of the new transition + * + * @eventType CurrentSceneTransitionChanged + * @eventSubscription Transitions + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category transitions + */ +void EventHandler::HandleCurrentSceneTransitionChanged() +{ + OBSSourceAutoRelease transition = obs_frontend_get_current_transition(); + + json eventData; + eventData["transitionName"] = obs_source_get_name(transition); + BroadcastEvent(EventSubscription::Transitions, "CurrentSceneTransitionChanged", eventData); +} + +/** + * The current scene transition duration has changed. + * + * @dataField transitionDuration | Number | Transition duration in milliseconds + * + * @eventType CurrentSceneTransitionDurationChanged + * @eventSubscription Transitions + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category transitions + */ +void EventHandler::HandleCurrentSceneTransitionDurationChanged() +{ + json eventData; + eventData["transitionDuration"] = obs_frontend_get_transition_duration(); + BroadcastEvent(EventSubscription::Transitions, "CurrentSceneTransitionDurationChanged", eventData); +} From e80bcad1e1b6db184059da56bbd20bcbea76f6ee Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Sat, 29 Jan 2022 00:56:54 +0000 Subject: [PATCH 105/128] docs(ci): Update generated docs - d2ddde3 [skip ci] --- docs/generated/protocol.json | 34 ++++++++++++++++++++++++++++++++ docs/generated/protocol.md | 38 +++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index bcb6b37b..38a31b0c 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -4655,6 +4655,40 @@ } ] }, + { + "description": "The current scene transition has changed.", + "eventType": "CurrentSceneTransitionChanged", + "eventSubscription": "Transitions", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "transitions", + "dataFields": [ + { + "valueName": "transitionName", + "valueType": "String", + "valueDescription": "Name of the new transition" + } + ] + }, + { + "description": "The current scene transition duration has changed.", + "eventType": "CurrentSceneTransitionDurationChanged", + "eventSubscription": "Transitions", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "transitions", + "dataFields": [ + { + "valueName": "transitionDuration", + "valueType": "Number", + "valueDescription": "Transition duration in milliseconds" + } + ] + }, { "description": "Studio mode has been enabled or disabled.", "eventType": "StudioModeStateChanged", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 7c7f66e4..6532df7c 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -1268,6 +1268,9 @@ Subscription value to receive the `SceneItemTransformChanged` high-volume event. - [InputAudioTracksChanged](#inputaudiotrackschanged) - [InputAudioMonitorTypeChanged](#inputaudiomonitortypechanged) - [InputVolumeMeters](#inputvolumemeters) +- [Transitions](#transitions) + - [CurrentSceneTransitionChanged](#currentscenetransitionchanged) + - [CurrentSceneTransitionDurationChanged](#currentscenetransitiondurationchanged) - [Scene Items](#scene-items) - [SceneItemCreated](#sceneitemcreated) - [SceneItemRemoved](#sceneitemremoved) @@ -1759,6 +1762,39 @@ A high-volume event providing volume levels of all active inputs every 50 millis | Name | Type | Description | | ---- | :---: | ----------- | | inputs | Array<Object> | Array of active inputs with their associated volume levels | +## Transitions + +### CurrentSceneTransitionChanged + +The current scene transition has changed. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| transitionName | String | Name of the new transition | + +--- + +### CurrentSceneTransitionDurationChanged + +The current scene transition duration has changed. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| transitionDuration | Number | Transition duration in milliseconds | ## Scene Items ### SceneItemCreated @@ -2116,7 +2152,7 @@ Studio mode has been enabled or disabled. - [SetInputAudioTracks](#setinputaudiotracks) - [GetInputPropertiesListPropertyItems](#getinputpropertieslistpropertyitems) - [PressInputPropertiesButton](#pressinputpropertiesbutton) -- [Transitions](#transitions) +- [Transitions](#transitions-1) - [GetTransitionKindList](#gettransitionkindlist) - [GetSceneTransitionList](#getscenetransitionlist) - [GetCurrentSceneTransition](#getcurrentscenetransition) From ddf752fd036c0d153c1c025a208a979994b2d6f0 Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Sat, 29 Jan 2022 23:50:12 +0900 Subject: [PATCH 106/128] docs: Fix wrong field name in `SceneItemLockStateChanged` --- src/eventhandler/EventHandler_SceneItems.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/eventhandler/EventHandler_SceneItems.cpp b/src/eventhandler/EventHandler_SceneItems.cpp index 9b5e2b6f..a161f78e 100644 --- a/src/eventhandler/EventHandler_SceneItems.cpp +++ b/src/eventhandler/EventHandler_SceneItems.cpp @@ -158,9 +158,9 @@ void EventHandler::HandleSceneItemEnableStateChanged(void *param, calldata_t *da /** * A scene item's lock state has changed. * - * @dataField sceneName | String | Name of the scene the item is in - * @dataField sceneItemId | Number | Numeric ID of the scene item - * @dataField sceneItemEnabled | Boolean | Whether the scene item is locked + * @dataField sceneName | String | Name of the scene the item is in + * @dataField sceneItemId | Number | Numeric ID of the scene item + * @dataField sceneItemLocked | Boolean | Whether the scene item is locked * * @eventType SceneItemLockStateChanged * @eventSubscription SceneItems From 7113055218c1b0d83b318e0ef8a4bf143b6a3be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lepin?= Date: Tue, 1 Feb 2022 10:12:42 +0100 Subject: [PATCH 107/128] ci(macos): configure productsign with installer certificate --- .github/workflows/main.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d8e27ccd..47ebe6e4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -366,11 +366,16 @@ jobs: repository: obsproject/obs-studio path: ${{ github.workspace }}/obs-studio submodules: 'recursive' - - name: 'Install Prerequisite: Binary/Installer Signing Certificate' + - name: 'Install Prerequisite: Binary Signing Certificate' uses: apple-actions/import-codesign-certs@v1 with: p12-file-base64: ${{ secrets.MACOS_SIGNING_CERT }} p12-password: ${{ secrets.MACOS_SIGNING_CERT_PASSWORD }} + - name: 'Install Prerequisite: Installer Signing Certificate' + uses: apple-actions/import-codesign-certs@v1 + with: + p12-file-base64: ${{ secrets.MACOS_INSTALLER_CERT }} + p12-password: ${{ secrets.MACOS_INSTALLER_CERT_PASSWORD }} - name: 'Get OBS Studio Git Info' shell: bash working-directory: ${{ github.workspace }}/obs-studio @@ -505,7 +510,7 @@ jobs: working-directory: ${{ github.workspace }}/obs-websocket run: | productsign \ - --sign "${{ secrets.MACOS_SIGNING_IDENTITY }}" \ + --sign "${{ secrets.MACOS_INSTALLER_IDENTITY }}" \ ./release/${{ env.MACOS_FILENAME_UNSIGNED }} \ ./release/${{ env.MACOS_FILENAME }} rm ./release/${{ env.MACOS_FILENAME_UNSIGNED }} From eeb7bac4b74dcfd3d980303d67befb6d1bafea8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lepin?= Date: Tue, 1 Feb 2022 10:19:36 +0100 Subject: [PATCH 108/128] ci(macos): import installer certificate in existing keychain --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 47ebe6e4..61f2641d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -376,6 +376,7 @@ jobs: with: p12-file-base64: ${{ secrets.MACOS_INSTALLER_CERT }} p12-password: ${{ secrets.MACOS_INSTALLER_CERT_PASSWORD }} + create-keychain: false - name: 'Get OBS Studio Git Info' shell: bash working-directory: ${{ github.workspace }}/obs-studio From 403c69463a8cd843116fd355bd7a62289de4841f Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Wed, 2 Feb 2022 10:36:59 +0900 Subject: [PATCH 109/128] server: Fix int type of batch execution enum --- src/requesthandler/types/RequestBatchExecutionType.h | 4 ++-- src/websocketserver/WebSocketServer_Protocol.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/requesthandler/types/RequestBatchExecutionType.h b/src/requesthandler/types/RequestBatchExecutionType.h index d778ee99..df158ffe 100644 --- a/src/requesthandler/types/RequestBatchExecutionType.h +++ b/src/requesthandler/types/RequestBatchExecutionType.h @@ -22,7 +22,7 @@ with this program. If not, see #include namespace RequestBatchExecutionType { - enum RequestBatchExecutionType { + enum RequestBatchExecutionType: int8_t { /** * Not a request batch. * @@ -77,7 +77,7 @@ namespace RequestBatchExecutionType { Parallel = 2, }; - inline bool IsValid(int executionType) + inline bool IsValid(int8_t executionType) { return executionType >= None && executionType <= Parallel; } diff --git a/src/websocketserver/WebSocketServer_Protocol.cpp b/src/websocketserver/WebSocketServer_Protocol.cpp index 689ef977..67c082c3 100644 --- a/src/websocketserver/WebSocketServer_Protocol.cpp +++ b/src/websocketserver/WebSocketServer_Protocol.cpp @@ -233,7 +233,7 @@ void WebSocketServer::ProcessMessage(SessionPtr session, WebSocketServer::Proces return; } - uint8_t requestedExecutionType = payloadData["executionType"]; + int8_t requestedExecutionType = payloadData["executionType"]; if (!RequestBatchExecutionType::IsValid(requestedExecutionType) || requestedExecutionType == RequestBatchExecutionType::None) { ret.closeCode = WebSocketCloseCode::InvalidDataFieldValue; ret.closeReason = "Your `executionType` has an invalid value."; From 7c35d6e738071f0e46524694a5e0f8f01aa36052 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Sun, 13 Feb 2022 22:41:10 +0000 Subject: [PATCH 110/128] docs(ci): Update generated docs - b206321 [skip ci] --- docs/generated/protocol.json | 2 +- docs/generated/protocol.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 38a31b0c..219b0a60 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -4483,7 +4483,7 @@ "valueDescription": "Numeric ID of the scene item" }, { - "valueName": "sceneItemEnabled", + "valueName": "sceneItemLocked", "valueType": "Boolean", "valueDescription": "Whether the scene item is locked" } diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 6532df7c..8332ead1 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -1890,7 +1890,7 @@ A scene item's lock state has changed. | ---- | :---: | ----------- | | sceneName | String | Name of the scene the item is in | | sceneItemId | Number | Numeric ID of the scene item | -| sceneItemEnabled | Boolean | Whether the scene item is locked | +| sceneItemLocked | Boolean | Whether the scene item is locked | --- From 341259e610d5478f0afdf82ac5b52925102adfa1 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sun, 13 Feb 2022 14:46:11 -0800 Subject: [PATCH 111/128] RequestHandler: Save config after profile parameter change Fixes a bug where changed parameters were not applying across loads Fixes #895 --- src/requesthandler/RequestHandler_Config.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/requesthandler/RequestHandler_Config.cpp b/src/requesthandler/RequestHandler_Config.cpp index 86d92f7e..f84de970 100644 --- a/src/requesthandler/RequestHandler_Config.cpp +++ b/src/requesthandler/RequestHandler_Config.cpp @@ -408,6 +408,8 @@ RequestResult RequestHandler::SetProfileParameter(const Request& request) return RequestResult::Error(RequestStatus::InvalidRequestFieldType, "The field `parameterValue` must be a string."); } + config_save(profile); + return RequestResult::Success(); } From 7ca8140a342c8e508a3bf6f3e6b11218e02a6c24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lepin?= Date: Sun, 13 Feb 2022 23:47:32 +0100 Subject: [PATCH 112/128] ci(macos): use a common password for keychain import steps --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 61f2641d..42ef844f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -371,12 +371,15 @@ jobs: with: p12-file-base64: ${{ secrets.MACOS_SIGNING_CERT }} p12-password: ${{ secrets.MACOS_SIGNING_CERT_PASSWORD }} + create-keychain: true + keychain-password: ${{ secrets.MACOS_TEMP_CI_KEYCHAIN_PASSWORD }} - name: 'Install Prerequisite: Installer Signing Certificate' uses: apple-actions/import-codesign-certs@v1 with: p12-file-base64: ${{ secrets.MACOS_INSTALLER_CERT }} p12-password: ${{ secrets.MACOS_INSTALLER_CERT_PASSWORD }} create-keychain: false + keychain-password: ${{ secrets.MACOS_TEMP_CI_KEYCHAIN_PASSWORD }} - name: 'Get OBS Studio Git Info' shell: bash working-directory: ${{ github.workspace }}/obs-studio From 3362d3f9986c50b5bb3ffdb418ce354cfebcc54b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lepin?= Date: Sun, 13 Feb 2022 23:51:39 +0100 Subject: [PATCH 113/128] ci(macos): bump Packages version --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 42ef844f..004ac3fc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -416,7 +416,7 @@ jobs: run: | curl -L -O http://s.sudre.free.fr/Software/files/Packages.dmg sudo hdiutil attach ./Packages.dmg - sudo installer -pkg /Volumes/Packages\ 1.2.9/Install\ Packages.pkg -target / + sudo installer -pkg /Volumes/Packages\ 1.2.10/Install\ Packages.pkg -target / - name: 'Restore Cached Qt & OBS Studio dependencies' id: deps-cache uses: actions/cache@v2 From ab137ce8a4b365342570d7e895e4b3f1502a7bd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lepin?= Date: Mon, 14 Feb 2022 00:19:19 +0100 Subject: [PATCH 114/128] ci: restrict push builds to the master branch --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 004ac3fc..9336984b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,7 +5,7 @@ on: paths-ignore: - 'docs/**' branches: - - '*' + - master tags: - '[45].[0-9]+.[0-9]+*' pull_request: From fa8a091a3e84ef85e415551ab0945f62f16a3328 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Sun, 13 Feb 2022 15:19:53 -0800 Subject: [PATCH 115/128] RequestHandler: Add SendStreamCaption --- src/requesthandler/RequestHandler.cpp | 1 + src/requesthandler/RequestHandler.h | 1 + src/requesthandler/RequestHandler_Stream.cpp | 32 ++++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index ca1275ab..075ade1d 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -143,6 +143,7 @@ const std::unordered_map RequestHandler::_han {"ToggleStream", &RequestHandler::ToggleStream}, {"StartStream", &RequestHandler::StartStream}, {"StopStream", &RequestHandler::StopStream}, + {"SendStreamCaption", &RequestHandler::SendStreamCaption}, // Record {"GetRecordStatus", &RequestHandler::GetRecordStatus}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 2e5927de..d678ecf4 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -161,6 +161,7 @@ class RequestHandler { RequestResult ToggleStream(const Request&); RequestResult StartStream(const Request&); RequestResult StopStream(const Request&); + RequestResult SendStreamCaption(const Request&); // Record RequestResult GetRecordStatus(const Request&); diff --git a/src/requesthandler/RequestHandler_Stream.cpp b/src/requesthandler/RequestHandler_Stream.cpp index 98c9e60b..367ebd48 100644 --- a/src/requesthandler/RequestHandler_Stream.cpp +++ b/src/requesthandler/RequestHandler_Stream.cpp @@ -122,3 +122,35 @@ RequestResult RequestHandler::StopStream(const Request&) return RequestResult::Success(); } + +/** + * Sends CEA-608 caption text over the stream output. + * + * @requestField captionText | String | Caption text + * + * @requestType SendStreamCaption + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category stream + * @api requests + */ +RequestResult RequestHandler::SendStreamCaption(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + if (!request.ValidateString("captionText", statusCode, comment, true)) + return RequestResult::Error(statusCode, comment); + + if (!obs_frontend_streaming_active()) + return RequestResult::Error(RequestStatus::OutputNotRunning); + + std::string captionText = request.RequestData["captionText"]; + + OBSOutputAutoRelease output = obs_frontend_get_streaming_output(); + + // 0.0 means no delay until the next caption can be sent + obs_output_output_caption_text2(output, captionText.c_str(), 0.0); + + return RequestResult::Success(); +} From 559212682ac1ebaca38d7f127b51823b3f638a50 Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Sun, 13 Feb 2022 23:20:38 +0000 Subject: [PATCH 116/128] docs(ci): Update generated docs - fa8a091 [skip ci] --- docs/generated/protocol.json | 20 ++++++++++++++++++++ docs/generated/protocol.md | 18 ++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 219b0a60..0530d23d 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -3542,6 +3542,26 @@ "requestFields": [], "responseFields": [] }, + { + "description": "Sends CEA-608 caption text over the stream output.", + "requestType": "SendStreamCaption", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "stream", + "requestFields": [ + { + "valueName": "captionText", + "valueType": "String", + "valueDescription": "Caption text", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, { "description": "Gets an array of all available transition kinds.\n\nSimilar to `GetInputKindList`", "requestType": "GetTransitionKindList", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 8332ead1..b4c8af30 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -2195,6 +2195,7 @@ Studio mode has been enabled or disabled. - [ToggleStream](#togglestream) - [StartStream](#startstream) - [StopStream](#stopstream) + - [SendStreamCaption](#sendstreamcaption) - [Record](#record) - [GetRecordStatus](#getrecordstatus) - [ToggleRecord](#togglerecord) @@ -4243,6 +4244,23 @@ Stops the stream output. - Latest Supported RPC Version: `1` - Added in v5.0.0 +--- + +### SendStreamCaption + +Sends CEA-608 caption text over the stream output. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| captionText | String | Caption text | None | N/A | + ## Record From d9070f9edbf48148e0e3212d6153a4289111c263 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Mon, 14 Feb 2022 15:57:33 -0800 Subject: [PATCH 117/128] requesthandler: Add scene scene transition override requests It's named like: `Get Scene (Scene Transition) Override` --- src/requesthandler/RequestHandler.cpp | 2 + src/requesthandler/RequestHandler.h | 2 + src/requesthandler/RequestHandler_Scenes.cpp | 102 +++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 075ade1d..b83e2263 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -69,6 +69,8 @@ const std::unordered_map RequestHandler::_han {"CreateScene", &RequestHandler::CreateScene}, {"RemoveScene", &RequestHandler::RemoveScene}, {"SetSceneName", &RequestHandler::SetSceneName}, + {"GetSceneSceneTransitionOverride", &RequestHandler::GetSceneSceneTransitionOverride}, + {"SetSceneSceneTransitionOverride", &RequestHandler::SetSceneSceneTransitionOverride}, // Inputs {"GetInputList", &RequestHandler::GetInputList}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index d678ecf4..7a4c3052 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -87,6 +87,8 @@ class RequestHandler { RequestResult CreateScene(const Request&); RequestResult RemoveScene(const Request&); RequestResult SetSceneName(const Request&); + RequestResult GetSceneSceneTransitionOverride(const Request&); + RequestResult SetSceneSceneTransitionOverride(const Request&); // Inputs RequestResult GetInputList(const Request&); diff --git a/src/requesthandler/RequestHandler_Scenes.cpp b/src/requesthandler/RequestHandler_Scenes.cpp index a972306f..d4d376fd 100644 --- a/src/requesthandler/RequestHandler_Scenes.cpp +++ b/src/requesthandler/RequestHandler_Scenes.cpp @@ -273,3 +273,105 @@ RequestResult RequestHandler::SetSceneName(const Request& request) return RequestResult::Success(); } + +/** + * Gets the scene transition overridden for a scene. + * + * @requestField sceneName | String | Name 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` + * + * @requestType GetSceneSceneTransitionOverride + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scenes + */ +RequestResult RequestHandler::GetSceneSceneTransitionOverride(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSourceAutoRelease scene = request.ValidateScene("sceneName", statusCode, comment); + if (!scene) + return RequestResult::Error(statusCode, comment); + + OBSDataAutoRelease privateSettings = obs_source_get_private_settings(scene); + + json responseData; + const char *transitionName = obs_data_get_string(privateSettings, "transition"); + if (transitionName && strlen(transitionName)) + responseData["transitionName"] = transitionName; + else + responseData["transitionName"] = nullptr; + + if (obs_data_has_user_value(privateSettings, "transition_duration")) + responseData["transitionDuration"] = obs_data_get_int(privateSettings, "transition_duration"); + else + responseData["transitionDuration"] = nullptr; + + return RequestResult::Success(responseData); +} + +/** + * Gets the scene transition overridden for a scene. + * + * @requestField sceneName | String | Name of the scene + * @requestField ?transitionName | String | Name of the scene transition to use as override. Specify `null` to remove | Unchanged + * @requestField ?transitionDuration | Number | Duration to use for any overridden transition. Specify `null` to remove | >= 50, <= 20000 | Unchanged + * + * @requestType SetSceneSceneTransitionOverride + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category scenes + */ +RequestResult RequestHandler::SetSceneSceneTransitionOverride(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSourceAutoRelease scene = request.ValidateScene("sceneName", statusCode, comment); + if (!scene) + return RequestResult::Error(statusCode, comment); + + OBSDataAutoRelease privateSettings = obs_source_get_private_settings(scene); + + bool hasName = request.RequestData.contains("transitionName"); + if (hasName && !request.RequestData["transitionName"].is_null()) { + if (!request.ValidateOptionalString("transitionName", statusCode, comment)) + return RequestResult::Error(statusCode, comment); + OBSSourceAutoRelease transition = Utils::Obs::SearchHelper::GetSceneTransitionByName(request.RequestData["transitionName"]); + if (!transition) + return RequestResult::Error(RequestStatus::ResourceNotFound, "No scene transition was found by that name."); + } + + bool hasDuration = request.RequestData.contains("transitionDuration"); + if (hasDuration && !request.RequestData["transitionDuration"].is_null()) { + if (!request.ValidateOptionalNumber("transitionDuration", statusCode, comment, 50, 20000)) + return RequestResult::Error(statusCode, comment); + } + + if (!hasName && !hasDuration) + return RequestResult::Error(RequestStatus::MissingRequestField, "Your request data must include either `transitionName` or `transitionDuration`."); + + if (hasName) { + if (request.RequestData["transitionName"].is_null()) { + obs_data_erase(privateSettings, "transition"); + } else { + std::string transitionName = request.RequestData["transitionName"]; + obs_data_set_string(privateSettings, "transition", transitionName.c_str()); + } + } + + if (hasDuration) { + if (request.RequestData["transitionDuration"].is_null()) { + obs_data_erase(privateSettings, "transition_duration"); + } else { + obs_data_set_int(privateSettings, "transition_duration", request.RequestData["transitionDuration"]); + } + } + + return RequestResult::Success(); +} From 9664f28483e720d197ccfebfbe164471b6110362 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Mon, 14 Feb 2022 17:01:44 -0800 Subject: [PATCH 118/128] requesthandler: Finish transition requests --- src/requesthandler/RequestHandler.cpp | 2 + src/requesthandler/RequestHandler.h | 2 + .../RequestHandler_Transitions.cpp | 73 +++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index b83e2263..0767a9d4 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -105,7 +105,9 @@ const std::unordered_map RequestHandler::_han {"SetCurrentSceneTransition", &RequestHandler::SetCurrentSceneTransition}, {"SetCurrentSceneTransitionDuration", &RequestHandler::SetCurrentSceneTransitionDuration}, {"SetCurrentSceneTransitionSettings", &RequestHandler::SetCurrentSceneTransitionSettings}, + {"GetCurrentSceneTransitionCursor", &RequestHandler::GetCurrentSceneTransitionCursor}, {"TriggerStudioModeTransition", &RequestHandler::TriggerStudioModeTransition}, + {"SetTBarPosition", &RequestHandler::SetTBarPosition}, // Filters {"GetSourceFilter", &RequestHandler::GetSourceFilter}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 7a4c3052..7ed8b346 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -123,7 +123,9 @@ class RequestHandler { RequestResult SetCurrentSceneTransition(const Request&); RequestResult SetCurrentSceneTransitionDuration(const Request&); RequestResult SetCurrentSceneTransitionSettings(const Request&); + RequestResult GetCurrentSceneTransitionCursor(const Request&); RequestResult TriggerStudioModeTransition(const Request&); + RequestResult SetTBarPosition(const Request&); // Filters RequestResult GetSourceFilter(const Request&); diff --git a/src/requesthandler/RequestHandler_Transitions.cpp b/src/requesthandler/RequestHandler_Transitions.cpp index aaa793e7..a1ebabe8 100644 --- a/src/requesthandler/RequestHandler_Transitions.cpp +++ b/src/requesthandler/RequestHandler_Transitions.cpp @@ -17,6 +17,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see */ +#include + #include "RequestHandler.h" /** @@ -226,6 +228,32 @@ RequestResult RequestHandler::SetCurrentSceneTransitionSettings(const Request& r return RequestResult::Success(); } +/** + * Gets the cursor position of the current scene transition. + * + * Note: `transitionCursor` will return 1.0 when the transition is inactive. + * + * @responseField transitionCursor | Number | Cursor position, between 0.0 and 1.0 + * + * @requestType GetCurrentSceneTransitionCursor + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category transitions + */ +RequestResult RequestHandler::GetCurrentSceneTransitionCursor(const Request&) +{ + OBSSourceAutoRelease transition = obs_frontend_get_current_transition(); + if (!transition) + return RequestResult::Error(RequestStatus::InvalidResourceState, "OBS does not currently have a scene transition set."); // This should not happen! + + json responseData; + responseData["transitionCursor"] = obs_transition_get_time(transition); + + return RequestResult::Success(responseData); +} + /** * Triggers the current scene transition. Same functionality as the `Transition` button in studio mode. * @@ -247,3 +275,48 @@ RequestResult RequestHandler::TriggerStudioModeTransition(const Request&) return RequestResult::Success(); } + +/** + * Sets the position of the TBar. + * + * **Very important note**: This will be deprecated and replaced in a future version of obs-websocket. + * + * @requestField position | Number | New position | >= 0.0, <= 1.0 + * @requestField ?release | Boolean | Whether to release the TBar. Only set `false` if you know that you will be sending another position update | `true` + * + * @requestType SetTBarPosition + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category transitions + */ +RequestResult RequestHandler::SetTBarPosition(const Request& request) +{ + if (!obs_frontend_preview_program_mode_active()) + return RequestResult::Error(RequestStatus::StudioModeNotActive); + + RequestStatus::RequestStatus statusCode; + std::string comment; + if (!request.ValidateNumber("position", statusCode, comment, 0.0, 1.0)) + return RequestResult::Error(statusCode, comment); + + bool release = true; + if (request.Contains("release")) { + if (!request.ValidateOptionalBoolean("release", statusCode, comment)) + return RequestResult::Error(statusCode, comment); + } + + OBSSourceAutoRelease transition = obs_frontend_get_current_transition(); + if (!transition) + return RequestResult::Error(RequestStatus::InvalidResourceState, "OBS does not currently have a scene transition set."); // This should not happen! + + float position = request.RequestData["position"]; + + obs_frontend_set_tbar_position((int)round(position * 1024.0)); + + if (release) + obs_frontend_release_tbar(); + + return RequestResult::Success(); +} From 7b52d7e015a22fc59dfb81ae68280fd680acf0be Mon Sep 17 00:00:00 2001 From: tt2468 Date: Mon, 14 Feb 2022 17:11:07 -0800 Subject: [PATCH 119/128] requesthandler: Move GetRecordDirectory to config More consistency --- src/requesthandler/RequestHandler.cpp | 2 +- src/requesthandler/RequestHandler.h | 2 +- src/requesthandler/RequestHandler_Config.cpp | 20 ++++++++++++++++++++ src/requesthandler/RequestHandler_Record.cpp | 20 -------------------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 0767a9d4..b9933890 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -51,6 +51,7 @@ const std::unordered_map RequestHandler::_han {"SetVideoSettings", &RequestHandler::SetVideoSettings}, {"GetStreamServiceSettings", &RequestHandler::GetStreamServiceSettings}, {"SetStreamServiceSettings", &RequestHandler::SetStreamServiceSettings}, + {"GetRecordDirectory", &RequestHandler::GetRecordDirectory}, // Sources {"GetSourceActive", &RequestHandler::GetSourceActive}, @@ -157,7 +158,6 @@ const std::unordered_map RequestHandler::_han {"ToggleRecordPause", &RequestHandler::ToggleRecordPause}, {"PauseRecord", &RequestHandler::PauseRecord}, {"ResumeRecord", &RequestHandler::ResumeRecord}, - {"GetRecordDirectory", &RequestHandler::GetRecordDirectory}, // Media Inputs {"GetMediaInputStatus", &RequestHandler::GetMediaInputStatus}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 7ed8b346..65517370 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -69,6 +69,7 @@ class RequestHandler { RequestResult SetVideoSettings(const Request&); RequestResult GetStreamServiceSettings(const Request&); RequestResult SetStreamServiceSettings(const Request&); + RequestResult GetRecordDirectory(const Request&); // Sources RequestResult GetSourceActive(const Request&); @@ -175,7 +176,6 @@ class RequestHandler { RequestResult ToggleRecordPause(const Request&); RequestResult PauseRecord(const Request&); RequestResult ResumeRecord(const Request&); - RequestResult GetRecordDirectory(const Request&); // Media Inputs RequestResult GetMediaInputStatus(const Request&); diff --git a/src/requesthandler/RequestHandler_Config.cpp b/src/requesthandler/RequestHandler_Config.cpp index f84de970..ab3612ec 100644 --- a/src/requesthandler/RequestHandler_Config.cpp +++ b/src/requesthandler/RequestHandler_Config.cpp @@ -594,3 +594,23 @@ RequestResult RequestHandler::SetStreamServiceSettings(const Request& request) return RequestResult::Success(); } + +/** + * Gets the current directory that the record output is set to. + * + * @responseField recordDirectory | String | Output directory + * + * @requestType GetRecordDirectory + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category rconfig + */ +RequestResult RequestHandler::GetRecordDirectory(const Request&) +{ + json responseData; + responseData["recordDirectory"] = Utils::Obs::StringHelper::GetCurrentRecordOutputPath(); + + return RequestResult::Success(responseData); +} diff --git a/src/requesthandler/RequestHandler_Record.cpp b/src/requesthandler/RequestHandler_Record.cpp index c6e2e21a..9eb248ea 100644 --- a/src/requesthandler/RequestHandler_Record.cpp +++ b/src/requesthandler/RequestHandler_Record.cpp @@ -182,23 +182,3 @@ RequestResult RequestHandler::ResumeRecord(const Request&) return RequestResult::Success(); } - -/** - * Gets the current directory that the record output is set to. - * - * @responseField recordDirectory | String | Output directory - * - * @requestType GetRecordDirectory - * @complexity 1 - * @rpcVersion -1 - * @initialVersion 5.0.0 - * @api requests - * @category record - */ -RequestResult RequestHandler::GetRecordDirectory(const Request&) -{ - json responseData; - responseData["recordDirectory"] = Utils::Obs::StringHelper::GetCurrentRecordOutputPath(); - - return RequestResult::Success(responseData); -} From 0b294734a270f66cd39b2e765ea1f63a467a7a1a Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Tue, 15 Feb 2022 05:02:03 +0000 Subject: [PATCH 120/128] docs(ci): Update generated docs - 7b52d7e [skip ci] --- docs/generated/protocol.json | 146 +++++++++++++++++++++++++++++++---- docs/generated/protocol.md | 105 ++++++++++++++++++++----- 2 files changed, 216 insertions(+), 35 deletions(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 0530d23d..75fb3d24 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -1129,6 +1129,23 @@ ], "responseFields": [] }, + { + "description": "Gets the current directory that the record output is set to.", + "requestType": "GetRecordDirectory", + "complexity": 1, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "rconfig", + "requestFields": [], + "responseFields": [ + { + "valueName": "recordDirectory", + "valueType": "String", + "valueDescription": "Output directory" + } + ] + }, { "description": "Gets the info for a specific source filter.", "requestType": "GetSourceFilter", @@ -2550,23 +2567,6 @@ "requestFields": [], "responseFields": [] }, - { - "description": "Gets the current directory that the record output is set to.", - "requestType": "GetRecordDirectory", - "complexity": 1, - "rpcVersion": "1", - "deprecated": false, - "initialVersion": "5.0.0", - "category": "record", - "requestFields": [], - "responseFields": [ - { - "valueName": "recordDirectory", - "valueType": "String", - "valueDescription": "Output directory" - } - ] - }, { "description": "Gets a list of all scene items in a scene.\n\nScenes only", "requestType": "GetSceneItemList", @@ -3301,6 +3301,73 @@ ], "responseFields": [] }, + { + "description": "Gets the scene transition overridden for a scene.", + "requestType": "GetSceneSceneTransitionOverride", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scenes", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "transitionName", + "valueType": "String", + "valueDescription": "Name of the overridden scene transition, else `null`" + }, + { + "valueName": "transitionDuration", + "valueType": "Number", + "valueDescription": "Duration of the overridden scene transition, else `null`" + } + ] + }, + { + "description": "Gets the scene transition overridden for a scene.", + "requestType": "SetSceneSceneTransitionOverride", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "scenes", + "requestFields": [ + { + "valueName": "sceneName", + "valueType": "String", + "valueDescription": "Name of the scene", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "transitionName", + "valueType": "String", + "valueDescription": "Name of the scene transition to use as override. Specify `null` to remove", + "valueRestrictions": null, + "valueOptional": true, + "valueOptionalBehavior": "Unchanged" + }, + { + "valueName": "transitionDuration", + "valueType": "Number", + "valueDescription": "Duration to use for any overridden transition. Specify `null` to remove", + "valueRestrictions": ">= 50, <= 20000", + "valueOptional": true, + "valueOptionalBehavior": "Unchanged" + } + ], + "responseFields": [] + }, { "description": "Gets the active and show state of a source.\n\n**Compatible with inputs and scenes.**", "requestType": "GetSourceActive", @@ -3716,6 +3783,23 @@ ], "responseFields": [] }, + { + "description": "Gets the cursor position of the current scene transition.\n\nNote: `transitionCursor` will return 1.0 when the transition is inactive.", + "requestType": "GetCurrentSceneTransitionCursor", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "transitions", + "requestFields": [], + "responseFields": [ + { + "valueName": "transitionCursor", + "valueType": "Number", + "valueDescription": "Cursor position, between 0.0 and 1.0" + } + ] + }, { "description": "Triggers the current scene transition. Same functionality as the `Transition` button in studio mode.", "requestType": "TriggerStudioModeTransition", @@ -3727,6 +3811,34 @@ "requestFields": [], "responseFields": [] }, + { + "description": "Sets the position of the TBar.\n\n**Very important note**: This will be deprecated and replaced in a future version of obs-websocket.", + "requestType": "SetTBarPosition", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "transitions", + "requestFields": [ + { + "valueName": "position", + "valueType": "Number", + "valueDescription": "New position", + "valueRestrictions": ">= 0.0, <= 1.0", + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "release", + "valueType": "Boolean", + "valueDescription": "Whether to release the TBar. Only set `false` if you know that you will be sending another position update", + "valueRestrictions": null, + "valueOptional": true, + "valueOptionalBehavior": "`true`" + } + ], + "responseFields": [] + }, { "description": "Gets whether studio is enabled.", "requestType": "GetStudioModeEnabled", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index b4c8af30..a436a6d8 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -2127,6 +2127,8 @@ Studio mode has been enabled or disabled. - [CreateScene](#createscene) - [RemoveScene](#removescene) - [SetSceneName](#setscenename) + - [GetSceneSceneTransitionOverride](#getscenescenetransitionoverride) + - [SetSceneSceneTransitionOverride](#setscenescenetransitionoverride) - [Inputs](#inputs-1) - [GetInputList](#getinputlist) - [GetInputKindList](#getinputkindlist) @@ -2159,7 +2161,9 @@ Studio mode has been enabled or disabled. - [SetCurrentSceneTransition](#setcurrentscenetransition) - [SetCurrentSceneTransitionDuration](#setcurrentscenetransitionduration) - [SetCurrentSceneTransitionSettings](#setcurrentscenetransitionsettings) + - [GetCurrentSceneTransitionCursor](#getcurrentscenetransitioncursor) - [TriggerStudioModeTransition](#triggerstudiomodetransition) + - [SetTBarPosition](#settbarposition) - [Filters](#filters) - [GetSourceFilter](#getsourcefilter) - [Scene Items](#scene-items-1) @@ -2204,7 +2208,6 @@ Studio mode has been enabled or disabled. - [ToggleRecordPause](#togglerecordpause) - [PauseRecord](#pauserecord) - [ResumeRecord](#resumerecord) - - [GetRecordDirectory](#getrecorddirectory) - [Media Inputs](#media-inputs-1) - [GetMediaInputStatus](#getmediainputstatus) - [SetMediaInputCursor](#setmediainputcursor) @@ -2947,6 +2950,50 @@ Sets the name of a scene (rename). | sceneName | String | Name of the scene to be renamed | None | N/A | | newSceneName | String | New name for the scene | None | N/A | +--- + +### GetSceneSceneTransitionOverride + +Gets the scene transition overridden for a scene. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene | None | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| transitionName | String | Name of the overridden scene transition, else `null` | +| transitionDuration | Number | Duration of the overridden scene transition, else `null` | + +--- + +### SetSceneSceneTransitionOverride + +Gets the scene transition overridden for a scene. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sceneName | String | Name of the scene | None | N/A | +| ?transitionName | String | Name of the scene transition to use as override. Specify `null` to remove | None | Unchanged | +| ?transitionDuration | Number | Duration to use for any overridden transition. Specify `null` to remove | >= 50, <= 20000 | Unchanged | + ## Inputs @@ -3602,6 +3649,25 @@ Sets the settings of the current scene transition. --- +### GetCurrentSceneTransitionCursor + +Gets the cursor position of the current scene transition. + +Note: `transitionCursor` will return 1.0 when the transition is inactive. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| transitionCursor | Number | Cursor position, between 0.0 and 1.0 | + +--- + ### TriggerStudioModeTransition Triggers the current scene transition. Same functionality as the `Transition` button in studio mode. @@ -3610,6 +3676,26 @@ Triggers the current scene transition. Same functionality as the `Transition` bu - Latest Supported RPC Version: `1` - Added in v5.0.0 +--- + +### SetTBarPosition + +Sets the position of the TBar. + +**Very important note**: This will be deprecated and replaced in a future version of obs-websocket. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| position | Number | New position | >= 0.0, <= 1.0 | N/A | +| ?release | Boolean | Whether to release the TBar. Only set `false` if you know that you will be sending another position update | None | `true` | + ## Filters @@ -4343,23 +4429,6 @@ Resumes the record output. - Latest Supported RPC Version: `1` - Added in v5.0.0 ---- - -### GetRecordDirectory - -Gets the current directory that the record output is set to. - -- Complexity Rating: `1/5` -- Latest Supported RPC Version: `1` -- Added in v5.0.0 - - -**Response Fields:** - -| Name | Type | Description | -| ---- | :---: | ----------- | -| recordDirectory | String | Output directory | - ## Media Inputs From f76de69b34c9c810d716093f7a8f11af11475fc3 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 16 Feb 2022 11:55:57 -0800 Subject: [PATCH 121/128] CI: Use windows-2019 explicitly Github actions recently migrated windows-latest to windows-2022 and in the process broke a bunch of shit. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9336984b..961f40ce 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,7 +18,7 @@ on: jobs: windows: name: 'Windows 32/64-bit' - runs-on: [windows-latest] + runs-on: [windows-2019] if: contains(github.event.head_commit.message, '[skip ci]') != true env: QT_CACHE_VERSION: '2' # Change whenever updating OBS dependencies URL, in order to force a cache reset From b3a5c55bef0e064ff20a670bcd4a221c2cbe598b Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 16 Feb 2022 12:00:01 -0800 Subject: [PATCH 122/128] CI: Only codesign when not PR --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 961f40ce..93b7dad7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -367,6 +367,7 @@ jobs: path: ${{ github.workspace }}/obs-studio submodules: 'recursive' - name: 'Install Prerequisite: Binary Signing Certificate' + if: github.event_name != 'pull_request' uses: apple-actions/import-codesign-certs@v1 with: p12-file-base64: ${{ secrets.MACOS_SIGNING_CERT }} @@ -374,6 +375,7 @@ jobs: create-keychain: true keychain-password: ${{ secrets.MACOS_TEMP_CI_KEYCHAIN_PASSWORD }} - name: 'Install Prerequisite: Installer Signing Certificate' + if: github.event_name != 'pull_request' uses: apple-actions/import-codesign-certs@v1 with: p12-file-base64: ${{ secrets.MACOS_INSTALLER_CERT }} @@ -492,6 +494,7 @@ jobs: @executable_path/../Frameworks/QtSvg.framework/Versions/5/QtSvg \ ./obs-websocket.so - name: 'Sign plugin binary' + if: github.event_name != 'pull_request' shell: bash working-directory: ${{ github.workspace }}/obs-websocket/build run: | From 361547a96da704d9b7e4eedfe4872953efbdc7e9 Mon Sep 17 00:00:00 2001 From: Brendan Allan Date: Thu, 17 Feb 2022 05:17:06 +0800 Subject: [PATCH 123/128] requesthandler: Filter requests & events (#888) * Implement filter requests * Fix CreateSourceFilter * Implement most Filter events * build against 27.1.3 * Update main.yml * SourceFilterNameChanged rename * revert main.yml changes * rename SourceFilterCreated and revert CI changes * cleanup * Base: Various cleanups + fix -Werror * Base: A few nitpicks/fixes * requesthandler: Fix CreateSourceFilter * utils: Fix CreateSourceFilter Use obs_source_t* instead of OBSSourceAutoRelease to prevent double release * requesthandler: Remove filterIndex from CreateSourceFilter The purpose of sceneItemEnabled in CreateSceneItem is to hide the scene item while we still hold the scene mutex (guaranteeing the input will never be shown). Since we don't hold a mutex when creating filters, there's no reason to do any extra steps. * requesthandler: Validate input/filter kinds in *DefaultSettings Co-authored-by: tt2468 --- .gitignore | 1 + src/eventhandler/EventHandler.cpp | 118 +++++++-- src/eventhandler/EventHandler.h | 10 + src/eventhandler/EventHandler_Filters.cpp | 171 ++++++++++++ src/requesthandler/RequestHandler.cpp | 7 + src/requesthandler/RequestHandler.h | 7 + src/requesthandler/RequestHandler_Filters.cpp | 244 ++++++++++++++++++ src/requesthandler/RequestHandler_Inputs.cpp | 3 + src/requesthandler/types/RequestStatus.h | 11 + src/utils/Obs.h | 4 + src/utils/Obs_ActionHelper.cpp | 27 ++ src/utils/Obs_ArrayHelper.cpp | 35 +++ 12 files changed, 613 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 11f19da9..b234aa97 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ /docs/node_modules/ /src/plugin-macros.generated.h /installer/installer-windows.generated.iss +/cmake-build-debug/ diff --git a/src/eventhandler/EventHandler.cpp b/src/eventhandler/EventHandler.cpp index 1ac8f9f3..211fd750 100644 --- a/src/eventhandler/EventHandler.cpp +++ b/src/eventhandler/EventHandler.cpp @@ -135,9 +135,12 @@ void EventHandler::ConnectSourceSignals(obs_source_t *source) // Applies to inpu signal_handler_connect(sh, "mute", HandleInputMuteStateChanged, this); signal_handler_connect(sh, "volume", HandleInputVolumeChanged, this); signal_handler_connect(sh, "audio_balance", HandleInputAudioBalanceChanged, this); - signal_handler_connect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this); - signal_handler_connect(sh, "audio_mixers", HandleInputAudioTracksChanged, this); - signal_handler_connect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this); + signal_handler_connect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this); + signal_handler_connect(sh, "audio_mixers", HandleInputAudioTracksChanged, this); + signal_handler_connect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this); + signal_handler_connect(sh, "filter_add", HandleSourceFilterCreated, this); + signal_handler_connect(sh, "filter_remove", HandleSourceFilterRemoved, this); + signal_handler_connect(sh, "reorder_filters", HandleSourceFilterListReindexed, this); if (sourceType == OBS_SOURCE_TYPE_INPUT) { signal_handler_connect(sh, "media_started", HandleMediaInputPlaybackStarted, this); @@ -188,6 +191,9 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source) signal_handler_disconnect(sh, "media_stopped", SourceMediaStopMultiHandler, this); signal_handler_disconnect(sh, "media_next", SourceMediaNextMultiHandler, this); signal_handler_disconnect(sh, "media_previous", SourceMediaPreviousMultiHandler, this); + signal_handler_disconnect(sh, "filter_add", HandleSourceFilterCreated, this); + signal_handler_disconnect(sh, "filter_remove", HandleSourceFilterRemoved, this); + signal_handler_disconnect(sh, "reorder_filters", HandleSourceFilterListReindexed, this); // Scenes signal_handler_disconnect(sh, "item_add", HandleSceneItemCreated, this); @@ -199,6 +205,30 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source) signal_handler_disconnect(sh, "item_transform", HandleSceneItemTransformChanged, this); } +void EventHandler::ConnectFilterSignals(obs_source_t *filter) +{ + if (!filter || obs_source_removed(filter)) + return; + + DisconnectFilterSignals(filter); + + signal_handler_t* sh = obs_source_get_signal_handler(filter); + + signal_handler_connect(sh, "enable", HandleSourceFilterEnableStateChanged, this); + signal_handler_connect(sh, "rename", HandleSourceFilterNameChanged, this); +} + +void EventHandler::DisconnectFilterSignals(obs_source_t *filter) +{ + if (!filter) + return; + + signal_handler_t* sh = obs_source_get_signal_handler(filter); + + signal_handler_disconnect(sh, "enable", HandleSourceFilterEnableStateChanged, this); + signal_handler_disconnect(sh, "rename", HandleSourceFilterNameChanged, this); +} + void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_data) { auto eventHandler = static_cast(private_data); @@ -211,18 +241,38 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_ // In the case that plugins become hotloadable, this will have to go back into `EventHandler::EventHandler()` // Enumerate inputs and connect each one - obs_enum_sources([](void* param, obs_source_t* source) { - auto eventHandler = static_cast(param); - eventHandler->ConnectSourceSignals(source); - return true; - }, private_data); + { + auto enumInputs = [](void *param, obs_source_t *source) { + auto eventHandler = static_cast(param); + eventHandler->ConnectSourceSignals(source); + + auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){ + auto eventHandler = static_cast(param); + eventHandler->ConnectFilterSignals(filter); + }; + obs_source_enum_filters(source, enumFilters, param); + + return true; + }; + obs_enum_sources(enumInputs, private_data); + } // Enumerate scenes and connect each one - obs_enum_scenes([](void* param, obs_source_t* source) { - auto eventHandler = static_cast(param); - eventHandler->ConnectSourceSignals(source); - return true; - }, private_data); + { + auto enumScenes = [](void *param, obs_source_t *source) { + auto eventHandler = static_cast(param); + eventHandler->ConnectSourceSignals(source); + + auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){ + auto eventHandler = static_cast(param); + eventHandler->ConnectFilterSignals(filter); + }; + obs_source_enum_filters(source, enumFilters, param); + + return true; + }; + obs_enum_scenes(enumScenes, private_data); + } blog_debug("[EventHandler::OnFrontendEvent] Finished."); @@ -244,18 +294,38 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_ // In the case that plugins become hotloadable, this will have to go back into `EventHandler::~EventHandler()` // Enumerate inputs and disconnect each one - obs_enum_sources([](void* param, obs_source_t* source) { - auto eventHandler = static_cast(param); - eventHandler->DisconnectSourceSignals(source); - return true; - }, private_data); + { + auto enumInputs = [](void *param, obs_source_t *source) { + auto eventHandler = static_cast(param); + eventHandler->DisconnectSourceSignals(source); + + auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){ + auto eventHandler = static_cast(param); + eventHandler->ConnectFilterSignals(filter); + }; + obs_source_enum_filters(source, enumFilters, param); + + return true; + }; + obs_enum_sources(enumInputs, private_data); + } // Enumerate scenes and disconnect each one - obs_enum_scenes([](void* param, obs_source_t* source) { - auto eventHandler = static_cast(param); - eventHandler->DisconnectSourceSignals(source); - return true; - }, private_data); + { + auto enumScenes = [](void *param, obs_source_t *source) { + auto eventHandler = static_cast(param); + eventHandler->DisconnectSourceSignals(source); + + auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param){ + auto eventHandler = static_cast(param); + eventHandler->ConnectFilterSignals(filter); + }; + obs_source_enum_filters(source, enumFilters, param); + + return true; + }; + obs_enum_scenes(enumScenes, private_data); + } blog_debug("[EventHandler::OnFrontendEvent] Finished."); @@ -465,8 +535,6 @@ void EventHandler::SourceRenamedMultiHandler(void *param, calldata_t *data) case OBS_SOURCE_TYPE_INPUT: eventHandler->HandleInputNameChanged(source, oldSourceName, sourceName); break; - case OBS_SOURCE_TYPE_FILTER: - break; case OBS_SOURCE_TYPE_TRANSITION: break; case OBS_SOURCE_TYPE_SCENE: diff --git a/src/eventhandler/EventHandler.h b/src/eventhandler/EventHandler.h index 7049864e..3f71caff 100644 --- a/src/eventhandler/EventHandler.h +++ b/src/eventhandler/EventHandler.h @@ -58,6 +58,9 @@ class EventHandler void ConnectSourceSignals(obs_source_t *source); void DisconnectSourceSignals(obs_source_t *source); + void ConnectFilterSignals(obs_source_t *filter); + void DisconnectFilterSignals(obs_source_t *filter); + void BroadcastEvent(uint64_t requiredIntent, std::string eventType, json eventData = nullptr, uint8_t rpcVersion = 0); // Signal handler: frontend @@ -136,4 +139,11 @@ class EventHandler static void HandleMediaInputPlaybackStarted(void *param, calldata_t *data); // Direct callback static void HandleMediaInputPlaybackEnded(void *param, calldata_t *data); // Direct callback void HandleMediaInputActionTriggered(obs_source_t *source, ObsMediaInputAction action); + + // Filters + static void HandleSourceFilterNameChanged(void *param, calldata_t *data); // Direct callback + static void HandleSourceFilterCreated(void *param, calldata_t *data); // Direct callback + static void HandleSourceFilterRemoved(void *param, calldata_t *data); // Direct callback + static void HandleSourceFilterListReindexed(void *param, calldata_t *data); // Direct callback + static void HandleSourceFilterEnableStateChanged(void *param, calldata_t *data); // Direct callback }; diff --git a/src/eventhandler/EventHandler_Filters.cpp b/src/eventhandler/EventHandler_Filters.cpp index 6e0f4c11..308b81b8 100644 --- a/src/eventhandler/EventHandler_Filters.cpp +++ b/src/eventhandler/EventHandler_Filters.cpp @@ -18,3 +18,174 @@ with this program. If not, see */ #include "EventHandler.h" + +/** + * A filter has been added to a source. + * + * @dataField sourceName | String | Name of the source the filter was added to + * @dataField filterName | String | Name of the filter + * @dataField filterKind | String | The kind of the filter + * @dataField filterIndex | Number | Index position of the filter + * @dataField filterSettings | Object | The settings configured to the filter when it was created + * @dataField defaultFilterSettings | Object | The default settings for the filter + * + * @eventType SourceFilterCreated + * @eventSubscription Filters + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category filters + */ +void EventHandler::HandleSourceFilterCreated(void *param, calldata_t *data) +{ + auto eventHandler = static_cast(param); + + obs_source_t *source = GetCalldataPointer(data, "source"); + obs_source_t *filter = GetCalldataPointer(data, "filter"); + + if (!(source && filter)) + return; + + eventHandler->ConnectFilterSignals(filter); + + std::string filterKind = obs_source_get_id(filter); + OBSDataAutoRelease filterSettings = obs_source_get_settings(filter); + OBSDataAutoRelease defaultFilterSettings = obs_get_source_defaults(filterKind.c_str()); + + json eventData; + eventData["sourceName"] = obs_source_get_name(source); + eventData["filterName"] = obs_source_get_name(filter); + eventData["filterKind"] = filterKind; + eventData["filterIndex"] = Utils::Obs::NumberHelper::GetSourceFilterIndex(source, filter); + eventData["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings); + eventData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultFilterSettings, true); + eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterCreated", eventData); +} + +/** + * A filter has been removed from a source. + * + * @dataField sourceName | String | Name of the source the filter was on + * @dataField filterName | String | Name of the filter + * + * @eventType SourceFilterRemoved + * @eventSubscription Filters + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category filters + */ +void EventHandler::HandleSourceFilterRemoved(void *param, calldata_t *data) +{ + auto eventHandler = static_cast(param); + + obs_source_t *source = GetCalldataPointer(data, "source"); + obs_source_t *filter = GetCalldataPointer(data, "filter"); + + if (!(source && filter)) + return; + + eventHandler->DisconnectFilterSignals(filter); + + json eventData; + eventData["sourceName"] = obs_source_get_name(source); + eventData["filterName"] = obs_source_get_name(filter); + eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterRemoved", eventData); +} + +/** + * A source's filter list has been reindexed. + * + * @dataField sourceName | String | Name of the source + * @dataField filters | Array | Array of filter objects + * + * @eventType SourceFilterListReindexed + * @eventSubscription Filters + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category filters + */ +void EventHandler::HandleSourceFilterListReindexed(void *param, calldata_t *data) +{ + auto eventHandler = static_cast(param); + + obs_source_t *source = GetCalldataPointer(data, "source"); + if (!source) + return; + + json eventData; + eventData["sourceName"] = obs_source_get_name(source); + eventData["filters"] = Utils::Obs::ArrayHelper::GetSourceFilterList(source); + eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterListReindexed", eventData); +} + +/** + * A source filter's enable state has changed. + * + * @dataField sourceName | String | Name of the source the filter is on + * @dataField filterName | String | Name of the filter + * @dataField filterEnabled | Boolean | Whether the filter is enabled + * + * @eventType SourceFilterEnableStateChanged + * @eventSubscription Filters + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category filters + */ +void EventHandler::HandleSourceFilterEnableStateChanged(void *param, calldata_t *data) +{ + auto eventHandler = static_cast(param); + + obs_source_t *filter = GetCalldataPointer(data, "source"); + if (!filter) + return; + + // Not OBSSourceAutoRelease as get_parent doesn't increment refcount + obs_source_t *source = obs_filter_get_parent(filter); + if (!source) + return; + + bool filterEnabled = calldata_bool(data, "enabled"); + + json eventData; + eventData["sourceName"] = obs_source_get_name(source); + eventData["filterName"] = obs_source_get_name(filter); + eventData["filterEnabled"] = filterEnabled; + eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterEnableStateChanged", eventData); +} + +/** + * The name of a source filter has changed. + * + * @dataField sourceName | String | The source the filter is on + * @dataField oldFilterName | String | Old name of the filter + * @dataField filterName | String | New name of the filter + * + * @eventType SourceFilterNameChanged + * @eventSubscription Filters + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api events + * @category filters + */ +void EventHandler::HandleSourceFilterNameChanged(void *param, calldata_t *data) +{ + auto eventHandler = static_cast(param); + + obs_source_t *filter = GetCalldataPointer(data, "source"); + if (!filter) + return; + + json eventData; + eventData["sourceName"] = obs_source_get_name(obs_filter_get_parent(filter)); + eventData["oldFilterName"] = calldata_string(data, "prev_name"); + eventData["filterName"] = calldata_string(data, "new_name"); + eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterNameChanged", eventData); +} diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index b9933890..59ef9d1e 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -111,7 +111,14 @@ const std::unordered_map RequestHandler::_han {"SetTBarPosition", &RequestHandler::SetTBarPosition}, // Filters + {"GetSourceFilterList", &RequestHandler::GetSourceFilterList}, + {"CreateSourceFilter", &RequestHandler::CreateSourceFilter}, + {"RemoveSourceFilter", &RequestHandler::RemoveSourceFilter}, + {"GetSourceFilterDefaultSettings", &RequestHandler::GetSourceFilterDefaultSettings}, {"GetSourceFilter", &RequestHandler::GetSourceFilter}, + {"SetSourceFilterIndex", &RequestHandler::SetSourceFilterIndex}, + {"SetSourceFilterSettings", &RequestHandler::SetSourceFilterSettings}, + {"SetSourceFilterEnabled", &RequestHandler::SetSourceFilterEnabled}, // Scene Items {"GetSceneItemList", &RequestHandler::GetSceneItemList}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 65517370..2d9bf20c 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -129,7 +129,14 @@ class RequestHandler { RequestResult SetTBarPosition(const Request&); // Filters + RequestResult GetSourceFilterList(const Request&); + RequestResult CreateSourceFilter(const Request&); + RequestResult RemoveSourceFilter(const Request&); + RequestResult GetSourceFilterDefaultSettings(const Request&); RequestResult GetSourceFilter(const Request&); + RequestResult SetSourceFilterIndex(const Request&); + RequestResult SetSourceFilterSettings(const Request&); + RequestResult SetSourceFilterEnabled(const Request&); // Scene Items RequestResult GetSceneItemList(const Request&); diff --git a/src/requesthandler/RequestHandler_Filters.cpp b/src/requesthandler/RequestHandler_Filters.cpp index 7bb6e0e0..21d51097 100644 --- a/src/requesthandler/RequestHandler_Filters.cpp +++ b/src/requesthandler/RequestHandler_Filters.cpp @@ -19,6 +19,145 @@ with this program. If not, see #include "RequestHandler.h" +/** + * Gets an array of all of a source's filters. + * + * @requestField sourceName | String | Name of the source + * + * @responseField filters | Array | Array of filters + * + * @requestType GetSourceFilterList + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category filters + */ +RequestResult RequestHandler::GetSourceFilterList(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment); + if(!source) + return RequestResult::Error(statusCode, comment); + + json responseData; + responseData["filters"] = Utils::Obs::ArrayHelper::GetSourceFilterList(source); + + return RequestResult::Success(responseData); +} + +/** + * Creates a new filter, adding it to the specified source. + * + * @requestField sourceName | String | Name of the source to add the filter to + * @requestField filterName | String | Name of the new filter to be created + * @requestField filterKind | String | The kind of filter to be created + * @requestField ?filterSettings | Object | Settings object to initialize the filter with | Default settings used + * + * @requestType CreateSourceFilter + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category filters + */ +RequestResult RequestHandler::CreateSourceFilter(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + + OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment); + if (!(source && request.ValidateString("filterName", statusCode, comment) && request.ValidateString("filterKind", statusCode, comment))) + return RequestResult::Error(statusCode, comment); + + std::string filterName = request.RequestData["filterName"]; + OBSSourceAutoRelease existingFilter = obs_source_get_filter_by_name(source, filterName.c_str()); + if (existingFilter) + return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A filter already exists by that name."); + + std::string filterKind = request.RequestData["filterKind"]; + auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList(); + if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end()) + return RequestResult::Error(RequestStatus::InvalidFilterKind, "Your specified filter kind is not supported by OBS. Check that any necessary plugins are loaded."); + + OBSDataAutoRelease filterSettings = nullptr; + if (request.Contains("filterSettings")) { + if (!request.ValidateOptionalObject("filterSettings", statusCode, comment, true)) + return RequestResult::Error(statusCode, comment); + + filterSettings = Utils::Json::JsonToObsData(request.RequestData["filterSettings"]); + } + + OBSSourceAutoRelease filter = Utils::Obs::ActionHelper::CreateSourceFilter(source, filterName, filterKind, filterSettings); + + if(!filter) + return RequestResult::Error(RequestStatus::ResourceCreationFailed, "Creation of the filter failed."); + + return RequestResult::Success(); +} + +/** + * Removes a filter from a source. + * + * @requestField sourceName | String | Name of the source the filter is on + * @requestField filterName | String | Name of the filter to remove + * + * @requestType RemoveSourceFilter + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category filters + */ +RequestResult RequestHandler::RemoveSourceFilter(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); + if (!pair.filter) + return RequestResult::Error(statusCode, comment); + + obs_source_filter_remove(pair.source, pair.filter); + + return RequestResult::Success(); +} + +/** + * Gets the default settings for a filter kind. + * + * @requestField filterKind | String | Filter kind to get the default settings for + * + * @responseField defaultFilterSettings | Object | Object of default settings for the filter kind + * + * @requestType GetSourceFilterDefaultSettings + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category filters + */ +RequestResult RequestHandler::GetSourceFilterDefaultSettings(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + if (!request.ValidateString("filterKind", statusCode, comment)) + return RequestResult::Error(statusCode, comment); + + std::string filterKind = request.RequestData["filterKind"]; + auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList(); + if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end()) + return RequestResult::Error(RequestStatus::InvalidFilterKind); + + OBSDataAutoRelease defaultSettings = obs_get_source_defaults(filterKind.c_str()); + if (!defaultSettings) + return RequestResult::Error(RequestStatus::InvalidFilterKind); + + json responseData; + responseData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultSettings, true); + return RequestResult::Success(responseData); +} + /** * Gets the info for a specific source filter. * @@ -55,3 +194,108 @@ RequestResult RequestHandler::GetSourceFilter(const Request& request) return RequestResult::Success(responseData); } + +/** + * Sets the index position of a filter on a source. + * + * @requestField sourceName | String | Name of the source the filter is on + * @requestField filterName | String | Name of the filter + * @requestField filterIndex | Number | New index position of the filter | >= 0 + * + * @requestType SetSourceFilterIndex + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category filters + */ +RequestResult RequestHandler::SetSourceFilterIndex(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); + if (!(pair.filter && request.ValidateNumber("filterIndex", statusCode, comment, 0, 8192))) + return RequestResult::Error(statusCode, comment); + + int filterIndex = request.RequestData["filterIndex"]; + + Utils::Obs::ActionHelper::SetSourceFilterIndex(pair.source, pair.filter, filterIndex); + + return RequestResult::Success(); +} + +/** + * Sets the settings of a source filter. + * + * @requestField sourceName | String | Name of the source the filter is on + * @requestField filterName | String | Name of the filter to set the settings of + * @requestField filterSettings | Object | Object of settings to apply + * @requestField ?overlay | Boolean | True == apply the settings on top of existing ones, False == reset the input to its defaults, then apply settings. | true + * + * @requestType SetSourceFilterSettings + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category filters + */ +RequestResult RequestHandler::SetSourceFilterSettings(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); + if (!(pair.filter && request.ValidateObject("filterSettings", statusCode, comment, true))) + return RequestResult::Error(statusCode, comment); + + // Almost identical to SetInputSettings + + bool overlay = true; + if (request.Contains("overlay")) { + if (!request.ValidateOptionalBoolean("overlay", statusCode, comment)) + return RequestResult::Error(statusCode, comment); + + overlay = request.RequestData["overlay"]; + } + + OBSDataAutoRelease newSettings = Utils::Json::JsonToObsData(request.RequestData["filterSettings"]); + if (!newSettings) + return RequestResult::Error(RequestStatus::RequestProcessingFailed, "An internal data conversion operation failed. Please report this!"); + + if (overlay) + obs_source_update(pair.filter, newSettings); + else + obs_source_reset_settings(pair.filter, newSettings); + + obs_source_update_properties(pair.filter); + + return RequestResult::Success(); +} + +/** + * Sets the enable state of a source filter. + * + * @requestField sourceName | String | Name of the source the filter is on + * @requestField filterName | Number | Name of the filter + * @requestField filterEnabled | Boolean | New enable state of the filter + * + * @requestType SetSourceFilterEnabled + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category filters + */ +RequestResult RequestHandler::SetSourceFilterEnabled(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); + if (!(pair.filter && request.ValidateBoolean("filterEnabled", statusCode, comment))) + return RequestResult::Error(statusCode, comment); + + bool filterEnabled = request.RequestData["filterEnabled"]; + + obs_source_set_enabled(pair.filter, filterEnabled); + + return RequestResult::Success(); +} diff --git a/src/requesthandler/RequestHandler_Inputs.cpp b/src/requesthandler/RequestHandler_Inputs.cpp index 3ec5d076..227ae656 100644 --- a/src/requesthandler/RequestHandler_Inputs.cpp +++ b/src/requesthandler/RequestHandler_Inputs.cpp @@ -269,6 +269,9 @@ RequestResult RequestHandler::GetInputDefaultSettings(const Request& request) return RequestResult::Error(statusCode, comment); std::string inputKind = request.RequestData["inputKind"]; + auto kinds = Utils::Obs::ArrayHelper::GetInputKindList(); + if (std::find(kinds.begin(), kinds.end(), inputKind) == kinds.end()) + return RequestResult::Error(RequestStatus::InvalidInputKind); OBSDataAutoRelease defaultSettings = obs_get_source_defaults(inputKind.c_str()); if (!defaultSettings) diff --git a/src/requesthandler/types/RequestStatus.h b/src/requesthandler/types/RequestStatus.h index 12999bfb..45d7e04e 100644 --- a/src/requesthandler/types/RequestStatus.h +++ b/src/requesthandler/types/RequestStatus.h @@ -345,6 +345,17 @@ namespace RequestStatus { * @api enums */ ResourceNotConfigurable = 606, + /** + * The specified filter (obs_source_t-OBS_SOURCE_TYPE_FILTER) had the wrong kind. + * + * @enumIdentifier InvalidFilterKind + * @enumValue 607 + * @enumType RequestStatus + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api enums + */ + InvalidFilterKind = 607, /** * Creating the resource failed. diff --git a/src/utils/Obs.h b/src/utils/Obs.h index f0d1baff..40f7c93c 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -193,6 +193,8 @@ namespace Utils { std::vector GetListPropertyItems(obs_property_t *property); std::vector GetTransitionKindList(); std::vector GetSceneTransitionList(); + std::vector GetSourceFilterList(obs_source_t *source); + std::vector GetFilterKindList(); } namespace ObjectHelper { @@ -209,6 +211,8 @@ namespace Utils { namespace ActionHelper { obs_sceneitem_t *CreateSceneItem(obs_source_t *source, obs_scene_t *scene, bool sceneItemEnabled = true, obs_transform_info *sceneItemTransform = nullptr, obs_sceneitem_crop *sceneItemCrop = nullptr); // Increments ref. Use OBSSceneItemAutoRelease obs_sceneitem_t *CreateInput(std::string inputName, std::string inputKind, obs_data_t *inputSettings, obs_scene_t *scene, bool sceneItemEnabled = true); // Increments ref. Use OBSSceneItemAutoRelease + obs_source_t *CreateSourceFilter(obs_source_t *source, std::string filterName, std::string filterKind, obs_data_t *filterSettings); // Increments source ref. Use OBSSourceAutoRelease + void SetSourceFilterIndex(obs_source_t *source, obs_source_t *filter, size_t index); } } } diff --git a/src/utils/Obs_ActionHelper.cpp b/src/utils/Obs_ActionHelper.cpp index 407f374e..c68e4f77 100644 --- a/src/utils/Obs_ActionHelper.cpp +++ b/src/utils/Obs_ActionHelper.cpp @@ -87,3 +87,30 @@ obs_sceneitem_t *Utils::Obs::ActionHelper::CreateInput(std::string inputName, st return ret; } + +obs_source_t *Utils::Obs::ActionHelper::CreateSourceFilter(obs_source_t *source, std::string filterName, std::string filterKind, obs_data_t *filterSettings) +{ + obs_source_t *filter = obs_source_create_private(filterKind.c_str(), filterName.c_str(), filterSettings); + + if (!filter) + return nullptr; + + obs_source_filter_add(source, filter); + + return filter; +} + +void Utils::Obs::ActionHelper::SetSourceFilterIndex(obs_source_t *source, obs_source_t *filter, size_t index) +{ + size_t currentIndex = Utils::Obs::NumberHelper::GetSourceFilterIndex(source, filter); + obs_order_movement direction = index > currentIndex ? OBS_ORDER_MOVE_DOWN : OBS_ORDER_MOVE_UP; + + while(currentIndex != index) { + obs_source_filter_set_order(source, filter, direction); + + if (direction == OBS_ORDER_MOVE_DOWN) + currentIndex++; + else + currentIndex--; + } +} diff --git a/src/utils/Obs_ArrayHelper.cpp b/src/utils/Obs_ArrayHelper.cpp index 997512c1..ec6ed9b4 100644 --- a/src/utils/Obs_ArrayHelper.cpp +++ b/src/utils/Obs_ArrayHelper.cpp @@ -276,3 +276,38 @@ std::vector Utils::Obs::ArrayHelper::GetSceneTransitionList() return ret; } + +std::vector Utils::Obs::ArrayHelper::GetFilterKindList() +{ + std::vector ret; + + size_t idx = 0; + const char *kind; + while(obs_enum_filter_types(idx++, &kind)) + ret.push_back(kind); + + return ret; +} + +std::vector Utils::Obs::ArrayHelper::GetSourceFilterList(obs_source_t *source) +{ + std::vector filters; + + auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param) { + auto filters = reinterpret_cast*>(param); + + json filterJson; + filterJson["filterEnabled"] = obs_source_enabled(filter); + filterJson["filterIndex"] = filters->size(); + filterJson["filterKind"] = obs_source_get_id(filter); + filterJson["filterName"] = obs_source_get_name(filter); + + OBSDataAutoRelease filterSettings = obs_source_get_settings(filter); + filterJson["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings); + + filters->push_back(filterJson); + }; + obs_source_enum_filters(source, enumFilters, &filters); + + return filters; +} From 29b2b1bd5dde1d69d4da5a2d2274eac219c85cef Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Wed, 16 Feb 2022 21:17:24 +0000 Subject: [PATCH 124/128] docs(ci): Update generated docs - 361547a [skip ci] --- docs/generated/protocol.json | 352 +++++++++++++++++++++++++++++++++++ docs/generated/protocol.md | 245 +++++++++++++++++++++++- 2 files changed, 596 insertions(+), 1 deletion(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 75fb3d24..48943ae4 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -405,6 +405,14 @@ "initialVersion": "5.0.0", "enumValue": 606 }, + { + "description": "The specified filter (obs_source_t-OBS_SOURCE_TYPE_FILTER) had the wrong kind.", + "enumIdentifier": "InvalidFilterKind", + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "enumValue": 607 + }, { "description": "Creating the resource failed.", "enumIdentifier": "ResourceCreationFailed", @@ -1146,6 +1154,130 @@ } ] }, + { + "description": "Gets an array of all of a source's filters.", + "requestType": "GetSourceFilterList", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "filters", + "requestFields": [ + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the source", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "filters", + "valueType": "Array", + "valueDescription": "Array of filters" + } + ] + }, + { + "description": "Creates a new filter, adding it to the specified source.", + "requestType": "CreateSourceFilter", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "filters", + "requestFields": [ + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the source to add the filter to", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "filterName", + "valueType": "String", + "valueDescription": "Name of the new filter to be created", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "filterKind", + "valueType": "String", + "valueDescription": "The kind of filter to be created", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "filterSettings", + "valueType": "Object", + "valueDescription": "Settings object to initialize the filter with", + "valueRestrictions": null, + "valueOptional": true, + "valueOptionalBehavior": "Default settings used" + } + ], + "responseFields": [] + }, + { + "description": "Removes a filter from a source.", + "requestType": "RemoveSourceFilter", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "filters", + "requestFields": [ + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the source the filter is on", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "filterName", + "valueType": "String", + "valueDescription": "Name of the filter to remove", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, + { + "description": "Gets the default settings for a filter kind.", + "requestType": "GetSourceFilterDefaultSettings", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "filters", + "requestFields": [ + { + "valueName": "filterKind", + "valueType": "String", + "valueDescription": "Filter kind to get the default settings for", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "defaultFilterSettings", + "valueType": "Object", + "valueDescription": "Object of default settings for the filter kind" + } + ] + }, { "description": "Gets the info for a specific source filter.", "requestType": "GetSourceFilter", @@ -1195,6 +1327,86 @@ } ] }, + { + "description": "Sets the index position of a filter on a source.", + "requestType": "SetSourceFilterIndex", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "filters", + "requestFields": [ + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the source the filter is on", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "filterName", + "valueType": "String", + "valueDescription": "Name of the filter", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "filterIndex", + "valueType": "Number", + "valueDescription": "New index position of the filter", + "valueRestrictions": ">= 0", + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [] + }, + { + "description": "Sets the settings of a source filter.", + "requestType": "SetSourceFilterSettings", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "filters", + "requestFields": [ + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the source the filter is on", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "filterName", + "valueType": "String", + "valueDescription": "Name of the filter to set the settings of", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "filterSettings", + "valueType": "Object", + "valueDescription": "Object of settings to apply", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "overlay", + "valueType": "Boolean", + "valueDescription": "True == apply the settings on top of existing ones, False == reset the input to its defaults, then apply settings.", + "valueRestrictions": null, + "valueOptional": true, + "valueOptionalBehavior": "true" + } + ], + "responseFields": [] + }, { "description": "Gets data about the current plugin and RPC version.", "requestType": "GetVersion", @@ -4040,6 +4252,146 @@ } ] }, + { + "description": "A filter has been added to a source.", + "eventType": "SourceFilterCreated", + "eventSubscription": "Filters", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "filters", + "dataFields": [ + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the source the filter was added to" + }, + { + "valueName": "filterName", + "valueType": "String", + "valueDescription": "Name of the filter" + }, + { + "valueName": "filterKind", + "valueType": "String", + "valueDescription": "The kind of the filter" + }, + { + "valueName": "filterIndex", + "valueType": "Number", + "valueDescription": "Index position of the filter" + }, + { + "valueName": "filterSettings", + "valueType": "Object", + "valueDescription": "The settings configured to the filter when it was created" + }, + { + "valueName": "defaultFilterSettings", + "valueType": "Object", + "valueDescription": "The default settings for the filter" + } + ] + }, + { + "description": "A filter has been removed from a source.", + "eventType": "SourceFilterRemoved", + "eventSubscription": "Filters", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "filters", + "dataFields": [ + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the source the filter was on" + }, + { + "valueName": "filterName", + "valueType": "String", + "valueDescription": "Name of the filter" + } + ] + }, + { + "description": "A source's filter list has been reindexed.", + "eventType": "SourceFilterListReindexed", + "eventSubscription": "Filters", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "filters", + "dataFields": [ + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the source" + }, + { + "valueName": "filters", + "valueType": "Array", + "valueDescription": "Array of filter objects" + } + ] + }, + { + "description": "A source filter's enable state has changed.", + "eventType": "SourceFilterEnableStateChanged", + "eventSubscription": "Filters", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "filters", + "dataFields": [ + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "Name of the source the filter is on" + }, + { + "valueName": "filterName", + "valueType": "String", + "valueDescription": "Name of the filter" + }, + { + "valueName": "filterEnabled", + "valueType": "Boolean", + "valueDescription": "Whether the filter is enabled" + } + ] + }, + { + "description": "The name of a source filter has changed.", + "eventType": "SourceFilterNameChanged", + "eventSubscription": "Filters", + "complexity": 2, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "filters", + "dataFields": [ + { + "valueName": "sourceName", + "valueType": "String", + "valueDescription": "The source the filter is on" + }, + { + "valueName": "oldFilterName", + "valueType": "String", + "valueDescription": "Old name of the filter" + }, + { + "valueName": "filterName", + "valueType": "String", + "valueDescription": "New name of the filter" + } + ] + }, { "description": "OBS has begun the shutdown process.", "eventType": "ExitStarted", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index a436a6d8..76c5c61f 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -443,6 +443,7 @@ These are enumeration declarations, which are referenced throughout obs-websocke - [RequestStatus::InvalidResourceState](#requeststatusinvalidresourcestate) - [RequestStatus::InvalidInputKind](#requeststatusinvalidinputkind) - [RequestStatus::ResourceNotConfigurable](#requeststatusresourcenotconfigurable) + - [RequestStatus::InvalidFilterKind](#requeststatusinvalidfilterkind) - [RequestStatus::ResourceCreationFailed](#requeststatusresourcecreationfailed) - [RequestStatus::ResourceActionFailed](#requeststatusresourceactionfailed) - [RequestStatus::RequestProcessingFailed](#requeststatusrequestprocessingfailed) @@ -1025,6 +1026,16 @@ This is particularly relevant to transitions, where they do not always have chan --- +### RequestStatus::InvalidFilterKind + +The specified filter (obs_source_t-OBS_SOURCE_TYPE_FILTER) had the wrong kind. + +- Identifier Value: `607` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + +--- + ### RequestStatus::ResourceCreationFailed Creating the resource failed. @@ -1271,6 +1282,12 @@ Subscription value to receive the `SceneItemTransformChanged` high-volume event. - [Transitions](#transitions) - [CurrentSceneTransitionChanged](#currentscenetransitionchanged) - [CurrentSceneTransitionDurationChanged](#currentscenetransitiondurationchanged) +- [Filters](#filters) + - [SourceFilterCreated](#sourcefiltercreated) + - [SourceFilterRemoved](#sourcefilterremoved) + - [SourceFilterListReindexed](#sourcefilterlistreindexed) + - [SourceFilterEnableStateChanged](#sourcefilterenablestatechanged) + - [SourceFilterNameChanged](#sourcefilternamechanged) - [Scene Items](#scene-items) - [SceneItemCreated](#sceneitemcreated) - [SceneItemRemoved](#sceneitemremoved) @@ -1795,6 +1812,101 @@ The current scene transition duration has changed. | Name | Type | Description | | ---- | :---: | ----------- | | transitionDuration | Number | Transition duration in milliseconds | +## Filters + +### SourceFilterCreated + +A filter has been added to a source. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sourceName | String | Name of the source the filter was added to | +| filterName | String | Name of the filter | +| filterKind | String | The kind of the filter | +| filterIndex | Number | Index position of the filter | +| filterSettings | Object | The settings configured to the filter when it was created | +| defaultFilterSettings | Object | The default settings for the filter | + +--- + +### SourceFilterRemoved + +A filter has been removed from a source. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sourceName | String | Name of the source the filter was on | +| filterName | String | Name of the filter | + +--- + +### SourceFilterListReindexed + +A source's filter list has been reindexed. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sourceName | String | Name of the source | +| filters | Array<Object> | Array of filter objects | + +--- + +### SourceFilterEnableStateChanged + +A source filter's enable state has changed. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sourceName | String | Name of the source the filter is on | +| filterName | String | Name of the filter | +| filterEnabled | Boolean | Whether the filter is enabled | + +--- + +### SourceFilterNameChanged + +The name of a source filter has changed. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Data Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| sourceName | String | The source the filter is on | +| oldFilterName | String | Old name of the filter | +| filterName | String | New name of the filter | ## Scene Items ### SceneItemCreated @@ -2164,8 +2276,14 @@ Studio mode has been enabled or disabled. - [GetCurrentSceneTransitionCursor](#getcurrentscenetransitioncursor) - [TriggerStudioModeTransition](#triggerstudiomodetransition) - [SetTBarPosition](#settbarposition) -- [Filters](#filters) +- [Filters](#filters-1) + - [GetSourceFilterList](#getsourcefilterlist) + - [CreateSourceFilter](#createsourcefilter) + - [RemoveSourceFilter](#removesourcefilter) + - [GetSourceFilterDefaultSettings](#getsourcefilterdefaultsettings) - [GetSourceFilter](#getsourcefilter) + - [SetSourceFilterIndex](#setsourcefilterindex) + - [SetSourceFilterSettings](#setsourcefiltersettings) - [Scene Items](#scene-items-1) - [GetSceneItemList](#getsceneitemlist) - [GetGroupItemList](#getgroupitemlist) @@ -3699,6 +3817,92 @@ Sets the position of the TBar. ## Filters +### GetSourceFilterList + +Gets an array of all of a source's filters. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sourceName | String | Name of the source | None | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| filters | Array<Object> | Array of filters | + +--- + +### CreateSourceFilter + +Creates a new filter, adding it to the specified source. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sourceName | String | Name of the source to add the filter to | None | N/A | +| filterName | String | Name of the new filter to be created | None | N/A | +| filterKind | String | The kind of filter to be created | None | N/A | +| ?filterSettings | Object | Settings object to initialize the filter with | None | Default settings used | + +--- + +### RemoveSourceFilter + +Removes a filter from a source. + +- Complexity Rating: `2/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sourceName | String | Name of the source the filter is on | None | N/A | +| filterName | String | Name of the filter to remove | None | N/A | + +--- + +### GetSourceFilterDefaultSettings + +Gets the default settings for a filter kind. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| filterKind | String | Filter kind to get the default settings for | None | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| defaultFilterSettings | Object | Object of default settings for the filter kind | + +--- + ### GetSourceFilter Gets the info for a specific source filter. @@ -3725,6 +3929,45 @@ Gets the info for a specific source filter. | filterKind | String | The kind of filter | | filterSettings | Object | Settings object associated with the filter | +--- + +### SetSourceFilterIndex + +Sets the index position of a filter on a source. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sourceName | String | Name of the source the filter is on | None | N/A | +| filterName | String | Name of the filter | None | N/A | +| filterIndex | Number | New index position of the filter | >= 0 | N/A | + +--- + +### SetSourceFilterSettings + +Sets the settings of a source filter. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| sourceName | String | Name of the source the filter is on | None | N/A | +| filterName | String | Name of the filter to set the settings of | None | N/A | +| filterSettings | Object | Object of settings to apply | None | N/A | +| ?overlay | Boolean | True == apply the settings on top of existing ones, False == reset the input to its defaults, then apply settings. | None | true | + ## Scene Items From 66c14dced593f88e89b3dda2bf41714621b9658c Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 16 Feb 2022 13:23:49 -0800 Subject: [PATCH 125/128] requesthandler: Reorder a filter request --- src/requesthandler/RequestHandler.cpp | 2 +- src/requesthandler/RequestHandler.h | 2 +- src/requesthandler/RequestHandler_Filters.cpp | 70 +++++++++---------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 59ef9d1e..2ca7c096 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -112,9 +112,9 @@ const std::unordered_map RequestHandler::_han // Filters {"GetSourceFilterList", &RequestHandler::GetSourceFilterList}, + {"GetSourceFilterDefaultSettings", &RequestHandler::GetSourceFilterDefaultSettings}, {"CreateSourceFilter", &RequestHandler::CreateSourceFilter}, {"RemoveSourceFilter", &RequestHandler::RemoveSourceFilter}, - {"GetSourceFilterDefaultSettings", &RequestHandler::GetSourceFilterDefaultSettings}, {"GetSourceFilter", &RequestHandler::GetSourceFilter}, {"SetSourceFilterIndex", &RequestHandler::SetSourceFilterIndex}, {"SetSourceFilterSettings", &RequestHandler::SetSourceFilterSettings}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 2d9bf20c..ac59afad 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -130,9 +130,9 @@ class RequestHandler { // Filters RequestResult GetSourceFilterList(const Request&); + RequestResult GetSourceFilterDefaultSettings(const Request&); RequestResult CreateSourceFilter(const Request&); RequestResult RemoveSourceFilter(const Request&); - RequestResult GetSourceFilterDefaultSettings(const Request&); RequestResult GetSourceFilter(const Request&); RequestResult SetSourceFilterIndex(const Request&); RequestResult SetSourceFilterSettings(const Request&); diff --git a/src/requesthandler/RequestHandler_Filters.cpp b/src/requesthandler/RequestHandler_Filters.cpp index 21d51097..25bf1ec1 100644 --- a/src/requesthandler/RequestHandler_Filters.cpp +++ b/src/requesthandler/RequestHandler_Filters.cpp @@ -47,6 +47,41 @@ RequestResult RequestHandler::GetSourceFilterList(const Request& request) return RequestResult::Success(responseData); } +/** + * Gets the default settings for a filter kind. + * + * @requestField filterKind | String | Filter kind to get the default settings for + * + * @responseField defaultFilterSettings | Object | Object of default settings for the filter kind + * + * @requestType GetSourceFilterDefaultSettings + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category filters + */ +RequestResult RequestHandler::GetSourceFilterDefaultSettings(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + if (!request.ValidateString("filterKind", statusCode, comment)) + return RequestResult::Error(statusCode, comment); + + std::string filterKind = request.RequestData["filterKind"]; + auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList(); + if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end()) + return RequestResult::Error(RequestStatus::InvalidFilterKind); + + OBSDataAutoRelease defaultSettings = obs_get_source_defaults(filterKind.c_str()); + if (!defaultSettings) + return RequestResult::Error(RequestStatus::InvalidFilterKind); + + json responseData; + responseData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultSettings, true); + return RequestResult::Success(responseData); +} + /** * Creates a new filter, adding it to the specified source. * @@ -123,41 +158,6 @@ RequestResult RequestHandler::RemoveSourceFilter(const Request& request) return RequestResult::Success(); } -/** - * Gets the default settings for a filter kind. - * - * @requestField filterKind | String | Filter kind to get the default settings for - * - * @responseField defaultFilterSettings | Object | Object of default settings for the filter kind - * - * @requestType GetSourceFilterDefaultSettings - * @complexity 3 - * @rpcVersion -1 - * @initialVersion 5.0.0 - * @api requests - * @category filters - */ -RequestResult RequestHandler::GetSourceFilterDefaultSettings(const Request& request) -{ - RequestStatus::RequestStatus statusCode; - std::string comment; - if (!request.ValidateString("filterKind", statusCode, comment)) - return RequestResult::Error(statusCode, comment); - - std::string filterKind = request.RequestData["filterKind"]; - auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList(); - if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end()) - return RequestResult::Error(RequestStatus::InvalidFilterKind); - - OBSDataAutoRelease defaultSettings = obs_get_source_defaults(filterKind.c_str()); - if (!defaultSettings) - return RequestResult::Error(RequestStatus::InvalidFilterKind); - - json responseData; - responseData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultSettings, true); - return RequestResult::Success(responseData); -} - /** * Gets the info for a specific source filter. * From db2ffa569a3fac8f47bbc1d9207ed69f6f89dee0 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 16 Feb 2022 13:30:10 -0800 Subject: [PATCH 126/128] Base: Fix some formatting --- src/eventhandler/EventHandler.cpp | 40 ++-- src/eventhandler/EventHandler.h | 10 +- src/eventhandler/EventHandler_Filters.cpp | 120 ++++++------ src/requesthandler/RequestHandler.cpp | 12 +- src/requesthandler/RequestHandler.h | 12 +- src/requesthandler/RequestHandler_Filters.cpp | 180 +++++++++--------- src/utils/Obs.h | 8 +- src/utils/Obs_ActionHelper.cpp | 26 +-- src/utils/Obs_ArrayHelper.cpp | 40 ++-- 9 files changed, 224 insertions(+), 224 deletions(-) diff --git a/src/eventhandler/EventHandler.cpp b/src/eventhandler/EventHandler.cpp index 211fd750..07638dc0 100644 --- a/src/eventhandler/EventHandler.cpp +++ b/src/eventhandler/EventHandler.cpp @@ -135,12 +135,12 @@ void EventHandler::ConnectSourceSignals(obs_source_t *source) // Applies to inpu signal_handler_connect(sh, "mute", HandleInputMuteStateChanged, this); signal_handler_connect(sh, "volume", HandleInputVolumeChanged, this); signal_handler_connect(sh, "audio_balance", HandleInputAudioBalanceChanged, this); - signal_handler_connect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this); - signal_handler_connect(sh, "audio_mixers", HandleInputAudioTracksChanged, this); - signal_handler_connect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this); - signal_handler_connect(sh, "filter_add", HandleSourceFilterCreated, this); - signal_handler_connect(sh, "filter_remove", HandleSourceFilterRemoved, this); - signal_handler_connect(sh, "reorder_filters", HandleSourceFilterListReindexed, this); + signal_handler_connect(sh, "audio_sync", HandleInputAudioSyncOffsetChanged, this); + signal_handler_connect(sh, "audio_mixers", HandleInputAudioTracksChanged, this); + signal_handler_connect(sh, "audio_monitoring", HandleInputAudioMonitorTypeChanged, this); + signal_handler_connect(sh, "filter_add", HandleSourceFilterCreated, this); + signal_handler_connect(sh, "filter_remove", HandleSourceFilterRemoved, this); + signal_handler_connect(sh, "reorder_filters", HandleSourceFilterListReindexed, this); if (sourceType == OBS_SOURCE_TYPE_INPUT) { signal_handler_connect(sh, "media_started", HandleMediaInputPlaybackStarted, this); @@ -191,9 +191,9 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source) signal_handler_disconnect(sh, "media_stopped", SourceMediaStopMultiHandler, this); signal_handler_disconnect(sh, "media_next", SourceMediaNextMultiHandler, this); signal_handler_disconnect(sh, "media_previous", SourceMediaPreviousMultiHandler, this); - signal_handler_disconnect(sh, "filter_add", HandleSourceFilterCreated, this); - signal_handler_disconnect(sh, "filter_remove", HandleSourceFilterRemoved, this); - signal_handler_disconnect(sh, "reorder_filters", HandleSourceFilterListReindexed, this); + signal_handler_disconnect(sh, "filter_add", HandleSourceFilterCreated, this); + signal_handler_disconnect(sh, "filter_remove", HandleSourceFilterRemoved, this); + signal_handler_disconnect(sh, "reorder_filters", HandleSourceFilterListReindexed, this); // Scenes signal_handler_disconnect(sh, "item_add", HandleSceneItemCreated, this); @@ -207,26 +207,26 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source) void EventHandler::ConnectFilterSignals(obs_source_t *filter) { - if (!filter || obs_source_removed(filter)) - return; + if (!filter || obs_source_removed(filter)) + return; - DisconnectFilterSignals(filter); + DisconnectFilterSignals(filter); - signal_handler_t* sh = obs_source_get_signal_handler(filter); + signal_handler_t* sh = obs_source_get_signal_handler(filter); - signal_handler_connect(sh, "enable", HandleSourceFilterEnableStateChanged, this); - signal_handler_connect(sh, "rename", HandleSourceFilterNameChanged, this); + signal_handler_connect(sh, "enable", HandleSourceFilterEnableStateChanged, this); + signal_handler_connect(sh, "rename", HandleSourceFilterNameChanged, this); } void EventHandler::DisconnectFilterSignals(obs_source_t *filter) { - if (!filter) - return; + if (!filter) + return; - signal_handler_t* sh = obs_source_get_signal_handler(filter); + signal_handler_t* sh = obs_source_get_signal_handler(filter); - signal_handler_disconnect(sh, "enable", HandleSourceFilterEnableStateChanged, this); - signal_handler_disconnect(sh, "rename", HandleSourceFilterNameChanged, this); + signal_handler_disconnect(sh, "enable", HandleSourceFilterEnableStateChanged, this); + signal_handler_disconnect(sh, "rename", HandleSourceFilterNameChanged, this); } void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_data) diff --git a/src/eventhandler/EventHandler.h b/src/eventhandler/EventHandler.h index 3f71caff..00ac4410 100644 --- a/src/eventhandler/EventHandler.h +++ b/src/eventhandler/EventHandler.h @@ -141,9 +141,9 @@ class EventHandler void HandleMediaInputActionTriggered(obs_source_t *source, ObsMediaInputAction action); // Filters - static void HandleSourceFilterNameChanged(void *param, calldata_t *data); // Direct callback - static void HandleSourceFilterCreated(void *param, calldata_t *data); // Direct callback - static void HandleSourceFilterRemoved(void *param, calldata_t *data); // Direct callback - static void HandleSourceFilterListReindexed(void *param, calldata_t *data); // Direct callback - static void HandleSourceFilterEnableStateChanged(void *param, calldata_t *data); // Direct callback + static void HandleSourceFilterNameChanged(void *param, calldata_t *data); // Direct callback + static void HandleSourceFilterCreated(void *param, calldata_t *data); // Direct callback + static void HandleSourceFilterRemoved(void *param, calldata_t *data); // Direct callback + static void HandleSourceFilterListReindexed(void *param, calldata_t *data); // Direct callback + static void HandleSourceFilterEnableStateChanged(void *param, calldata_t *data); // Direct callback }; diff --git a/src/eventhandler/EventHandler_Filters.cpp b/src/eventhandler/EventHandler_Filters.cpp index 308b81b8..a66d5035 100644 --- a/src/eventhandler/EventHandler_Filters.cpp +++ b/src/eventhandler/EventHandler_Filters.cpp @@ -39,28 +39,28 @@ with this program. If not, see */ void EventHandler::HandleSourceFilterCreated(void *param, calldata_t *data) { - auto eventHandler = static_cast(param); + auto eventHandler = static_cast(param); - obs_source_t *source = GetCalldataPointer(data, "source"); - obs_source_t *filter = GetCalldataPointer(data, "filter"); + obs_source_t *source = GetCalldataPointer(data, "source"); + obs_source_t *filter = GetCalldataPointer(data, "filter"); - if (!(source && filter)) - return; + if (!(source && filter)) + return; - eventHandler->ConnectFilterSignals(filter); + eventHandler->ConnectFilterSignals(filter); - std::string filterKind = obs_source_get_id(filter); - OBSDataAutoRelease filterSettings = obs_source_get_settings(filter); - OBSDataAutoRelease defaultFilterSettings = obs_get_source_defaults(filterKind.c_str()); + std::string filterKind = obs_source_get_id(filter); + OBSDataAutoRelease filterSettings = obs_source_get_settings(filter); + OBSDataAutoRelease defaultFilterSettings = obs_get_source_defaults(filterKind.c_str()); - json eventData; - eventData["sourceName"] = obs_source_get_name(source); - eventData["filterName"] = obs_source_get_name(filter); - eventData["filterKind"] = filterKind; - eventData["filterIndex"] = Utils::Obs::NumberHelper::GetSourceFilterIndex(source, filter); - eventData["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings); - eventData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultFilterSettings, true); - eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterCreated", eventData); + json eventData; + eventData["sourceName"] = obs_source_get_name(source); + eventData["filterName"] = obs_source_get_name(filter); + eventData["filterKind"] = filterKind; + eventData["filterIndex"] = Utils::Obs::NumberHelper::GetSourceFilterIndex(source, filter); + eventData["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings); + eventData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultFilterSettings, true); + eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterCreated", eventData); } /** @@ -79,27 +79,27 @@ void EventHandler::HandleSourceFilterCreated(void *param, calldata_t *data) */ void EventHandler::HandleSourceFilterRemoved(void *param, calldata_t *data) { - auto eventHandler = static_cast(param); + auto eventHandler = static_cast(param); - obs_source_t *source = GetCalldataPointer(data, "source"); - obs_source_t *filter = GetCalldataPointer(data, "filter"); + obs_source_t *source = GetCalldataPointer(data, "source"); + obs_source_t *filter = GetCalldataPointer(data, "filter"); - if (!(source && filter)) - return; + if (!(source && filter)) + return; - eventHandler->DisconnectFilterSignals(filter); + eventHandler->DisconnectFilterSignals(filter); - json eventData; - eventData["sourceName"] = obs_source_get_name(source); - eventData["filterName"] = obs_source_get_name(filter); - eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterRemoved", eventData); + json eventData; + eventData["sourceName"] = obs_source_get_name(source); + eventData["filterName"] = obs_source_get_name(filter); + eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterRemoved", eventData); } /** * A source's filter list has been reindexed. * - * @dataField sourceName | String | Name of the source - * @dataField filters | Array | Array of filter objects + * @dataField sourceName | String | Name of the source + * @dataField filters | Array | Array of filter objects * * @eventType SourceFilterListReindexed * @eventSubscription Filters @@ -111,16 +111,16 @@ void EventHandler::HandleSourceFilterRemoved(void *param, calldata_t *data) */ void EventHandler::HandleSourceFilterListReindexed(void *param, calldata_t *data) { - auto eventHandler = static_cast(param); + auto eventHandler = static_cast(param); - obs_source_t *source = GetCalldataPointer(data, "source"); - if (!source) - return; + obs_source_t *source = GetCalldataPointer(data, "source"); + if (!source) + return; - json eventData; - eventData["sourceName"] = obs_source_get_name(source); - eventData["filters"] = Utils::Obs::ArrayHelper::GetSourceFilterList(source); - eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterListReindexed", eventData); + json eventData; + eventData["sourceName"] = obs_source_get_name(source); + eventData["filters"] = Utils::Obs::ArrayHelper::GetSourceFilterList(source); + eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterListReindexed", eventData); } /** @@ -140,24 +140,24 @@ void EventHandler::HandleSourceFilterListReindexed(void *param, calldata_t *data */ void EventHandler::HandleSourceFilterEnableStateChanged(void *param, calldata_t *data) { - auto eventHandler = static_cast(param); + auto eventHandler = static_cast(param); - obs_source_t *filter = GetCalldataPointer(data, "source"); - if (!filter) - return; + obs_source_t *filter = GetCalldataPointer(data, "source"); + if (!filter) + return; - // Not OBSSourceAutoRelease as get_parent doesn't increment refcount - obs_source_t *source = obs_filter_get_parent(filter); - if (!source) - return; + // Not OBSSourceAutoRelease as get_parent doesn't increment refcount + obs_source_t *source = obs_filter_get_parent(filter); + if (!source) + return; - bool filterEnabled = calldata_bool(data, "enabled"); + bool filterEnabled = calldata_bool(data, "enabled"); - json eventData; - eventData["sourceName"] = obs_source_get_name(source); - eventData["filterName"] = obs_source_get_name(filter); - eventData["filterEnabled"] = filterEnabled; - eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterEnableStateChanged", eventData); + json eventData; + eventData["sourceName"] = obs_source_get_name(source); + eventData["filterName"] = obs_source_get_name(filter); + eventData["filterEnabled"] = filterEnabled; + eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterEnableStateChanged", eventData); } /** @@ -177,15 +177,15 @@ void EventHandler::HandleSourceFilterEnableStateChanged(void *param, calldata_t */ void EventHandler::HandleSourceFilterNameChanged(void *param, calldata_t *data) { - auto eventHandler = static_cast(param); + auto eventHandler = static_cast(param); - obs_source_t *filter = GetCalldataPointer(data, "source"); - if (!filter) - return; + obs_source_t *filter = GetCalldataPointer(data, "source"); + if (!filter) + return; - json eventData; - eventData["sourceName"] = obs_source_get_name(obs_filter_get_parent(filter)); - eventData["oldFilterName"] = calldata_string(data, "prev_name"); - eventData["filterName"] = calldata_string(data, "new_name"); - eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterNameChanged", eventData); + json eventData; + eventData["sourceName"] = obs_source_get_name(obs_filter_get_parent(filter)); + eventData["oldFilterName"] = calldata_string(data, "prev_name"); + eventData["filterName"] = calldata_string(data, "new_name"); + eventHandler->BroadcastEvent(EventSubscription::Filters, "SourceFilterNameChanged", eventData); } diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 2ca7c096..000b894d 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -111,14 +111,14 @@ const std::unordered_map RequestHandler::_han {"SetTBarPosition", &RequestHandler::SetTBarPosition}, // Filters - {"GetSourceFilterList", &RequestHandler::GetSourceFilterList}, + {"GetSourceFilterList", &RequestHandler::GetSourceFilterList}, {"GetSourceFilterDefaultSettings", &RequestHandler::GetSourceFilterDefaultSettings}, - {"CreateSourceFilter", &RequestHandler::CreateSourceFilter}, - {"RemoveSourceFilter", &RequestHandler::RemoveSourceFilter}, + {"CreateSourceFilter", &RequestHandler::CreateSourceFilter}, + {"RemoveSourceFilter", &RequestHandler::RemoveSourceFilter}, {"GetSourceFilter", &RequestHandler::GetSourceFilter}, - {"SetSourceFilterIndex", &RequestHandler::SetSourceFilterIndex}, - {"SetSourceFilterSettings", &RequestHandler::SetSourceFilterSettings}, - {"SetSourceFilterEnabled", &RequestHandler::SetSourceFilterEnabled}, + {"SetSourceFilterIndex", &RequestHandler::SetSourceFilterIndex}, + {"SetSourceFilterSettings", &RequestHandler::SetSourceFilterSettings}, + {"SetSourceFilterEnabled", &RequestHandler::SetSourceFilterEnabled}, // Scene Items {"GetSceneItemList", &RequestHandler::GetSceneItemList}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index ac59afad..2823127a 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -129,14 +129,14 @@ class RequestHandler { RequestResult SetTBarPosition(const Request&); // Filters - RequestResult GetSourceFilterList(const Request&); + RequestResult GetSourceFilterList(const Request&); RequestResult GetSourceFilterDefaultSettings(const Request&); - RequestResult CreateSourceFilter(const Request&); - RequestResult RemoveSourceFilter(const Request&); + RequestResult CreateSourceFilter(const Request&); + RequestResult RemoveSourceFilter(const Request&); RequestResult GetSourceFilter(const Request&); - RequestResult SetSourceFilterIndex(const Request&); - RequestResult SetSourceFilterSettings(const Request&); - RequestResult SetSourceFilterEnabled(const Request&); + RequestResult SetSourceFilterIndex(const Request&); + RequestResult SetSourceFilterSettings(const Request&); + RequestResult SetSourceFilterEnabled(const Request&); // Scene Items RequestResult GetSceneItemList(const Request&); diff --git a/src/requesthandler/RequestHandler_Filters.cpp b/src/requesthandler/RequestHandler_Filters.cpp index 25bf1ec1..34078008 100644 --- a/src/requesthandler/RequestHandler_Filters.cpp +++ b/src/requesthandler/RequestHandler_Filters.cpp @@ -35,16 +35,16 @@ with this program. If not, see */ RequestResult RequestHandler::GetSourceFilterList(const Request& request) { - RequestStatus::RequestStatus statusCode; - std::string comment; - OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment); - if(!source) - return RequestResult::Error(statusCode, comment); + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment); + if(!source) + return RequestResult::Error(statusCode, comment); - json responseData; - responseData["filters"] = Utils::Obs::ArrayHelper::GetSourceFilterList(source); + json responseData; + responseData["filters"] = Utils::Obs::ArrayHelper::GetSourceFilterList(source); - return RequestResult::Success(responseData); + return RequestResult::Success(responseData); } /** @@ -63,23 +63,23 @@ RequestResult RequestHandler::GetSourceFilterList(const Request& request) */ RequestResult RequestHandler::GetSourceFilterDefaultSettings(const Request& request) { - RequestStatus::RequestStatus statusCode; - std::string comment; - if (!request.ValidateString("filterKind", statusCode, comment)) - return RequestResult::Error(statusCode, comment); + RequestStatus::RequestStatus statusCode; + std::string comment; + if (!request.ValidateString("filterKind", statusCode, comment)) + return RequestResult::Error(statusCode, comment); - std::string filterKind = request.RequestData["filterKind"]; - auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList(); - if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end()) - return RequestResult::Error(RequestStatus::InvalidFilterKind); + std::string filterKind = request.RequestData["filterKind"]; + auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList(); + if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end()) + return RequestResult::Error(RequestStatus::InvalidFilterKind); - OBSDataAutoRelease defaultSettings = obs_get_source_defaults(filterKind.c_str()); - if (!defaultSettings) - return RequestResult::Error(RequestStatus::InvalidFilterKind); + OBSDataAutoRelease defaultSettings = obs_get_source_defaults(filterKind.c_str()); + if (!defaultSettings) + return RequestResult::Error(RequestStatus::InvalidFilterKind); - json responseData; - responseData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultSettings, true); - return RequestResult::Success(responseData); + json responseData; + responseData["defaultFilterSettings"] = Utils::Json::ObsDataToJson(defaultSettings, true); + return RequestResult::Success(responseData); } /** @@ -88,7 +88,7 @@ RequestResult RequestHandler::GetSourceFilterDefaultSettings(const Request& requ * @requestField sourceName | String | Name of the source to add the filter to * @requestField filterName | String | Name of the new filter to be created * @requestField filterKind | String | The kind of filter to be created - * @requestField ?filterSettings | Object | Settings object to initialize the filter with | Default settings used + * @requestField ?filterSettings | Object | Settings object to initialize the filter with | Default settings used * * @requestType CreateSourceFilter * @complexity 3 @@ -99,37 +99,37 @@ RequestResult RequestHandler::GetSourceFilterDefaultSettings(const Request& requ */ RequestResult RequestHandler::CreateSourceFilter(const Request& request) { - RequestStatus::RequestStatus statusCode; - std::string comment; + RequestStatus::RequestStatus statusCode; + std::string comment; - OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment); - if (!(source && request.ValidateString("filterName", statusCode, comment) && request.ValidateString("filterKind", statusCode, comment))) - return RequestResult::Error(statusCode, comment); + OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment); + if (!(source && request.ValidateString("filterName", statusCode, comment) && request.ValidateString("filterKind", statusCode, comment))) + return RequestResult::Error(statusCode, comment); - std::string filterName = request.RequestData["filterName"]; - OBSSourceAutoRelease existingFilter = obs_source_get_filter_by_name(source, filterName.c_str()); - if (existingFilter) - return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A filter already exists by that name."); + std::string filterName = request.RequestData["filterName"]; + OBSSourceAutoRelease existingFilter = obs_source_get_filter_by_name(source, filterName.c_str()); + if (existingFilter) + return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A filter already exists by that name."); - std::string filterKind = request.RequestData["filterKind"]; - auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList(); - if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end()) - return RequestResult::Error(RequestStatus::InvalidFilterKind, "Your specified filter kind is not supported by OBS. Check that any necessary plugins are loaded."); + std::string filterKind = request.RequestData["filterKind"]; + auto kinds = Utils::Obs::ArrayHelper::GetFilterKindList(); + if (std::find(kinds.begin(), kinds.end(), filterKind) == kinds.end()) + return RequestResult::Error(RequestStatus::InvalidFilterKind, "Your specified filter kind is not supported by OBS. Check that any necessary plugins are loaded."); - OBSDataAutoRelease filterSettings = nullptr; - if (request.Contains("filterSettings")) { - if (!request.ValidateOptionalObject("filterSettings", statusCode, comment, true)) - return RequestResult::Error(statusCode, comment); + OBSDataAutoRelease filterSettings = nullptr; + if (request.Contains("filterSettings")) { + if (!request.ValidateOptionalObject("filterSettings", statusCode, comment, true)) + return RequestResult::Error(statusCode, comment); - filterSettings = Utils::Json::JsonToObsData(request.RequestData["filterSettings"]); - } + filterSettings = Utils::Json::JsonToObsData(request.RequestData["filterSettings"]); + } - OBSSourceAutoRelease filter = Utils::Obs::ActionHelper::CreateSourceFilter(source, filterName, filterKind, filterSettings); + OBSSourceAutoRelease filter = Utils::Obs::ActionHelper::CreateSourceFilter(source, filterName, filterKind, filterSettings); - if(!filter) - return RequestResult::Error(RequestStatus::ResourceCreationFailed, "Creation of the filter failed."); + if(!filter) + return RequestResult::Error(RequestStatus::ResourceCreationFailed, "Creation of the filter failed."); - return RequestResult::Success(); + return RequestResult::Success(); } /** @@ -147,15 +147,15 @@ RequestResult RequestHandler::CreateSourceFilter(const Request& request) */ RequestResult RequestHandler::RemoveSourceFilter(const Request& request) { - RequestStatus::RequestStatus statusCode; - std::string comment; - FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); - if (!pair.filter) - return RequestResult::Error(statusCode, comment); + RequestStatus::RequestStatus statusCode; + std::string comment; + FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); + if (!pair.filter) + return RequestResult::Error(statusCode, comment); - obs_source_filter_remove(pair.source, pair.filter); + obs_source_filter_remove(pair.source, pair.filter); - return RequestResult::Success(); + return RequestResult::Success(); } /** @@ -211,17 +211,17 @@ RequestResult RequestHandler::GetSourceFilter(const Request& request) */ RequestResult RequestHandler::SetSourceFilterIndex(const Request& request) { - RequestStatus::RequestStatus statusCode; - std::string comment; - FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); - if (!(pair.filter && request.ValidateNumber("filterIndex", statusCode, comment, 0, 8192))) - return RequestResult::Error(statusCode, comment); + RequestStatus::RequestStatus statusCode; + std::string comment; + FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); + if (!(pair.filter && request.ValidateNumber("filterIndex", statusCode, comment, 0, 8192))) + return RequestResult::Error(statusCode, comment); - int filterIndex = request.RequestData["filterIndex"]; + int filterIndex = request.RequestData["filterIndex"]; - Utils::Obs::ActionHelper::SetSourceFilterIndex(pair.source, pair.filter, filterIndex); + Utils::Obs::ActionHelper::SetSourceFilterIndex(pair.source, pair.filter, filterIndex); - return RequestResult::Success(); + return RequestResult::Success(); } /** @@ -241,34 +241,34 @@ RequestResult RequestHandler::SetSourceFilterIndex(const Request& request) */ RequestResult RequestHandler::SetSourceFilterSettings(const Request& request) { - RequestStatus::RequestStatus statusCode; - std::string comment; - FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); - if (!(pair.filter && request.ValidateObject("filterSettings", statusCode, comment, true))) - return RequestResult::Error(statusCode, comment); + RequestStatus::RequestStatus statusCode; + std::string comment; + FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); + if (!(pair.filter && request.ValidateObject("filterSettings", statusCode, comment, true))) + return RequestResult::Error(statusCode, comment); - // Almost identical to SetInputSettings + // Almost identical to SetInputSettings - bool overlay = true; - if (request.Contains("overlay")) { - if (!request.ValidateOptionalBoolean("overlay", statusCode, comment)) - return RequestResult::Error(statusCode, comment); + bool overlay = true; + if (request.Contains("overlay")) { + if (!request.ValidateOptionalBoolean("overlay", statusCode, comment)) + return RequestResult::Error(statusCode, comment); - overlay = request.RequestData["overlay"]; - } + overlay = request.RequestData["overlay"]; + } - OBSDataAutoRelease newSettings = Utils::Json::JsonToObsData(request.RequestData["filterSettings"]); - if (!newSettings) - return RequestResult::Error(RequestStatus::RequestProcessingFailed, "An internal data conversion operation failed. Please report this!"); + OBSDataAutoRelease newSettings = Utils::Json::JsonToObsData(request.RequestData["filterSettings"]); + if (!newSettings) + return RequestResult::Error(RequestStatus::RequestProcessingFailed, "An internal data conversion operation failed. Please report this!"); - if (overlay) - obs_source_update(pair.filter, newSettings); - else - obs_source_reset_settings(pair.filter, newSettings); + if (overlay) + obs_source_update(pair.filter, newSettings); + else + obs_source_reset_settings(pair.filter, newSettings); - obs_source_update_properties(pair.filter); + obs_source_update_properties(pair.filter); - return RequestResult::Success(); + return RequestResult::Success(); } /** @@ -287,15 +287,15 @@ RequestResult RequestHandler::SetSourceFilterSettings(const Request& request) */ RequestResult RequestHandler::SetSourceFilterEnabled(const Request& request) { - RequestStatus::RequestStatus statusCode; - std::string comment; - FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); - if (!(pair.filter && request.ValidateBoolean("filterEnabled", statusCode, comment))) - return RequestResult::Error(statusCode, comment); + RequestStatus::RequestStatus statusCode; + std::string comment; + FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); + if (!(pair.filter && request.ValidateBoolean("filterEnabled", statusCode, comment))) + return RequestResult::Error(statusCode, comment); - bool filterEnabled = request.RequestData["filterEnabled"]; + bool filterEnabled = request.RequestData["filterEnabled"]; - obs_source_set_enabled(pair.filter, filterEnabled); + obs_source_set_enabled(pair.filter, filterEnabled); - return RequestResult::Success(); + return RequestResult::Success(); } diff --git a/src/utils/Obs.h b/src/utils/Obs.h index 40f7c93c..4eda079a 100644 --- a/src/utils/Obs.h +++ b/src/utils/Obs.h @@ -193,8 +193,8 @@ namespace Utils { std::vector GetListPropertyItems(obs_property_t *property); std::vector GetTransitionKindList(); std::vector GetSceneTransitionList(); - std::vector GetSourceFilterList(obs_source_t *source); - std::vector GetFilterKindList(); + std::vector GetSourceFilterList(obs_source_t *source); + std::vector GetFilterKindList(); } namespace ObjectHelper { @@ -211,8 +211,8 @@ namespace Utils { namespace ActionHelper { obs_sceneitem_t *CreateSceneItem(obs_source_t *source, obs_scene_t *scene, bool sceneItemEnabled = true, obs_transform_info *sceneItemTransform = nullptr, obs_sceneitem_crop *sceneItemCrop = nullptr); // Increments ref. Use OBSSceneItemAutoRelease obs_sceneitem_t *CreateInput(std::string inputName, std::string inputKind, obs_data_t *inputSettings, obs_scene_t *scene, bool sceneItemEnabled = true); // Increments ref. Use OBSSceneItemAutoRelease - obs_source_t *CreateSourceFilter(obs_source_t *source, std::string filterName, std::string filterKind, obs_data_t *filterSettings); // Increments source ref. Use OBSSourceAutoRelease - void SetSourceFilterIndex(obs_source_t *source, obs_source_t *filter, size_t index); + obs_source_t *CreateSourceFilter(obs_source_t *source, std::string filterName, std::string filterKind, obs_data_t *filterSettings); // Increments source ref. Use OBSSourceAutoRelease + void SetSourceFilterIndex(obs_source_t *source, obs_source_t *filter, size_t index); } } } diff --git a/src/utils/Obs_ActionHelper.cpp b/src/utils/Obs_ActionHelper.cpp index c68e4f77..8e981125 100644 --- a/src/utils/Obs_ActionHelper.cpp +++ b/src/utils/Obs_ActionHelper.cpp @@ -90,27 +90,27 @@ obs_sceneitem_t *Utils::Obs::ActionHelper::CreateInput(std::string inputName, st obs_source_t *Utils::Obs::ActionHelper::CreateSourceFilter(obs_source_t *source, std::string filterName, std::string filterKind, obs_data_t *filterSettings) { - obs_source_t *filter = obs_source_create_private(filterKind.c_str(), filterName.c_str(), filterSettings); + obs_source_t *filter = obs_source_create_private(filterKind.c_str(), filterName.c_str(), filterSettings); - if (!filter) - return nullptr; + if (!filter) + return nullptr; - obs_source_filter_add(source, filter); + obs_source_filter_add(source, filter); - return filter; + return filter; } void Utils::Obs::ActionHelper::SetSourceFilterIndex(obs_source_t *source, obs_source_t *filter, size_t index) { - size_t currentIndex = Utils::Obs::NumberHelper::GetSourceFilterIndex(source, filter); - obs_order_movement direction = index > currentIndex ? OBS_ORDER_MOVE_DOWN : OBS_ORDER_MOVE_UP; + size_t currentIndex = Utils::Obs::NumberHelper::GetSourceFilterIndex(source, filter); + obs_order_movement direction = index > currentIndex ? OBS_ORDER_MOVE_DOWN : OBS_ORDER_MOVE_UP; - while(currentIndex != index) { - obs_source_filter_set_order(source, filter, direction); + while(currentIndex != index) { + obs_source_filter_set_order(source, filter, direction); - if (direction == OBS_ORDER_MOVE_DOWN) - currentIndex++; - else + if (direction == OBS_ORDER_MOVE_DOWN) + currentIndex++; + else currentIndex--; - } + } } diff --git a/src/utils/Obs_ArrayHelper.cpp b/src/utils/Obs_ArrayHelper.cpp index ec6ed9b4..ecf26c16 100644 --- a/src/utils/Obs_ArrayHelper.cpp +++ b/src/utils/Obs_ArrayHelper.cpp @@ -279,35 +279,35 @@ std::vector Utils::Obs::ArrayHelper::GetSceneTransitionList() std::vector Utils::Obs::ArrayHelper::GetFilterKindList() { - std::vector ret; + std::vector ret; - size_t idx = 0; - const char *kind; - while(obs_enum_filter_types(idx++, &kind)) - ret.push_back(kind); + size_t idx = 0; + const char *kind; + while(obs_enum_filter_types(idx++, &kind)) + ret.push_back(kind); - return ret; + return ret; } std::vector Utils::Obs::ArrayHelper::GetSourceFilterList(obs_source_t *source) { - std::vector filters; + std::vector filters; - auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param) { - auto filters = reinterpret_cast*>(param); + auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *param) { + auto filters = reinterpret_cast*>(param); - json filterJson; - filterJson["filterEnabled"] = obs_source_enabled(filter); - filterJson["filterIndex"] = filters->size(); - filterJson["filterKind"] = obs_source_get_id(filter); - filterJson["filterName"] = obs_source_get_name(filter); + json filterJson; + filterJson["filterEnabled"] = obs_source_enabled(filter); + filterJson["filterIndex"] = filters->size(); + filterJson["filterKind"] = obs_source_get_id(filter); + filterJson["filterName"] = obs_source_get_name(filter); - OBSDataAutoRelease filterSettings = obs_source_get_settings(filter); - filterJson["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings); + OBSDataAutoRelease filterSettings = obs_source_get_settings(filter); + filterJson["filterSettings"] = Utils::Json::ObsDataToJson(filterSettings); - filters->push_back(filterJson); - }; - obs_source_enum_filters(source, enumFilters, &filters); + filters->push_back(filterJson); + }; + obs_source_enum_filters(source, enumFilters, &filters); - return filters; + return filters; } From aa13828cf5367a4bf3ef02270a9573626135588d Mon Sep 17 00:00:00 2001 From: tt2468 Date: Wed, 16 Feb 2022 13:37:18 -0800 Subject: [PATCH 127/128] requesthandler: Add SetSourceFilterName --- src/requesthandler/RequestHandler.cpp | 1 + src/requesthandler/RequestHandler.h | 1 + src/requesthandler/RequestHandler_Filters.cpp | 51 +++++++++++++++---- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 000b894d..9df48aa4 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -115,6 +115,7 @@ const std::unordered_map RequestHandler::_han {"GetSourceFilterDefaultSettings", &RequestHandler::GetSourceFilterDefaultSettings}, {"CreateSourceFilter", &RequestHandler::CreateSourceFilter}, {"RemoveSourceFilter", &RequestHandler::RemoveSourceFilter}, + {"SetSourceFilterName", &RequestHandler::SetSourceFilterName}, {"GetSourceFilter", &RequestHandler::GetSourceFilter}, {"SetSourceFilterIndex", &RequestHandler::SetSourceFilterIndex}, {"SetSourceFilterSettings", &RequestHandler::SetSourceFilterSettings}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 2823127a..e198a304 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -133,6 +133,7 @@ class RequestHandler { RequestResult GetSourceFilterDefaultSettings(const Request&); RequestResult CreateSourceFilter(const Request&); RequestResult RemoveSourceFilter(const Request&); + RequestResult SetSourceFilterName(const Request&); RequestResult GetSourceFilter(const Request&); RequestResult SetSourceFilterIndex(const Request&); RequestResult SetSourceFilterSettings(const Request&); diff --git a/src/requesthandler/RequestHandler_Filters.cpp b/src/requesthandler/RequestHandler_Filters.cpp index 34078008..2e6229eb 100644 --- a/src/requesthandler/RequestHandler_Filters.cpp +++ b/src/requesthandler/RequestHandler_Filters.cpp @@ -85,10 +85,10 @@ RequestResult RequestHandler::GetSourceFilterDefaultSettings(const Request& requ /** * Creates a new filter, adding it to the specified source. * - * @requestField sourceName | String | Name of the source to add the filter to - * @requestField filterName | String | Name of the new filter to be created - * @requestField filterKind | String | The kind of filter to be created - * @requestField ?filterSettings | Object | Settings object to initialize the filter with | Default settings used + * @requestField sourceName | String | Name of the source to add the filter to + * @requestField filterName | String | Name of the new filter to be created + * @requestField filterKind | String | The kind of filter to be created + * @requestField ?filterSettings | Object | Settings object to initialize the filter with | Default settings used * * @requestType CreateSourceFilter * @complexity 3 @@ -158,6 +158,39 @@ RequestResult RequestHandler::RemoveSourceFilter(const Request& request) return RequestResult::Success(); } +/** + * Sets the name of a source filter (rename). + * + * @requestField sourceName | String | Name of the source the filter is on + * @requestField filterName | String | Current name of the filter + * @requestField newFilterName | String | New name for the filter + * + * @requestType SetSourceFilterName + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category filters + */ +RequestResult RequestHandler::SetSourceFilterName(const Request& request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + FilterPair pair = request.ValidateFilter("sourceName", "filterName", statusCode, comment); + if (!pair.filter || !request.ValidateString("newFilterName", statusCode, comment)) + return RequestResult::Error(statusCode, comment); + + std::string newFilterName = request.RequestData["newFilterName"]; + + OBSSourceAutoRelease existingFilter = obs_source_get_filter_by_name(pair.source, newFilterName.c_str()); + if (existingFilter) + return RequestResult::Error(RequestStatus::ResourceAlreadyExists, "A filter already exists by that new name."); + + obs_source_set_name(pair.filter, newFilterName.c_str()); + + return RequestResult::Success(); +} + /** * Gets the info for a specific source filter. * @@ -198,8 +231,8 @@ RequestResult RequestHandler::GetSourceFilter(const Request& request) /** * Sets the index position of a filter on a source. * - * @requestField sourceName | String | Name of the source the filter is on - * @requestField filterName | String | Name of the filter + * @requestField sourceName | String | Name of the source the filter is on + * @requestField filterName | String | Name of the filter * @requestField filterIndex | Number | New index position of the filter | >= 0 * * @requestType SetSourceFilterIndex @@ -274,9 +307,9 @@ RequestResult RequestHandler::SetSourceFilterSettings(const Request& request) /** * Sets the enable state of a source filter. * - * @requestField sourceName | String | Name of the source the filter is on - * @requestField filterName | Number | Name of the filter - * @requestField filterEnabled | Boolean | New enable state of the filter + * @requestField sourceName | String | Name of the source the filter is on + * @requestField filterName | Number | Name of the filter + * @requestField filterEnabled | Boolean | New enable state of the filter * * @requestType SetSourceFilterEnabled * @complexity 3 From e0057b05db8a9dee7cf2cc7a87a974e5d19946ec Mon Sep 17 00:00:00 2001 From: Github Actions <> Date: Wed, 16 Feb 2022 22:26:10 +0000 Subject: [PATCH 128/128] docs(ci): Update generated docs - aa13828 [skip ci] --- docs/generated/protocol.json | 60 ++++++++++++++++++++++++++++-------- docs/generated/protocol.md | 44 ++++++++++++++++++-------- 2 files changed, 80 insertions(+), 24 deletions(-) diff --git a/docs/generated/protocol.json b/docs/generated/protocol.json index 48943ae4..16ac5dfa 100644 --- a/docs/generated/protocol.json +++ b/docs/generated/protocol.json @@ -1180,6 +1180,32 @@ } ] }, + { + "description": "Gets the default settings for a filter kind.", + "requestType": "GetSourceFilterDefaultSettings", + "complexity": 3, + "rpcVersion": "1", + "deprecated": false, + "initialVersion": "5.0.0", + "category": "filters", + "requestFields": [ + { + "valueName": "filterKind", + "valueType": "String", + "valueDescription": "Filter kind to get the default settings for", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + } + ], + "responseFields": [ + { + "valueName": "defaultFilterSettings", + "valueType": "Object", + "valueDescription": "Object of default settings for the filter kind" + } + ] + }, { "description": "Creates a new filter, adding it to the specified source.", "requestType": "CreateSourceFilter", @@ -1253,30 +1279,40 @@ "responseFields": [] }, { - "description": "Gets the default settings for a filter kind.", - "requestType": "GetSourceFilterDefaultSettings", - "complexity": 3, + "description": "Sets the name of a source filter (rename).", + "requestType": "SetSourceFilterName", + "complexity": 2, "rpcVersion": "1", "deprecated": false, "initialVersion": "5.0.0", "category": "filters", "requestFields": [ { - "valueName": "filterKind", + "valueName": "sourceName", "valueType": "String", - "valueDescription": "Filter kind to get the default settings for", + "valueDescription": "Name of the source the filter is on", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "filterName", + "valueType": "String", + "valueDescription": "Current name of the filter", + "valueRestrictions": null, + "valueOptional": false, + "valueOptionalBehavior": null + }, + { + "valueName": "newFilterName", + "valueType": "String", + "valueDescription": "New name for the filter", "valueRestrictions": null, "valueOptional": false, "valueOptionalBehavior": null } ], - "responseFields": [ - { - "valueName": "defaultFilterSettings", - "valueType": "Object", - "valueDescription": "Object of default settings for the filter kind" - } - ] + "responseFields": [] }, { "description": "Gets the info for a specific source filter.", diff --git a/docs/generated/protocol.md b/docs/generated/protocol.md index 76c5c61f..54a07b73 100644 --- a/docs/generated/protocol.md +++ b/docs/generated/protocol.md @@ -2278,9 +2278,10 @@ Studio mode has been enabled or disabled. - [SetTBarPosition](#settbarposition) - [Filters](#filters-1) - [GetSourceFilterList](#getsourcefilterlist) + - [GetSourceFilterDefaultSettings](#getsourcefilterdefaultsettings) - [CreateSourceFilter](#createsourcefilter) - [RemoveSourceFilter](#removesourcefilter) - - [GetSourceFilterDefaultSettings](#getsourcefilterdefaultsettings) + - [SetSourceFilterName](#setsourcefiltername) - [GetSourceFilter](#getsourcefilter) - [SetSourceFilterIndex](#setsourcefilterindex) - [SetSourceFilterSettings](#setsourcefiltersettings) @@ -3841,6 +3842,30 @@ Gets an array of all of a source's filters. --- +### GetSourceFilterDefaultSettings + +Gets the default settings for a filter kind. + +- Complexity Rating: `3/5` +- Latest Supported RPC Version: `1` +- Added in v5.0.0 + + +**Request Fields:** + +| Name | Type | Description | Value Restrictions | ?Default Behavior | +| ---- | :---: | ----------- | :----------------: | ----------------- | +| filterKind | String | Filter kind to get the default settings for | None | N/A | + + +**Response Fields:** + +| Name | Type | Description | +| ---- | :---: | ----------- | +| defaultFilterSettings | Object | Object of default settings for the filter kind | + +--- + ### CreateSourceFilter Creates a new filter, adding it to the specified source. @@ -3879,11 +3904,11 @@ Removes a filter from a source. --- -### GetSourceFilterDefaultSettings +### SetSourceFilterName -Gets the default settings for a filter kind. +Sets the name of a source filter (rename). -- Complexity Rating: `3/5` +- Complexity Rating: `2/5` - Latest Supported RPC Version: `1` - Added in v5.0.0 @@ -3892,14 +3917,9 @@ Gets the default settings for a filter kind. | Name | Type | Description | Value Restrictions | ?Default Behavior | | ---- | :---: | ----------- | :----------------: | ----------------- | -| filterKind | String | Filter kind to get the default settings for | None | N/A | - - -**Response Fields:** - -| Name | Type | Description | -| ---- | :---: | ----------- | -| defaultFilterSettings | Object | Object of default settings for the filter kind | +| sourceName | String | Name of the source the filter is on | None | N/A | +| filterName | String | Current name of the filter | None | N/A | +| newFilterName | String | New name for the filter | None | N/A | ---