EventHandler: General, Config, Scenes, Inputs

This commit is contained in:
tt2468 2021-05-14 01:13:27 -07:00
parent c8eac893f2
commit 45d62e5ce0
11 changed files with 340 additions and 56 deletions

View File

@ -78,6 +78,7 @@ set(obs-websocket_SOURCES
src/eventhandler/EventHandler_General.cpp src/eventhandler/EventHandler_General.cpp
src/eventhandler/EventHandler_Config.cpp src/eventhandler/EventHandler_Config.cpp
src/eventhandler/EventHandler_Scenes.cpp src/eventhandler/EventHandler_Scenes.cpp
src/eventhandler/EventHandler_Inputs.cpp
src/requesthandler/RequestHandler.cpp src/requesthandler/RequestHandler.cpp
src/requesthandler/RequestHandler_General.cpp src/requesthandler/RequestHandler_General.cpp
src/requesthandler/rpc/Request.cpp src/requesthandler/rpc/Request.cpp
@ -97,7 +98,7 @@ set(obs-websocket_HEADERS
src/WebSocketProtocol.h src/WebSocketProtocol.h
src/WebSocketSession.h src/WebSocketSession.h
src/eventhandler/EventHandler.h src/eventhandler/EventHandler.h
src/eventhandler/types/EventSubscriptions.h src/eventhandler/types/EventSubscription.h
src/requesthandler/RequestHandler.h src/requesthandler/RequestHandler.h
src/requesthandler/rpc/Request.h src/requesthandler/rpc/Request.h
src/requesthandler/rpc/RequestResult.h src/requesthandler/rpc/RequestResult.h

View File

@ -247,7 +247,7 @@ enum WebSocketCloseCode {
#### EventSubscriptions Enum #### EventSubscriptions Enum
```cpp ```cpp
enum EventSubscriptions { enum EventSubscription {
// Set subscriptions to 0 to disable all events // Set subscriptions to 0 to disable all events
None = 0, None = 0,
// Receive events in the `General` category // Receive events in the `General` category
@ -344,7 +344,7 @@ Authentication is not required
"authentication": string(optional), "authentication": string(optional),
"ignoreInvalidMessages": bool(optional) = false, "ignoreInvalidMessages": bool(optional) = false,
"ignoreNonFatalRequestChecks": 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. - `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, "ignoreInvalidMessages": bool(optional) = false,
"ignoreNonFatalRequestChecks": 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. - Only the listed parameters may be changed after initial identification. To change a parameter not listed, you must reconnect to the obs-websocket server.

View File

@ -8,6 +8,7 @@
#include "WebSocketServer.h" #include "WebSocketServer.h"
#include "WebSocketProtocol.h" #include "WebSocketProtocol.h"
#include "Config.h" #include "Config.h"
#include "eventhandler/types/EventSubscription.h"
#include "plugin-macros.generated.h" #include "plugin-macros.generated.h"
@ -236,7 +237,7 @@ void WebSocketServer::BroadcastEvent(uint64_t requiredIntent, std::string eventT
} }
} }
lock.unlock(); 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()); blog(LOG_INFO, "[WebSocketServer::BroadcastEvent] Outgoing event:\n%s", eventMessage.dump(2).c_str());
}); });
} }

View File

@ -1,5 +1,5 @@
#include "WebSocketSession.h" #include "WebSocketSession.h"
#include "eventhandler/types/EventSubscriptions.h" #include "eventhandler/types/EventSubscription.h"
#include "plugin-macros.generated.h" #include "plugin-macros.generated.h"
@ -14,7 +14,7 @@ WebSocketSession::WebSocketSession() :
_isIdentified(false), _isIdentified(false),
_ignoreInvalidMessages(false), _ignoreInvalidMessages(false),
_ignoreNonFatalRequestChecks(false), _ignoreNonFatalRequestChecks(false),
_eventSubscriptions(EventSubscriptions::All) _eventSubscriptions(EventSubscription::All)
{ {
} }

View File

@ -4,32 +4,32 @@
std::string GetCalldataString(const calldata_t *data, const char* name) std::string GetCalldataString(const calldata_t *data, const char* name)
{ {
const char* value = nullptr; const char* value = calldata_string(data, name);
calldata_get_string(data, name, &value); if (!value)
return "";
return value; return value;
} }
EventHandler::EventHandler(WebSocketServerPtr webSocketServer) : EventHandler::EventHandler(WebSocketServerPtr webSocketServer) :
_webSocketServer(webSocketServer) _webSocketServer(webSocketServer),
_obsLoaded(false)
{ {
blog(LOG_INFO, "[EventHandler::EventHandler] Setting up event handlers..."); blog(LOG_INFO, "[EventHandler::EventHandler] Setting up event handlers...");
_cpuUsageInfo = os_cpu_usage_info_start(); _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(); signal_handler_t* coreSignalHandler = obs_get_signal_handler();
if (coreSignalHandler) { if (coreSignalHandler) {
signal_handler_connect(coreSignalHandler, "source_create", SourceCreatedMultiHandler, this); 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_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<EventHandler*>(param);
eventHandler->ConnectSourceSignals(source);
return true;
}, this);
blog(LOG_INFO, "[EventHandler::EventHandler] Finished."); blog(LOG_INFO, "[EventHandler::EventHandler] Finished.");
} }
@ -39,24 +39,22 @@ EventHandler::~EventHandler()
os_cpu_usage_info_destroy(_cpuUsageInfo); 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(); signal_handler_t* coreSignalHandler = obs_get_signal_handler();
if (coreSignalHandler) { 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_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<EventHandler*>(param);
eventHandler->DisconnectSourceSignals(source);
return true;
}, this);
blog(LOG_INFO, "[EventHandler::~EventHandler] Finished."); 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)) if (!source || obs_source_removed(source))
return; return;
@ -65,7 +63,15 @@ void EventHandler::ConnectSourceSignals(obs_source_t *source)
signal_handler_t* sh = obs_source_get_signal_handler(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) 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_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<EventHandler*>(private_data); auto eventHandler = reinterpret_cast<EventHandler*>(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<EventHandler*>(param);
eventHandler->ConnectSourceSignals(source);
return true;
}, private_data);
blog(LOG_INFO, "[EventHandler::OnFrontendEvent] Finished.");
} else {
return;
}
}
switch (event) { switch (event) {
// General // General
case OBS_FRONTEND_EVENT_EXIT: case OBS_FRONTEND_EVENT_EXIT:
eventHandler->HandleExitStarted(); 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<EventHandler*>(param);
eventHandler->DisconnectSourceSignals(source);
return true;
}, private_data);
blog(LOG_INFO, "[EventHandler::OnFrontendEvent] Finished.");
break; break;
case OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED: case OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED:
eventHandler->HandleStudioModeStateChanged(true); 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) void EventHandler::SourceCreatedMultiHandler(void *param, calldata_t *data)
{ {
auto eventHandler = reinterpret_cast<EventHandler*>(data); auto eventHandler = reinterpret_cast<EventHandler*>(param);
if (!eventHandler->_obsLoaded.load())
return;
OBSSource source = GetCalldataPointer<obs_source_t>(data, "source"); OBSSource source = GetCalldataPointer<obs_source_t>(data, "source");
if (!source) if (!source)
return; return;
obs_source_type sourceType = obs_source_get_type(source); // Connect all signals from the source
switch (sourceType) { eventHandler->ConnectSourceSignals(source);
switch (obs_source_get_type(source)) {
case OBS_SOURCE_TYPE_INPUT: 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); eventHandler->HandleSceneCreated(source);
break; break;
default:
break;
}
}
void EventHandler::SourceDestroyedMultiHandler(void *param, calldata_t *data)
{
auto eventHandler = reinterpret_cast<EventHandler*>(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<obs_source_t>(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: case OBS_SOURCE_TYPE_FILTER:
break; break;
case OBS_SOURCE_TYPE_TRANSITION: 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) void EventHandler::SourceRemovedMultiHandler(void *param, calldata_t *data)
{ {
auto eventHandler = reinterpret_cast<EventHandler*>(data); auto eventHandler = reinterpret_cast<EventHandler*>(param);
if (!eventHandler->_obsLoaded.load())
return;
OBSSource source = GetCalldataPointer<obs_source_t>(data, "source"); OBSSource source = GetCalldataPointer<obs_source_t>(data, "source");
if (!source) if (!source)
return; return;
obs_source_type sourceType = obs_source_get_type(source); switch (obs_source_get_type(source)) {
switch (sourceType) {
case OBS_SOURCE_TYPE_INPUT: case OBS_SOURCE_TYPE_INPUT:
eventHandler->HandleSceneRemoved(source);
break; break;
case OBS_SOURCE_TYPE_FILTER: case OBS_SOURCE_TYPE_FILTER:
break; break;
case OBS_SOURCE_TYPE_TRANSITION: case OBS_SOURCE_TYPE_TRANSITION:
break; break;
case OBS_SOURCE_TYPE_SCENE: case OBS_SOURCE_TYPE_SCENE:
eventHandler->HandleSceneRemoved(source);
break; break;
default: default:
break; break;
@ -211,27 +293,30 @@ void EventHandler::SourceRemovedMultiHandler(void *param, calldata_t *data)
void EventHandler::SourceRenamedMultiHandler(void *param, calldata_t *data) void EventHandler::SourceRenamedMultiHandler(void *param, calldata_t *data)
{ {
auto eventHandler = reinterpret_cast<EventHandler*>(data); auto eventHandler = reinterpret_cast<EventHandler*>(param);
if (!eventHandler->_obsLoaded.load())
return;
OBSSource source = GetCalldataPointer<obs_source_t>(data, "source"); OBSSource source = GetCalldataPointer<obs_source_t>(data, "source");
if (!source) if (!source)
return; return;
std::string oldSourceName = GetCalldataString(data, "old_name"); std::string oldSourceName = GetCalldataString(data, "prev_name");
std::string sourceName = GetCalldataString(data, "new_name"); std::string sourceName = GetCalldataString(data, "new_name");
if (oldSourceName.empty() || sourceName.empty()) if (oldSourceName.empty() || sourceName.empty())
return; return;
obs_source_type sourceType = obs_source_get_type(source); switch (obs_source_get_type(source)) {
switch (sourceType) {
case OBS_SOURCE_TYPE_INPUT: case OBS_SOURCE_TYPE_INPUT:
eventHandler->HandleSceneNameChanged(source, oldSourceName, sourceName); eventHandler->HandleInputNameChanged(source, oldSourceName, sourceName);
break; break;
case OBS_SOURCE_TYPE_FILTER: case OBS_SOURCE_TYPE_FILTER:
break; break;
case OBS_SOURCE_TYPE_TRANSITION: case OBS_SOURCE_TYPE_TRANSITION:
break; break;
case OBS_SOURCE_TYPE_SCENE: case OBS_SOURCE_TYPE_SCENE:
eventHandler->HandleSceneNameChanged(source, oldSourceName, sourceName);
break; break;
default: default:
break; break;

View File

@ -6,7 +6,7 @@
#include "../obs-websocket.h" #include "../obs-websocket.h"
#include "../WebSocketServer.h" #include "../WebSocketServer.h"
#include "types/EventSubscriptions.h" #include "types/EventSubscription.h"
template <typename T> T* GetCalldataPointer(const calldata_t *data, const char* name) { template <typename T> T* GetCalldataPointer(const calldata_t *data, const char* name) {
void* ptr = nullptr; void* ptr = nullptr;
@ -26,6 +26,8 @@ class EventHandler
WebSocketServerPtr _webSocketServer; WebSocketServerPtr _webSocketServer;
os_cpu_usage_info_t *_cpuUsageInfo; os_cpu_usage_info_t *_cpuUsageInfo;
std::atomic<bool> _obsLoaded;
void ConnectSourceSignals(obs_source_t *source); void ConnectSourceSignals(obs_source_t *source);
void DisconnectSourceSignals(obs_source_t *source); void DisconnectSourceSignals(obs_source_t *source);
@ -34,11 +36,13 @@ class EventHandler
// Signal handler: libobs // Signal handler: libobs
static void SourceCreatedMultiHandler(void *param, calldata_t *data); static void SourceCreatedMultiHandler(void *param, calldata_t *data);
static void SourceDestroyedMultiHandler(void *param, calldata_t *data);
static void SourceRemovedMultiHandler(void *param, calldata_t *data); static void SourceRemovedMultiHandler(void *param, calldata_t *data);
// Signal handler: source // Signal handler: source
static void SourceRenamedMultiHandler(void *param, calldata_t *data); static void SourceRenamedMultiHandler(void *param, calldata_t *data);
// General // General
void HandleExitStarted(); void HandleExitStarted();
void HandleStudioModeStateChanged(bool enabled); void HandleStudioModeStateChanged(bool enabled);
@ -56,4 +60,15 @@ class EventHandler
void HandleCurrentSceneChanged(); void HandleCurrentSceneChanged();
void HandleCurrentPreviewSceneChanged(); void HandleCurrentPreviewSceneChanged();
void HandleSceneListReindexed(); 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
}; };

View File

@ -4,20 +4,28 @@
void EventHandler::HandleCurrentSceneCollectionChanged() void EventHandler::HandleCurrentSceneCollectionChanged()
{ {
; json eventData;
eventData["sceneCollectionName"] = obs_frontend_get_current_scene_collection();
_webSocketServer->BroadcastEvent(EventSubscription::Config, "CurrentSceneCollectionChanged", eventData);
} }
void EventHandler::HandleSceneCollectionListChanged() void EventHandler::HandleSceneCollectionListChanged()
{ {
; json eventData;
eventData["sceneCollections"] = Utils::Obs::ListHelper::GetSceneCollectionList();
_webSocketServer->BroadcastEvent(EventSubscription::Config, "SceneCollectionListChanged", eventData);
} }
void EventHandler::HandleCurrentProfileChanged() void EventHandler::HandleCurrentProfileChanged()
{ {
; json eventData;
eventData["profileName"] = obs_frontend_get_current_profile();
_webSocketServer->BroadcastEvent(EventSubscription::Config, "CurrentProfileChanged", eventData);
} }
void EventHandler::HandleProfileListChanged() void EventHandler::HandleProfileListChanged()
{ {
; json eventData;
eventData["profiles"] = Utils::Obs::ListHelper::GetProfileList();
_webSocketServer->BroadcastEvent(EventSubscription::Config, "ProfileListChanged", eventData);
} }

View File

@ -4,12 +4,12 @@
void EventHandler::HandleExitStarted() void EventHandler::HandleExitStarted()
{ {
_webSocketServer->BroadcastEvent(EventSubscriptions::General, "ExitStarted"); _webSocketServer->BroadcastEvent(EventSubscription::General, "ExitStarted");
} }
void EventHandler::HandleStudioModeStateChanged(bool enabled) void EventHandler::HandleStudioModeStateChanged(bool enabled)
{ {
json eventData; json eventData;
eventData["studioModeEnabled"] = enabled; eventData["studioModeEnabled"] = enabled;
_webSocketServer->BroadcastEvent(EventSubscriptions::General, "StudioModeStateChanged", eventData); _webSocketServer->BroadcastEvent(EventSubscription::General, "StudioModeStateChanged", eventData);
} }

View File

@ -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<EventHandler*>(param);
OBSSource source = GetCalldataPointer<obs_source_t>(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<EventHandler*>(param);
OBSSource source = GetCalldataPointer<obs_source_t>(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<EventHandler*>(param);
OBSSource source = GetCalldataPointer<obs_source_t>(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<EventHandler*>(param);
OBSSource source = GetCalldataPointer<obs_source_t>(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<EventHandler*>(param);
OBSSource source = GetCalldataPointer<obs_source_t>(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<EventHandler*>(param);
OBSSource source = GetCalldataPointer<obs_source_t>(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);
}

View File

@ -4,30 +4,51 @@
void EventHandler::HandleSceneCreated(obs_source_t *source) 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) 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) 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() 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() 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() void EventHandler::HandleSceneListReindexed()
{ {
; json eventData;
eventData["scenes"] = Utils::Obs::ListHelper::GetSceneList();
_webSocketServer->BroadcastEvent(EventSubscription::Scenes, "SceneListReindexed", eventData);
} }

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
namespace EventSubscriptions { namespace EventSubscription {
enum EventSubscriptions { enum EventSubscription {
// Set subscriptions to 0 to disable all events // Set subscriptions to 0 to disable all events
None = 0, None = 0,
// Receive events in the `General` category // Receive events in the `General` category
@ -24,5 +24,7 @@ namespace EventSubscriptions {
MediaInputs = (1 << 8), MediaInputs = (1 << 8),
// Receive all event categories // Receive all event categories
All = (General | Config | Scenes | Inputs | Transitions | Filters | Outputs | SceneItems | MediaInputs), All = (General | Config | Scenes | Inputs | Transitions | Filters | Outputs | SceneItems | MediaInputs),
// InputVolumeMeters event (high-volume)
InputVolumeMeters = (1 << 9),
}; };
}; };