diff --git a/PROTOCOL.md b/PROTOCOL.md index 77165c75..70cf9635 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -68,7 +68,11 @@ The protocol in general is based on the OBS Remote protocol created by Bill Hami ### Description Events are sent exclusively by the server and broadcast to each connected client. An event message will contain at least one field : -- **update-type** (string) : the type of event +- **update-type** (string) : the type of event +- **stream-timecode** (string, optional) : time elapsed between now and stream start (only present if OBS Studio is streaming) +- **rec-timecode** (string, optional) : time elapsed between now and recording start (only present if OBS Studio is recording) + +Timecodes are in the following format : HH:MM:SS.mmm Additional fields will be present in the event message depending on the event type. diff --git a/WSEvents.cpp b/WSEvents.cpp index 7c5b56c2..6c87f5c4 100644 --- a/WSEvents.cpp +++ b/WSEvents.cpp @@ -37,6 +37,23 @@ bool transition_is_cut(obs_source_t *transition) return false; } +const char* ns_to_timestamp(uint64_t ns) +{ + uint64_t ms = ns / (1000 * 1000); + uint64_t secs = ms / 1000; + uint64_t minutes = secs / 60; + + uint64_t hours_part = minutes / 60; + uint64_t minutes_part = minutes % 60; + uint64_t secs_part = secs % 60; + uint64_t ms_part = ms % 1000; + + char* ts = (char*)bmalloc(64); + sprintf(ts, "%02d:%02d:%02d.%03d", hours_part, minutes_part, secs_part, ms_part); + + return ts; +} + WSEvents::WSEvents(WSServer *srv) { _srv = srv; @@ -63,6 +80,9 @@ WSEvents::WSEvents(WSServer *srv) obs_source_release(scene); }); + _streaming_active = false; + _recording_active = false; + _stream_starttime = 0; _rec_starttime = 0; } @@ -119,6 +139,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private } else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTED) { + owner->_streaming_active = true; owner->OnStreamStarted(); } else if (event == OBS_FRONTEND_EVENT_STREAMING_STOPPING) @@ -127,6 +148,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private } else if (event == OBS_FRONTEND_EVENT_STREAMING_STOPPED) { + owner->_streaming_active = false; owner->OnStreamStopped(); } else if (event == OBS_FRONTEND_EVENT_RECORDING_STARTING) @@ -135,6 +157,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private } else if (event == OBS_FRONTEND_EVENT_RECORDING_STARTED) { + owner->_recording_active = true; owner->OnRecordingStarted(); } else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPING) @@ -143,6 +166,7 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private } else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPED) { + owner->_recording_active = false; owner->OnRecordingStopped(); } else if (event == OBS_FRONTEND_EVENT_EXIT) @@ -154,8 +178,23 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void *private void WSEvents::broadcastUpdate(const char *updateType, obs_data_t *additionalFields = NULL) { obs_data_t *update = obs_data_create(); - obs_data_set_string(update, "update-type", updateType); + + const char* ts = nullptr; + if (_streaming_active) + { + ts = ns_to_timestamp(os_gettime_ns() - _stream_starttime); + obs_data_set_string(update, "stream-timecode", ts); + bfree((void*)ts); + } + + if (_recording_active) + { + ts = ns_to_timestamp(os_gettime_ns() - _rec_starttime); + obs_data_set_string(update, "rec-timecode", ts); + bfree((void*)ts); + } + if (additionalFields != NULL) { obs_data_apply(update, additionalFields); } @@ -367,10 +406,7 @@ void WSEvents::StreamStatus() int total_frames = obs_output_get_total_frames(stream_output); int dropped_frames = obs_output_get_frames_dropped(stream_output); - float strain = 0.0; - if (total_frames > 0) { - strain = (dropped_frames / total_frames) * 100.0; - } + float strain = obs_output_get_congestion(stream_output); obs_data_t *data = obs_data_create(); obs_data_set_bool(data, "streaming", streaming_active); diff --git a/WSEvents.h b/WSEvents.h index cef81a6a..aa8e6641 100644 --- a/WSEvents.h +++ b/WSEvents.h @@ -43,8 +43,12 @@ class WSEvents : public QObject signal_handler_t *transition_handler; signal_handler_t *scene_handler; + bool _streaming_active; + bool _recording_active; + uint64_t _stream_starttime; uint64_t _rec_starttime; + uint64_t _lastBytesSent; uint64_t _lastBytesSentTime;