mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
Transition events + scene change compatibility with OBS 18.0.0
This commit is contained in:
12
PROTOCOL.md
12
PROTOCOL.md
@ -16,6 +16,8 @@ The protocol in general is based on the OBS Remote protocol created by Bill Hami
|
|||||||
- ["SwitchTransition"](#switchtransition)
|
- ["SwitchTransition"](#switchtransition)
|
||||||
- ["TransitionDurationChanged"](#transitiondurationchanged)
|
- ["TransitionDurationChanged"](#transitiondurationchanged)
|
||||||
- ["TransitionListChanged"](#transitionlistchanged)
|
- ["TransitionListChanged"](#transitionlistchanged)
|
||||||
|
- ["TransitionBegin"](#transitionbegin)
|
||||||
|
- ["TransitionEnd"](#transitionend)
|
||||||
- ["ProfileChanged"](#profilechanged)
|
- ["ProfileChanged"](#profilechanged)
|
||||||
- ["ProfileListChanged"](#profilelistchanged)
|
- ["ProfileListChanged"](#profilelistchanged)
|
||||||
- ["StreamStarting"](#streamstarting)
|
- ["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"
|
#### "ProfileChanged"
|
||||||
Triggered when switching to another profile or when renaming the current profile.
|
Triggered when switching to another profile or when renaming the current profile.
|
||||||
|
|
||||||
|
99
WSEvents.cpp
99
WSEvents.cpp
@ -34,6 +34,15 @@ WSEvents::WSEvents(WSServer *srv)
|
|||||||
connect(statusTimer, SIGNAL(timeout()), this, SLOT(StreamStatus()));
|
connect(statusTimer, SIGNAL(timeout()), this, SLOT(StreamStatus()));
|
||||||
statusTimer->start(2000); // equal to frontend's constant BITRATE_UPDATE_SECONDS
|
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;
|
_stream_starttime = 0;
|
||||||
_rec_starttime = 0;
|
_rec_starttime = 0;
|
||||||
}
|
}
|
||||||
@ -50,7 +59,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private
|
|||||||
if (!owner->_srv)
|
if (!owner->_srv)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO : implement SourceChanged, SourceOrderChanged and RepopulateSources
|
// TODO : implement SourceOrderChanged and RepopulateSources
|
||||||
|
|
||||||
if (event == OBS_FRONTEND_EVENT_SCENE_CHANGED)
|
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);
|
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()
|
void WSEvents::OnSceneChange()
|
||||||
{
|
{
|
||||||
// Implements an existing update type from bilhamil's OBS Remote
|
// 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_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);
|
broadcastUpdate("SwitchScenes", data);
|
||||||
|
|
||||||
obs_data_release(data);
|
obs_data_release(data);
|
||||||
obs_source_release(new_scene);
|
obs_source_release(current_scene);
|
||||||
obs_source_release(transition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSEvents::OnSceneListChange()
|
void WSEvents::OnSceneListChange()
|
||||||
@ -188,16 +190,22 @@ void WSEvents::OnSceneCollectionListChange()
|
|||||||
|
|
||||||
void WSEvents::OnTransitionChange()
|
void WSEvents::OnTransitionChange()
|
||||||
{
|
{
|
||||||
obs_source_t *transition = obs_frontend_get_current_transition();
|
if (transition_handler)
|
||||||
const char *transition_name = obs_source_get_name(transition);
|
{
|
||||||
|
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_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);
|
broadcastUpdate("SwitchTransition", data);
|
||||||
|
|
||||||
obs_data_release(data);
|
obs_data_release(data);
|
||||||
obs_source_release(transition);
|
obs_source_release(current_transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSEvents::OnTransitionListChange()
|
void WSEvents::OnTransitionListChange()
|
||||||
@ -352,4 +360,31 @@ void WSEvents::TransitionDurationChanged(int ms)
|
|||||||
broadcastUpdate("TransitionDurationChanged", fields);
|
broadcastUpdate("TransitionDurationChanged", fields);
|
||||||
|
|
||||||
obs_data_release(fields);
|
obs_data_release(fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WSEvents::OnTransitionBegin(void* param, calldata_t* data)
|
||||||
|
{
|
||||||
|
UNUSED_PARAMETER(data);
|
||||||
|
|
||||||
|
WSEvents* instance = static_cast<WSEvents*>(param);
|
||||||
|
instance->broadcastUpdate("TransitionBegin");
|
||||||
|
|
||||||
|
blog(LOG_INFO, "transition begin");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WSEvents::OnTransitionEnd(void* param, calldata_t* data)
|
||||||
|
{
|
||||||
|
UNUSED_PARAMETER(data);
|
||||||
|
|
||||||
|
WSEvents* instance = static_cast<WSEvents*>(param);
|
||||||
|
instance->broadcastUpdate("TransitionEnd");
|
||||||
|
|
||||||
|
blog(LOG_INFO, "transition end");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WSEvents::OnTransitionStopped(void* param, calldata_t* data)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
blog(LOG_INFO, "transition stopped");
|
||||||
}
|
}
|
10
WSEvents.h
10
WSEvents.h
@ -31,6 +31,7 @@ class WSEvents : public QObject
|
|||||||
explicit WSEvents(WSServer *srv);
|
explicit WSEvents(WSServer *srv);
|
||||||
~WSEvents();
|
~WSEvents();
|
||||||
static void FrontendEventHandler(enum obs_frontend_event event, void *private_data);
|
static void FrontendEventHandler(enum obs_frontend_event event, void *private_data);
|
||||||
|
void connectTransitionSignals(obs_source_t* current_transition);
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void StreamStatus();
|
void StreamStatus();
|
||||||
@ -38,12 +39,15 @@ class WSEvents : public QObject
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
WSServer *_srv;
|
WSServer *_srv;
|
||||||
|
signal_handler_t *transition_handler;
|
||||||
|
|
||||||
uint64_t _stream_starttime;
|
uint64_t _stream_starttime;
|
||||||
uint64_t _rec_starttime;
|
uint64_t _rec_starttime;
|
||||||
uint64_t _lastBytesSent;
|
uint64_t _lastBytesSent;
|
||||||
uint64_t _lastBytesSentTime;
|
uint64_t _lastBytesSentTime;
|
||||||
void broadcastUpdate(const char *updateType, obs_data_t *additionalFields);
|
|
||||||
|
|
||||||
|
void broadcastUpdate(const char *updateType, obs_data_t *additionalFields);
|
||||||
|
|
||||||
void OnSceneChange();
|
void OnSceneChange();
|
||||||
void OnSceneListChange();
|
void OnSceneListChange();
|
||||||
void OnSceneCollectionChange();
|
void OnSceneCollectionChange();
|
||||||
@ -66,6 +70,10 @@ class WSEvents : public QObject
|
|||||||
void OnRecordingStopped();
|
void OnRecordingStopped();
|
||||||
|
|
||||||
void OnExit();
|
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
|
#endif // WSEVENTS_H
|
12
WSServer.cpp
12
WSServer.cpp
@ -27,7 +27,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
QT_USE_NAMESPACE
|
QT_USE_NAMESPACE
|
||||||
|
|
||||||
WSServer* WSServer::Instance = nullptr;
|
WSServer* WSServer::Instance = new WSServer();
|
||||||
|
|
||||||
WSServer::WSServer(QObject *parent) :
|
WSServer::WSServer(QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
@ -97,6 +97,10 @@ void WSServer::broadcast(QString message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_clMutex.unlock();
|
_clMutex.unlock();
|
||||||
|
|
||||||
|
// Dirty hack because several quick successive calls to sendTextMessage()
|
||||||
|
// can deadlock the socket
|
||||||
|
QThread::msleep(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSServer::onNewConnection()
|
void WSServer::onNewConnection()
|
||||||
@ -126,6 +130,10 @@ void WSServer::textMessageReceived(QString message)
|
|||||||
{
|
{
|
||||||
WSRequestHandler handler(pSocket);
|
WSRequestHandler handler(pSocket);
|
||||||
handler.processIncomingMessage(message);
|
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();
|
_clMutex.lock();
|
||||||
_clients.removeAll(pSocket);
|
_clients.removeAll(pSocket);
|
||||||
_clMutex.unlock();
|
_clMutex.unlock();
|
||||||
|
|
||||||
pSocket->deleteLater();
|
pSocket->deleteLater();
|
||||||
|
|
||||||
QByteArray client_ip = pSocket->peerAddress().toString().toUtf8();
|
QByteArray client_ip = pSocket->peerAddress().toString().toUtf8();
|
||||||
|
@ -42,8 +42,6 @@ bool obs_module_load(void)
|
|||||||
Config* config = Config::Current();
|
Config* config = Config::Current();
|
||||||
config->Load();
|
config->Load();
|
||||||
|
|
||||||
WSServer::Instance = new WSServer();
|
|
||||||
|
|
||||||
if (config->ServerEnabled)
|
if (config->ServerEnabled)
|
||||||
WSServer::Instance->Start(config->ServerPort);
|
WSServer::Instance->Start(config->ServerPort);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user