From 0671ded7d1104a5a3ccad2b21fdbc4ac4676964a Mon Sep 17 00:00:00 2001
From: tt2468 <tt2468@gmail.com>
Date: Wed, 17 Nov 2021 00:29:33 -0800
Subject: [PATCH] Requests: Add recording requests

---
 CMakeLists.txt                               |  1 +
 src/requesthandler/RequestHandler.cpp        | 10 +++
 src/requesthandler/RequestHandler.h          | 10 +++
 src/requesthandler/RequestHandler_Record.cpp | 95 ++++++++++++++++++++
 src/requesthandler/rpc/RequestStatus.h       |  2 +
 src/utils/Obs.cpp                            | 10 +++
 src/utils/Obs.h                              |  1 +
 7 files changed, 129 insertions(+)
 create mode 100644 src/requesthandler/RequestHandler_Record.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index f4288218..dc1f5707 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -107,6 +107,7 @@ set(obs-websocket_SOURCES
 	src/requesthandler/RequestHandler_Inputs.cpp
 	src/requesthandler/RequestHandler_SceneItems.cpp
 	src/requesthandler/RequestHandler_Stream.cpp
+	src/requesthandler/RequestHandler_Record.cpp
 	src/requesthandler/rpc/Request.cpp
 	src/requesthandler/rpc/RequestResult.cpp
 	src/forms/SettingsDialog.cpp
diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp
index 32db9e07..168a7a2a 100644
--- a/src/requesthandler/RequestHandler.cpp
+++ b/src/requesthandler/RequestHandler.cpp
@@ -87,6 +87,16 @@ const std::map<std::string, RequestMethodHandler> RequestHandler::_handlerMap
 	{"ToggleStream", &RequestHandler::ToggleStream},
 	{"StartStream", &RequestHandler::StartStream},
 	{"StopStream", &RequestHandler::StopStream},
+
+	// Record
+	{"GetRecordStatus", &RequestHandler::GetRecordStatus},
+	{"ToggleRecord", &RequestHandler::ToggleRecord},
+	{"StartRecord", &RequestHandler::StartRecord},
+	{"StopRecord", &RequestHandler::StopRecord},
+	{"ToggleRecordPause", &RequestHandler::ToggleRecordPause},
+	{"PauseRecord", &RequestHandler::PauseRecord},
+	{"ResumeRecord", &RequestHandler::ResumeRecord},
+	//{"GetRecordDirectory", &RequestHandler::GetRecordDirectory},
 };
 
 RequestHandler::RequestHandler(SessionPtr session) :
diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h
index db88f440..f426e3e4 100644
--- a/src/requesthandler/RequestHandler.h
+++ b/src/requesthandler/RequestHandler.h
@@ -109,6 +109,16 @@ class RequestHandler {
 		RequestResult StartStream(const Request&);
 		RequestResult StopStream(const Request&);
 
+		// Record
+		RequestResult GetRecordStatus(const Request&);
+		RequestResult ToggleRecord(const Request&);
+		RequestResult StartRecord(const Request&);
+		RequestResult StopRecord(const Request&);
+		RequestResult ToggleRecordPause(const Request&);
+		RequestResult PauseRecord(const Request&);
+		RequestResult ResumeRecord(const Request&);
+		RequestResult GetRecordDirectory(const Request&);
+
 		SessionPtr _session;
 		static const std::map<std::string, RequestMethodHandler> _handlerMap;
 };
diff --git a/src/requesthandler/RequestHandler_Record.cpp b/src/requesthandler/RequestHandler_Record.cpp
new file mode 100644
index 00000000..ef6699f1
--- /dev/null
+++ b/src/requesthandler/RequestHandler_Record.cpp
@@ -0,0 +1,95 @@
+#include "RequestHandler.h"
+
+RequestResult RequestHandler::GetRecordStatus(const Request& request)
+{
+	OBSOutputAutoRelease recordOutput = obs_frontend_get_streaming_output();
+
+	json responseData;
+	responseData["outputActive"] = obs_output_active(recordOutput);
+	responseData["outputPaused"] = obs_output_paused(recordOutput);
+	responseData["outputTimecode"] = Utils::Obs::StringHelper::GetOutputTimecodeString(recordOutput);
+	responseData["outputDuration"] = Utils::Obs::NumberHelper::GetOutputDuration(recordOutput);
+	responseData["outputBytes"] = (uint64_t)obs_output_get_total_bytes(recordOutput);
+
+	return RequestResult::Success(responseData);
+}
+
+RequestResult RequestHandler::ToggleRecord(const Request& request)
+{
+	json responseData;
+	if (obs_frontend_recording_active()) {
+		obs_frontend_recording_stop();
+		responseData["outputActive"] = false;
+	} else {
+		obs_frontend_recording_start();
+		responseData["outputActive"] = true;
+	}
+
+	return RequestResult::Success(responseData);
+}
+
+RequestResult RequestHandler::StartRecord(const Request& request)
+{
+	if (obs_frontend_recording_active())
+		return RequestResult::Error(RequestStatus::OutputRunning);
+
+	// TODO: Call signal directly to perform blocking wait
+	obs_frontend_recording_start();
+
+	return RequestResult::Success();
+}
+
+RequestResult RequestHandler::StopRecord(const Request& request)
+{
+	if (!obs_frontend_recording_active())
+		return RequestResult::Error(RequestStatus::OutputNotRunning);
+
+	// TODO: Call signal directly to perform blocking wait
+	obs_frontend_recording_stop();
+
+	return RequestResult::Success();
+}
+
+RequestResult RequestHandler::ToggleRecordPause(const Request& request)
+{
+	json responseData;
+	if (obs_frontend_recording_paused()) {
+		obs_frontend_recording_pause(false);
+		responseData["outputPaused"] = false;
+	} else {
+		obs_frontend_recording_pause(true);
+		responseData["outputPaused"] = true;
+	}
+
+	return RequestResult::Success(responseData);
+}
+
+RequestResult RequestHandler::PauseRecord(const Request& request)
+{
+	if (obs_frontend_recording_paused())
+		return RequestResult::Error(RequestStatus::OutputPaused);
+
+	// TODO: Call signal directly to perform blocking wait
+	obs_frontend_recording_pause(true);
+
+	return RequestResult::Success();
+}
+
+RequestResult RequestHandler::ResumeRecord(const Request& request)
+{
+	if (!obs_frontend_recording_paused())
+		return RequestResult::Error(RequestStatus::OutputNotPaused);
+
+	// TODO: Call signal directly to perform blocking wait
+	obs_frontend_recording_pause(false);
+
+	return RequestResult::Success();
+}
+
+RequestResult RequestHandler::GetRecordDirectory(const Request& request)
+{
+	json responseData;
+	responseData["recordDirectory"] = Utils::Obs::StringHelper::GetCurrentRecordOutputPath();
+
+	return RequestResult::Success(responseData);
+}
diff --git a/src/requesthandler/rpc/RequestStatus.h b/src/requesthandler/rpc/RequestStatus.h
index 3d1566e8..6c868daa 100644
--- a/src/requesthandler/rpc/RequestStatus.h
+++ b/src/requesthandler/rpc/RequestStatus.h
@@ -46,6 +46,8 @@ namespace RequestStatus {
 		StudioModeActive = 504,
 		// Studio mode is not active and should be
 		StudioModeNotActive = 505,
+		// An output is not paused and should be
+		OutputNotPaused = 506,
 
 		// The resource was not found
 		ResourceNotFound = 600,
diff --git a/src/utils/Obs.cpp b/src/utils/Obs.cpp
index a15af7b0..a4f6c7d4 100644
--- a/src/utils/Obs.cpp
+++ b/src/utils/Obs.cpp
@@ -67,6 +67,16 @@ std::string Utils::Obs::StringHelper::GetCurrentProfilePath()
 	return ret;
 }
 
+std::string Utils::Obs::StringHelper::GetCurrentRecordOutputPath()
+{
+	//char *recordOutputPath = obs_frontend_get_current_record_output_path();
+	//std::string ret = recordOutputPath;
+	//bfree(recordOutputPath);
+	//return ret;
+
+	return "";
+}
+
 std::string Utils::Obs::StringHelper::GetSourceTypeString(obs_source_t *source)
 {
 	obs_source_type sourceType = obs_source_get_type(source);
diff --git a/src/utils/Obs.h b/src/utils/Obs.h
index 63b2880a..8819003f 100644
--- a/src/utils/Obs.h
+++ b/src/utils/Obs.h
@@ -31,6 +31,7 @@ namespace Utils {
 			std::string GetCurrentSceneCollection();
 			std::string GetCurrentProfile();
 			std::string GetCurrentProfilePath();
+			std::string GetCurrentRecordOutputPath();
 			std::string GetSourceTypeString(obs_source_t *source);
 			std::string GetInputMonitorTypeString(obs_source_t *input);
 			std::string GetMediaInputStateString(obs_source_t *input);