diff --git a/obs-studio-client/source/nodeobs_service.cpp b/obs-studio-client/source/nodeobs_service.cpp index 206a47ca9..3557bc458 100644 --- a/obs-studio-client/source/nodeobs_service.cpp +++ b/obs-studio-client/source/nodeobs_service.cpp @@ -164,6 +164,38 @@ Napi::Value service::OBS_service_stopReplayBuffer(const Napi::CallbackInfo& info return info.Env().Undefined(); } +Napi::Value service::OBS_service_canPauseRecording(const Napi::CallbackInfo& info) +{ + auto conn = GetConnection(info); + if (!conn) + return info.Env().Undefined(); + + std::vector response = conn->call_synchronous_helper("NodeOBS_Service", "OBS_service_canPauseRecording", {}); + return Napi::Boolean::New(info.Env(), (bool)response[1].value_union.i32); +} + +Napi::Value service::OBS_service_pauseRecording(const Napi::CallbackInfo& info) +{ + bool shouldPause = info[0].ToBoolean().Value(); + + auto conn = GetConnection(info); + if (!conn) + return info.Env().Undefined(); + + std::vector response = conn->call_synchronous_helper("NodeOBS_Service", "OBS_service_pauseRecording", {ipc::value(shouldPause)}); + return Napi::Boolean::New(info.Env(), (bool)response[1].value_union.i32); +} + +Napi::Value service::OBS_service_isPausedRecording(const Napi::CallbackInfo& info) +{ + auto conn = GetConnection(info); + if (!conn) + return info.Env().Undefined(); + + std::vector response = conn->call_synchronous_helper("NodeOBS_Service", "OBS_service_isPausedRecording", {}); + return Napi::Boolean::New(info.Env(), (bool)response[1].value_union.i32); +} + static v8::Persistent serviceCallbackObject; Napi::Value service::OBS_service_connectOutputSignals(const Napi::CallbackInfo& info) @@ -464,6 +496,15 @@ void service::Init(Napi::Env env, Napi::Object exports) exports.Set( Napi::String::New(env, "OBS_service_stopReplayBuffer"), Napi::Function::New(env, service::OBS_service_stopReplayBuffer)); + exports.Set( + Napi::String::New(env, "OBS_service_canPauseRecording"), + Napi::Function::New(env, service::OBS_service_canPauseRecording)); + exports.Set( + Napi::String::New(env, "OBS_service_pauseRecording"), + Napi::Function::New(env, service::OBS_service_pauseRecording)); + exports.Set( + Napi::String::New(env, "OBS_service_isPausedRecording"), + Napi::Function::New(env, service::OBS_service_isPausedRecording)); exports.Set( Napi::String::New(env, "OBS_service_connectOutputSignals"), Napi::Function::New(env, service::OBS_service_connectOutputSignals)); diff --git a/obs-studio-client/source/nodeobs_service.hpp b/obs-studio-client/source/nodeobs_service.hpp index 4e26ae8ef..4a8defa7f 100644 --- a/obs-studio-client/source/nodeobs_service.hpp +++ b/obs-studio-client/source/nodeobs_service.hpp @@ -57,6 +57,10 @@ namespace service Napi::Value OBS_service_stopRecording(const Napi::CallbackInfo& info); Napi::Value OBS_service_stopReplayBuffer(const Napi::CallbackInfo& info); + Napi::Value OBS_service_canPauseRecording(const Napi::CallbackInfo& info); + Napi::Value OBS_service_pauseRecording(const Napi::CallbackInfo& info); + Napi::Value OBS_service_isPausedRecording(const Napi::CallbackInfo& info); + Napi::Value OBS_service_connectOutputSignals(const Napi::CallbackInfo& info); Napi::Value OBS_service_removeCallback(const Napi::CallbackInfo& info); Napi::Value OBS_service_processReplayBufferHotkey(const Napi::CallbackInfo& info); diff --git a/obs-studio-server/source/nodeobs_service.cpp b/obs-studio-server/source/nodeobs_service.cpp index 8662d8d88..2bd2ec8ae 100644 --- a/obs-studio-server/source/nodeobs_service.cpp +++ b/obs-studio-server/source/nodeobs_service.cpp @@ -95,6 +95,12 @@ void OBS_service::Register(ipc::server& srv) "OBS_service_stopRecording", std::vector{}, OBS_service_stopRecording)); cls->register_function(std::make_shared( "OBS_service_stopReplayBuffer", std::vector{ipc::type::Int32}, OBS_service_stopReplayBuffer)); + cls->register_function(std::make_shared( + "OBS_service_canPauseRecording", std::vector{}, OBS_service_canPauseRecording)); + cls->register_function(std::make_shared( + "OBS_service_pauseRecording", std::vector{ipc::type::Int32}, OBS_service_pauseRecording)); + cls->register_function(std::make_shared( + "OBS_service_isPausedRecording", std::vector{}, OBS_service_isPausedRecording)); cls->register_function(std::make_shared( "OBS_service_connectOutputSignals", std::vector{}, OBS_service_connectOutputSignals)); cls->register_function(std::make_shared("Query", std::vector{}, Query)); @@ -244,6 +250,42 @@ void OBS_service::OBS_service_stopReplayBuffer( AUTO_DEBUG; } +void OBS_service::OBS_service_canPauseRecording( + void* data, + const int64_t id, + const std::vector& args, + std::vector& rval) +{ + bool result = canPauseRecording(); + rval.push_back(ipc::value((uint64_t)ErrorCode::Ok)); + rval.push_back(ipc::value(result)); + AUTO_DEBUG; +} + +void OBS_service::OBS_service_pauseRecording( + void* data, + const int64_t id, + const std::vector& args, + std::vector& rval) +{ + bool result = pauseRecording((bool)args[0].value_union.i32); + rval.push_back(ipc::value((uint64_t)ErrorCode::Ok)); + rval.push_back(ipc::value(result)); + AUTO_DEBUG; +} + +void OBS_service::OBS_service_isPausedRecording( + void* data, + const int64_t id, + const std::vector& args, + std::vector& rval) +{ + bool result = isPausedRecording(); + rval.push_back(ipc::value((uint64_t)ErrorCode::Ok)); + rval.push_back(ipc::value(result)); + AUTO_DEBUG; +} + bool OBS_service::resetAudioContext(bool reload) { struct obs_audio_info ai; @@ -1363,6 +1405,21 @@ void OBS_service::stopRecording(void) isRecording = false; } +bool OBS_service::canPauseRecording(void) +{ + return obs_output_can_pause(recordingOutput); +} + +bool OBS_service::pauseRecording(bool shouldPause) +{ + return obs_output_pause(recordingOutput, shouldPause); +} + +bool OBS_service::isPausedRecording(void) +{ + return obs_output_paused(recordingOutput); +} + void OBS_service::updateReplayBufferOutput(bool isSimpleMode, bool useStreamEncoder) { const char* path; @@ -2317,6 +2374,8 @@ void OBS_service::OBS_service_connectOutputSignals( recordingSignals.push_back(SignalInfo("recording", "stop")); recordingSignals.push_back(SignalInfo("recording", "stopping")); recordingSignals.push_back(SignalInfo("recording", "wrote")); + recordingSignals.push_back(SignalInfo("recording", "pause")); + recordingSignals.push_back(SignalInfo("recording", "unpause")); replayBufferSignals.push_back(SignalInfo("replay-buffer", "start")); replayBufferSignals.push_back(SignalInfo("replay-buffer", "stop")); diff --git a/obs-studio-server/source/nodeobs_service.h b/obs-studio-server/source/nodeobs_service.h index f4888199f..715105100 100644 --- a/obs-studio-server/source/nodeobs_service.h +++ b/obs-studio-server/source/nodeobs_service.h @@ -161,6 +161,21 @@ class OBS_service const int64_t id, const std::vector& args, std::vector& rval); + static void OBS_service_canPauseRecording( + void* data, + const int64_t id, + const std::vector& args, + std::vector& rval); + static void OBS_service_pauseRecording( + void* data, + const int64_t id, + const std::vector& args, + std::vector& rval); + static void OBS_service_isPausedRecording( + void* data, + const int64_t id, + const std::vector& args, + std::vector& rval); static void OBS_service_connectOutputSignals( void* data, const int64_t id, @@ -212,6 +227,10 @@ class OBS_service static void stopReplayBuffer(bool forceStop); static void stopRecording(void); + static bool canPauseRecording(void); + static bool pauseRecording(bool shouldPause); + static bool isPausedRecording(void); + static void releaseStreamingOutput(void); static void LoadRecordingPreset_h264(const char* encoder); diff --git a/tests/osn-tests/src/test_nodeobs_service.ts b/tests/osn-tests/src/test_nodeobs_service.ts index cea857781..c2eb67487 100644 --- a/tests/osn-tests/src/test_nodeobs_service.ts +++ b/tests/osn-tests/src/test_nodeobs_service.ts @@ -148,6 +148,45 @@ describe(testName, function() { expect(signalInfo.signal).to.equal(EOBSOutputSignal.Wrote, GetErrorMessage(ETestErrorMsg.RecordingOutput)); }); + it('Simple mode - Pause recording and resume', async function() { + // Preparing environment + obs.setSetting(EOBSSettingsCategories.Output, 'Mode', 'Simple'); + obs.setSetting(EOBSSettingsCategories.Output, 'StreamEncoder', obs.os === 'win32' ? 'x264' : 'obs_x264'); + obs.setSetting(EOBSSettingsCategories.Output, 'FilePath', path.join(path.normalize(__dirname), '..', 'osnData')); + + let signalInfo: IOBSOutputSignalInfo; + + osn.NodeObs.OBS_service_startRecording(); + + signalInfo = await obs.getNextSignalInfo(EOBSOutputType.Recording, EOBSOutputSignal.Start); + + if (signalInfo.signal == EOBSOutputSignal.Stop) { + throw Error(GetErrorMessage(ETestErrorMsg.RecordOutputDidNotStart, signalInfo.code.toString(), signalInfo.error)); + } + + expect(signalInfo.type).to.equal(EOBSOutputType.Recording, GetErrorMessage(ETestErrorMsg.RecordingOutput)); + expect(signalInfo.signal).to.equal(EOBSOutputSignal.Start, GetErrorMessage(ETestErrorMsg.RecordingOutput)); + + await sleep(500); + + expect(osn.NodeObs.OBS_service_canPauseRecording()).to.equal(true) + expect(osn.NodeObs.OBS_service_isPausedRecording()).to.equal(false) + + expect(osn.NodeObs.OBS_service_pauseRecording(true)).to.equal(true); + signalInfo = await obs.getNextSignalInfo(EOBSOutputType.Recording, EOBSOutputSignal.Pause); + + expect(signalInfo.signal).to.equal(EOBSOutputSignal.Pause, GetErrorMessage(ETestErrorMsg.RecordingOutput)); + expect(osn.NodeObs.OBS_service_isPausedRecording()).to.equal(true); + + expect(osn.NodeObs.OBS_service_pauseRecording(false)).to.equal(true) + signalInfo = await obs.getNextSignalInfo(EOBSOutputType.Recording, EOBSOutputSignal.Unpause); + + expect(signalInfo.signal).to.equal(EOBSOutputSignal.Unpause, GetErrorMessage(ETestErrorMsg.RecordingOutput)); + expect(osn.NodeObs.OBS_service_isPausedRecording()).to.equal(false) + + osn.NodeObs.OBS_service_stopRecording(); + }); + it('Simple mode - Start replay buffer, save replay and stop', async function() { // Preparing environment obs.setSetting(EOBSSettingsCategories.Output, 'Mode', 'Simple'); diff --git a/tests/osn-tests/util/obs_enums.ts b/tests/osn-tests/util/obs_enums.ts index 0115be499..df8d85696 100644 --- a/tests/osn-tests/util/obs_enums.ts +++ b/tests/osn-tests/util/obs_enums.ts @@ -17,6 +17,8 @@ export const enum EOBSOutputSignal { Writing = 'writing', Wrote = 'wrote', WriteError = 'writing_error', + Pause = 'pause', + Unpause = 'unpause', } export const enum EOBSInputTypes {