Skip to content

Commit 61f53ee

Browse files
authored
util-osx: init cef before [app run] (#1614)
* Apparently CEF 6533 (obs31.1) is a bit more strict how it is initialized. Now CefInitialize() will be invoked before NSApplication is instantiated.
1 parent e8748b6 commit 61f53ee

File tree

6 files changed

+101
-9
lines changed

6 files changed

+101
-9
lines changed

obs-studio-server/source/nodeobs_api.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,13 @@ void OBS_API::OBS_API_initAPI(void *data, const int64_t id, const std::vector<ip
10491049
rval.push_back(ipc::value((uint64_t)ErrorCode::Ok));
10501050
rval.push_back(ipc::value(OBS_VIDEO_SUCCESS));
10511051

1052+
#if defined(__APPLE__)
1053+
// Block until CEF has been initialized by the main thread.
1054+
g_util_osx->nextState();
1055+
while (!g_util_osx->hasInitCef()) {
1056+
std::this_thread::sleep_for(std::chrono::milliseconds(50));
1057+
}
1058+
#endif
10521059
AUTO_DEBUG;
10531060
}
10541061

obs-studio-server/source/util-osx-impl.mm

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
******************************************************************************/
1818

1919
#include "util-osx-impl.h"
20+
#include "obs.h"
2021
#include <iostream>
2122
#include <unistd.h>
2223
#include <sys/types.h>
@@ -43,13 +44,13 @@
4344
return;
4445

4546
while (true) {
46-
if (!appRunning) {
47+
if (state == UtilObjCInt::EState::Stop) {
4748
break;
4849
}
4950
int ret = ::read(file_descriptor, buffer.data(), count);
5051
if (ret > 0) {
5152
bool appCrashed = *reinterpret_cast<bool *>(buffer.data());
52-
if (appCrashed && appRunning)
53+
if (appCrashed && state != UtilObjCInt::EState::Stop)
5354
this->stopApplication();
5455
break;
5556
}
@@ -86,17 +87,33 @@ @implementation UtilImplObj
8687

8788
void UtilObjCInt::runApplication(void)
8889
{
89-
worker = new std::thread(&UtilObjCInt::wait_terminate, this);
90+
// Wait for OBS_API_initAPI to be invoked
91+
while (!hasInitApi() && isRunning()) {
92+
std::this_thread::sleep_for(std::chrono::milliseconds(50));
93+
}
94+
if (isRunning()) {
95+
// Create a dummy source to init obs-browser plugin. Must be init from main thread before [NSApplication run]
96+
obs_source_t *source = obs_source_create("browser_source", "dummy", NULL, NULL);
97+
obs_source_release(source);
98+
nextState();
9099

91-
@autoreleasepool {
92-
NSApplication *app = [NSApplication sharedApplication];
93-
appRunning = true;
94-
[app run];
100+
worker = new std::thread(&UtilObjCInt::wait_terminate, this);
101+
102+
@autoreleasepool {
103+
NSApplication *app = [NSApplication sharedApplication];
104+
[app run];
105+
}
95106
}
96107
}
97108

98109
void UtilObjCInt::stopApplication(void)
99110
{
111+
if (!hasInitCef()) {
112+
state = UtilObjCInt::EState::Stop;
113+
return;
114+
} else {
115+
state = UtilObjCInt::EState::Stop;
116+
}
100117
dispatch_async(dispatch_get_main_queue(), ^{
101118
[[NSApplication sharedApplication] stop:nil];
102119
NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
@@ -110,12 +127,17 @@ @implementation UtilImplObj
110127
data2:0];
111128
[NSApp postEvent:event atStart:TRUE];
112129

113-
appRunning = false;
130+
state = UtilObjCInt::EState::Stop;
114131
if (worker->joinable())
115132
worker->join();
116133
});
117134
}
118135

136+
bool UtilObjCInt::isRunning(void)
137+
{
138+
return state != UtilObjCInt::EState::Stop;
139+
}
140+
119141
unsigned long long UtilObjCInt::getTotalPhysicalMemory(void)
120142
{
121143
return [NSProcessInfo processInfo].physicalMemory;
@@ -191,4 +213,22 @@ @implementation UtilImplObj
191213
return 0;
192214
return physical_cores;
193215
}
216+
217+
void UtilObjCInt::nextState(void)
218+
{
219+
if (state + 1 < UtilObjCInt::EState::Max) {
220+
state = state + 1;
221+
}
222+
}
223+
224+
bool UtilObjCInt::hasInitApi(void)
225+
{
226+
return state == UtilObjCInt::EState::InitializedApi;
227+
}
228+
229+
bool UtilObjCInt::hasInitCef(void)
230+
{
231+
return state == UtilObjCInt::EState::InitializedCEF;
232+
}
233+
194234
@end

obs-studio-server/source/util-osx-int.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class UtilObjCInt {
3232
std::string getDefaultVideoSavePath(void);
3333
void runApplication(void);
3434
void stopApplication(void);
35+
bool isRunning(void);
3536
unsigned long long getTotalPhysicalMemory(void);
3637
unsigned long long getAvailableMemory(void);
3738
std::vector<std::pair<uint32_t, uint32_t>> getAvailableScreenResolutions(void);
@@ -40,10 +41,20 @@ class UtilObjCInt {
4041
std::string getComputerName(void);
4142
int getPhysicalCores(void);
4243
void wait_terminate(void);
44+
void nextState(void);
45+
bool hasInitApi(void);
46+
bool hasInitCef(void);
4347

4448
private:
49+
enum EState {
50+
Idle = 0,
51+
InitializedApi, // Was initAPI invoked?
52+
InitializedCEF, // Was CefInitialize() invoked?
53+
Stop,
54+
Max
55+
};
4556
void *self;
46-
std::atomic<bool> appRunning;
57+
std::atomic<int> state; // See EState enum. Tracks application state
4758
std::thread *worker;
4859
};
4960

obs-studio-server/source/util-osx.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ void UtilInt::stopApplication(void)
4949
_impl->stopApplication();
5050
}
5151

52+
bool UtilInt::isRunning(void)
53+
{
54+
return _impl->isRunning();
55+
}
56+
5257
unsigned long long UtilInt::getTotalPhysicalMemory(void)
5358
{
5459
return _impl->getTotalPhysicalMemory();
@@ -83,3 +88,18 @@ int UtilInt::getPhysicalCores(void)
8388
{
8489
return _impl->getPhysicalCores();
8590
}
91+
92+
void UtilInt::nextState(void)
93+
{
94+
_impl->nextState();
95+
}
96+
97+
bool UtilInt::hasInitApi(void)
98+
{
99+
return _impl->hasInitApi();
100+
}
101+
102+
bool UtilInt::hasInitCef(void)
103+
{
104+
return _impl->hasInitCef();
105+
}

obs-studio-server/source/util-osx.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,17 @@ class UtilInt {
3333
std::string getDefaultVideoSavePath(void);
3434
void runApplication(void);
3535
void stopApplication(void);
36+
bool isRunning(void);
3637
unsigned long long getTotalPhysicalMemory(void);
3738
unsigned long long getAvailableMemory(void);
3839
std::vector<std::pair<uint32_t, uint32_t>> getAvailableScreenResolutions(void);
3940
std::string getUserDataPath(void);
4041
std::string getWorkingDirectory(void);
4142
std::string getComputerName(void);
4243
int getPhysicalCores(void);
44+
void nextState(void);
45+
bool hasInitApi(void);
46+
bool hasInitCef(void);
4347

4448
private:
4549
UtilObjCInt *_impl;

tests/osn-tests/src/test_osn_input.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ describe(testName, () => {
8181
});
8282
});
8383

84+
it('Create Browser source and verify Chromium Embedded Framework (CEF) functionality', () => {
85+
const input = osn.InputFactory.create(EOBSInputTypes.BrowserSource, 'input');
86+
87+
// Checking if input source was created correctly
88+
expect(input).to.not.equal(undefined, GetErrorMessage(ETestErrorMsg.CreateInput, EOBSInputTypes.BrowserSource));
89+
expect(input.id).to.equal(EOBSInputTypes.BrowserSource, GetErrorMessage(ETestErrorMsg.InputId, EOBSInputTypes.BrowserSource));
90+
expect(input.name).to.equal('input', GetErrorMessage(ETestErrorMsg.InputName, EOBSInputTypes.BrowserSource));
91+
input.release();
92+
});
93+
8494
it('Create all types of input with settings parameter', () => {
8595
// Create all input sources available with settings parameter
8696
obs.inputTypes.forEach(function(inputType) {

0 commit comments

Comments
 (0)