diff --git a/PROTOCOL.md b/PROTOCOL.md index 1b604979..59b63c01 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -16,6 +16,8 @@ The protocol in general is based on the OBS Remote protocol created by Bill Hami - ["SwitchTransition"](#switchtransition) - ["TransitionDurationChanged"](#transitiondurationchanged) - ["TransitionListChanged"](#transitionlistchanged) + - ["TransitionBegin"](#transitionbegin) + - ["TransitionEnd"](#transitionend) - ["ProfileChanged"](#profilechanged) - ["ProfileListChanged"](#profilelistchanged) - ["StreamStarting"](#streamstarting) @@ -106,6 +108,16 @@ The list of available transitions has been modified (Transitions have been added --- +#### "TransitionBegin" +A non-fixed transition has begun. + +--- + +#### "TransitionEnd" +A non-fixed transition has ended. + +--- + #### "ProfileChanged" Triggered when switching to another profile or when renaming the current profile. diff --git a/WSEvents.cpp b/WSEvents.cpp index 9ae977ca..c68d0fef 100644 --- a/WSEvents.cpp +++ b/WSEvents.cpp @@ -34,6 +34,15 @@ WSEvents::WSEvents(WSServer *srv) connect(statusTimer, SIGNAL(timeout()), this, SLOT(StreamStatus())); statusTimer->start(2000); // equal to frontend's constant BITRATE_UPDATE_SECONDS + transition_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); + }); + _stream_starttime = 0; _rec_starttime = 0; } @@ -50,7 +59,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private if (!owner->_srv) return; - // TODO : implement SourceChanged, SourceOrderChanged and RepopulateSources + // TODO : implement SourceOrderChanged and RepopulateSources if (event == OBS_FRONTEND_EVENT_SCENE_CHANGED) { @@ -136,39 +145,32 @@ void WSEvents::broadcastUpdate(const char *updateType, obs_data_t *additionalFie obs_data_release(update); } +void WSEvents::connectTransitionSignals(obs_source_t* current_transition) +{ + if (!obs_transition_fixed(current_transition)) + { + transition_handler = obs_source_get_signal_handler(current_transition); + signal_handler_connect(transition_handler, "transition_start", OnTransitionBegin, this); + signal_handler_connect(transition_handler, "transition_stop", OnTransitionEnd, this); + } + else + { + transition_handler = nullptr; + } +} + void WSEvents::OnSceneChange() { // Implements an existing update type from bilhamil's OBS Remote - - // Default behavior : get the new scene from the running transition - obs_source_t *transition = obs_frontend_get_current_transition(); - obs_source_t *new_scene = obs_transition_get_source(transition, OBS_TRANSITION_SOURCE_B); - if (!new_scene) - { - obs_source_release(transition); - return; - } - - const char *scene_name = obs_source_get_name(new_scene); - if (!scene_name) - { - // Fallback behaviour : get the new scene straight from the API - obs_source_release(new_scene); - new_scene = obs_frontend_get_current_scene(); - - if (new_scene) { - scene_name = obs_source_get_name(new_scene); - } - } - obs_data_t *data = obs_data_create(); - obs_data_set_string(data, "scene-name", scene_name); + + obs_source_t* current_scene = obs_frontend_get_current_scene(); + obs_data_set_string(data, "scene-name", obs_source_get_name(current_scene)); broadcastUpdate("SwitchScenes", data); obs_data_release(data); - obs_source_release(new_scene); - obs_source_release(transition); + obs_source_release(current_scene); } void WSEvents::OnSceneListChange() @@ -188,16 +190,22 @@ void WSEvents::OnSceneCollectionListChange() void WSEvents::OnTransitionChange() { - obs_source_t *transition = obs_frontend_get_current_transition(); - const char *transition_name = obs_source_get_name(transition); + if (transition_handler) + { + signal_handler_disconnect(transition_handler, "transition_start", OnTransitionBegin, this); + signal_handler_disconnect(transition_handler, "transition_stop", OnTransitionEnd, this); + } + + obs_source_t* current_transition = obs_frontend_get_current_transition(); + connectTransitionSignals(current_transition); obs_data_t *data = obs_data_create(); - obs_data_set_string(data, "transition-name", transition_name); - + obs_data_set_string(data, "transition-name", obs_source_get_name(current_transition)); + broadcastUpdate("SwitchTransition", data); - + obs_data_release(data); - obs_source_release(transition); + obs_source_release(current_transition); } void WSEvents::OnTransitionListChange() @@ -352,4 +360,31 @@ void WSEvents::TransitionDurationChanged(int ms) broadcastUpdate("TransitionDurationChanged", fields); obs_data_release(fields); +} + +void WSEvents::OnTransitionBegin(void* param, calldata_t* data) +{ + UNUSED_PARAMETER(data); + + WSEvents* instance = static_cast(param); + instance->broadcastUpdate("TransitionBegin"); + + blog(LOG_INFO, "transition begin"); +} + +void WSEvents::OnTransitionEnd(void* param, calldata_t* data) +{ + UNUSED_PARAMETER(data); + + WSEvents* instance = static_cast(param); + instance->broadcastUpdate("TransitionEnd"); + + blog(LOG_INFO, "transition end"); +} + +void WSEvents::OnTransitionStopped(void* param, calldata_t* data) +{ + + + blog(LOG_INFO, "transition stopped"); } \ No newline at end of file diff --git a/WSEvents.h b/WSEvents.h index 3b0b65b0..b94713ab 100644 --- a/WSEvents.h +++ b/WSEvents.h @@ -31,6 +31,7 @@ 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); private Q_SLOTS: void StreamStatus(); @@ -38,12 +39,15 @@ class WSEvents : public QObject private: WSServer *_srv; + signal_handler_t *transition_handler; + uint64_t _stream_starttime; uint64_t _rec_starttime; uint64_t _lastBytesSent; uint64_t _lastBytesSentTime; - void broadcastUpdate(const char *updateType, obs_data_t *additionalFields); + void broadcastUpdate(const char *updateType, obs_data_t *additionalFields); + void OnSceneChange(); void OnSceneListChange(); void OnSceneCollectionChange(); @@ -66,6 +70,10 @@ class WSEvents : public QObject void OnRecordingStopped(); void OnExit(); + + static void OnTransitionBegin(void *param, calldata_t *data); + static void OnTransitionEnd(void *param, calldata_t *data); + static void OnTransitionStopped(void *param, calldata_t *data); }; #endif // WSEVENTS_H \ No newline at end of file diff --git a/WSServer.cpp b/WSServer.cpp index ffdeea97..555609c6 100644 --- a/WSServer.cpp +++ b/WSServer.cpp @@ -27,7 +27,7 @@ with this program. If not, see QT_USE_NAMESPACE -WSServer* WSServer::Instance = nullptr; +WSServer* WSServer::Instance = new WSServer(); WSServer::WSServer(QObject *parent) : QObject(parent), @@ -97,6 +97,10 @@ void WSServer::broadcast(QString message) } _clMutex.unlock(); + + // Dirty hack because several quick successive calls to sendTextMessage() + // can deadlock the socket + QThread::msleep(50); } void WSServer::onNewConnection() @@ -126,6 +130,10 @@ void WSServer::textMessageReceived(QString message) { WSRequestHandler handler(pSocket); handler.processIncomingMessage(message); + + // Dirty hack because several quick successive calls to sendTextMessage() + // can deadlock the socket + QThread::msleep(50); } } @@ -140,7 +148,7 @@ void WSServer::socketDisconnected() _clMutex.lock(); _clients.removeAll(pSocket); _clMutex.unlock(); - + pSocket->deleteLater(); QByteArray client_ip = pSocket->peerAddress().toString().toUtf8(); diff --git a/obs-websocket.cpp b/obs-websocket.cpp index 558d0adb..fc3e3cea 100644 --- a/obs-websocket.cpp +++ b/obs-websocket.cpp @@ -42,8 +42,6 @@ bool obs_module_load(void) Config* config = Config::Current(); config->Load(); - WSServer::Instance = new WSServer(); - if (config->ServerEnabled) WSServer::Instance->Start(config->ServerPort);