diff --git a/WSEvents.cpp b/WSEvents.cpp index 20942dc0..54f779ed 100644 --- a/WSEvents.cpp +++ b/WSEvents.cpp @@ -69,6 +69,9 @@ WSEvents::WSEvents(WSServer* srv) { QTimer* statusTimer = new QTimer(); connect(statusTimer, SIGNAL(timeout()), this, SLOT(StreamStatus())); + pulse = false; + connect(statusTimer, SIGNAL(timeout()), + this, SLOT(Heartbeat())); statusTimer->start(2000); // equal to frontend's constant BITRATE_UPDATE_SECONDS QListWidget* sceneList = Utils::GetSceneListControl(); @@ -83,6 +86,8 @@ WSEvents::WSEvents(WSServer* srv) { QTimer::singleShot(1000, this, SLOT(deferredInitOperations())); + Heartbeat_active = false; + _streaming_active = false; _recording_active = false; @@ -664,6 +669,67 @@ void WSEvents::StreamStatus() { obs_output_release(stream_output); } +/************************************************************************************************************ +* Heatbeat is emitted every 2 seconds, when enabled with request: SetHeartbeat * +* * +* @return {boolean} `pulse` Toggles between every JSON meassage as an "I am alive" indicator. * +* @return {string (optional)} `current-profile` Current active profile. * +* @return {string (optional)} `current-scene` Current active scene. * +* @return {boolean (optional)} `streaming` Current streaming state. * +* @return {int (optional)} `total-stream-time` Total time (in seconds) since the stream started. * +* @return {int (optional)} `total-stream-bytes` Total bytes sent since the stream started. * +* @return {int (optional)} `total-stream-frames` Total frames streamed since the stream started. * +* @return {boolean (optional)} `recording` Current recording state. * +* @return {int (optional)} `total-record-time` Total time (in seconds) since recording started. * +* @return {int (optional)} `total-record-bytes` Total bytes recorded since the recording started. * +* @return {int (optional)} `total-record-frames` Total frames recorded since the recording started. * +* * +* @api events * +* @name Heartbeat * +* @category general * +************************************************************************ September 2017 *** by RainbowEK ***/ +void WSEvents::Heartbeat() { + + if (!Heartbeat_active) return; + + bool streaming_active = obs_frontend_streaming_active(); + bool recording_active = obs_frontend_recording_active(); + obs_data_t* data = obs_data_create(); + obs_output_t* record_output = obs_frontend_get_recording_output(); + obs_output_t* stream_output = obs_frontend_get_streaming_output(); + + pulse = !pulse; + obs_data_set_bool(data, "pulse", pulse); + + obs_data_set_string(data, "current-profile", obs_frontend_get_current_profile()); + + obs_source_t* current_scene = obs_frontend_get_current_scene(); + const char* name = obs_source_get_name(current_scene); + obs_source_release(current_scene); + obs_data_set_string(data, "current-scene", name); + + obs_data_set_bool(data, "streaming", streaming_active); + if (streaming_active) { + uint64_t totalStreamTime = (os_gettime_ns() - _stream_starttime) / 1000000000; + obs_data_set_int(data, "total-stream-time", totalStreamTime); + obs_data_set_int(data, "total-stream-bytes", (uint64_t)obs_output_get_total_bytes(stream_output)); + obs_data_set_int(data, "total-stream-frames", obs_output_get_total_frames(stream_output)); + } + + obs_data_set_bool(data, "recording", recording_active); + if (recording_active) { + uint64_t totalRecordTime = (os_gettime_ns() - _rec_starttime) / 1000000000; + obs_data_set_int(data, "total-record-time", totalRecordTime); + obs_data_set_int(data, "total-record-bytes", (uint64_t)obs_output_get_total_bytes(record_output)); + obs_data_set_int(data, "total-record-frames", obs_output_get_total_frames(record_output)); + } + + broadcastUpdate("Heartbeat", data); + obs_data_release(data); + obs_output_release(record_output); + obs_output_release(stream_output); +} + /** * The active transition duration has been changed. * diff --git a/WSEvents.h b/WSEvents.h index f93e0a74..68ec90ca 100644 --- a/WSEvents.h +++ b/WSEvents.h @@ -22,7 +22,6 @@ with this program. If not, see #include #include - #include "WSServer.h" class WSEvents : public QObject { @@ -41,9 +40,12 @@ class WSEvents : public QObject { uint64_t GetRecordingTime(); const char* GetRecordingTimecode(); + bool Heartbeat_active; + private slots: void deferredInitOperations(); void StreamStatus(); + void Heartbeat(); void TransitionDurationChanged(int ms); void SelectedSceneChanged( QListWidgetItem* current, QListWidgetItem* prev); @@ -54,6 +56,8 @@ class WSEvents : public QObject { signal_handler_t* transition_handler; signal_handler_t* scene_handler; + bool pulse; + bool _streaming_active; bool _recording_active; diff --git a/WSRequestHandler.cpp b/WSRequestHandler.cpp index 62f9b193..a14e543f 100644 --- a/WSRequestHandler.cpp +++ b/WSRequestHandler.cpp @@ -45,6 +45,8 @@ WSRequestHandler::WSRequestHandler(QWebSocket* client) : messageMap["GetAuthRequired"] = WSRequestHandler::HandleGetAuthRequired; messageMap["Authenticate"] = WSRequestHandler::HandleAuthenticate; + messageMap["SetHeartbeat"] = WSRequestHandler::HandleSetHeartbeat; + messageMap["SetCurrentScene"] = WSRequestHandler::HandleSetCurrentScene; messageMap["GetCurrentScene"] = WSRequestHandler::HandleGetCurrentScene; messageMap["GetSceneList"] = WSRequestHandler::HandleGetSceneList; @@ -298,6 +300,35 @@ void WSRequestHandler::HandleAuthenticate(WSRequestHandler* req) { } } +/************************************************************************************************************ +* Heatbeat update message is emitted every 2 seconds, when enabled with this request. * +* When the Heartbeat is enabled it always sends a `pulse` to indicate that the host obs is alive. * +* Read comment from 'void WSEvents::Heartbeat()' for the total picture. * +* * +* @param {boolean} `enable` Starts/Stops emitting heartbeat messages * +* * +* @api requests * +* @name HandleSetHeartbeat * +* @category general * +************************************************************************ September 2017 *** by RainbowEK ***/ +void WSRequestHandler::HandleSetHeartbeat(WSRequestHandler* req) { + if (!req->hasField("enable")) { + req->SendErrorResponse("Heartbeat parameter missing"); + return; + } + + obs_data_t* response = obs_data_create(); + + bool keyValue = obs_data_get_bool(req->data, "enable"); + if (keyValue) WSEvents::Instance->Heartbeat_active = true; + else WSEvents::Instance->Heartbeat_active = false; + + obs_data_set_bool(response, "enable", keyValue); + req->SendOKResponse(response); + + obs_data_release(response); +} + /** * Switch to the specified scene. * diff --git a/WSRequestHandler.h b/WSRequestHandler.h index c6598b74..c22ccba3 100644 --- a/WSRequestHandler.h +++ b/WSRequestHandler.h @@ -53,6 +53,8 @@ class WSRequestHandler : public QObject { static void HandleGetAuthRequired(WSRequestHandler* req); static void HandleAuthenticate(WSRequestHandler* req); + static void HandleSetHeartbeat(WSRequestHandler* req); + static void HandleSetCurrentScene(WSRequestHandler* req); static void HandleGetCurrentScene(WSRequestHandler* req); static void HandleGetSceneList(WSRequestHandler* req);