diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2fd6952e1..d1561b7d3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,7 +24,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: 30.2.4sl51 + LibOBSVersion: 31.1.2test4 PACKAGE_NAME: osn jobs: @@ -254,22 +254,6 @@ jobs: steps: - name: 'Add msbuild to PATH' uses: microsoft/setup-msbuild@v1 - - name: Install older build components - run: | - # For versions update see here: https://learn.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-build-tools?view=vs-2022 - Set-Location "C:\Program Files (x86)\Microsoft Visual Studio\Installer\" - $InstallPath = "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" - $componentsToInstall= @( - "Microsoft.VisualStudio.Component.VC.v141.x86.x64" - "Microsoft.VisualStudio.Component.VC.14.39.17.9.x86.x64" - "Microsoft.VisualStudio.Component.VC.14.39.17.9.ATL" - ) - [string]$workloadArgs = $componentsToInstall | ForEach-Object {" --add " + $_} - $Arguments = ('/c', "vs_installer.exe", 'modify', '--installPath', "`"$InstallPath`"",$workloadArgs, '--quiet', '--norestart', '--nocache') - # should be run twice - $process = Start-Process -FilePath cmd.exe -ArgumentList $Arguments -Wait -PassThru -WindowStyle Hidden - $process = Start-Process -FilePath cmd.exe -ArgumentList $Arguments -Wait -PassThru -WindowStyle Hidden - shell: powershell - name: 'Checkout' uses: actions/checkout@v3 with: diff --git a/js/module.d.ts b/js/module.d.ts index 2bb3aee9f..3365f441d 100644 --- a/js/module.d.ts +++ b/js/module.d.ts @@ -623,7 +623,6 @@ export interface IVolmeterFactory { create(type: EFaderType): IVolmeter; } export interface IVolmeter { - updateInterval: number; destroy(): void; attach(source: IInput): void; detach(): void; diff --git a/js/module.ts b/js/module.ts index e3c03b84b..68a8d8488 100644 --- a/js/module.ts +++ b/js/module.ts @@ -581,12 +581,12 @@ export interface IGlobal { readonly version: number; /** - * Percentage of CPU being used + * Percentage of CPU being used */ readonly cpuPercentage: number; /** - * Current FPS + * Current FPS */ readonly currentFrameRate: number; @@ -601,7 +601,7 @@ export interface IGlobal { readonly diskSpaceAvailable: number; /** - * Current memory usage + * Current memory usage */ readonly memoryUsage: number; } @@ -1381,11 +1381,6 @@ export interface IVolmeterFactory { * Object representing a volmeter control corresponding to a source. */ export interface IVolmeter { - /** - * The interval at which the volmeter will call the callback. - */ - updateInterval: number; - /** * Destroy the volmeter object object */ diff --git a/obs-studio-client/source/volmeter.cpp b/obs-studio-client/source/volmeter.cpp index d5e0bdc1c..fc32e700e 100644 --- a/obs-studio-client/source/volmeter.cpp +++ b/obs-studio-client/source/volmeter.cpp @@ -77,8 +77,7 @@ Napi::Value osn::Volmeter::Create(const Napi::CallbackInfo &info) if (!ValidateResponse(info, response)) return info.Env().Undefined(); - auto instance = osn::Volmeter::constructor.New({Napi::Number::New(info.Env(), static_cast(response[1].value_union.ui64)), - Napi::Number::New(info.Env(), static_cast(response[2].value_union.ui32))}); + auto instance = osn::Volmeter::constructor.New({Napi::Number::New(info.Env(), static_cast(response[1].value_union.ui64))}); globalCallback::add_volmeter(response[1].value_union.ui64); diff --git a/obs-studio-server/source/nodeobs_api.cpp b/obs-studio-server/source/nodeobs_api.cpp index 34fffa7e9..6ab0e3511 100644 --- a/obs-studio-server/source/nodeobs_api.cpp +++ b/obs-studio-server/source/nodeobs_api.cpp @@ -972,6 +972,18 @@ void OBS_API::OBS_API_initAPI(void *data, const int64_t id, const std::vectornextState(); + while (!g_util_osx->hasInitCef()) { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } +#endif AUTO_DEBUG; } diff --git a/obs-studio-server/source/osn-volmeter.cpp b/obs-studio-server/source/osn-volmeter.cpp index e126567eb..9f6e16ac5 100644 --- a/obs-studio-server/source/osn-volmeter.cpp +++ b/obs-studio-server/source/osn-volmeter.cpp @@ -84,7 +84,6 @@ void osn::Volmeter::Create(void *data, const int64_t id, const std::vectorid)); - rval.push_back(ipc::value(obs_volmeter_get_update_interval(meter->self))); AUTO_DEBUG; } diff --git a/obs-studio-server/source/util-osx-impl.mm b/obs-studio-server/source/util-osx-impl.mm index 8a6e7554d..5d9f09699 100644 --- a/obs-studio-server/source/util-osx-impl.mm +++ b/obs-studio-server/source/util-osx-impl.mm @@ -17,6 +17,7 @@ ******************************************************************************/ #include "util-osx-impl.h" +#include "obs.h" #include #include #include @@ -43,13 +44,13 @@ return; while (true) { - if (!appRunning) { + if (state == UtilObjCInt::EState::Stop) { break; } int ret = ::read(file_descriptor, buffer.data(), count); if (ret > 0) { bool appCrashed = *reinterpret_cast(buffer.data()); - if (appCrashed && appRunning) + if (appCrashed && state != UtilObjCInt::EState::Stop) this->stopApplication(); break; } @@ -86,17 +87,33 @@ @implementation UtilImplObj void UtilObjCInt::runApplication(void) { - worker = new std::thread(&UtilObjCInt::wait_terminate, this); + // Wait for OBS_API_initAPI to be invoked + while (!hasInitApi() && isRunning()) { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + if (isRunning()) { + // Create a dummy source to init obs-browser plugin. Must be init from main thread before [NSApplication run] + obs_source_t *source = obs_source_create("browser_source", "dummy", NULL, NULL); + obs_source_release(source); + nextState(); - @autoreleasepool { - NSApplication *app = [NSApplication sharedApplication]; - appRunning = true; - [app run]; + worker = new std::thread(&UtilObjCInt::wait_terminate, this); + + @autoreleasepool { + NSApplication *app = [NSApplication sharedApplication]; + [app run]; + } } } void UtilObjCInt::stopApplication(void) { + if (!hasInitCef()) { + state = UtilObjCInt::EState::Stop; + return; + } else { + state = UtilObjCInt::EState::Stop; + } dispatch_async(dispatch_get_main_queue(), ^{ [[NSApplication sharedApplication] stop:nil]; NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined @@ -110,12 +127,17 @@ @implementation UtilImplObj data2:0]; [NSApp postEvent:event atStart:TRUE]; - appRunning = false; + state = UtilObjCInt::EState::Stop; if (worker->joinable()) worker->join(); }); } +bool UtilObjCInt::isRunning(void) +{ + return state != UtilObjCInt::EState::Stop; +} + unsigned long long UtilObjCInt::getTotalPhysicalMemory(void) { return [NSProcessInfo processInfo].physicalMemory; @@ -191,4 +213,22 @@ @implementation UtilImplObj return 0; return physical_cores; } + +void UtilObjCInt::nextState(void) +{ + if (state + 1 < UtilObjCInt::EState::Max) { + state = state + 1; + } +} + +bool UtilObjCInt::hasInitApi(void) +{ + return state == UtilObjCInt::EState::InitializedApi; +} + +bool UtilObjCInt::hasInitCef(void) +{ + return state == UtilObjCInt::EState::InitializedCEF; +} + @end diff --git a/obs-studio-server/source/util-osx-int.h b/obs-studio-server/source/util-osx-int.h index b2fd748a4..4f04ee8cc 100644 --- a/obs-studio-server/source/util-osx-int.h +++ b/obs-studio-server/source/util-osx-int.h @@ -32,6 +32,7 @@ class UtilObjCInt { std::string getDefaultVideoSavePath(void); void runApplication(void); void stopApplication(void); + bool isRunning(void); unsigned long long getTotalPhysicalMemory(void); unsigned long long getAvailableMemory(void); std::vector> getAvailableScreenResolutions(void); @@ -40,10 +41,20 @@ class UtilObjCInt { std::string getComputerName(void); int getPhysicalCores(void); void wait_terminate(void); + void nextState(void); + bool hasInitApi(void); + bool hasInitCef(void); private: + enum EState { + Idle = 0, + InitializedApi, // Was initAPI invoked? + InitializedCEF, // Was CefInitialize() invoked? + Stop, + Max + }; void *self; - std::atomic appRunning; + std::atomic state; // See EState enum. Tracks application state std::thread *worker; }; diff --git a/obs-studio-server/source/util-osx.cpp b/obs-studio-server/source/util-osx.cpp index 519111820..ad49a5d6a 100644 --- a/obs-studio-server/source/util-osx.cpp +++ b/obs-studio-server/source/util-osx.cpp @@ -49,6 +49,11 @@ void UtilInt::stopApplication(void) _impl->stopApplication(); } +bool UtilInt::isRunning(void) +{ + return _impl->isRunning(); +} + unsigned long long UtilInt::getTotalPhysicalMemory(void) { return _impl->getTotalPhysicalMemory(); @@ -83,3 +88,18 @@ int UtilInt::getPhysicalCores(void) { return _impl->getPhysicalCores(); } + +void UtilInt::nextState(void) +{ + _impl->nextState(); +} + +bool UtilInt::hasInitApi(void) +{ + return _impl->hasInitApi(); +} + +bool UtilInt::hasInitCef(void) +{ + return _impl->hasInitCef(); +} diff --git a/obs-studio-server/source/util-osx.hpp b/obs-studio-server/source/util-osx.hpp index 01043151d..80cac6227 100644 --- a/obs-studio-server/source/util-osx.hpp +++ b/obs-studio-server/source/util-osx.hpp @@ -33,6 +33,7 @@ class UtilInt { std::string getDefaultVideoSavePath(void); void runApplication(void); void stopApplication(void); + bool isRunning(void); unsigned long long getTotalPhysicalMemory(void); unsigned long long getAvailableMemory(void); std::vector> getAvailableScreenResolutions(void); @@ -40,6 +41,9 @@ class UtilInt { std::string getWorkingDirectory(void); std::string getComputerName(void); int getPhysicalCores(void); + void nextState(void); + bool hasInitApi(void); + bool hasInitCef(void); private: UtilObjCInt *_impl; diff --git a/tests/osn-tests/src/test_osn_input.ts b/tests/osn-tests/src/test_osn_input.ts index fd09763bc..0ee9d8e89 100644 --- a/tests/osn-tests/src/test_osn_input.ts +++ b/tests/osn-tests/src/test_osn_input.ts @@ -81,6 +81,16 @@ describe(testName, () => { }); }); + it('Create Browser source and verify Chromium Embedded Framework (CEF) functionality', () => { + const input = osn.InputFactory.create(EOBSInputTypes.BrowserSource, 'input'); + + // Checking if input source was created correctly + expect(input).to.not.equal(undefined, GetErrorMessage(ETestErrorMsg.CreateInput, EOBSInputTypes.BrowserSource)); + expect(input.id).to.equal(EOBSInputTypes.BrowserSource, GetErrorMessage(ETestErrorMsg.InputId, EOBSInputTypes.BrowserSource)); + expect(input.name).to.equal('input', GetErrorMessage(ETestErrorMsg.InputName, EOBSInputTypes.BrowserSource)); + input.release(); + }); + it('Create all types of input with settings parameter', () => { // Create all input sources available with settings parameter obs.inputTypes.forEach(function(inputType) {