diff --git a/PROTOCOL.md b/PROTOCOL.md index 7e710cc1..2312b724 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -11,6 +11,9 @@ The protocol in general is based on the OBS Remote protocol created by Bill Hami - [Event Types](#event-types) - ["SwitchScenes"](#switchscenes) - ["ScenesChanged"](#sceneschanged) + - ["SourceOrderChanged"](#sourceorderchanged) + - ["SceneItemAdded"](#sceneitemadded) + - ["SceneItemRemoved"](#sceneitemremoved) - ["SceneCollectionChanged"](#scenecollectionchanged) - ["SceneCollectionListChanged"](#scenecollectionlistchanged) - ["SwitchTransition"](#switchtransition) @@ -80,6 +83,26 @@ The scene list has been modified (Scenes have been added, removed, or renamed). --- +#### "SourceOrderChanged" +Scene items have been reordered. +- **"scene-name"** (string) : name of the scene where items have been reordered + +--- + +#### "SceneItemAdded" +An item has been added to the current scene. +- **"scene-name"** (string) : name of the scene +- **"item-name"** (string) : name of the item added to **scene-name** + +--- + +#### "SceneItemRemoved" +An item has been removed from the current scene. +- **"scene-name"** (string) : name of the scene +- **"item-name"** (string) : name of the item removed from **scene-name** + +--- + #### "SceneCollectionChanged" Triggered when switching to another scene collection or when renaming the current scene collection. diff --git a/WSEvents.cpp b/WSEvents.cpp index e9554482..03f953f8 100644 --- a/WSEvents.cpp +++ b/WSEvents.cpp @@ -21,6 +21,7 @@ with this program. If not, see #include #include "Utils.h" #include "WSEvents.h" +#include "obs-websocket.h" bool transition_is_cut(obs_source_t *transition) { @@ -49,12 +50,17 @@ WSEvents::WSEvents(WSServer *srv) statusTimer->start(2000); // equal to frontend's constant BITRATE_UPDATE_SECONDS transition_handler = nullptr; + scene_handler = nullptr; WSEvents* instance = this; QTimer::singleShot(1000, [instance]() { obs_source_t* transition = obs_frontend_get_current_transition(); instance->connectTransitionSignals(transition); obs_source_release(transition); + + obs_source_t* scene = obs_frontend_get_current_scene(); + instance->connectSceneSignals(scene); + obs_source_release(scene); }); _stream_starttime = 0; @@ -159,11 +165,16 @@ void WSEvents::broadcastUpdate(const char *updateType, obs_data_t *additionalFie obs_data_release(update); } -void WSEvents::connectTransitionSignals(obs_source_t* current_transition) +void WSEvents::connectTransitionSignals(obs_source_t* transition) { - if (!transition_is_cut(current_transition)) + if (transition_handler) { - transition_handler = obs_source_get_signal_handler(current_transition); + signal_handler_disconnect(transition_handler, "transition_start", OnTransitionBegin, this); + } + + if (!transition_is_cut(transition)) + { + transition_handler = obs_source_get_signal_handler(transition); signal_handler_connect(transition_handler, "transition_start", OnTransitionBegin, this); } else { @@ -171,12 +182,31 @@ void WSEvents::connectTransitionSignals(obs_source_t* current_transition) } } +void WSEvents::connectSceneSignals(obs_source_t* scene) +{ + // TODO : connect to all scenes, not just the current one. + + if (scene_handler) + { + signal_handler_disconnect(scene_handler, "reorder", OnSceneReordered, this); + signal_handler_disconnect(scene_handler, "item_add", OnSceneItemAdd, this); + signal_handler_disconnect(scene_handler, "item_remove", OnSceneItemDelete, this); + } + + scene_handler = obs_source_get_signal_handler(scene); + signal_handler_connect(scene_handler, "reorder", OnSceneReordered, this); + signal_handler_connect(scene_handler, "item_add", OnSceneItemAdd, this); + signal_handler_connect(scene_handler, "item_remove", OnSceneItemDelete, this); +} + void WSEvents::OnSceneChange() { // Implements an existing update type from bilhamil's OBS Remote obs_data_t *data = obs_data_create(); obs_source_t* current_scene = obs_frontend_get_current_scene(); + connectSceneSignals(current_scene); + obs_data_set_string(data, "scene-name", obs_source_get_name(current_scene)); broadcastUpdate("SwitchScenes", data); @@ -202,11 +232,6 @@ void WSEvents::OnSceneCollectionListChange() void WSEvents::OnTransitionChange() { - if (transition_handler) - { - signal_handler_disconnect(transition_handler, "transition_start", OnTransitionBegin, this); - } - obs_source_t* current_transition = obs_frontend_get_current_transition(); connectTransitionSignals(current_transition); @@ -381,4 +406,63 @@ void WSEvents::OnTransitionBegin(void* param, calldata_t* data) instance->broadcastUpdate("TransitionBegin"); blog(LOG_INFO, "transition begin"); +} + +void WSEvents::OnSceneReordered(void *param, calldata_t *data) +{ + WSEvents* instance = static_cast(param); + + obs_scene_t* scene = nullptr; + calldata_get_ptr(data, "scene", &scene); + + obs_data_t *fields = obs_data_create(); + obs_data_set_string(fields, "scene-name", obs_source_get_name(obs_scene_get_source(scene))); + + instance->broadcastUpdate("SourceOrderChanged", fields); + + obs_data_release(fields); +} + +void WSEvents::OnSceneItemAdd(void *param, calldata_t *data) +{ + WSEvents* instance = static_cast(param); + + obs_scene_t* scene = nullptr; + calldata_get_ptr(data, "scene", &scene); + + obs_sceneitem_t* scene_item = nullptr; + calldata_get_ptr(data, "item", &scene_item); + + const char* scene_name = obs_source_get_name(obs_scene_get_source(scene)); + const char* sceneitem_name = obs_source_get_name(obs_sceneitem_get_source(scene_item)); + + obs_data_t* fields = obs_data_create(); + obs_data_set_string(fields, "scene-name", scene_name); + obs_data_set_string(fields, "item-name", sceneitem_name); + + instance->broadcastUpdate("SceneItemAdded", fields); + + obs_data_release(fields); +} + +void WSEvents::OnSceneItemDelete(void *param, calldata_t *data) +{ + WSEvents* instance = static_cast(param); + + obs_scene_t* scene = nullptr; + calldata_get_ptr(data, "scene", &scene); + + obs_sceneitem_t* scene_item = nullptr; + calldata_get_ptr(data, "item", &scene_item); + + const char* scene_name = obs_source_get_name(obs_scene_get_source(scene)); + const char* sceneitem_name = obs_source_get_name(obs_sceneitem_get_source(scene_item)); + + obs_data_t* fields = obs_data_create(); + obs_data_set_string(fields, "scene-name", scene_name); + obs_data_set_string(fields, "item-name", sceneitem_name); + + instance->broadcastUpdate("SceneItemRemoved", fields); + + obs_data_release(fields); } \ No newline at end of file diff --git a/WSEvents.h b/WSEvents.h index 9c24fb02..f5db5599 100644 --- a/WSEvents.h +++ b/WSEvents.h @@ -31,7 +31,8 @@ class WSEvents : public QObject explicit WSEvents(WSServer *srv); ~WSEvents(); static void FrontendEventHandler(enum obs_frontend_event event, void *private_data); - void connectTransitionSignals(obs_source_t* current_transition); + void connectTransitionSignals(obs_source_t* transition); + void connectSceneSignals(obs_source_t* scene); private Q_SLOTS: void StreamStatus(); @@ -40,7 +41,8 @@ class WSEvents : public QObject private: WSServer *_srv; signal_handler_t *transition_handler; - + signal_handler_t *scene_handler; + uint64_t _stream_starttime; uint64_t _rec_starttime; uint64_t _lastBytesSent; @@ -72,6 +74,10 @@ class WSEvents : public QObject void OnExit(); static void OnTransitionBegin(void *param, calldata_t *data); + + static void OnSceneReordered(void *param, calldata_t *data); + static void OnSceneItemAdd(void *param, calldata_t *data); + static void OnSceneItemDelete(void *param, calldata_t *data); }; #endif // WSEVENTS_H \ No newline at end of file