From 45d62e5ce02b8151db1ace0c35043ad69669c103 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Fri, 14 May 2021 01:13:27 -0700 Subject: [PATCH] EventHandler: General, Config, Scenes, Inputs --- CMakeLists.txt | 3 +- docs/partials/introduction.md | 6 +- src/WebSocketServer.cpp | 3 +- src/WebSocketSession.cpp | 4 +- src/eventhandler/EventHandler.cpp | 153 ++++++++++++++---- src/eventhandler/EventHandler.h | 17 +- src/eventhandler/EventHandler_Config.cpp | 16 +- src/eventhandler/EventHandler_General.cpp | 4 +- src/eventhandler/EventHandler_Inputs.cpp | 151 +++++++++++++++++ src/eventhandler/EventHandler_Scenes.cpp | 33 +++- ...entSubscriptions.h => EventSubscription.h} | 6 +- 11 files changed, 340 insertions(+), 56 deletions(-) create mode 100644 src/eventhandler/EventHandler_Inputs.cpp rename src/eventhandler/types/{EventSubscriptions.h => EventSubscription.h} (86%) diff --git a/CMakeLists.txt b/CMakeLists.txt index beb54327..2ea3e2b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ set(obs-websocket_SOURCES src/eventhandler/EventHandler_General.cpp src/eventhandler/EventHandler_Config.cpp src/eventhandler/EventHandler_Scenes.cpp + src/eventhandler/EventHandler_Inputs.cpp src/requesthandler/RequestHandler.cpp src/requesthandler/RequestHandler_General.cpp src/requesthandler/rpc/Request.cpp @@ -97,7 +98,7 @@ set(obs-websocket_HEADERS src/WebSocketProtocol.h src/WebSocketSession.h src/eventhandler/EventHandler.h - src/eventhandler/types/EventSubscriptions.h + src/eventhandler/types/EventSubscription.h src/requesthandler/RequestHandler.h src/requesthandler/rpc/Request.h src/requesthandler/rpc/RequestResult.h diff --git a/docs/partials/introduction.md b/docs/partials/introduction.md index e743b7e5..6534efb0 100644 --- a/docs/partials/introduction.md +++ b/docs/partials/introduction.md @@ -247,7 +247,7 @@ enum WebSocketCloseCode { #### EventSubscriptions Enum ```cpp -enum EventSubscriptions { +enum EventSubscription { // Set subscriptions to 0 to disable all events None = 0, // Receive events in the `General` category @@ -344,7 +344,7 @@ Authentication is not required "authentication": string(optional), "ignoreInvalidMessages": bool(optional) = false, "ignoreNonFatalRequestChecks": bool(optional) = false, - "eventSubscriptions": number(optional) = (EventSubscriptions::All) + "eventSubscriptions": number(optional) = (EventSubscription::All) } ``` - `rpcVersion` is the version number that the client would like the obs-websocket server to use. @@ -397,7 +397,7 @@ Authentication is not required { "ignoreInvalidMessages": bool(optional) = false, "ignoreNonFatalRequestChecks": bool(optional) = false, - "eventSubscriptions": number(optional) = (EventSubscriptions::All) + "eventSubscriptions": number(optional) = (EventSubscription::All) } ``` - Only the listed parameters may be changed after initial identification. To change a parameter not listed, you must reconnect to the obs-websocket server. diff --git a/src/WebSocketServer.cpp b/src/WebSocketServer.cpp index 892223db..294d74ac 100644 --- a/src/WebSocketServer.cpp +++ b/src/WebSocketServer.cpp @@ -8,6 +8,7 @@ #include "WebSocketServer.h" #include "WebSocketProtocol.h" #include "Config.h" +#include "eventhandler/types/EventSubscription.h" #include "plugin-macros.generated.h" @@ -236,7 +237,7 @@ void WebSocketServer::BroadcastEvent(uint64_t requiredIntent, std::string eventT } } lock.unlock(); - if (_debugEnabled) + if (_debugEnabled && (EventSubscription::All & requiredIntent) != 0) // Don't log high volume events blog(LOG_INFO, "[WebSocketServer::BroadcastEvent] Outgoing event:\n%s", eventMessage.dump(2).c_str()); }); } diff --git a/src/WebSocketSession.cpp b/src/WebSocketSession.cpp index 2b5d5a6f..43c19c15 100644 --- a/src/WebSocketSession.cpp +++ b/src/WebSocketSession.cpp @@ -1,5 +1,5 @@ #include "WebSocketSession.h" -#include "eventhandler/types/EventSubscriptions.h" +#include "eventhandler/types/EventSubscription.h" #include "plugin-macros.generated.h" @@ -14,7 +14,7 @@ WebSocketSession::WebSocketSession() : _isIdentified(false), _ignoreInvalidMessages(false), _ignoreNonFatalRequestChecks(false), - _eventSubscriptions(EventSubscriptions::All) + _eventSubscriptions(EventSubscription::All) { } diff --git a/src/eventhandler/EventHandler.cpp b/src/eventhandler/EventHandler.cpp index 59ba98bc..5b6aeb05 100644 --- a/src/eventhandler/EventHandler.cpp +++ b/src/eventhandler/EventHandler.cpp @@ -4,32 +4,32 @@ std::string GetCalldataString(const calldata_t *data, const char* name) { - const char* value = nullptr; - calldata_get_string(data, name, &value); + const char* value = calldata_string(data, name); + if (!value) + return ""; return value; } EventHandler::EventHandler(WebSocketServerPtr webSocketServer) : - _webSocketServer(webSocketServer) + _webSocketServer(webSocketServer), + _obsLoaded(false) { blog(LOG_INFO, "[EventHandler::EventHandler] Setting up event handlers..."); _cpuUsageInfo = os_cpu_usage_info_start(); - obs_frontend_add_event_callback(EventHandler::OnFrontendEvent, this); + obs_frontend_add_event_callback(OnFrontendEvent, this); signal_handler_t* coreSignalHandler = obs_get_signal_handler(); if (coreSignalHandler) { signal_handler_connect(coreSignalHandler, "source_create", SourceCreatedMultiHandler, this); + signal_handler_connect(coreSignalHandler, "source_destroy", SourceDestroyedMultiHandler, this); signal_handler_connect(coreSignalHandler, "source_remove", SourceRemovedMultiHandler, this); + signal_handler_connect(coreSignalHandler, "source_rename", SourceRenamedMultiHandler, this); + } else { + blog(LOG_ERROR, "[EventHandler::EventHandler] Unable to get libobs signal handler!"); } - obs_enum_sources([](void* param, obs_source_t* source) { - auto eventHandler = reinterpret_cast(param); - eventHandler->ConnectSourceSignals(source); - return true; - }, this); - blog(LOG_INFO, "[EventHandler::EventHandler] Finished."); } @@ -39,24 +39,22 @@ EventHandler::~EventHandler() os_cpu_usage_info_destroy(_cpuUsageInfo); - obs_frontend_remove_event_callback(EventHandler::OnFrontendEvent, this); + obs_frontend_remove_event_callback(OnFrontendEvent, this); signal_handler_t* coreSignalHandler = obs_get_signal_handler(); if (coreSignalHandler) { - signal_handler_disconnect(coreSignalHandler, "source_destroy", SourceCreatedMultiHandler, this); + signal_handler_disconnect(coreSignalHandler, "source_create", SourceCreatedMultiHandler, this); + signal_handler_disconnect(coreSignalHandler, "source_destroy", SourceDestroyedMultiHandler, this); signal_handler_disconnect(coreSignalHandler, "source_remove", SourceRemovedMultiHandler, this); + signal_handler_disconnect(coreSignalHandler, "source_rename", SourceRenamedMultiHandler, this); + } else { + blog(LOG_ERROR, "[EventHandler::~EventHandler] Unable to get libobs signal handler!"); } - obs_enum_sources([](void* param, obs_source_t* source) { - auto eventHandler = reinterpret_cast(param); - eventHandler->DisconnectSourceSignals(source); - return true; - }, this); - blog(LOG_INFO, "[EventHandler::~EventHandler] Finished."); } -void EventHandler::ConnectSourceSignals(obs_source_t *source) +void EventHandler::ConnectSourceSignals(obs_source_t *source) // These signals are only reliably connected to inputs. { if (!source || obs_source_removed(source)) return; @@ -65,7 +63,15 @@ void EventHandler::ConnectSourceSignals(obs_source_t *source) signal_handler_t* sh = obs_source_get_signal_handler(source); - signal_handler_connect(sh, "rename", SourceRenamedMultiHandler, this); + // Inputs + signal_handler_connect(sh, "activate", HandleInputActiveStateChanged, this); + signal_handler_connect(sh, "deactivate", HandleInputActiveStateChanged, this); + signal_handler_connect(sh, "show", HandleInputShowStateChanged, this); + 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_sync", HandleInputAudioSyncOffsetChanged, this); + signal_handler_connect(sh, "audio_mixers", HandleInputAudioTracksChanged, this); } void EventHandler::DisconnectSourceSignals(obs_source_t *source) @@ -75,16 +81,54 @@ void EventHandler::DisconnectSourceSignals(obs_source_t *source) signal_handler_t* sh = obs_source_get_signal_handler(source); - signal_handler_disconnect(sh, "rename", SourceRenamedMultiHandler, this); + // Inputs + signal_handler_disconnect(sh, "activate", HandleInputActiveStateChanged, this); + signal_handler_disconnect(sh, "deactivate", HandleInputActiveStateChanged, this); + signal_handler_disconnect(sh, "show", HandleInputShowStateChanged, this); + 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_sync", HandleInputAudioSyncOffsetChanged, this); + signal_handler_disconnect(sh, "audio_mixers", HandleInputAudioTracksChanged, this); } -void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_data) { +void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_data) +{ auto eventHandler = reinterpret_cast(private_data); + if (!eventHandler->_obsLoaded.load()) { + if (event == OBS_FRONTEND_EVENT_FINISHED_LOADING) { + blog(LOG_INFO, "[EventHandler::OnFrontendEvent] OBS has finished loading. Connecting final handlers and enabling events..."); + // Connect source signals and enable events only after OBS has fully loaded (to reduce extra logging). + eventHandler->_obsLoaded.store(true); + // In the case that plugins become hotloadable, this will have to go back into `EventHandler::EventHandler()` + obs_enum_sources([](void* param, obs_source_t* source) { + auto eventHandler = reinterpret_cast(param); + eventHandler->ConnectSourceSignals(source); + return true; + }, private_data); + blog(LOG_INFO, "[EventHandler::OnFrontendEvent] Finished."); + } else { + return; + } + } + switch (event) { // General case OBS_FRONTEND_EVENT_EXIT: eventHandler->HandleExitStarted(); + + blog(LOG_INFO, "[EventHandler::OnFrontendEvent] OBS is unloading. Disabling events..."); + // Disconnect source signals and disable events when OBS starts unloading (to reduce extra logging). + eventHandler->_obsLoaded.store(false); + // In the case that plugins become hotloadable, this will have to go back into `EventHandler::~EventHandler()` + obs_enum_sources([](void* param, obs_source_t* source) { + auto eventHandler = reinterpret_cast(param); + eventHandler->DisconnectSourceSignals(source); + return true; + }, private_data); + blog(LOG_INFO, "[EventHandler::OnFrontendEvent] Finished."); + break; case OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED: eventHandler->HandleStudioModeStateChanged(true); @@ -163,17 +207,53 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_ void EventHandler::SourceCreatedMultiHandler(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(data); + auto eventHandler = reinterpret_cast(param); + + if (!eventHandler->_obsLoaded.load()) + return; OBSSource source = GetCalldataPointer(data, "source"); if (!source) return; - obs_source_type sourceType = obs_source_get_type(source); - switch (sourceType) { + // Connect all signals from the source + eventHandler->ConnectSourceSignals(source); + + switch (obs_source_get_type(source)) { 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; + default: + break; + } +} + +void EventHandler::SourceDestroyedMultiHandler(void *param, calldata_t *data) +{ + auto eventHandler = reinterpret_cast(param); + + if (!eventHandler->_obsLoaded.load()) + return; + + // We can't use any smart types because releasing the source will cause infinite recursion + obs_source_t *source = GetCalldataPointer(data, "source"); + if (!source) + return; + + // Disconnect all signals from the source + eventHandler->DisconnectSourceSignals(source); + + switch (obs_source_get_type(source)) { + case OBS_SOURCE_TYPE_INPUT: + eventHandler->HandleInputRemoved(source); // We have to call `InputRemoved` with source_destroy because source_removed is not called when a source is *only* destroyed + break; case OBS_SOURCE_TYPE_FILTER: break; case OBS_SOURCE_TYPE_TRANSITION: @@ -187,22 +267,24 @@ void EventHandler::SourceCreatedMultiHandler(void *param, calldata_t *data) void EventHandler::SourceRemovedMultiHandler(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(data); + auto eventHandler = reinterpret_cast(param); + + if (!eventHandler->_obsLoaded.load()) + return; OBSSource source = GetCalldataPointer(data, "source"); if (!source) return; - obs_source_type sourceType = obs_source_get_type(source); - switch (sourceType) { + switch (obs_source_get_type(source)) { case OBS_SOURCE_TYPE_INPUT: - eventHandler->HandleSceneRemoved(source); break; case OBS_SOURCE_TYPE_FILTER: break; case OBS_SOURCE_TYPE_TRANSITION: break; case OBS_SOURCE_TYPE_SCENE: + eventHandler->HandleSceneRemoved(source); break; default: break; @@ -211,27 +293,30 @@ void EventHandler::SourceRemovedMultiHandler(void *param, calldata_t *data) void EventHandler::SourceRenamedMultiHandler(void *param, calldata_t *data) { - auto eventHandler = reinterpret_cast(data); + auto eventHandler = reinterpret_cast(param); + + if (!eventHandler->_obsLoaded.load()) + return; OBSSource source = GetCalldataPointer(data, "source"); if (!source) return; - std::string oldSourceName = GetCalldataString(data, "old_name"); + std::string oldSourceName = GetCalldataString(data, "prev_name"); std::string sourceName = GetCalldataString(data, "new_name"); if (oldSourceName.empty() || sourceName.empty()) return; - obs_source_type sourceType = obs_source_get_type(source); - switch (sourceType) { + switch (obs_source_get_type(source)) { case OBS_SOURCE_TYPE_INPUT: - eventHandler->HandleSceneNameChanged(source, oldSourceName, sourceName); + eventHandler->HandleInputNameChanged(source, oldSourceName, sourceName); break; case OBS_SOURCE_TYPE_FILTER: break; case OBS_SOURCE_TYPE_TRANSITION: break; case OBS_SOURCE_TYPE_SCENE: + eventHandler->HandleSceneNameChanged(source, oldSourceName, sourceName); break; default: break; diff --git a/src/eventhandler/EventHandler.h b/src/eventhandler/EventHandler.h index 34ca1a4c..dee30907 100644 --- a/src/eventhandler/EventHandler.h +++ b/src/eventhandler/EventHandler.h @@ -6,7 +6,7 @@ #include "../obs-websocket.h" #include "../WebSocketServer.h" -#include "types/EventSubscriptions.h" +#include "types/EventSubscription.h" template T* GetCalldataPointer(const calldata_t *data, const char* name) { void* ptr = nullptr; @@ -26,6 +26,8 @@ class EventHandler WebSocketServerPtr _webSocketServer; os_cpu_usage_info_t *_cpuUsageInfo; + std::atomic _obsLoaded; + void ConnectSourceSignals(obs_source_t *source); void DisconnectSourceSignals(obs_source_t *source); @@ -34,11 +36,13 @@ class EventHandler // Signal handler: libobs static void SourceCreatedMultiHandler(void *param, calldata_t *data); + static void SourceDestroyedMultiHandler(void *param, calldata_t *data); static void SourceRemovedMultiHandler(void *param, calldata_t *data); // Signal handler: source static void SourceRenamedMultiHandler(void *param, calldata_t *data); + // General void HandleExitStarted(); void HandleStudioModeStateChanged(bool enabled); @@ -56,4 +60,15 @@ class EventHandler void HandleCurrentSceneChanged(); void HandleCurrentPreviewSceneChanged(); void HandleSceneListReindexed(); + + // Inputs + void HandleInputCreated(obs_source_t *source); + void HandleInputRemoved(obs_source_t *source); + void HandleInputNameChanged(obs_source_t *source, std::string oldInputName, std::string inputName); + static void HandleInputActiveStateChanged(void *param, calldata_t *data); // Direct callback + 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 HandleInputAudioSyncOffsetChanged(void *param, calldata_t *data); // Direct callback + static void HandleInputAudioTracksChanged(void *param, calldata_t *data); // Direct callback }; diff --git a/src/eventhandler/EventHandler_Config.cpp b/src/eventhandler/EventHandler_Config.cpp index 93b7df4b..f0c05203 100644 --- a/src/eventhandler/EventHandler_Config.cpp +++ b/src/eventhandler/EventHandler_Config.cpp @@ -4,20 +4,28 @@ void EventHandler::HandleCurrentSceneCollectionChanged() { - ; + json eventData; + eventData["sceneCollectionName"] = obs_frontend_get_current_scene_collection(); + _webSocketServer->BroadcastEvent(EventSubscription::Config, "CurrentSceneCollectionChanged", eventData); } void EventHandler::HandleSceneCollectionListChanged() { - ; + json eventData; + eventData["sceneCollections"] = Utils::Obs::ListHelper::GetSceneCollectionList(); + _webSocketServer->BroadcastEvent(EventSubscription::Config, "SceneCollectionListChanged", eventData); } void EventHandler::HandleCurrentProfileChanged() { - ; + json eventData; + eventData["profileName"] = obs_frontend_get_current_profile(); + _webSocketServer->BroadcastEvent(EventSubscription::Config, "CurrentProfileChanged", eventData); } void EventHandler::HandleProfileListChanged() { - ; + json eventData; + eventData["profiles"] = Utils::Obs::ListHelper::GetProfileList(); + _webSocketServer->BroadcastEvent(EventSubscription::Config, "ProfileListChanged", eventData); } diff --git a/src/eventhandler/EventHandler_General.cpp b/src/eventhandler/EventHandler_General.cpp index 4599456e..ae769171 100644 --- a/src/eventhandler/EventHandler_General.cpp +++ b/src/eventhandler/EventHandler_General.cpp @@ -4,12 +4,12 @@ void EventHandler::HandleExitStarted() { - _webSocketServer->BroadcastEvent(EventSubscriptions::General, "ExitStarted"); + _webSocketServer->BroadcastEvent(EventSubscription::General, "ExitStarted"); } void EventHandler::HandleStudioModeStateChanged(bool enabled) { json eventData; eventData["studioModeEnabled"] = enabled; - _webSocketServer->BroadcastEvent(EventSubscriptions::General, "StudioModeStateChanged", eventData); + _webSocketServer->BroadcastEvent(EventSubscription::General, "StudioModeStateChanged", eventData); } diff --git a/src/eventhandler/EventHandler_Inputs.cpp b/src/eventhandler/EventHandler_Inputs.cpp new file mode 100644 index 00000000..1b3129df --- /dev/null +++ b/src/eventhandler/EventHandler_Inputs.cpp @@ -0,0 +1,151 @@ +#include "EventHandler.h" + +#include "../plugin-macros.generated.h" + +void EventHandler::HandleInputCreated(obs_source_t *source) +{ + json eventData; + eventData["inputName"] = obs_source_get_name(source); + _webSocketServer->BroadcastEvent(EventSubscription::Inputs, "InputCreated", eventData); +} + +void EventHandler::HandleInputRemoved(obs_source_t *source) +{ + json eventData; + eventData["inputName"] = obs_source_get_name(source); + _webSocketServer->BroadcastEvent(EventSubscription::Inputs, "InputRemoved", eventData); +} + +void EventHandler::HandleInputNameChanged(obs_source_t *source, std::string oldInputName, std::string inputName) +{ + json eventData; + eventData["oldInputName"] = oldInputName; + eventData["inputName"] = inputName; + _webSocketServer->BroadcastEvent(EventSubscription::Inputs, "InputNameChanged", eventData); +} + +void EventHandler::HandleInputActiveStateChanged(void *param, calldata_t *data) +{ + auto eventHandler = reinterpret_cast(param); + + OBSSource source = GetCalldataPointer(data, "source"); + if (!source) + return; + + if (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT) + return; + + json eventData; + eventData["inputName"] = obs_source_get_name(source); + eventData["videoActive"] = obs_source_active(source); + eventHandler->_webSocketServer->BroadcastEvent(EventSubscription::Inputs, "InputActiveStateChanged", eventData); +} + +void EventHandler::HandleInputShowStateChanged(void *param, calldata_t *data) +{ + auto eventHandler = reinterpret_cast(param); + + OBSSource source = GetCalldataPointer(data, "source"); + if (!source) + return; + + if (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT) + return; + + json eventData; + eventData["inputName"] = obs_source_get_name(source); + eventData["videoShowing"] = obs_source_showing(source); + eventHandler->_webSocketServer->BroadcastEvent(EventSubscription::Inputs, "InputShowStateChanged", eventData); +} + +void EventHandler::HandleInputMuteStateChanged(void *param, calldata_t *data) +{ + auto eventHandler = reinterpret_cast(param); + + OBSSource source = GetCalldataPointer(data, "source"); + if (!source) + return; + + if (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT) + return; + + json eventData; + eventData["inputName"] = obs_source_get_name(source); + eventData["inputMuted"] = obs_source_muted(source); + eventHandler->_webSocketServer->BroadcastEvent(EventSubscription::Inputs, "InputMuteStateChanged", eventData); +} + +void EventHandler::HandleInputVolumeChanged(void *param, calldata_t *data) +{ + auto eventHandler = reinterpret_cast(param); + + OBSSource source = GetCalldataPointer(data, "source"); + if (!source) + return; + + if (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT) + return; + + // Volume must be grabbed from the calldata. Running obs_source_get_volume() will return the previous value. + double inputVolumeMul = 0; + if (!calldata_get_float(data, "volume", &inputVolumeMul)) + return; + + double inputVolumeDb = obs_mul_to_db(inputVolumeMul); + if (inputVolumeDb == -INFINITY) + inputVolumeDb = -100; + + json eventData; + eventData["inputName"] = obs_source_get_name(source); + eventData["inputVolumeMul"] = inputVolumeMul; + eventData["inputVolumeDb"] = inputVolumeDb; + eventHandler->_webSocketServer->BroadcastEvent(EventSubscription::Inputs, "InputVolumeChanged", eventData); +} + +void EventHandler::HandleInputAudioSyncOffsetChanged(void *param, calldata_t *data) +{ + auto eventHandler = reinterpret_cast(param); + + OBSSource source = GetCalldataPointer(data, "source"); + if (!source) + return; + + if (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT) + return; + + long long inputAudioSyncOffset = 0; + if (!calldata_get_int(data, "offset", &inputAudioSyncOffset)) + return; + + json eventData; + eventData["inputName"] = obs_source_get_name(source); + eventData["inputAudioSyncOffset"] = inputAudioSyncOffset / 1000000; + eventHandler->_webSocketServer->BroadcastEvent(EventSubscription::Inputs, "InputAudioSyncOffsetChanged", eventData); +} + +void EventHandler::HandleInputAudioTracksChanged(void *param, calldata_t *data) +{ + auto eventHandler = reinterpret_cast(param); + + OBSSource source = GetCalldataPointer(data, "source"); + if (!source) + return; + + if (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT) + return; + + long long tracks; + if (!calldata_get_int(data, "mixers", &tracks)) { + return; + } + + json inputAudioTracks; + for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) { + inputAudioTracks[std::to_string(i + 1)] = (bool)((1 << i) & tracks); + } + + json eventData; + eventData["inputName"] = obs_source_get_name(source); + eventData["inputAudioTracks"] = inputAudioTracks; + eventHandler->_webSocketServer->BroadcastEvent(EventSubscription::Inputs, "InputAudioTracksChanged", eventData); +} diff --git a/src/eventhandler/EventHandler_Scenes.cpp b/src/eventhandler/EventHandler_Scenes.cpp index bddb29df..95c61acb 100644 --- a/src/eventhandler/EventHandler_Scenes.cpp +++ b/src/eventhandler/EventHandler_Scenes.cpp @@ -4,30 +4,51 @@ void EventHandler::HandleSceneCreated(obs_source_t *source) { - ; + json eventData; + eventData["sceneName"] = obs_source_get_name(source); + _webSocketServer->BroadcastEvent(EventSubscription::Scenes, "SceneCreated", eventData); } void EventHandler::HandleSceneRemoved(obs_source_t *source) { - ; + json eventData; + eventData["sceneName"] = obs_source_get_name(source); + _webSocketServer->BroadcastEvent(EventSubscription::Scenes, "SceneRemoved", eventData); } void EventHandler::HandleSceneNameChanged(obs_source_t *source, std::string oldSceneName, std::string sceneName) { - ; + json eventData; + eventData["oldSceneName"] = oldSceneName; + eventData["sceneName"] = sceneName; + _webSocketServer->BroadcastEvent(EventSubscription::Scenes, "SceneNameChanged", eventData); } void EventHandler::HandleCurrentSceneChanged() { - ; + OBSSourceAutoRelease currentScene = obs_frontend_get_current_scene(); + + json eventData; + eventData["sceneName"] = obs_source_get_name(currentScene); + _webSocketServer->BroadcastEvent(EventSubscription::Scenes, "CurrentSceneChanged", eventData); } void EventHandler::HandleCurrentPreviewSceneChanged() { - ; + OBSSourceAutoRelease currentPreviewScene = obs_frontend_get_current_preview_scene(); + + // This event may be called when OBS is not in studio mode, however retreiving the source while not in studio mode will return null. + if (!currentPreviewScene) + return; + + json eventData; + eventData["sceneName"] = obs_source_get_name(currentPreviewScene); + _webSocketServer->BroadcastEvent(EventSubscription::Scenes, "CurrentPreviewSceneChanged", eventData); } void EventHandler::HandleSceneListReindexed() { - ; + json eventData; + eventData["scenes"] = Utils::Obs::ListHelper::GetSceneList(); + _webSocketServer->BroadcastEvent(EventSubscription::Scenes, "SceneListReindexed", eventData); } diff --git a/src/eventhandler/types/EventSubscriptions.h b/src/eventhandler/types/EventSubscription.h similarity index 86% rename from src/eventhandler/types/EventSubscriptions.h rename to src/eventhandler/types/EventSubscription.h index e7e5a665..53bdc6ec 100644 --- a/src/eventhandler/types/EventSubscriptions.h +++ b/src/eventhandler/types/EventSubscription.h @@ -1,7 +1,7 @@ #pragma once -namespace EventSubscriptions { - enum EventSubscriptions { +namespace EventSubscription { + enum EventSubscription { // Set subscriptions to 0 to disable all events None = 0, // Receive events in the `General` category @@ -24,5 +24,7 @@ namespace EventSubscriptions { MediaInputs = (1 << 8), // Receive all event categories All = (General | Config | Scenes | Inputs | Transitions | Filters | Outputs | SceneItems | MediaInputs), + // InputVolumeMeters event (high-volume) + InputVolumeMeters = (1 << 9), }; };