diff --git a/CMakeLists.txt b/CMakeLists.txt index 1608c156..56f3605d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ set(obs-websocket_SOURCES src/WSRequestHandler_SceneItems.cpp src/WSRequestHandler_Sources.cpp src/WSRequestHandler_Streaming.cpp + src/WSRequestHandler_VirtualCam.cpp src/WSRequestHandler_StudioMode.cpp src/WSRequestHandler_Transitions.cpp src/WSRequestHandler_Outputs.cpp diff --git a/src/WSEvents.cpp b/src/WSEvents.cpp index da1bf052..e3ac47bd 100644 --- a/src/WSEvents.cpp +++ b/src/WSEvents.cpp @@ -202,6 +202,14 @@ void WSEvents::FrontendEventHandler(enum obs_frontend_event event, void* private owner->OnRecordingResumed(); break; + case OBS_FRONTEND_EVENT_VIRTUALCAM_STARTED: + owner->OnVirtualCamStarted(); + break; + + case OBS_FRONTEND_EVENT_VIRTUALCAM_STOPPED: + owner->OnVirtualCamStopped(); + break; + case OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTING: owner->OnReplayStarting(); break; @@ -422,6 +430,11 @@ uint64_t WSEvents::getRecordingTime() { return getOutputRunningTime(recordingOutput); } +uint64_t WSEvents::getVirtualCamTime() { + OBSOutputAutoRelease virtualCamOutput = obs_frontend_get_virtualcam_output(); + return getOutputRunningTime(virtualCamOutput); +} + QString WSEvents::getStreamingTimecode() { return Utils::nsToTimestamp(getStreamingTime()); } @@ -430,6 +443,10 @@ QString WSEvents::getRecordingTimecode() { return Utils::nsToTimestamp(getRecordingTime()); } +QString WSEvents::getVirtualCamTimecode() { + return Utils::nsToTimestamp(getVirtualCamTime()); +} + OBSDataAutoRelease getMediaSourceData(calldata_t* data) { OBSDataAutoRelease fields = obs_data_create(); OBSSource source = calldata_get_pointer(data, "source"); @@ -764,6 +781,30 @@ void WSEvents::OnRecordingResumed() { broadcastUpdate("RecordingResumed"); } +/** + * Virtual cam started successfully. + * + * @api events + * @name VirtualCamStarted + * @category virtual cam + * @since unreleased + */ +void WSEvents::OnVirtualCamStarted() { + broadcastUpdate("VirtualCamStarted"); +} + +/** + * Virtual cam stopped successfully. + * + * @api events + * @name VirtualCamStopped + * @category virtual cam + * @since unreleased + */ +void WSEvents::OnVirtualCamStopped() { + broadcastUpdate("VirtualCamStopped"); +} + /** * A request to start the replay buffer has been issued. * diff --git a/src/WSEvents.h b/src/WSEvents.h index dc814e83..ed480e88 100644 --- a/src/WSEvents.h +++ b/src/WSEvents.h @@ -48,9 +48,11 @@ public: uint64_t getStreamingTime(); uint64_t getRecordingTime(); + uint64_t getVirtualCamTime(); QString getStreamingTimecode(); QString getRecordingTimecode(); + QString getVirtualCamTimecode(); obs_data_t* GetStats(); @@ -101,6 +103,9 @@ private: void OnRecordingStopped(); void OnRecordingPaused(); void OnRecordingResumed(); + + void OnVirtualCamStarted(); + void OnVirtualCamStopped(); void OnReplayStarting(); void OnReplayStarted(); diff --git a/src/WSRequestHandler.cpp b/src/WSRequestHandler.cpp index 78706ea1..f72ad6a0 100644 --- a/src/WSRequestHandler.cpp +++ b/src/WSRequestHandler.cpp @@ -163,6 +163,12 @@ const QHash WSRequestHandler::messageMap{ { "GetStreamSettings", &WSRequestHandler::GetStreamSettings }, { "SaveStreamSettings", &WSRequestHandler::SaveStreamSettings }, { "SendCaptions", &WSRequestHandler::SendCaptions }, + + // Category: VirtualCam + { "GetVirtualCamStatus", &WSRequestHandler::GetVirtualCamStatus }, + { "StartStopVirtualCam", &WSRequestHandler::StartStopVirtualCam }, + { "StartVirtualCam", &WSRequestHandler::StartVirtualCam }, + { "StopVirtualCam", &WSRequestHandler::StopVirtualCam }, // Category: Studio Mode { "GetStudioModeStatus", &WSRequestHandler::GetStudioModeStatus }, diff --git a/src/WSRequestHandler.h b/src/WSRequestHandler.h index bd57a731..157db426 100644 --- a/src/WSRequestHandler.h +++ b/src/WSRequestHandler.h @@ -180,6 +180,12 @@ class WSRequestHandler { RpcResponse GetStreamSettings(const RpcRequest&); RpcResponse SaveStreamSettings(const RpcRequest&); RpcResponse SendCaptions(const RpcRequest&); + + // Category: Virtual Cam + RpcResponse GetVirtualCamStatus(const RpcRequest&); + RpcResponse StartStopVirtualCam(const RpcRequest&); + RpcResponse StartVirtualCam(const RpcRequest&); + RpcResponse StopVirtualCam(const RpcRequest&); // Category: Studio Mode RpcResponse GetStudioModeStatus(const RpcRequest&); diff --git a/src/WSRequestHandler_Streaming.cpp b/src/WSRequestHandler_Streaming.cpp index 56e9a001..fa3b0b3c 100644 --- a/src/WSRequestHandler_Streaming.cpp +++ b/src/WSRequestHandler_Streaming.cpp @@ -12,9 +12,11 @@ * @return {boolean} `streaming` Current streaming status. * @return {boolean} `recording` Current recording status. * @return {boolean} `recording-paused` If recording is paused. + * @return {boolean} `virtualcam` Current virtual cam status. * @return {boolean} `preview-only` Always false. Retrocompatibility with OBSRemote. * @return {String (optional)} `stream-timecode` Time elapsed since streaming started (only present if currently streaming). * @return {String (optional)} `rec-timecode` Time elapsed since recording started (only present if currently recording). + * @return {String (optional)} `virtualcam-timecode` Time elapsed since virtual cam started (only present if virtual cam currently active). * * @api requests * @name GetStreamingStatus @@ -28,6 +30,7 @@ RpcResponse WSRequestHandler::GetStreamingStatus(const RpcRequest& request) { obs_data_set_bool(data, "streaming", obs_frontend_streaming_active()); obs_data_set_bool(data, "recording", obs_frontend_recording_active()); obs_data_set_bool(data, "recording-paused", obs_frontend_recording_paused()); + obs_data_set_bool(data, "virtualcam", obs_frontend_virtualcam_active()); obs_data_set_bool(data, "preview-only", false); if (obs_frontend_streaming_active()) { @@ -40,6 +43,11 @@ RpcResponse WSRequestHandler::GetStreamingStatus(const RpcRequest& request) { obs_data_set_string(data, "rec-timecode", recordingTimecode.toUtf8().constData()); } + if (obs_frontend_virtualcam_active()) { + QString virtualCamTimecode = events->getVirtualCamTimecode(); + obs_data_set_string(data, "virtualcam-timecode", virtualCamTimecode.toUtf8().constData()); + } + return request.success(data); } diff --git a/src/WSRequestHandler_VirtualCam.cpp b/src/WSRequestHandler_VirtualCam.cpp new file mode 100644 index 00000000..625e5e45 --- /dev/null +++ b/src/WSRequestHandler_VirtualCam.cpp @@ -0,0 +1,79 @@ +#include "obs-websocket.h" +#include "Utils.h" +#include "WSEvents.h" + +#include "WSRequestHandler.h" + + /** + * Get current virtual cam status. + * + * @return {boolean} `isVirtualCam` Current virtual camera status. + * @return {String (optional)} `virtualCamTimecode` Time elapsed since virtual cam started (only present if virtual cam currently active). + * + * @api requests + * @name GetVirtualCamStatus + * @category virtual cam + * @since unreleased + */ +RpcResponse WSRequestHandler::GetVirtualCamStatus(const RpcRequest& request) { + auto events = GetEventsSystem(); + + OBSDataAutoRelease data = obs_data_create(); + obs_data_set_bool(data, "isVirtualCam", obs_frontend_virtualcam_active()); + + if (obs_frontend_virtualcam_active()) { + QString virtualCamTimecode = events->getVirtualCamTimecode(); + obs_data_set_string(data, "virtualCamTimecode", virtualCamTimecode.toUtf8().constData()); + } + + return request.success(data); +} + +/** + * Toggle virtual cam on or off (depending on the current virtual cam state). + * + * @api requests + * @name StartStopVirtualCam + * @category virtual cam + * @since unreleased + */ +RpcResponse WSRequestHandler::StartStopVirtualCam(const RpcRequest& request) { + (obs_frontend_virtualcam_active() ? obs_frontend_stop_virtualcam() : obs_frontend_start_virtualcam()); + return request.success(); +} + +/** + * Start virtual cam. + * Will return an `error` if virtual cam is already active. + * + * @api requests + * @name StartVirtualCam + * @category virtual cam + * @since unreleased + */ +RpcResponse WSRequestHandler::StartVirtualCam(const RpcRequest& request) { + if (obs_frontend_virtualcam_active()) { + return request.failed("virtual cam already active"); + } + + obs_frontend_start_virtualcam(); + return request.success(); +} + +/** + * Stop virtual cam. + * Will return an `error` if virtual cam is not active. + * + * @api requests + * @name StopVirtualCam + * @category virtual cam + * @since unreleased + */ + RpcResponse WSRequestHandler::StopVirtualCam(const RpcRequest& request) { + if (!obs_frontend_virtualcam_active()) { + return request.failed("virtual cam not active"); + } + + obs_frontend_stop_virtualcam(); + return request.success(); +}