diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index 9a03cec7..ca1275ab 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -131,6 +131,12 @@ const std::unordered_map RequestHandler::_han {"ToggleVirtualCam", &RequestHandler::ToggleVirtualCam}, {"StartVirtualCam", &RequestHandler::StartVirtualCam}, {"StopVirtualCam", &RequestHandler::StopVirtualCam}, + {"GetReplayBufferStatus", &RequestHandler::GetReplayBufferStatus}, + {"ToggleReplayBuffer", &RequestHandler::ToggleReplayBuffer}, + {"StartReplayBuffer", &RequestHandler::StartReplayBuffer}, + {"StopReplayBuffer", &RequestHandler::StopReplayBuffer}, + {"SaveReplayBuffer", &RequestHandler::SaveReplayBuffer}, + {"GetLastReplayBufferReplay", &RequestHandler::GetLastReplayBufferReplay}, // Stream {"GetStreamStatus", &RequestHandler::GetStreamStatus}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 6f34759b..2e5927de 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -149,6 +149,12 @@ class RequestHandler { RequestResult ToggleVirtualCam(const Request&); RequestResult StartVirtualCam(const Request&); RequestResult StopVirtualCam(const Request&); + RequestResult GetReplayBufferStatus(const Request&); + RequestResult ToggleReplayBuffer(const Request&); + RequestResult StartReplayBuffer(const Request&); + RequestResult StopReplayBuffer(const Request&); + RequestResult SaveReplayBuffer(const Request&); + RequestResult GetLastReplayBufferReplay(const Request&); // Stream RequestResult GetStreamStatus(const Request&); diff --git a/src/requesthandler/RequestHandler_Outputs.cpp b/src/requesthandler/RequestHandler_Outputs.cpp index d7c4d493..d85f839a 100644 --- a/src/requesthandler/RequestHandler_Outputs.cpp +++ b/src/requesthandler/RequestHandler_Outputs.cpp @@ -28,6 +28,12 @@ static bool VirtualCamAvailable() return obs_data_get_bool(privateData, "vcamEnabled"); } +static bool ReplayBufferAvailable() +{ + OBSOutputAutoRelease output = obs_frontend_get_replay_buffer_output(); + return output != nullptr; +} + /** * Gets the status of the virtualcam output. * @@ -124,3 +130,148 @@ RequestResult RequestHandler::StopVirtualCam(const Request&) return RequestResult::Success(); } + +/** + * Gets the status of the replay buffer output. + * + * @responseField outputActive | Boolean | Whether the output is active + * + * @requestType GetReplayBufferStatus + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category outputs + * @api requests + */ +RequestResult RequestHandler::GetReplayBufferStatus(const Request&) +{ + if (!ReplayBufferAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available."); + + json responseData; + responseData["outputActive"] = obs_frontend_replay_buffer_active(); + return RequestResult::Success(responseData); +} + +/** + * Toggles the state of the replay buffer output. + * + * @responseField outputActive | Boolean | Whether the output is active + * + * @requestType ToggleReplayBuffer + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @category outputs + * @api requests + */ +RequestResult RequestHandler::ToggleReplayBuffer(const Request&) +{ + if (!ReplayBufferAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available."); + + bool outputActive = obs_frontend_replay_buffer_active(); + + if (outputActive) + obs_frontend_replay_buffer_stop(); + else + obs_frontend_replay_buffer_start(); + + json responseData; + responseData["outputActive"] = !outputActive; + return RequestResult::Success(responseData); +} + +/** + * Starts the replay buffer output. + * + * @requestType StartReplayBuffer + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category outputs + */ +RequestResult RequestHandler::StartReplayBuffer(const Request&) +{ + if (!ReplayBufferAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available."); + + if (obs_frontend_replay_buffer_active()) + return RequestResult::Error(RequestStatus::OutputRunning); + + obs_frontend_replay_buffer_start(); + + return RequestResult::Success(); +} + +/** + * Stops the replay buffer output. + * + * @requestType StopReplayBuffer + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category outputs + */ +RequestResult RequestHandler::StopReplayBuffer(const Request&) +{ + if (!ReplayBufferAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available."); + + if (!obs_frontend_replay_buffer_active()) + return RequestResult::Error(RequestStatus::OutputNotRunning); + + obs_frontend_replay_buffer_stop(); + + return RequestResult::Success(); +} + +/** + * Saves the contents of the replay buffer output. + * + * @requestType SaveReplayBuffer + * @complexity 1 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category outputs + */ +RequestResult RequestHandler::SaveReplayBuffer(const Request&) +{ + if (!ReplayBufferAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available."); + + if (!obs_frontend_replay_buffer_active()) + return RequestResult::Error(RequestStatus::OutputNotRunning); + + obs_frontend_replay_buffer_save(); + + return RequestResult::Success(); +} + +/** + * Gets the filename of the last replay buffer save file. + * + * @responseField savedReplayPath | String | File path + * + * @requestType GetLastReplayBufferReplay + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.0.0 + * @api requests + * @category outputs + */ +RequestResult RequestHandler::GetLastReplayBufferReplay(const Request&) +{ + if (!ReplayBufferAvailable()) + return RequestResult::Error(RequestStatus::InvalidResourceState, "Replay buffer is not available."); + + if (!obs_frontend_replay_buffer_active()) + return RequestResult::Error(RequestStatus::OutputNotRunning); + + json responseData; + responseData["savedReplayPath"] = Utils::Obs::StringHelper::GetLastReplayBufferFilePath(); + return RequestResult::Success(responseData); +} diff --git a/src/utils/Obs_StringHelper.cpp b/src/utils/Obs_StringHelper.cpp index ef040bf1..c5e1bc07 100644 --- a/src/utils/Obs_StringHelper.cpp +++ b/src/utils/Obs_StringHelper.cpp @@ -120,12 +120,19 @@ std::string Utils::Obs::StringHelper::GetMediaInputState(obs_source_t *input) std::string Utils::Obs::StringHelper::GetLastReplayBufferFilePath() { OBSOutputAutoRelease output = obs_frontend_get_replay_buffer_output(); + if (!output) + return ""; + calldata_t cd = {0}; proc_handler_t *ph = obs_output_get_proc_handler(output); proc_handler_call(ph, "get_last_replay", &cd); - auto ret = calldata_string(&cd, "path"); + const char *savedReplayPath = calldata_string(&cd, "path"); calldata_free(&cd); - return ret; + + if (!savedReplayPath) + return ""; + + return savedReplayPath; } std::string Utils::Obs::StringHelper::GetSceneItemBoundsType(enum obs_bounds_type type)