mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
358 lines
13 KiB
C++
358 lines
13 KiB
C++
#include "EventHandler.h"
|
|
|
|
#include "../plugin-macros.generated.h"
|
|
|
|
std::string GetCalldataString(const calldata_t *data, const char* name)
|
|
{
|
|
const char* value = calldata_string(data, name);
|
|
if (!value)
|
|
return "";
|
|
return value;
|
|
}
|
|
|
|
EventHandler::EventHandler(WebSocketServerPtr 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(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!");
|
|
}
|
|
|
|
blog(LOG_INFO, "[EventHandler::EventHandler] Finished.");
|
|
}
|
|
|
|
EventHandler::~EventHandler()
|
|
{
|
|
blog(LOG_INFO, "[EventHandler::~EventHandler] Removing event handlers...");
|
|
|
|
os_cpu_usage_info_destroy(_cpuUsageInfo);
|
|
|
|
obs_frontend_remove_event_callback(OnFrontendEvent, this);
|
|
|
|
signal_handler_t* coreSignalHandler = obs_get_signal_handler();
|
|
if (coreSignalHandler) {
|
|
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!");
|
|
}
|
|
|
|
blog(LOG_INFO, "[EventHandler::~EventHandler] Finished.");
|
|
}
|
|
|
|
void EventHandler::ConnectSourceSignals(obs_source_t *source) // These signals are only reliably connected to inputs.
|
|
{
|
|
if (!source || obs_source_removed(source))
|
|
return;
|
|
|
|
DisconnectSourceSignals(source);
|
|
|
|
signal_handler_t* sh = obs_source_get_signal_handler(source);
|
|
|
|
// 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);
|
|
signal_handler_connect(sh, "media_started", HandleMediaInputPlaybackStarted, this);
|
|
signal_handler_connect(sh, "media_ended", HandleMediaInputPlaybackEnded, this);
|
|
signal_handler_connect(sh, "media_pause", SourceMediaPauseMultiHandler, this);
|
|
signal_handler_connect(sh, "media_play", SourceMediaPlayMultiHandler, this);
|
|
signal_handler_connect(sh, "media_restart", SourceMediaRestartMultiHandler, this);
|
|
signal_handler_connect(sh, "media_stopped", SourceMediaStopMultiHandler, this);
|
|
signal_handler_connect(sh, "media_next", SourceMediaNextMultiHandler, this);
|
|
signal_handler_connect(sh, "media_previous", SourceMediaPreviousMultiHandler, this);
|
|
}
|
|
|
|
void EventHandler::DisconnectSourceSignals(obs_source_t *source)
|
|
{
|
|
if (!source)
|
|
return;
|
|
|
|
signal_handler_t* sh = obs_source_get_signal_handler(source);
|
|
|
|
// 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);
|
|
signal_handler_disconnect(sh, "media_started", HandleMediaInputPlaybackStarted, this);
|
|
signal_handler_disconnect(sh, "media_ended", HandleMediaInputPlaybackEnded, this);
|
|
signal_handler_disconnect(sh, "media_pause", SourceMediaPauseMultiHandler, this);
|
|
signal_handler_disconnect(sh, "media_play", SourceMediaPlayMultiHandler, this);
|
|
signal_handler_disconnect(sh, "media_restart", SourceMediaRestartMultiHandler, this);
|
|
signal_handler_disconnect(sh, "media_stopped", SourceMediaStopMultiHandler, this);
|
|
signal_handler_disconnect(sh, "media_next", SourceMediaNextMultiHandler, this);
|
|
signal_handler_disconnect(sh, "media_previous", SourceMediaPreviousMultiHandler, this);
|
|
}
|
|
|
|
void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *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) {
|
|
// 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<EventHandler*>(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);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED:
|
|
eventHandler->HandleStudioModeStateChanged(false);
|
|
break;
|
|
|
|
// Config
|
|
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_CHANGED:
|
|
eventHandler->HandleCurrentProfileChanged();
|
|
break;
|
|
case OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED:
|
|
eventHandler->HandleProfileListChanged();
|
|
break;
|
|
|
|
// Scenes
|
|
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
|
|
eventHandler->HandleCurrentSceneChanged();
|
|
break;
|
|
case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED:
|
|
eventHandler->HandleCurrentPreviewSceneChanged();
|
|
break;
|
|
case OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED:
|
|
eventHandler->HandleSceneListReindexed();
|
|
break;
|
|
|
|
// Transitions
|
|
case OBS_FRONTEND_EVENT_TRANSITION_CHANGED:
|
|
break;
|
|
case OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED:
|
|
break;
|
|
case OBS_FRONTEND_EVENT_TRANSITION_DURATION_CHANGED:
|
|
break;
|
|
|
|
// Outputs
|
|
case OBS_FRONTEND_EVENT_STREAMING_STARTING:
|
|
eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_STARTING);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_STREAMING_STARTED:
|
|
eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_STARTED);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_STREAMING_STOPPING:
|
|
eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_STOPPING);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
|
|
eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_STOPPED);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_RECORDING_STARTING:
|
|
eventHandler->HandleRecordStateChanged(OBS_WEBSOCKET_OUTPUT_STARTING);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_RECORDING_STARTED:
|
|
eventHandler->HandleRecordStateChanged(OBS_WEBSOCKET_OUTPUT_STARTED);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_RECORDING_STOPPING:
|
|
eventHandler->HandleRecordStateChanged(OBS_WEBSOCKET_OUTPUT_STOPPING);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_RECORDING_STOPPED:
|
|
eventHandler->HandleRecordStateChanged(OBS_WEBSOCKET_OUTPUT_STOPPED);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTING:
|
|
eventHandler->HandleReplayBufferStateChanged(OBS_WEBSOCKET_OUTPUT_STARTING);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTED:
|
|
eventHandler->HandleReplayBufferStateChanged(OBS_WEBSOCKET_OUTPUT_STARTED);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPING:
|
|
eventHandler->HandleReplayBufferStateChanged(OBS_WEBSOCKET_OUTPUT_STOPPING);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPED:
|
|
eventHandler->HandleReplayBufferStateChanged(OBS_WEBSOCKET_OUTPUT_STOPPED);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_VIRTUALCAM_STARTED:
|
|
eventHandler->HandleVirtualcamStateChanged(OBS_WEBSOCKET_OUTPUT_STARTED);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_VIRTUALCAM_STOPPED:
|
|
eventHandler->HandleVirtualcamStateChanged(OBS_WEBSOCKET_OUTPUT_STOPPED);
|
|
break;
|
|
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED:
|
|
eventHandler->HandleReplayBufferSaved();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void EventHandler::SourceCreatedMultiHandler(void *param, calldata_t *data)
|
|
{
|
|
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
|
|
|
if (!eventHandler->_obsLoaded.load())
|
|
return;
|
|
|
|
OBSSource source = GetCalldataPointer<obs_source_t>(data, "source");
|
|
if (!source)
|
|
return;
|
|
|
|
// Connect all signals to 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<EventHandler*>(param);
|
|
|
|
// 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);
|
|
|
|
if (!eventHandler->_obsLoaded.load())
|
|
return;
|
|
|
|
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:
|
|
break;
|
|
case OBS_SOURCE_TYPE_SCENE:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void EventHandler::SourceRemovedMultiHandler(void *param, calldata_t *data)
|
|
{
|
|
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
|
|
|
if (!eventHandler->_obsLoaded.load())
|
|
return;
|
|
|
|
OBSSource source = GetCalldataPointer<obs_source_t>(data, "source");
|
|
if (!source)
|
|
return;
|
|
|
|
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:
|
|
eventHandler->HandleSceneRemoved(source);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void EventHandler::SourceRenamedMultiHandler(void *param, calldata_t *data)
|
|
{
|
|
auto eventHandler = reinterpret_cast<EventHandler*>(param);
|
|
|
|
if (!eventHandler->_obsLoaded.load())
|
|
return;
|
|
|
|
OBSSource source = GetCalldataPointer<obs_source_t>(data, "source");
|
|
if (!source)
|
|
return;
|
|
|
|
std::string oldSourceName = GetCalldataString(data, "prev_name");
|
|
std::string sourceName = GetCalldataString(data, "new_name");
|
|
if (oldSourceName.empty() || sourceName.empty())
|
|
return;
|
|
|
|
switch (obs_source_get_type(source)) {
|
|
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:
|
|
eventHandler->HandleSceneNameChanged(source, oldSourceName, sourceName);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|