mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
Merge branch 'better-signals-handling' into 4.x-current
This commit is contained in:
127
src/WSEvents.cpp
127
src/WSEvents.cpp
@ -83,16 +83,6 @@ const char* calldata_get_string(const calldata_t* data, const char* name) {
|
||||
return value;
|
||||
}
|
||||
|
||||
WSEventsPtr WSEvents::_instance = WSEventsPtr(nullptr);
|
||||
|
||||
WSEventsPtr WSEvents::Current() {
|
||||
return _instance;
|
||||
}
|
||||
|
||||
void WSEvents::ResetCurrent(WSServerPtr srv) {
|
||||
_instance = WSEventsPtr(new WSEvents(srv));
|
||||
}
|
||||
|
||||
WSEvents::WSEvents(WSServerPtr srv) :
|
||||
_srv(srv),
|
||||
_streamStarttime(0),
|
||||
@ -114,6 +104,13 @@ WSEvents::WSEvents(WSServerPtr srv) :
|
||||
|
||||
heartbeatTimer.start(STATUS_INTERVAL);
|
||||
|
||||
// Connect to signals of all existing sources
|
||||
obs_enum_sources([](void* param, obs_source_t* source) {
|
||||
auto self = reinterpret_cast<WSEvents*>(param);
|
||||
self->connectSourceSignals(source);
|
||||
return true;
|
||||
}, this);
|
||||
|
||||
signal_handler_t* coreSignalHandler = obs_get_signal_handler();
|
||||
if (coreSignalHandler) {
|
||||
signal_handler_connect(coreSignalHandler, "source_create", OnSourceCreate, this);
|
||||
@ -128,8 +125,17 @@ WSEvents::~WSEvents() {
|
||||
signal_handler_disconnect(coreSignalHandler, "source_create", OnSourceCreate, this);
|
||||
}
|
||||
|
||||
// Disconnect from signals of all existing sources
|
||||
obs_enum_sources([](void* param, obs_source_t* source) {
|
||||
auto self = reinterpret_cast<WSEvents*>(param);
|
||||
self->disconnectSourceSignals(source);
|
||||
return true;
|
||||
}, this);
|
||||
|
||||
obs_frontend_remove_event_callback(WSEvents::FrontendEventHandler, this);
|
||||
os_cpu_usage_info_destroy(cpuUsageInfo);
|
||||
|
||||
blog(LOG_INFO, "wsevents destroyed");
|
||||
}
|
||||
|
||||
void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private_data) {
|
||||
@ -247,6 +253,73 @@ void WSEvents::broadcastUpdate(const char* updateType,
|
||||
}
|
||||
}
|
||||
|
||||
void WSEvents::connectSourceSignals(obs_source_t* source) {
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disconnect everything first to avoid double-binding
|
||||
disconnectSourceSignals(source);
|
||||
|
||||
obs_source_type sourceType = obs_source_get_type(source);
|
||||
signal_handler_t* sh = obs_source_get_signal_handler(source);
|
||||
|
||||
signal_handler_connect(sh, "rename", OnSourceRename, this);
|
||||
|
||||
signal_handler_connect(sh, "mute", OnSourceMuteStateChange, this);
|
||||
signal_handler_connect(sh, "volume", OnSourceVolumeChange, this);
|
||||
signal_handler_connect(sh, "audio_sync", OnSourceAudioSyncOffsetChanged, this);
|
||||
signal_handler_connect(sh, "audio_mixers", OnSourceAudioMixersChanged, this);
|
||||
|
||||
signal_handler_connect(sh, "filter_add", OnSourceFilterAdded, this);
|
||||
signal_handler_connect(sh, "filter_remove", OnSourceFilterRemoved, this);
|
||||
signal_handler_connect(sh, "reorder_filters", OnSourceFilterOrderChanged, this);
|
||||
|
||||
if (sourceType == OBS_SOURCE_TYPE_SCENE) {
|
||||
signal_handler_connect(sh, "reorder", OnSceneReordered, this);
|
||||
signal_handler_connect(sh, "item_add", OnSceneItemAdd, this);
|
||||
signal_handler_connect(sh, "item_remove", OnSceneItemDelete, this);
|
||||
signal_handler_connect(sh,
|
||||
"item_visible", OnSceneItemVisibilityChanged, this);
|
||||
signal_handler_connect(sh, "item_transform", OnSceneItemTransform, this);
|
||||
signal_handler_connect(sh, "item_select", OnSceneItemSelected, this);
|
||||
signal_handler_connect(sh, "item_deselect", OnSceneItemDeselected, this);
|
||||
}
|
||||
if (sourceType == OBS_SOURCE_TYPE_TRANSITION) {
|
||||
signal_handler_connect(sh, "transition_start", OnTransitionBegin, this);
|
||||
}
|
||||
}
|
||||
|
||||
void WSEvents::disconnectSourceSignals(obs_source_t* source) {
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
signal_handler_t* sh = obs_source_get_signal_handler(source);
|
||||
|
||||
signal_handler_disconnect(sh, "rename", OnSourceRename, this);
|
||||
|
||||
signal_handler_disconnect(sh, "mute", OnSourceMuteStateChange, this);
|
||||
signal_handler_disconnect(sh, "volume", OnSourceVolumeChange, this);
|
||||
signal_handler_disconnect(sh, "audio_sync", OnSourceAudioSyncOffsetChanged, this);
|
||||
signal_handler_disconnect(sh, "audio_mixers", OnSourceAudioMixersChanged, this);
|
||||
|
||||
signal_handler_disconnect(sh, "filter_add", OnSourceFilterAdded, this);
|
||||
signal_handler_disconnect(sh, "filter_remove", OnSourceFilterRemoved, this);
|
||||
signal_handler_disconnect(sh, "reorder_filters", OnSourceFilterOrderChanged, this);
|
||||
|
||||
signal_handler_disconnect(sh, "reorder", OnSceneReordered, this);
|
||||
signal_handler_disconnect(sh, "item_add", OnSceneItemAdd, this);
|
||||
signal_handler_disconnect(sh, "item_remove", OnSceneItemDelete, this);
|
||||
signal_handler_disconnect(sh,
|
||||
"item_visible", OnSceneItemVisibilityChanged, this);
|
||||
signal_handler_disconnect(sh, "item_transform", OnSceneItemTransform, this);
|
||||
signal_handler_disconnect(sh, "item_select", OnSceneItemSelected, this);
|
||||
signal_handler_disconnect(sh, "item_deselect", OnSceneItemDeselected, this);
|
||||
|
||||
signal_handler_disconnect(sh, "transition_start", OnTransitionBegin, this);
|
||||
}
|
||||
|
||||
uint64_t WSEvents::GetStreamingTime() {
|
||||
if (obs_frontend_streaming_active())
|
||||
return (os_gettime_ns() - _streamStarttime);
|
||||
@ -801,39 +874,15 @@ void WSEvents::OnSourceCreate(void* param, calldata_t* data) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs_source_type sourceType = obs_source_get_type(source);
|
||||
signal_handler_t* sh = obs_source_get_signal_handler(source);
|
||||
|
||||
signal_handler_connect(sh, "rename", OnSourceRename, self);
|
||||
|
||||
signal_handler_connect(sh, "mute", OnSourceMuteStateChange, self);
|
||||
signal_handler_connect(sh, "volume", OnSourceVolumeChange, self);
|
||||
signal_handler_connect(sh, "audio_sync", OnSourceAudioSyncOffsetChanged, self);
|
||||
signal_handler_connect(sh, "audio_mixers", OnSourceAudioMixersChanged, self);
|
||||
|
||||
signal_handler_connect(sh, "filter_add", OnSourceFilterAdded, self);
|
||||
signal_handler_connect(sh, "filter_remove", OnSourceFilterRemoved, self);
|
||||
signal_handler_connect(sh, "reorder_filters", OnSourceFilterOrderChanged, self);
|
||||
|
||||
if (sourceType == OBS_SOURCE_TYPE_SCENE) {
|
||||
signal_handler_connect(sh, "reorder", OnSceneReordered, self);
|
||||
signal_handler_connect(sh, "item_add", OnSceneItemAdd, self);
|
||||
signal_handler_connect(sh, "item_remove", OnSceneItemDelete, self);
|
||||
signal_handler_connect(sh,
|
||||
"item_visible", OnSceneItemVisibilityChanged, self);
|
||||
signal_handler_connect(sh, "item_transform", OnSceneItemTransform, self);
|
||||
signal_handler_connect(sh, "item_select", OnSceneItemSelected, self);
|
||||
signal_handler_connect(sh, "item_deselect", OnSceneItemDeselected, self);
|
||||
}
|
||||
if (sourceType == OBS_SOURCE_TYPE_TRANSITION) {
|
||||
signal_handler_connect(sh, "transition_start", OnTransitionBegin, self);
|
||||
}
|
||||
self->connectSourceSignals(source);
|
||||
|
||||
OBSDataAutoRelease sourceSettings = obs_source_get_settings(source);
|
||||
|
||||
OBSDataAutoRelease fields = obs_data_create();
|
||||
obs_data_set_string(fields, "sourceName", obs_source_get_name(source));
|
||||
obs_data_set_string(fields, "sourceType", sourceTypeToString(sourceType));
|
||||
obs_data_set_string(fields, "sourceType",
|
||||
sourceTypeToString(obs_source_get_type(source))
|
||||
);
|
||||
obs_data_set_string(fields, "sourceKind", obs_source_get_id(source));
|
||||
obs_data_set_obj(fields, "sourceSettings", sourceSettings);
|
||||
self->broadcastUpdate("SourceCreated", fields);
|
||||
@ -859,6 +908,8 @@ void WSEvents::OnSourceDestroy(void* param, calldata_t* data) {
|
||||
return;
|
||||
}
|
||||
|
||||
self->disconnectSourceSignals(source);
|
||||
|
||||
obs_source_type sourceType = obs_source_get_type(source);
|
||||
|
||||
OBSDataAutoRelease fields = obs_data_create();
|
||||
|
@ -29,21 +29,16 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
#include "WSServer.h"
|
||||
|
||||
class WSEvents;
|
||||
typedef QSharedPointer<WSEvents> WSEventsPtr;
|
||||
|
||||
class WSEvents : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static WSEventsPtr Current();
|
||||
static void ResetCurrent(WSServerPtr srv);
|
||||
|
||||
explicit WSEvents(WSServerPtr srv);
|
||||
~WSEvents();
|
||||
static void FrontendEventHandler(
|
||||
enum obs_frontend_event event, void* privateData);
|
||||
|
||||
void connectSourceSignals(obs_source_t* source);
|
||||
void disconnectSourceSignals(obs_source_t* source);
|
||||
|
||||
uint64_t GetStreamingTime();
|
||||
const char* GetStreamingTimecode();
|
||||
@ -59,8 +54,6 @@ private slots:
|
||||
void TransitionDurationChanged(int ms);
|
||||
|
||||
private:
|
||||
static WSEventsPtr _instance;
|
||||
|
||||
WSServerPtr _srv;
|
||||
QTimer streamStatusTimer;
|
||||
QTimer heartbeatTimer;
|
||||
@ -108,6 +101,9 @@ private:
|
||||
|
||||
void OnExit();
|
||||
|
||||
static void FrontendEventHandler(
|
||||
enum obs_frontend_event event, void* privateData);
|
||||
|
||||
static void OnTransitionBegin(void* param, calldata_t* data);
|
||||
|
||||
static void OnSourceCreate(void* param, calldata_t* data);
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "obs-websocket.h"
|
||||
#include "Config.h"
|
||||
#include "Utils.h"
|
||||
#include "WSEvents.h"
|
||||
@ -114,7 +115,7 @@ HandlerResponse WSRequestHandler::HandleSetHeartbeat(WSRequestHandler* req) {
|
||||
return req->SendErrorResponse("Heartbeat <enable> parameter missing");
|
||||
}
|
||||
|
||||
auto events = WSEvents::Current();
|
||||
auto events = GetEventsSystem();
|
||||
events->HeartbeatIsActive = obs_data_get_bool(req->data, "enable");
|
||||
|
||||
OBSDataAutoRelease response = obs_data_create();
|
||||
@ -164,18 +165,18 @@ HandlerResponse WSRequestHandler::HandleGetFilenameFormatting(WSRequestHandler*
|
||||
|
||||
/**
|
||||
* Get OBS stats (almost the same info as provided in OBS' stats window)
|
||||
*
|
||||
*
|
||||
* @return {OBSStats} `stats` OBS stats
|
||||
*
|
||||
*
|
||||
* @api requests
|
||||
* @name GetStats
|
||||
* @category general
|
||||
* @since 4.6.0
|
||||
* @since 4.6.0
|
||||
*/
|
||||
HandlerResponse WSRequestHandler::HandleGetStats(WSRequestHandler* req) {
|
||||
OBSDataAutoRelease stats = WSEvents::Current()->GetStats();
|
||||
OBSDataAutoRelease stats = GetEventsSystem()->GetStats();
|
||||
|
||||
OBSDataAutoRelease response = obs_data_create();
|
||||
obs_data_set_obj(response, "stats", stats);
|
||||
return req->SendOKResponse(response);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "obs-websocket.h"
|
||||
#include "Utils.h"
|
||||
#include "WSEvents.h"
|
||||
|
||||
@ -20,7 +21,7 @@
|
||||
* @since 0.3
|
||||
*/
|
||||
HandlerResponse WSRequestHandler::HandleGetStreamingStatus(WSRequestHandler* req) {
|
||||
auto events = WSEvents::Current();
|
||||
auto events = GetEventsSystem();
|
||||
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
obs_data_set_bool(data, "streaming", obs_frontend_streaming_active());
|
||||
|
@ -38,7 +38,7 @@ void ___output_dummy_addref(obs_output_t*) {}
|
||||
OBS_DECLARE_MODULE()
|
||||
OBS_MODULE_USE_DEFAULT_LOCALE("obs-websocket", "en-US")
|
||||
|
||||
SettingsDialog* settings_dialog;
|
||||
WSEventsPtr _eventsSystem;
|
||||
|
||||
bool obs_module_load(void) {
|
||||
blog(LOG_INFO, "you can haz websockets (version %s)", OBS_WEBSOCKET_VERSION);
|
||||
@ -50,26 +50,27 @@ bool obs_module_load(void) {
|
||||
config->MigrateFromGlobalSettings(); // TODO remove this on the next minor jump
|
||||
config->Load();
|
||||
|
||||
WSEvents::ResetCurrent(WSServer::Current());
|
||||
_eventsSystem = WSEventsPtr(new WSEvents(WSServer::Current()));
|
||||
|
||||
if (config->ServerEnabled) {
|
||||
WSServer::Current()->start(config->ServerPort);
|
||||
}
|
||||
|
||||
// UI setup
|
||||
QAction* menu_action = (QAction*)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("OBSWebsocket.Menu.SettingsItem")
|
||||
);
|
||||
|
||||
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||
QMainWindow* main_window = (QMainWindow*)obs_frontend_get_main_window();
|
||||
settings_dialog = new SettingsDialog(main_window);
|
||||
QMainWindow* mainWindow = (QMainWindow*)obs_frontend_get_main_window();
|
||||
SettingsDialog* settingsDialog = new SettingsDialog(mainWindow);
|
||||
obs_frontend_pop_ui_translation();
|
||||
|
||||
auto menu_cb = [] {
|
||||
settings_dialog->ToggleShowHide();
|
||||
};
|
||||
menu_action->connect(menu_action, &QAction::triggered, menu_cb);
|
||||
const char* menuActionText =
|
||||
obs_module_text("OBSWebsocket.Menu.SettingsItem");
|
||||
QAction* menuAction =
|
||||
(QAction*)obs_frontend_add_tools_menu_qaction(menuActionText);
|
||||
QObject::connect(menuAction, &QAction::triggered, [settingsDialog] {
|
||||
// The settings dialog belongs to the main window. Should be ok
|
||||
// to pass the pointer to this QAction belonging to the main window
|
||||
settingsDialog->ToggleShowHide();
|
||||
});
|
||||
|
||||
// Loading finished
|
||||
blog(LOG_INFO, "module loaded!");
|
||||
@ -82,3 +83,6 @@ void obs_module_unload() {
|
||||
blog(LOG_INFO, "goodbye!");
|
||||
}
|
||||
|
||||
WSEventsPtr GetEventsSystem() {
|
||||
return _eventsSystem;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
#pragma once
|
||||
|
||||
#include <obs.hpp>
|
||||
#include <memory>
|
||||
|
||||
void ___source_dummy_addref(obs_source_t*);
|
||||
void ___sceneitem_dummy_addref(obs_sceneitem_t*);
|
||||
@ -37,6 +38,11 @@ using OBSDataArrayAutoRelease =
|
||||
using OBSOutputAutoRelease =
|
||||
OBSRef<obs_output_t*, ___output_dummy_addref, obs_output_release>;
|
||||
|
||||
class WSEvents;
|
||||
typedef std::shared_ptr<WSEvents> WSEventsPtr;
|
||||
|
||||
std::shared_ptr<WSEvents> GetEventsSystem();
|
||||
|
||||
#define OBS_WEBSOCKET_VERSION "4.6.0"
|
||||
|
||||
#define blog(level, msg, ...) blog(level, "[obs-websocket] " msg, ##__VA_ARGS__)
|
||||
|
Reference in New Issue
Block a user