Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ env:
SLGenerator: Visual Studio 17 2022
SLDistributeDirectory: distribute
SLFullDistributePath: "streamlabs-build.app/distribute" # The .app extension is required to run macOS tests correctly.
LibOBSVersion: 31.1.2sl19
LibOBSVersion: 31.1.2sl19b5
PACKAGE_NAME: osn

jobs:
Expand Down
35 changes: 29 additions & 6 deletions obs-studio-client/source/advanced-recording.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "advanced-recording.hpp"
#include "utility.hpp"
#include "advanced-streaming.hpp"
#include "enhanced-broadcasting-advanced-streaming.hpp"

Napi::FunctionReference osn::AdvancedRecording::constructor;

Expand Down Expand Up @@ -310,22 +311,44 @@ void osn::AdvancedRecording::SetStreaming(const Napi::CallbackInfo &info, const
return;
}

Napi::Object obj = value.As<Napi::Object>();
if (!obj.InstanceOf(osn::AdvancedStreaming::constructor.Value()))
if (!value.IsObject()) {
Napi::TypeError::New(info.Env(), "Object is not a AdvancedStreaming").ThrowAsJavaScriptException();
return;
}

osn::AdvancedStreaming *streaming = Napi::ObjectWrap<osn::AdvancedStreaming>::Unwrap(value.ToObject());
Napi::Object obj = value.As<Napi::Object>();
uint64_t streamingUid = UINT64_MAX;
if (obj.InstanceOf(osn::AdvancedStreaming::constructor.Value())) {
osn::AdvancedStreaming *streaming = Napi::ObjectWrap<osn::AdvancedStreaming>::Unwrap(obj);
if (!streaming) {
Napi::TypeError::New(info.Env(), "Invalid streaming argument").ThrowAsJavaScriptException();
return;
}

streamingUid = streaming->uid;
} else if (obj.InstanceOf(osn::EnhancedBroadcastingAdvancedStreaming::constructor.Value())) {
osn::EnhancedBroadcastingAdvancedStreaming *streaming = Napi::ObjectWrap<osn::EnhancedBroadcastingAdvancedStreaming>::Unwrap(obj);
if (!streaming) {
Napi::TypeError::New(info.Env(), "Invalid streaming argument").ThrowAsJavaScriptException();
return;
}

streamingUid = streaming->uid;
} else {
Napi::TypeError::New(info.Env(), "Object is not a AdvancedStreaming").ThrowAsJavaScriptException();
return;
}

if (!streaming) {
if (streamingUid == UINT64_MAX) {
Napi::TypeError::New(info.Env(), "Invalid streaming argument").ThrowAsJavaScriptException();
return;
}

auto response = conn->call_synchronous_helper(className, "SetStreaming", {ipc::value(this->uid), ipc::value(streaming->uid)});
auto response = conn->call_synchronous_helper(className, "SetStreaming", {ipc::value(this->uid), ipc::value(streamingUid)});
if (!ValidateResponse(info, response))
return;

if (!streamingRef.IsEmpty())
streamingRef.Reset();
streamingRef = Napi::Persistent(obj);
}
}
35 changes: 29 additions & 6 deletions obs-studio-client/source/advanced-replay-buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "audio-encoder.hpp"
#include "advanced-streaming.hpp"
#include "advanced-recording.hpp"
#include "enhanced-broadcasting-advanced-streaming.hpp"

Napi::FunctionReference osn::AdvancedReplayBuffer::constructor;

Expand Down Expand Up @@ -209,18 +210,40 @@ void osn::AdvancedReplayBuffer::SetStreaming(const Napi::CallbackInfo &info, con
return;
}

Napi::Object obj = value.As<Napi::Object>();
if (!obj.InstanceOf(osn::AdvancedStreaming::constructor.Value()))
if (!value.IsObject()) {
Napi::TypeError::New(info.Env(), "Object is not a valid Streaming").ThrowAsJavaScriptException();
return;
}

osn::AdvancedStreaming *streaming = Napi::ObjectWrap<osn::AdvancedStreaming>::Unwrap(value.ToObject());
Napi::Object obj = value.As<Napi::Object>();
uint64_t streamingUid = UINT64_MAX;
if (obj.InstanceOf(osn::AdvancedStreaming::constructor.Value())) {
osn::AdvancedStreaming *streaming = Napi::ObjectWrap<osn::AdvancedStreaming>::Unwrap(obj);
if (!streaming) {
Napi::TypeError::New(info.Env(), "Invalid streaming argument").ThrowAsJavaScriptException();
return;
}

streamingUid = streaming->uid;
} else if (obj.InstanceOf(osn::EnhancedBroadcastingAdvancedStreaming::constructor.Value())) {
osn::EnhancedBroadcastingAdvancedStreaming *streaming = Napi::ObjectWrap<osn::EnhancedBroadcastingAdvancedStreaming>::Unwrap(obj);
if (!streaming) {
Napi::TypeError::New(info.Env(), "Invalid streaming argument").ThrowAsJavaScriptException();
return;
}

streamingUid = streaming->uid;
} else {
Napi::TypeError::New(info.Env(), "Object is not a valid Streaming").ThrowAsJavaScriptException();
return;
}

if (!streaming) {
if (streamingUid == UINT64_MAX) {
Napi::TypeError::New(info.Env(), "Invalid streaming argument").ThrowAsJavaScriptException();
return;
}

auto response = conn->call_synchronous_helper(className, "SetStreaming", {ipc::value(this->uid), ipc::value(streaming->uid)});
auto response = conn->call_synchronous_helper(className, "SetStreaming", {ipc::value(this->uid), ipc::value(streamingUid)});
if (!ValidateResponse(info, response))
return;

Expand Down Expand Up @@ -272,4 +295,4 @@ void osn::AdvancedReplayBuffer::SetRecording(const Napi::CallbackInfo &info, con
if (!parentOutputRef.IsEmpty())
parentOutputRef.Reset();
parentOutputRef = Napi::Persistent(obj);
}
}
35 changes: 29 additions & 6 deletions obs-studio-client/source/simple-recording.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "reconnect.hpp"
#include "network.hpp"
#include "simple-streaming.hpp"
#include "enhanced-broadcasting-simple-streaming.hpp"

Napi::FunctionReference osn::SimpleRecording::constructor;

Expand Down Expand Up @@ -282,22 +283,44 @@ void osn::SimpleRecording::SetStreaming(const Napi::CallbackInfo &info, const Na
return;
}

Napi::Object obj = value.As<Napi::Object>();
if (!obj.InstanceOf(osn::SimpleStreaming::constructor.Value()))
if (!value.IsObject()) {
Napi::TypeError::New(info.Env(), "Object is not a SimpleStreaming").ThrowAsJavaScriptException();
return;
}

osn::SimpleStreaming *streaming = Napi::ObjectWrap<osn::SimpleStreaming>::Unwrap(value.ToObject());
Napi::Object obj = value.As<Napi::Object>();
uint64_t streamingUid = UINT64_MAX;
if (obj.InstanceOf(osn::SimpleStreaming::constructor.Value())) {
osn::SimpleStreaming *streaming = Napi::ObjectWrap<osn::SimpleStreaming>::Unwrap(obj);
if (!streaming) {
Napi::TypeError::New(info.Env(), "Invalid streaming argument").ThrowAsJavaScriptException();
return;
}

streamingUid = streaming->uid;
} else if (obj.InstanceOf(osn::EnhancedBroadcastingSimpleStreaming::constructor.Value())) {
osn::EnhancedBroadcastingSimpleStreaming *streaming = Napi::ObjectWrap<osn::EnhancedBroadcastingSimpleStreaming>::Unwrap(obj);
if (!streaming) {
Napi::TypeError::New(info.Env(), "Invalid streaming argument").ThrowAsJavaScriptException();
return;
}

streamingUid = streaming->uid;
} else {
Napi::TypeError::New(info.Env(), "Object is not a SimpleStreaming").ThrowAsJavaScriptException();
return;
}

if (!streaming) {
if (streamingUid == UINT64_MAX) {
Napi::TypeError::New(info.Env(), "Invalid streaming argument").ThrowAsJavaScriptException();
return;
}

auto response = conn->call_synchronous_helper(className, "SetStreaming", {ipc::value(this->uid), ipc::value(streaming->uid)});
auto response = conn->call_synchronous_helper(className, "SetStreaming", {ipc::value(this->uid), ipc::value(streamingUid)});
if (!ValidateResponse(info, response))
return;

if (!streamingRef.IsEmpty())
streamingRef.Reset();
streamingRef = Napi::Persistent(obj);
}
}
35 changes: 29 additions & 6 deletions obs-studio-client/source/simple-replay-buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "audio-encoder.hpp"
#include "simple-streaming.hpp"
#include "simple-recording.hpp"
#include "enhanced-broadcasting-simple-streaming.hpp"

Napi::FunctionReference osn::SimpleReplayBuffer::constructor;

Expand Down Expand Up @@ -184,18 +185,40 @@ void osn::SimpleReplayBuffer::SetStreaming(const Napi::CallbackInfo &info, const
return;
}

Napi::Object obj = value.As<Napi::Object>();
if (!obj.InstanceOf(osn::SimpleStreaming::constructor.Value()))
if (!value.IsObject()) {
Napi::TypeError::New(info.Env(), "Object is not a SimpleStreaming").ThrowAsJavaScriptException();
return;
}

osn::SimpleStreaming *streaming = Napi::ObjectWrap<osn::SimpleStreaming>::Unwrap(value.ToObject());
Napi::Object obj = value.As<Napi::Object>();
uint64_t streamingUid = UINT64_MAX;
if (obj.InstanceOf(osn::SimpleStreaming::constructor.Value())) {
osn::SimpleStreaming *streaming = Napi::ObjectWrap<osn::SimpleStreaming>::Unwrap(obj);
if (!streaming) {
Napi::TypeError::New(info.Env(), "Invalid streaming argument").ThrowAsJavaScriptException();
return;
}

streamingUid = streaming->uid;
} else if (obj.InstanceOf(osn::EnhancedBroadcastingSimpleStreaming::constructor.Value())) {
osn::EnhancedBroadcastingSimpleStreaming *streaming = Napi::ObjectWrap<osn::EnhancedBroadcastingSimpleStreaming>::Unwrap(obj);
if (!streaming) {
Napi::TypeError::New(info.Env(), "Invalid streaming argument").ThrowAsJavaScriptException();
return;
}

streamingUid = streaming->uid;
} else {
Napi::TypeError::New(info.Env(), "Object is not a SimpleStreaming").ThrowAsJavaScriptException();
return;
}

if (!streaming) {
if (streamingUid == UINT64_MAX) {
Napi::TypeError::New(info.Env(), "Invalid streaming argument").ThrowAsJavaScriptException();
return;
}

auto response = conn->call_synchronous_helper(className, "SetStreaming", {ipc::value(this->uid), ipc::value(streaming->uid)});
auto response = conn->call_synchronous_helper(className, "SetStreaming", {ipc::value(this->uid), ipc::value(streamingUid)});
if (!ValidateResponse(info, response))
return;

Expand Down Expand Up @@ -247,4 +270,4 @@ void osn::SimpleReplayBuffer::SetRecording(const Napi::CallbackInfo &info, const
if (!parentOutputRef.IsEmpty())
parentOutputRef.Reset();
parentOutputRef = Napi::Persistent(obj);
}
}
11 changes: 11 additions & 0 deletions obs-studio-server/source/osn-advanced-recording.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,17 @@ void osn::IAdvancedRecording::Start(void *data, const int64_t id, const std::vec
PRETTY_ERROR_RETURN(ErrorCode::CriticalError, "The specified video encoder is not valid for recording.");
}

const char *encoderId = obs_encoder_get_id(recording->videoEncoder);
const bool encoderIsOwned = !recording->useStreamEncoders || obs_get_multiple_rendering();
const bool encoderSupportsScaling = encoderId && strcmp(encoderId, ENCODER_NVENC_H264_TEX) != 0;
if (encoderIsOwned && encoderSupportsScaling) {
const bool applyRescale = recording->rescaling && recording->outputWidth > 0 && recording->outputHeight > 0;
const uint32_t cx = applyRescale ? recording->outputWidth : 0;
const uint32_t cy = applyRescale ? recording->outputHeight : 0;
obs_encoder_set_scaled_size(recording->videoEncoder, cx, cy);
obs_encoder_set_gpu_scale_type(recording->videoEncoder, applyRescale ? OBS_SCALE_BILINEAR : OBS_SCALE_DISABLE);
}

obs_output_set_video_encoder(recording->GetOutput(), recording->videoEncoder);

std::string path = recording->path;
Expand Down
5 changes: 4 additions & 1 deletion obs-studio-server/source/osn-encoders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ const std::vector<osn::EncoderUtils::EncoderSettings> osn::EncoderUtils::videoEn
APPLE_HARDWARE_VIDEO_ENCODER_M1, "", true, true, true, false, true, false, PRESET_APPLE, FAMILY_APPLE},
// get_simple_output_encoder had Apple HEVC so add it here, never used with an advanced name but follow the pattern of M1 above
{"Apple VT HEVC Hardware Encoder", APPLE_HARDWARE_VIDEO_ENCODER_HEVC, "Hardware (Apple, HEVC)", SIMPLE_ENCODER_APPLE_HEVC,
APPLE_HARDWARE_VIDEO_ENCODER_HEVC, "", true, true, true, false, true, false, PRESET_APPLE, FAMILY_APPLE},
APPLE_HARDWARE_VIDEO_ENCODER_HEVC, "", true, true, true, true, true, false, PRESET_APPLE, FAMILY_APPLE},
// AMD HW H.264
{"AMD HW H.264", ADVANCED_ENCODER_AMD, "Hardware (AMD, H.264)", SIMPLE_ENCODER_AMD, ADVANCED_ENCODER_AMD, "", true, true, true, false, true, false,
PRESET_AMD, FAMILY_AMD},
Expand Down Expand Up @@ -212,6 +212,9 @@ bool osn::EncoderUtils::isEncoderCompatible(std::string encoderName, obs_service
}
if (!containerSupportsCodec(container, codec))
return false;
if (container == "flv" && videoEncoderOptions[checkIndex].family == FAMILY_APPLE) {
return false;
}
}

return true;
Expand Down
2 changes: 1 addition & 1 deletion obs-studio-server/source/util-osx-impl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@

@implementation UtilImplObj

UtilObjCInt::UtilObjCInt(void) : self(NULL) {}
UtilObjCInt::UtilObjCInt(void) : self(NULL), state(EState::Idle), worker(nullptr) {}

UtilObjCInt::~UtilObjCInt(void)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,34 @@ describe(testName, () => {
}
});

it('Can be used as the parent stream for advanced recording', function() {
const stream = osn.EnhancedBroadcastingAdvancedStreamingFactory.create();
const recording = osn.AdvancedRecordingFactory.create();

try {
recording.streaming = stream;

expect(recording.streaming).to.equal(stream);
} finally {
osn.AdvancedRecordingFactory.destroy(recording);
osn.EnhancedBroadcastingAdvancedStreamingFactory.destroy(stream);
}
});

it('Can be used as the parent stream for advanced replay buffer', function() {
const stream = osn.EnhancedBroadcastingAdvancedStreamingFactory.create();
const replayBuffer = osn.AdvancedReplayBufferFactory.create();

try {
replayBuffer.streaming = stream;

expect(replayBuffer.streaming).to.equal(stream);
} finally {
osn.AdvancedReplayBufferFactory.destroy(replayBuffer);
osn.EnhancedBroadcastingAdvancedStreamingFactory.destroy(stream);
}
});

it('Enhanced Broadcasting Advanced Streaming Single Canvas', async function() {
if (obs.isDarwin()) {
this.skip();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,34 @@ describe(testName, () => {
hasTestFailed = (await obs.finalizeRetryableTest(this)) || hasTestFailed;
});

it('Can be used as the parent stream for simple recording', function() {
const stream = osn.EnhancedBroadcastingSimpleStreamingFactory.create();
const recording = osn.SimpleRecordingFactory.create();

try {
recording.streaming = stream;

expect(recording.streaming).to.equal(stream);
} finally {
osn.SimpleRecordingFactory.destroy(recording);
osn.EnhancedBroadcastingSimpleStreamingFactory.destroy(stream);
}
});

it('Can be used as the parent stream for simple replay buffer', function() {
const stream = osn.EnhancedBroadcastingSimpleStreamingFactory.create();
const replayBuffer = osn.SimpleReplayBufferFactory.create();

try {
replayBuffer.streaming = stream;

expect(replayBuffer.streaming).to.equal(stream);
} finally {
osn.SimpleReplayBufferFactory.destroy(replayBuffer);
osn.EnhancedBroadcastingSimpleStreamingFactory.destroy(stream);
}
});

it('Enhanced Broadcasting Simple Streaming honors stream delay', async function() {
if (obs.isDarwin()) {
this.skip();
Expand Down
Loading