From a825f6d7b39b060bb43d60132d459c8034a031e1 Mon Sep 17 00:00:00 2001 From: Richard Osborne Date: Tue, 18 Nov 2025 17:54:03 -0600 Subject: [PATCH 1/7] add return to stderr (more readable) --- obs-studio-server/source/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/obs-studio-server/source/main.cpp b/obs-studio-server/source/main.cpp index c94e6ab2e..6e7f7b71b 100644 --- a/obs-studio-server/source/main.cpp +++ b/obs-studio-server/source/main.cpp @@ -212,7 +212,7 @@ int main(int argc, char *argv[]) // Check versions if (receivedVersion != myVersion) { - std::cerr << "Versions mismatch. Server version: " << myVersion << "but received client version: " << receivedVersion; + std::cerr << "Versions mismatch. Server version: " << myVersion << " but received client version: " << receivedVersion << std::endl; return ipc::ProcessInfo::ExitCode::VERSION_MISMATCH; } From a8e9cc1bb500e3f0022ff38037269a771fe7193f Mon Sep 17 00:00:00 2001 From: Richard Osborne Date: Wed, 19 Nov 2025 10:54:43 -0600 Subject: [PATCH 2/7] update readme / (mac dev only) fix OBS.app <-> obs-client.node version mismatch * Use obs-client.node included in OBS.app bundle. This way if developer were to update node dependencies etc it wont cause a version mismatch * update readme example to indicate developer has to use an abs path. Cant use ~ for CMAKE_INSTALL_PREFIX --- README.md | 2 +- js/module.js | 115 ++++++++++++++++++++++++++------------------------- js/module.ts | 9 +++- 3 files changed, 67 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 840236ede..169d49e90 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ yarn install git submodule update --init --recursive mkdir build cd build -cmake .. -DCMAKE_INSTALL_PREFIX=~/streamlabs/desktop/node_modules/obs-studio-node/OSN.app/distribute/obs-studio-node -DCMAKE_OSX_ARCHITECTURES=arm64 -G Xcode +cmake .. -DCMAKE_INSTALL_PREFIX=/Users//streamlabs/desktop/node_modules/obs-studio-node/OSN.app/distribute/obs-studio-node -DCMAKE_OSX_ARCHITECTURES=arm64 -G Xcode cmake --build . --target install --config RelWithDebInfo ``` 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. diff --git a/js/module.js b/js/module.js index e90a2c339..89ca7e0c9 100644 --- a/js/module.js +++ b/js/module.js @@ -1,49 +1,50 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -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; -const obs = require('./obs_studio_client.node'); -const path = require("path"); -const fs = require("fs"); -exports.DefaultD3D11Path = path.resolve(__dirname, `libobs-d3d11.dll`); -exports.DefaultOpenGLPath = path.resolve(__dirname, `libobs-opengl.dll`); -exports.DefaultDrawPluginPath = path.resolve(__dirname, `simple_draw.dll`); -exports.DefaultBinPath = path.resolve(__dirname); -exports.DefaultDataPath = path.resolve(__dirname, `data`); -exports.DefaultPluginPath = path.resolve(__dirname, `obs-plugins`); -exports.DefaultPluginDataPath = path.resolve(__dirname, `data/obs-plugins/%module%`); -exports.DefaultPluginPathMac = path.resolve(__dirname, `PlugIns`); -exports.Global = obs.Global; -exports.Video = obs.Video; -exports.VideoFactory = obs.Video; -exports.InputFactory = obs.Input; -exports.SceneFactory = obs.Scene; -exports.FilterFactory = obs.Filter; -exports.TransitionFactory = obs.Transition; -exports.DisplayFactory = obs.Display; -exports.VolmeterFactory = obs.Volmeter; -exports.FaderFactory = obs.Fader; -exports.Audio = obs.Audio; -exports.AudioFactory = obs.Audio; -exports.ModuleFactory = obs.Module; -exports.IPC = obs.IPC; -exports.VideoEncoderFactory = obs.VideoEncoder; -exports.ServiceFactory = obs.Service; -exports.SimpleStreamingFactory = obs.SimpleStreaming; -exports.AdvancedStreamingFactory = obs.AdvancedStreaming; -exports.DelayFactory = obs.Delay; -exports.ReconnectFactory = obs.Reconnect; -exports.NetworkFactory = obs.Network; -exports.AudioTrackFactory = obs.AudioTrack; -exports.SimpleRecordingFactory = obs.SimpleRecording; -exports.AdvancedRecordingFactory = obs.AdvancedRecording; -exports.AudioEncoderFactory = obs.AudioEncoder; -exports.SimpleReplayBufferFactory = obs.SimpleReplayBuffer; -exports.AdvancedReplayBufferFactory = obs.AdvancedReplayBuffer; +import * as path from 'path'; +import * as fs from 'fs'; +const hasDeveloperApp = fs.existsSync(path.join(__dirname, 'OSN.app')); // search for local developer OSN.app bundle which stores CEF helper apps, etc +const obs = hasDeveloperApp + ? require('./OSN.app/distribute/obs-studio-node/obs_studio_client.node') + : require('./obs_studio_client.node'); +/* Convenient paths to modules */ +export const DefaultD3D11Path = path.resolve(__dirname, `libobs-d3d11.dll`); +export const DefaultOpenGLPath = path.resolve(__dirname, `libobs-opengl.dll`); +export const DefaultDrawPluginPath = path.resolve(__dirname, `simple_draw.dll`); +export const DefaultBinPath = path.resolve(__dirname); +export const DefaultDataPath = path.resolve(__dirname, `data`); +export const DefaultPluginPath = path.resolve(__dirname, `obs-plugins`); +export const DefaultPluginDataPath = path.resolve(__dirname, `data/obs-plugins/%module%`); +export const DefaultPluginPathMac = path.resolve(__dirname, `PlugIns`); +export const Global = obs.Global; +export const Video = obs.Video; +export const VideoFactory = obs.Video; +export const InputFactory = obs.Input; +export const SceneFactory = obs.Scene; +export const FilterFactory = obs.Filter; +export const TransitionFactory = obs.Transition; +export const DisplayFactory = obs.Display; +export const VolmeterFactory = obs.Volmeter; +export const FaderFactory = obs.Fader; +export const Audio = obs.Audio; +export const AudioFactory = obs.Audio; +export const ModuleFactory = obs.Module; +export const IPC = obs.IPC; +export const VideoEncoderFactory = obs.VideoEncoder; +export const ServiceFactory = obs.Service; +export const SimpleStreamingFactory = obs.SimpleStreaming; +export const AdvancedStreamingFactory = obs.AdvancedStreaming; +export const DelayFactory = obs.Delay; +export const ReconnectFactory = obs.Reconnect; +export const NetworkFactory = obs.Network; +export const AudioTrackFactory = obs.AudioTrack; +export const SimpleRecordingFactory = obs.SimpleRecording; +export const AdvancedRecordingFactory = obs.AdvancedRecording; +export const AudioEncoderFactory = obs.AudioEncoder; +export const SimpleReplayBufferFactory = obs.SimpleReplayBuffer; +export const AdvancedReplayBufferFactory = obs.AdvancedReplayBuffer; ; ; ; ; -function addItems(scene, sceneItems) { +export function addItems(scene, sceneItems) { const items = []; if (Array.isArray(sceneItems)) { sceneItems.forEach(function (sceneItem) { @@ -54,19 +55,18 @@ function addItems(scene, sceneItems) { } return items; } -exports.addItems = addItems; -function createSources(sources) { +export function createSources(sources) { const items = []; if (Array.isArray(sources)) { sources.forEach(function (source) { let newSource = null; try { newSource = obs.Input.create(source.type, source.name, source.settings); - } catch (error) { + } + catch (error) { console.error(`[OSN] Failed to create input for source "${source.name}":`, error instanceof Error ? error.message : error); return; // Skip the rest of this iteration if input creation fails } - if (newSource) { if (newSource.audioMixers) { newSource.muted = source.muted ?? false; @@ -76,17 +76,16 @@ function createSources(sources) { newSource.deinterlaceMode = source.deinterlaceMode; newSource.deinterlaceFieldOrder = source.deinterlaceFieldOrder; items.push(newSource); - const filters = source.filters; if (Array.isArray(filters)) { filters.forEach(function (filter) { let ObsFilter = null; try { ObsFilter = obs.Filter.create(filter.type, filter.name, filter.settings); - } catch (filterError) { + } + catch (filterError) { console.error(`[OSN] Failed to create filter "${filter.name}" for source "${source.name}":`, filterError instanceof Error ? filterError.message : filterError); } - if (ObsFilter) { ObsFilter.enabled = filter.enabled ?? true; newSource.addFilter(ObsFilter); @@ -94,17 +93,18 @@ function createSources(sources) { } }); } - } else { + } + else { console.warn(`[OSN] Input creation failed for source: ${source.name}`); } }); - } else { + } + else { console.error(`[OSN] Invalid sources array provided:`, sources); } return items; } -exports.createSources = createSources; -function getSourcesSize(sourcesNames) { +export function getSourcesSize(sourcesNames) { const sourcesSize = []; if (Array.isArray(sourcesNames)) { sourcesNames.forEach(function (sourceName) { @@ -116,8 +116,11 @@ function getSourcesSize(sourcesNames) { } return sourcesSize; } -exports.getSourcesSize = getSourcesSize; -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 +; +// Initialization and other stuff which needs local data. +const __dirnameApple = hasDeveloperApp + ? path.join(__dirname, 'OSN.app', 'distribute', 'obs-studio-node', 'bin') + : path.join(__dirname, 'bin'); if (fs.existsSync(path.resolve(__dirnameApple).replace('app.asar', 'app.asar.unpacked'))) { obs.IPC.setServerPath(path.resolve(__dirnameApple, `obs64`).replace('app.asar', 'app.asar.unpacked'), path.resolve(__dirnameApple).replace('app.asar', 'app.asar.unpacked')); } @@ -127,4 +130,4 @@ else if (fs.existsSync(path.resolve(__dirname, `obs64.exe`).replace('app.asar', else { obs.IPC.setServerPath(path.resolve(__dirname, `obs32.exe`).replace('app.asar', 'app.asar.unpacked'), path.resolve(__dirname).replace('app.asar', 'app.asar.unpacked')); } -exports.NodeObs = obs; +export const NodeObs = obs; diff --git a/js/module.ts b/js/module.ts index 1712cfc67..824f2d0da 100644 --- a/js/module.ts +++ b/js/module.ts @@ -1,6 +1,9 @@ -const obs = require('./obs_studio_client.node'); import * as path from 'path'; import * as fs from 'fs'; +const hasDeveloperApp = fs.existsSync(path.join(__dirname, 'OSN.app')); // search for local developer OSN.app bundle which stores CEF helper apps, etc +const obs = hasDeveloperApp + ? require('./OSN.app/distribute/obs-studio-node/obs_studio_client.node') + : require('./obs_studio_client.node'); /* Convenient paths to modules */ export const DefaultD3D11Path: string = @@ -1895,7 +1898,9 @@ export const enum VCamOutputType { }; // Initialization and other stuff which needs local data. -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 +const __dirnameApple = hasDeveloperApp + ? path.join(__dirname, 'OSN.app', 'distribute', 'obs-studio-node', 'bin') + : path.join(__dirname, 'bin'); if (fs.existsSync(path.resolve(__dirnameApple).replace('app.asar', 'app.asar.unpacked'))) { obs.IPC.setServerPath(path.resolve(__dirnameApple, `obs64`).replace('app.asar', 'app.asar.unpacked'), path.resolve(__dirnameApple).replace('app.asar', 'app.asar.unpacked')); } From f9f10dfb9fcf28e6a36c1d6606538bbf69b91d53 Mon Sep 17 00:00:00 2001 From: Richard Osborne Date: Wed, 19 Nov 2025 18:03:43 -0600 Subject: [PATCH 3/7] revert js/module.js change --- js/module.js | 115 +++++++++++++++++++++++++-------------------------- 1 file changed, 56 insertions(+), 59 deletions(-) diff --git a/js/module.js b/js/module.js index 89ca7e0c9..e90a2c339 100644 --- a/js/module.js +++ b/js/module.js @@ -1,50 +1,49 @@ -import * as path from 'path'; -import * as fs from 'fs'; -const hasDeveloperApp = fs.existsSync(path.join(__dirname, 'OSN.app')); // search for local developer OSN.app bundle which stores CEF helper apps, etc -const obs = hasDeveloperApp - ? require('./OSN.app/distribute/obs-studio-node/obs_studio_client.node') - : require('./obs_studio_client.node'); -/* Convenient paths to modules */ -export const DefaultD3D11Path = path.resolve(__dirname, `libobs-d3d11.dll`); -export const DefaultOpenGLPath = path.resolve(__dirname, `libobs-opengl.dll`); -export const DefaultDrawPluginPath = path.resolve(__dirname, `simple_draw.dll`); -export const DefaultBinPath = path.resolve(__dirname); -export const DefaultDataPath = path.resolve(__dirname, `data`); -export const DefaultPluginPath = path.resolve(__dirname, `obs-plugins`); -export const DefaultPluginDataPath = path.resolve(__dirname, `data/obs-plugins/%module%`); -export const DefaultPluginPathMac = path.resolve(__dirname, `PlugIns`); -export const Global = obs.Global; -export const Video = obs.Video; -export const VideoFactory = obs.Video; -export const InputFactory = obs.Input; -export const SceneFactory = obs.Scene; -export const FilterFactory = obs.Filter; -export const TransitionFactory = obs.Transition; -export const DisplayFactory = obs.Display; -export const VolmeterFactory = obs.Volmeter; -export const FaderFactory = obs.Fader; -export const Audio = obs.Audio; -export const AudioFactory = obs.Audio; -export const ModuleFactory = obs.Module; -export const IPC = obs.IPC; -export const VideoEncoderFactory = obs.VideoEncoder; -export const ServiceFactory = obs.Service; -export const SimpleStreamingFactory = obs.SimpleStreaming; -export const AdvancedStreamingFactory = obs.AdvancedStreaming; -export const DelayFactory = obs.Delay; -export const ReconnectFactory = obs.Reconnect; -export const NetworkFactory = obs.Network; -export const AudioTrackFactory = obs.AudioTrack; -export const SimpleRecordingFactory = obs.SimpleRecording; -export const AdvancedRecordingFactory = obs.AdvancedRecording; -export const AudioEncoderFactory = obs.AudioEncoder; -export const SimpleReplayBufferFactory = obs.SimpleReplayBuffer; -export const AdvancedReplayBufferFactory = obs.AdvancedReplayBuffer; +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +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; +const obs = require('./obs_studio_client.node'); +const path = require("path"); +const fs = require("fs"); +exports.DefaultD3D11Path = path.resolve(__dirname, `libobs-d3d11.dll`); +exports.DefaultOpenGLPath = path.resolve(__dirname, `libobs-opengl.dll`); +exports.DefaultDrawPluginPath = path.resolve(__dirname, `simple_draw.dll`); +exports.DefaultBinPath = path.resolve(__dirname); +exports.DefaultDataPath = path.resolve(__dirname, `data`); +exports.DefaultPluginPath = path.resolve(__dirname, `obs-plugins`); +exports.DefaultPluginDataPath = path.resolve(__dirname, `data/obs-plugins/%module%`); +exports.DefaultPluginPathMac = path.resolve(__dirname, `PlugIns`); +exports.Global = obs.Global; +exports.Video = obs.Video; +exports.VideoFactory = obs.Video; +exports.InputFactory = obs.Input; +exports.SceneFactory = obs.Scene; +exports.FilterFactory = obs.Filter; +exports.TransitionFactory = obs.Transition; +exports.DisplayFactory = obs.Display; +exports.VolmeterFactory = obs.Volmeter; +exports.FaderFactory = obs.Fader; +exports.Audio = obs.Audio; +exports.AudioFactory = obs.Audio; +exports.ModuleFactory = obs.Module; +exports.IPC = obs.IPC; +exports.VideoEncoderFactory = obs.VideoEncoder; +exports.ServiceFactory = obs.Service; +exports.SimpleStreamingFactory = obs.SimpleStreaming; +exports.AdvancedStreamingFactory = obs.AdvancedStreaming; +exports.DelayFactory = obs.Delay; +exports.ReconnectFactory = obs.Reconnect; +exports.NetworkFactory = obs.Network; +exports.AudioTrackFactory = obs.AudioTrack; +exports.SimpleRecordingFactory = obs.SimpleRecording; +exports.AdvancedRecordingFactory = obs.AdvancedRecording; +exports.AudioEncoderFactory = obs.AudioEncoder; +exports.SimpleReplayBufferFactory = obs.SimpleReplayBuffer; +exports.AdvancedReplayBufferFactory = obs.AdvancedReplayBuffer; ; ; ; ; -export function addItems(scene, sceneItems) { +function addItems(scene, sceneItems) { const items = []; if (Array.isArray(sceneItems)) { sceneItems.forEach(function (sceneItem) { @@ -55,18 +54,19 @@ export function addItems(scene, sceneItems) { } return items; } -export function createSources(sources) { +exports.addItems = addItems; +function createSources(sources) { const items = []; if (Array.isArray(sources)) { sources.forEach(function (source) { let newSource = null; try { newSource = obs.Input.create(source.type, source.name, source.settings); - } - catch (error) { + } catch (error) { console.error(`[OSN] Failed to create input for source "${source.name}":`, error instanceof Error ? error.message : error); return; // Skip the rest of this iteration if input creation fails } + if (newSource) { if (newSource.audioMixers) { newSource.muted = source.muted ?? false; @@ -76,16 +76,17 @@ export function createSources(sources) { newSource.deinterlaceMode = source.deinterlaceMode; newSource.deinterlaceFieldOrder = source.deinterlaceFieldOrder; items.push(newSource); + const filters = source.filters; if (Array.isArray(filters)) { filters.forEach(function (filter) { let ObsFilter = null; try { ObsFilter = obs.Filter.create(filter.type, filter.name, filter.settings); - } - catch (filterError) { + } catch (filterError) { console.error(`[OSN] Failed to create filter "${filter.name}" for source "${source.name}":`, filterError instanceof Error ? filterError.message : filterError); } + if (ObsFilter) { ObsFilter.enabled = filter.enabled ?? true; newSource.addFilter(ObsFilter); @@ -93,18 +94,17 @@ export function createSources(sources) { } }); } - } - else { + } else { console.warn(`[OSN] Input creation failed for source: ${source.name}`); } }); - } - else { + } else { console.error(`[OSN] Invalid sources array provided:`, sources); } return items; } -export function getSourcesSize(sourcesNames) { +exports.createSources = createSources; +function getSourcesSize(sourcesNames) { const sourcesSize = []; if (Array.isArray(sourcesNames)) { sourcesNames.forEach(function (sourceName) { @@ -116,11 +116,8 @@ export function getSourcesSize(sourcesNames) { } return sourcesSize; } -; -// Initialization and other stuff which needs local data. -const __dirnameApple = hasDeveloperApp - ? path.join(__dirname, 'OSN.app', 'distribute', 'obs-studio-node', 'bin') - : path.join(__dirname, 'bin'); +exports.getSourcesSize = getSourcesSize; +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 if (fs.existsSync(path.resolve(__dirnameApple).replace('app.asar', 'app.asar.unpacked'))) { obs.IPC.setServerPath(path.resolve(__dirnameApple, `obs64`).replace('app.asar', 'app.asar.unpacked'), path.resolve(__dirnameApple).replace('app.asar', 'app.asar.unpacked')); } @@ -130,4 +127,4 @@ else if (fs.existsSync(path.resolve(__dirname, `obs64.exe`).replace('app.asar', else { obs.IPC.setServerPath(path.resolve(__dirname, `obs32.exe`).replace('app.asar', 'app.asar.unpacked'), path.resolve(__dirname).replace('app.asar', 'app.asar.unpacked')); } -export const NodeObs = obs; +exports.NodeObs = obs; From ed4cfd54cc546c78d709a0a5b6bded6654ad7010 Mon Sep 17 00:00:00 2001 From: Richard Osborne Date: Wed, 19 Nov 2025 18:06:20 -0600 Subject: [PATCH 4/7] manual update js/module.js --- js/module.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/js/module.js b/js/module.js index e90a2c339..03d1ba19c 100644 --- a/js/module.js +++ b/js/module.js @@ -1,9 +1,12 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 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; -const obs = require('./obs_studio_client.node'); const path = require("path"); const fs = require("fs"); +const hasDeveloperApp = fs.existsSync(path.join(__dirname, 'OSN.app')); // search for local developer OSN.app bundle which stores CEF helper apps, etc +const obs = hasDeveloperApp + ? require('./OSN.app/distribute/obs-studio-node/obs_studio_client.node') + : require('./obs_studio_client.node'); exports.DefaultD3D11Path = path.resolve(__dirname, `libobs-d3d11.dll`); exports.DefaultOpenGLPath = path.resolve(__dirname, `libobs-opengl.dll`); exports.DefaultDrawPluginPath = path.resolve(__dirname, `simple_draw.dll`); @@ -117,7 +120,9 @@ function getSourcesSize(sourcesNames) { return sourcesSize; } exports.getSourcesSize = getSourcesSize; -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 +const __dirnameApple = hasDeveloperApp + ? path.join(__dirname, 'OSN.app', 'distribute', 'obs-studio-node', 'bin') + : path.join(__dirname, 'bin'); if (fs.existsSync(path.resolve(__dirnameApple).replace('app.asar', 'app.asar.unpacked'))) { obs.IPC.setServerPath(path.resolve(__dirnameApple, `obs64`).replace('app.asar', 'app.asar.unpacked'), path.resolve(__dirnameApple).replace('app.asar', 'app.asar.unpacked')); } From 0f8d9867e5ede5048ad66bbb1f6553e2ff63d138 Mon Sep 17 00:00:00 2001 From: Richard Osborne Date: Thu, 20 Nov 2025 08:53:24 -0600 Subject: [PATCH 5/7] update note to specify yarn package:mac-arm64 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 169d49e90..7569ae22a 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ cd build cmake .. -DCMAKE_INSTALL_PREFIX=/Users//streamlabs/desktop/node_modules/obs-studio-node/OSN.app/distribute/obs-studio-node -DCMAKE_OSX_ARCHITECTURES=arm64 -G Xcode cmake --build . --target install --config RelWithDebInfo ``` -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. +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. ### Custom OBS Build 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. From 6f290e96810c7216db89ce2cf095e508606397e6 Mon Sep 17 00:00:00 2001 From: Richard Osborne Date: Thu, 20 Nov 2025 11:26:11 -0600 Subject: [PATCH 6/7] update comment about Google Chromium requirement & filter for macos only * filter for macos (optional but makes code more explicit) --- js/module.js | 3 ++- js/module.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/js/module.js b/js/module.js index 03d1ba19c..201946786 100644 --- a/js/module.js +++ b/js/module.js @@ -3,7 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); 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; const path = require("path"); const fs = require("fs"); -const hasDeveloperApp = fs.existsSync(path.join(__dirname, 'OSN.app')); // search for local developer OSN.app bundle which stores CEF helper apps, etc +// Mac- search for optional OSN.app bundle (Chromium requires an app bundle to finder helper apps) +const hasDeveloperApp = process.platform === 'darwin' && fs.existsSync(path.join(__dirname, 'OSN.app')); const obs = hasDeveloperApp ? require('./OSN.app/distribute/obs-studio-node/obs_studio_client.node') : require('./obs_studio_client.node'); diff --git a/js/module.ts b/js/module.ts index 824f2d0da..bb23034c9 100644 --- a/js/module.ts +++ b/js/module.ts @@ -1,6 +1,7 @@ import * as path from 'path'; import * as fs from 'fs'; -const hasDeveloperApp = fs.existsSync(path.join(__dirname, 'OSN.app')); // search for local developer OSN.app bundle which stores CEF helper apps, etc +// Mac- search for optional OSN.app bundle (Chromium requires an app bundle to finder helper apps) +const hasDeveloperApp = process.platform === 'darwin' && fs.existsSync(path.join(__dirname, 'OSN.app')); const obs = hasDeveloperApp ? require('./OSN.app/distribute/obs-studio-node/obs_studio_client.node') : require('./obs_studio_client.node'); From f8beba48cddd95427a24370fad63537dc2f30eec Mon Sep 17 00:00:00 2001 From: Richard Osborne Date: Thu, 20 Nov 2025 13:41:41 -0600 Subject: [PATCH 7/7] fix typo in comment --- js/module.js | 2 +- js/module.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/module.js b/js/module.js index 201946786..9ca431d08 100644 --- a/js/module.js +++ b/js/module.js @@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); 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; const path = require("path"); const fs = require("fs"); -// Mac- search for optional OSN.app bundle (Chromium requires an app bundle to finder helper apps) +// Mac- search for optional OSN.app bundle (Chromium requires an app bundle to find obs64 helper apps) const hasDeveloperApp = process.platform === 'darwin' && fs.existsSync(path.join(__dirname, 'OSN.app')); const obs = hasDeveloperApp ? require('./OSN.app/distribute/obs-studio-node/obs_studio_client.node') diff --git a/js/module.ts b/js/module.ts index bb23034c9..e3c03b84b 100644 --- a/js/module.ts +++ b/js/module.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import * as fs from 'fs'; -// Mac- search for optional OSN.app bundle (Chromium requires an app bundle to finder helper apps) +// Mac- search for optional OSN.app bundle (Chromium requires an app bundle to find obs64 helper apps) const hasDeveloperApp = process.platform === 'darwin' && fs.existsSync(path.join(__dirname, 'OSN.app')); const obs = hasDeveloperApp ? require('./OSN.app/distribute/obs-studio-node/obs_studio_client.node')