Skip to content

Commit e8748b6

Browse files
Merged branch staging into obs_merge_31.1.2
2 parents 6784a81 + 4434fda commit e8748b6

File tree

11 files changed

+86
-28
lines changed

11 files changed

+86
-28
lines changed

.github/workflows/main.yml

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ env:
2424
SLGenerator: Visual Studio 17 2022
2525
SLDistributeDirectory: distribute
2626
SLFullDistributePath: "streamlabs-build.app/distribute" # The .app extension is required to run macOS tests correctly.
27-
LibOBSVersion: 31.1.2test3
27+
LibOBSVersion: 31.1.2test4
2828
PACKAGE_NAME: osn
2929

3030
jobs:
@@ -82,12 +82,15 @@ jobs:
8282
run: node ci/bump-version.js "${{ steps.get_version.outputs.VERSION }}" "${{env.PACKAGE_PATH}}"
8383
env:
8484
PACKAGE_PATH: "${{env.SLFullDistributePath}}/${{env.InstallPath}}"
85+
- name: Package compiled artifacts
86+
run: |
87+
tar -cvzf build-artifacts.tar.gz -C "${{env.SLBUILDDIRECTORY}}" .
8588
- name: Upload compiled artifacts
8689
uses: actions/upload-artifact@v4
8790
with:
8891
name: build-artifacts-mac-${{matrix.Architecture}}
8992
path: |
90-
${{env.SLBUILDDIRECTORY}}/
93+
build-artifacts.tar.gz
9194
tests/osn-tests/osn/index.ts
9295
9396
run-tests-macos:
@@ -131,11 +134,10 @@ jobs:
131134
with:
132135
name: build-artifacts-mac-${{matrix.Architecture}}
133136
path: .
134-
- name: Set executable permissions
137+
- name: Extract artifacts
135138
run: |
136-
chmod +x streamlabs-build.app/distribute/obs-studio-node/bin/obs64
137-
chmod +x streamlabs-build.app/distribute/obs-studio-node/crashpad_*
138-
shell: bash
139+
mkdir -p "${{env.SLBUILDDIRECTORY}}"
140+
tar -xvzf build-artifacts.tar.gz -C "${{env.SLBUILDDIRECTORY}}"
139141
- name: 'Run tests'
140142
timeout-minutes: 30
141143
run: 'yarn run test'
@@ -173,6 +175,10 @@ jobs:
173175
with:
174176
name: build-artifacts-mac-${{matrix.Architecture}}
175177
path: .
178+
- name: Extract artifacts
179+
run: |
180+
mkdir -p "${{env.SLBUILDDIRECTORY}}"
181+
tar -xvzf build-artifacts.tar.gz -C "${{env.SLBUILDDIRECTORY}}"
176182
- name: Get the version
177183
id: get_version
178184
run: echo "VERSION=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT
@@ -226,6 +232,10 @@ jobs:
226232
with:
227233
name: build-artifacts-mac-${{matrix.Architecture}}
228234
path: .
235+
- name: Extract artifacts
236+
run: |
237+
mkdir -p "${{env.SLBUILDDIRECTORY}}"
238+
tar -xvzf build-artifacts.tar.gz -C "${{env.SLBUILDDIRECTORY}}"
229239
- name: Get the version
230240
id: get_version
231241
run: echo "VERSION=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ yarn install
4242
git submodule update --init --recursive
4343
mkdir build
4444
cd build
45-
cmake .. -DCMAKE_INSTALL_PREFIX=~/streamlabs/desktop/node_modules/obs-studio-node/OSN.app/distribute/obs-studio-node -DCMAKE_OSX_ARCHITECTURES=arm64 -G Xcode
45+
cmake .. -DCMAKE_INSTALL_PREFIX=/Users/<you>/streamlabs/desktop/node_modules/obs-studio-node/OSN.app/distribute/obs-studio-node -DCMAKE_OSX_ARCHITECTURES=arm64 -G Xcode
4646
cmake --build . --target install --config RelWithDebInfo
4747
```
48-
Note, the only gotcha is that if you later run `yarn package:mac` command in the desktop folder instead, then you should remove *OSN.app* from the `CMAKE_INSTALL_PREFIX` path. This is because the electron-builder scripts will throw an error this is not a fully formed app bundle during codesign.
48+
Note, the only gotcha is that if you later run `yarn package:mac-arm64` command in the desktop folder instead, then you should remove *OSN.app* from the `CMAKE_INSTALL_PREFIX` path. This is because the electron-builder scripts will throw an error this is not a fully formed app bundle during codesign.
4949

5050
### Custom OBS Build
5151
By default, we download a pre-built version of libobs if none is specified. However, this pre-built version may not be what you want to use or maybe you're testing a new obs feature.

js/module.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
"use strict";
22
Object.defineProperty(exports, "__esModule", { value: true });
33
exports.NodeObs = exports.getSourcesSize = exports.createSources = exports.addItems = exports.AdvancedReplayBufferFactory = exports.SimpleReplayBufferFactory = exports.AudioEncoderFactory = exports.AdvancedRecordingFactory = exports.SimpleRecordingFactory = exports.AudioTrackFactory = exports.NetworkFactory = exports.ReconnectFactory = exports.DelayFactory = exports.AdvancedStreamingFactory = exports.SimpleStreamingFactory = exports.ServiceFactory = exports.VideoEncoderFactory = exports.IPC = exports.ModuleFactory = exports.AudioFactory = exports.Audio = exports.FaderFactory = exports.VolmeterFactory = exports.DisplayFactory = exports.TransitionFactory = exports.FilterFactory = exports.SceneFactory = exports.InputFactory = exports.VideoFactory = exports.Video = exports.Global = exports.DefaultPluginPathMac = exports.DefaultPluginDataPath = exports.DefaultPluginPath = exports.DefaultDataPath = exports.DefaultBinPath = exports.DefaultDrawPluginPath = exports.DefaultOpenGLPath = exports.DefaultD3D11Path = void 0;
4-
const obs = require('./obs_studio_client.node');
54
const path = require("path");
65
const fs = require("fs");
6+
// Mac- search for optional OSN.app bundle (Chromium requires an app bundle to find obs64 helper apps)
7+
const hasDeveloperApp = process.platform === 'darwin' && fs.existsSync(path.join(__dirname, 'OSN.app'));
8+
const obs = hasDeveloperApp
9+
? require('./OSN.app/distribute/obs-studio-node/obs_studio_client.node')
10+
: require('./obs_studio_client.node');
711
exports.DefaultD3D11Path = path.resolve(__dirname, `libobs-d3d11.dll`);
812
exports.DefaultOpenGLPath = path.resolve(__dirname, `libobs-opengl.dll`);
913
exports.DefaultDrawPluginPath = path.resolve(__dirname, `simple_draw.dll`);
@@ -117,7 +121,9 @@ function getSourcesSize(sourcesNames) {
117121
return sourcesSize;
118122
}
119123
exports.getSourcesSize = getSourcesSize;
120-
const __dirnameApple = fs.existsSync(__dirname + '/OSN.app') ? __dirname + '/OSN.app/distribute/obs-studio-node/bin' : __dirname + '/bin'; // search for local developer OSN.app bundle which stores CEF helper apps
124+
const __dirnameApple = hasDeveloperApp
125+
? path.join(__dirname, 'OSN.app', 'distribute', 'obs-studio-node', 'bin')
126+
: path.join(__dirname, 'bin');
121127
if (fs.existsSync(path.resolve(__dirnameApple).replace('app.asar', 'app.asar.unpacked'))) {
122128
obs.IPC.setServerPath(path.resolve(__dirnameApple, `obs64`).replace('app.asar', 'app.asar.unpacked'), path.resolve(__dirnameApple).replace('app.asar', 'app.asar.unpacked'));
123129
}

js/module.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
const obs = require('./obs_studio_client.node');
21
import * as path from 'path';
32
import * as fs from 'fs';
3+
// Mac- search for optional OSN.app bundle (Chromium requires an app bundle to find obs64 helper apps)
4+
const hasDeveloperApp = process.platform === 'darwin' && fs.existsSync(path.join(__dirname, 'OSN.app'));
5+
const obs = hasDeveloperApp
6+
? require('./OSN.app/distribute/obs-studio-node/obs_studio_client.node')
7+
: require('./obs_studio_client.node');
48

59
/* Convenient paths to modules */
610
export const DefaultD3D11Path: string =
@@ -1890,7 +1894,9 @@ export const enum VCamOutputType {
18901894
};
18911895

18921896
// Initialization and other stuff which needs local data.
1893-
const __dirnameApple = fs.existsSync(__dirname + '/OSN.app') ? __dirname + '/OSN.app/distribute/obs-studio-node/bin' : __dirname + '/bin'; // search for local developer OSN.app bundle which stores CEF helper apps
1897+
const __dirnameApple = hasDeveloperApp
1898+
? path.join(__dirname, 'OSN.app', 'distribute', 'obs-studio-node', 'bin')
1899+
: path.join(__dirname, 'bin');
18941900
if (fs.existsSync(path.resolve(__dirnameApple).replace('app.asar', 'app.asar.unpacked'))) {
18951901
obs.IPC.setServerPath(path.resolve(__dirnameApple, `obs64`).replace('app.asar', 'app.asar.unpacked'), path.resolve(__dirnameApple).replace('app.asar', 'app.asar.unpacked'));
18961902
}

obs-studio-client/source/nodeobs_service.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ int service::getServiceIdByName(std::string serviceName)
268268
return 0;
269269
} else if (serviceName == "vertical") {
270270
return 1;
271+
} else if (serviceName == "both") {
272+
return 2;
271273
}
272274
return 0;
273275
}

obs-studio-server/source/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ int main(int argc, char *argv[])
212212

213213
// Check versions
214214
if (receivedVersion != myVersion) {
215-
std::cerr << "Versions mismatch. Server version: " << myVersion << "but received client version: " << receivedVersion;
215+
std::cerr << "Versions mismatch. Server version: " << myVersion << " but received client version: " << receivedVersion << std::endl;
216216
return ipc::ProcessInfo::ExitCode::VERSION_MISMATCH;
217217
}
218218

obs-studio-server/source/nodeobs_service.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -193,14 +193,23 @@ void OBS_service::OBS_service_setVideoInfo(void *data, const int64_t id, const s
193193
void OBS_service::OBS_service_startStreaming(void *data, const int64_t id, const std::vector<ipc::value> &args, std::vector<ipc::value> &rval)
194194
{
195195
StreamServiceId serviceid = static_cast<StreamServiceId>(args[0].value_union.i64);
196+
blog(LOG_INFO, "OBS_service_startStreaming - serviceid: %d", serviceid);
197+
198+
bool dualStreamingMode = false;
199+
if (serviceid == StreamServiceId::Both) {
200+
// Both is the special mode than needs to be implemented as a full scale service one day.
201+
// For now for simplicity and compatibility we just fall back to the Main.
202+
serviceid = StreamServiceId::Main;
203+
dualStreamingMode = true;
204+
}
196205

197206
if (isStreamingOutputActive(serviceid)) {
198207
rval.push_back(ipc::value((uint64_t)ErrorCode::Ok));
199208
AUTO_DEBUG;
200209
return;
201210
}
202211

203-
if (!startStreaming(serviceid)) {
212+
if (!startStreaming(serviceid, dualStreamingMode)) {
204213
PRETTY_ERROR_RETURN(ErrorCode::Error, "Failed to start streaming!");
205214
} else {
206215
rval.push_back(ipc::value((uint64_t)ErrorCode::Ok));
@@ -1354,9 +1363,9 @@ bool OBS_service::startSingleTrackStreaming(StreamServiceId serviceId)
13541363
return isStreaming[serviceId];
13551364
}
13561365

1357-
bool OBS_service::startMultiTrackStreaming(StreamServiceId serviceId)
1366+
bool OBS_service::startMultiTrackStreaming(StreamServiceId serviceId, bool dualStreamingMode)
13581367
{
1359-
blog(LOG_INFO, "startMultiTrackStreaming - serviceId: %d", serviceId);
1368+
blog(LOG_INFO, "startMultiTrackStreaming - serviceId: %d, dualStreamingMode: %d", serviceId, (int)dualStreamingMode);
13601369

13611370
const bool is_custom = strncmp("rtmp_custom", obs_service_get_type(services[serviceId]), 11) == 0;
13621371

@@ -1389,7 +1398,7 @@ bool OBS_service::startMultiTrackStreaming(StreamServiceId serviceId)
13891398

13901399
auto vod_track_mixer = IsVodTrackEnabled(services[serviceId]) ? std::optional{vodTrackIndex} : std::nullopt;
13911400

1392-
auto go_live_post = osn::constructGoLivePost(key, std::nullopt, std::nullopt, vod_track_mixer.has_value());
1401+
auto go_live_post = osn::constructGoLivePost(serviceId, dualStreamingMode, key, std::nullopt, std::nullopt, vod_track_mixer.has_value());
13931402
std::optional<osn::Config> go_live_config = osn::DownloadGoLiveConfig(auto_config_url, go_live_post);
13941403
if (!go_live_config.has_value()) {
13951404
throw std::runtime_error("startStreaming - go live config is empty");
@@ -1430,16 +1439,16 @@ bool OBS_service::startMultiTrackStreaming(StreamServiceId serviceId)
14301439
return isStreaming[serviceId];
14311440
}
14321441

1433-
bool OBS_service::startStreaming(StreamServiceId serviceId)
1442+
bool OBS_service::startStreaming(StreamServiceId serviceId, bool dualStreamingMode)
14341443
{
14351444
if (streamingOutput[serviceId]) {
14361445
obs_output_release(streamingOutput[serviceId]);
14371446
streamingOutput[serviceId] = nullptr;
14381447
}
14391448

14401449
try {
1441-
if (isTwitchStream(serviceId) && IsMultitrackVideoEnabled()) {
1442-
return startMultiTrackStreaming(serviceId);
1450+
if (isTwitchStream(serviceId) && (IsMultitrackVideoEnabled() || dualStreamingMode)) {
1451+
return startMultiTrackStreaming(serviceId, dualStreamingMode);
14431452
}
14441453

14451454
return startSingleTrackStreaming(serviceId);

obs-studio-server/source/nodeobs_service.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,12 @@
9191

9292
#define MAX_AUDIO_MIXES 6
9393

94-
enum StreamServiceId : int { Main = 0, Second = 1 };
94+
/*
95+
Main - is a horizontal canvas
96+
Second - is a vertical one
97+
Both - is a little bit special; it soes not create a service, but signals a special streaming mode.
98+
*/
99+
enum StreamServiceId : int { Main = 0, Second = 1, Both = 2 };
95100

96101
class SignalInfo {
97102
private:
@@ -158,9 +163,9 @@ class OBS_service {
158163
static void OBS_service_updateVirtualCam(void *data, const int64_t id, const std::vector<ipc::value> &args, std::vector<ipc::value> &rval);
159164

160165
private:
161-
static bool startStreaming(StreamServiceId serviceId);
166+
static bool startStreaming(StreamServiceId serviceId, bool dualStreamingMode);
162167
static bool startSingleTrackStreaming(StreamServiceId serviceId);
163-
static bool startMultiTrackStreaming(StreamServiceId serviceId);
168+
static bool startMultiTrackStreaming(StreamServiceId serviceId, bool dualStreamingMode);
164169
static void stopStreaming(bool forceStop, StreamServiceId serviceId);
165170
static bool startRecording(void);
166171
static bool startReplayBuffer(void);

obs-studio-server/source/nodeobs_settings.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3898,17 +3898,24 @@ void getDevices(const char *source_id, const char *property_name, std::vector<ip
38983898
obs_data_set_string(settings, "audio_device_id", dummy_device_name);
38993899
}
39003900

3901-
auto props = obs_get_source_properties(source_id);
3901+
// Create a dummy source so that the "device" property can be init
3902+
auto dummy_source = obs_source_create(source_id, dummy_device_name, settings, nullptr);
3903+
if (!dummy_source) {
3904+
obs_data_release(settings);
3905+
return;
3906+
}
3907+
3908+
auto props = obs_source_properties(dummy_source);
39023909
if (!props) {
3910+
obs_source_release(dummy_source);
39033911
obs_data_release(settings);
3904-
blog(LOG_WARNING, "Could not get source properties for source id: %s", source_id);
39053912
return;
39063913
}
39073914

39083915
auto prop = obs_properties_get(props, property_name);
39093916
if (!prop) {
3910-
blog(LOG_WARNING, "Could not get the property [%s] for source id: %s", property_name, source_id);
39113917
obs_properties_destroy(props);
3918+
obs_source_release(dummy_source);
39123919
obs_data_release(settings);
39133920
return;
39143921
}
@@ -3934,6 +3941,7 @@ void getDevices(const char *source_id, const char *property_name, std::vector<ip
39343941

39353942
obs_properties_destroy(props);
39363943
obs_data_release(settings);
3944+
obs_source_release(dummy_source);
39373945
}
39383946

39393947
#ifdef WIN32

obs-studio-server/source/osn-multitrack-video-configuration.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ std::string MultitrackVideoAutoConfigURL(obs_service_t *service)
218218
return url;
219219
}
220220

221-
PostData constructGoLivePost(std::string streamKey, const std::optional<uint64_t> &maximum_aggregate_bitrate,
221+
PostData constructGoLivePost(StreamServiceId serviceId, bool dualStreamingMode, std::string streamKey, const std::optional<uint64_t> &maximum_aggregate_bitrate,
222222
const std::optional<uint32_t> &maximum_video_tracks, bool vod_track_enabled)
223223
{
224224
PostData post_data{};
@@ -258,6 +258,17 @@ PostData constructGoLivePost(std::string streamKey, const std::optional<uint64_t
258258
const size_t contexts = obs_get_video_info_count();
259259
for (size_t i = 0; i < contexts; i++) {
260260
if (obs_get_video_info_by_index(i, &ovi)) {
261+
const bool isHorizontalCanvas = ovi.base_width >= ovi.base_height;
262+
if (!dualStreamingMode && isHorizontalCanvas && serviceId != StreamServiceId::Main) {
263+
blog(LOG_INFO, "constructGoLivePost - skipping horizontal canvas");
264+
continue;
265+
}
266+
267+
if (!dualStreamingMode && !isHorizontalCanvas && serviceId != StreamServiceId::Second) {
268+
blog(LOG_INFO, "constructGoLivePost - skipping vertical canvas");
269+
continue;
270+
}
271+
261272
preferences.canvases.emplace_back(
262273
Canvas{ovi.output_width, ovi.output_height, ovi.base_width, ovi.base_height, {ovi.fps_num, ovi.fps_den}});
263274
}

0 commit comments

Comments
 (0)