Skip to content

Commit 5f8807e

Browse files
Merged branch staging into obs_merge_31.0.3
2 parents dbca11d + 1d2e50d commit 5f8807e

File tree

13 files changed

+146
-52
lines changed

13 files changed

+146
-52
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ env:
2222
SLGenerator: Visual Studio 17 2022
2323
SLDistributeDirectory: distribute
2424
SLFullDistributePath: "streamlabs-build.app/distribute" # The .app extension is required to run macOS tests correctly.
25-
LibOBSVersion: 31.0.3test3
25+
LibOBSVersion: 31.0.3test4
2626
PACKAGE_NAME: osn
2727

2828
jobs:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ test-results.xml
1818
*.opendb
1919
docs/
2020
/*.log
21+
.vscode/
2122
streamlabs-build.app
2223

2324
tests/osn-tests/*-cache-local.zip

obs-studio-client/source/nodeobs_service.cpp

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
//#include <node.h>
2828
#include <sstream>
2929
#include <string>
30+
#include <fstream>
3031
#include "shared.hpp"
3132
#include "utility.hpp"
3233
#include "video.hpp"
@@ -420,6 +421,7 @@ Napi::Value service::OBS_service_updateVirtualCam(const Napi::CallbackInfo &info
420421

421422
Napi::Value service::OBS_service_installVirtualCamPlugin(const Napi::CallbackInfo &info)
422423
{
424+
bool isInstalled = true;
423425
#ifdef WIN32
424426
SHELLEXECUTEINFO ShExecInfo = {0};
425427
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
@@ -445,9 +447,9 @@ Napi::Value service::OBS_service_installVirtualCamPlugin(const Napi::CallbackInf
445447
WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
446448
CloseHandle(ShExecInfo.hProcess);
447449
#elif __APPLE__
448-
return OBS_service_createVirtualCam(info);
450+
isInstalled = g_util_osx->installPlugin();
449451
#endif
450-
return info.Env().Undefined();
452+
return Napi::Boolean::New(info.Env(), isInstalled);
451453
}
452454

453455
Napi::Value service::OBS_service_uninstallVirtualCamPlugin(const Napi::CallbackInfo &info)
@@ -477,9 +479,7 @@ Napi::Value service::OBS_service_uninstallVirtualCamPlugin(const Napi::CallbackI
477479
WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
478480
CloseHandle(ShExecInfo.hProcess);
479481
#elif __APPLE__
480-
// User must manually uninstall the Apple SystemExtension (new obs-virtualcam)
481-
// but we can uninstall the legacy DAL plugin if its there.
482-
g_util_osx->uninstallPlugin(); // uninstall legacy plugin
482+
g_util_osx->uninstallPlugin();
483483
#endif
484484
return info.Env().Undefined();
485485
}
@@ -490,20 +490,45 @@ Napi::Value service::OBS_service_isVirtualCamPluginInstalled(const Napi::Callbac
490490
HKEY OpenResult;
491491
LONG error;
492492

493-
error = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"CLSID\\{27B05C2D-93DC-474A-A5DA-9BBA34CB2A9C}", 0, KEY_READ | KEY_WOW64_64KEY, &OpenResult);
493+
const char *prefix = "CLSID\\{";
494+
std::string line = "";
495+
std::string guid = "";
496+
size_t pos = 0;
497+
size_t endPos = 0;
498+
499+
//open install file and search for the correct GUID
500+
std::wstring batPath = utfWorkingDir + L"\\data\\obs-plugins\\win-dshow\\virtualcam-install.bat";
501+
std::ifstream batFile(batPath.c_str());
502+
if (batFile.is_open()) {
503+
while (std::getline(batFile, line)) {
504+
pos = line.find(prefix);
505+
if (pos != std::string::npos) {
506+
pos += strlen(prefix);
507+
endPos = line.find("}");
508+
guid = line.substr(pos, endPos - pos);
509+
guid.insert(0, prefix);
510+
guid.append("}");
511+
break;
512+
}
513+
}
514+
batFile.close();
515+
}
516+
517+
std::wstring wideGUID(from_utf8_to_utf16_wide(guid.c_str()));
518+
error = RegOpenKeyEx(HKEY_CLASSES_ROOT, wideGUID.c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &OpenResult);
494519
if (error != ERROR_SUCCESS) {
495520
return Napi::Number::New(info.Env(), VcamInstalledStatus::NotInstalled);
496521
}
497522

498-
error = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"CLSID\\{27B05C2D-93DC-474A-A5DA-9BBA34CB2A9C}", 0, KEY_READ | KEY_WOW64_32KEY, &OpenResult);
523+
error = RegOpenKeyEx(HKEY_CLASSES_ROOT, wideGUID.c_str(), 0, KEY_READ | KEY_WOW64_32KEY, &OpenResult);
499524
if (error != ERROR_SUCCESS) {
500525
return Napi::Number::New(info.Env(), VcamInstalledStatus::NotInstalled);
501526
}
502527

503528
DWORD dwRet = 0;
504529
TCHAR buf[TOTALBYTES] = {0};
505530
DWORD dwBufSize = sizeof(buf);
506-
error = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"CLSID\\{27B05C2D-93DC-474A-A5DA-9BBA34CB2A9C}\\InprocServer32", 0, KEY_READ | KEY_QUERY_VALUE, &OpenResult);
531+
error = RegOpenKeyEx(HKEY_CLASSES_ROOT, wideGUID.c_str(), 0, KEY_READ | KEY_QUERY_VALUE, &OpenResult);
507532
if (error == ERROR_SUCCESS && OpenResult) {
508533
dwRet = RegQueryValueExW(OpenResult, TEXT(""), NULL, NULL, (LPBYTE)buf, &dwBufSize);
509534
if (dwRet == ERROR_SUCCESS) {

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

Lines changed: 89 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,85 @@
2121

2222
std::string g_server_working_dir;
2323

24+
void uninstallLegacyDALPlugin()
25+
{
26+
@try {
27+
NSDictionary *error = [NSDictionary dictionary];
28+
std::string cmd = "do shell script \"rm -rf /Library/CoreMediaIO/Plug-Ins/DAL/vcam-plugin.plugin \" with administrator privileges";
29+
30+
NSString *script = [NSString stringWithCString:cmd.c_str() encoding:[NSString defaultCStringEncoding]];
31+
NSAppleScript *run = [[NSAppleScript alloc] initWithSource:script];
32+
[run executeAndReturnError:&error];
33+
NSLog(@"errors: %@", error);
34+
} @catch (NSException *exception) {
35+
std::cout << "Caught an NSException!" << std::endl;
36+
std::cout << "Name: " << [[exception name] UTF8String] << std::endl;
37+
std::cout << "Reason: " << [[exception reason] UTF8String] << std::endl;
38+
}
39+
}
40+
41+
bool executeTaskAndCaptureOutput(const std::string &path, NSArray<NSString *> *exeArguments = nullptr)
42+
{
43+
bool success = true;
44+
@autoreleasepool {
45+
@try {
46+
// Create an NSTask instance
47+
NSTask *task = [[NSTask alloc] init];
48+
49+
// Set the launch path (program to execute)
50+
NSString *exePath = [NSString stringWithCString:path.c_str() encoding:[NSString defaultCStringEncoding]];
51+
task.launchPath = exePath; // Command (e.g., "ls")
52+
if (exeArguments && exeArguments.count > 0) {
53+
task.arguments = exeArguments;
54+
}
55+
56+
// Set up a pipe to capture the output
57+
NSPipe *outputPipe = [NSPipe pipe];
58+
task.standardOutput = outputPipe; // Redirect standard output to the pipe
59+
task.standardError = outputPipe; // Optional: Redirect errors as well
60+
61+
[task launch];
62+
[task waitUntilExit];
63+
64+
int exitCode = [task terminationStatus];
65+
66+
// Read the data from the pipe
67+
NSFileHandle *readHandle = [outputPipe fileHandleForReading];
68+
NSData *outputData = [readHandle readDataToEndOfFile];
69+
70+
// Convert the data to a string
71+
NSString *outputString = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding];
72+
73+
// Print the captured output
74+
std::cout << "Child process output:\n" << [outputString UTF8String] << std::endl;
75+
std::cout << "Child process exited with code: " << exitCode << std::endl;
76+
} @catch (NSException *exception) {
77+
std::cout << "Caught an NSException!" << std::endl;
78+
std::cout << "Name: " << [[exception name] UTF8String] << std::endl;
79+
std::cout << "Reason: " << [[exception reason] UTF8String] << std::endl;
80+
success = false;
81+
}
82+
}
83+
return success;
84+
}
85+
86+
// In our app bundle, we will search for the slobs-virtual-cam-installer.app which
87+
// exclusively handles installing/uninstalling the mac camera system extension.
88+
std::string getInstallerAppPath()
89+
{
90+
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
91+
std::string app_framework_path = bundlePath.UTF8String;
92+
char delimiter = '/';
93+
94+
size_t last_occurrence_pos = app_framework_path.rfind(delimiter);
95+
96+
if (last_occurrence_pos != std::string::npos) {
97+
app_framework_path.erase(last_occurrence_pos + 1); // Erase from after the delimiter
98+
}
99+
app_framework_path += "slobs-virtual-cam-installer.app/Contents/MacOS/slobs-virtual-cam-installer";
100+
return app_framework_path;
101+
}
102+
24103
@implementation UtilImplObj
25104

26105
UtilObjCInt::UtilObjCInt(void) : self(NULL) {}
@@ -90,32 +169,19 @@ bool replace(std::string &str, const std::string &from, const std::string &to)
90169
return true;
91170
}
92171

93-
void UtilObjCInt::installPlugin()
172+
bool UtilObjCInt::installPlugin()
94173
{
95-
NSDictionary *error = [NSDictionary dictionary];
96-
std::string pathToScript = g_server_working_dir + "/data/obs-plugins/slobs-virtual-cam/install-plugin.sh";
97-
std::cout << "launching: " << pathToScript.c_str() << std::endl;
98-
99-
replace(pathToScript, " ", "\\\\ ");
100-
std::string arg = g_server_working_dir + "/data/obs-plugins/slobs-virtual-cam";
101-
replace(arg, " ", "\\\\ ");
102-
std::string cmd = "do shell script \"/bin/sh " + pathToScript + " " + arg + "\" with administrator privileges";
103-
104-
NSString *script = [NSString stringWithCString:cmd.c_str() encoding:[NSString defaultCStringEncoding]];
105-
NSAppleScript *run = [[NSAppleScript alloc] initWithSource:script];
106-
[run executeAndReturnError:&error];
107-
NSLog(@"errors: %@", error);
174+
const std::string path = getInstallerAppPath();
175+
return executeTaskAndCaptureOutput(path); // Run the installer
108176
}
109177

110178
void UtilObjCInt::uninstallPlugin()
111179
{
112-
NSDictionary *error = [NSDictionary dictionary];
113-
std::string cmd = "do shell script \"rm -rf /Library/CoreMediaIO/Plug-Ins/DAL/vcam-plugin.plugin \" with administrator privileges";
180+
// Uninstall the camera system extension
181+
const std::string path = getInstallerAppPath();
182+
return executeTaskAndCaptureOutput(path, @[@"--deactivate"]); // Run the uninstaller
114183

115-
NSString *script = [NSString stringWithCString:cmd.c_str() encoding:[NSString defaultCStringEncoding]];
116-
NSAppleScript *run = [[NSAppleScript alloc] initWithSource:script];
117-
[run executeAndReturnError:&error];
118-
NSLog(@"errors: %@", error);
184+
uninstallLegacyDALPlugin();
119185
}
120186

121187
bool UtilObjCInt::isPluginInstalled()
@@ -132,7 +198,9 @@ bool replace(std::string &str, const std::string &from, const std::string &to)
132198
// Read the output from the command execution
133199
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
134200
std::string text(buffer.data());
135-
if (text.find("com.streamlabs.slobs.mac-camera-extension") != std::string::npos) {
201+
// Edge case- if it shows "terminated waiting to uninstall on reboot" then technically the plugin was uninstalled.
202+
if ((text.find("com.streamlabs.slobs.mac-camera-extension") != std::string::npos) &&
203+
(text.find("terminated waiting to uninstall on reboot") == std::string::npos)) {
136204
isInstalled = true;
137205
}
138206
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class UtilObjCInt {
3737
void init(void);
3838
void getPermissionsStatus(bool &webcam, bool &mic);
3939
void requestPermissions(void *async_cb, perms_cb cb);
40-
void installPlugin(void);
40+
bool installPlugin(void);
4141
void uninstallPlugin(void);
4242
void setServerWorkingDirectoryPath(std::string path);
4343
bool isPluginInstalled();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ void UtilInt::requestPermissions(void *async_cb, perms_cb cb)
4444
_impl->requestPermissions(async_cb, cb);
4545
}
4646

47-
void UtilInt::installPlugin(void)
47+
bool UtilInt::installPlugin(void)
4848
{
4949
_impl->installPlugin();
5050
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class UtilInt {
3333
void init(void);
3434
void getPermissionsStatus(bool &webcam, bool &mic);
3535
void requestPermissions(void *async_cb, perms_cb cb);
36-
void installPlugin(void);
36+
bool installPlugin(void);
3737
void uninstallPlugin(void);
3838
void setServerWorkingDirectoryPath(std::string path);
3939
bool isPluginInstalled();

obs-studio-server/source/nodeobs_autoconfig.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Encoder recordingEncoder = Encoder::Stream;
5959
Encoder streamingEncoder = Encoder::x264;
6060
Type type = Type::Streaming;
6161
FPSType fpsType = FPSType::PreferHighFPS;
62-
uint64_t idealBitrate = 2500;
62+
uint64_t idealBitrate = 4500;
6363
uint64_t baseResolutionCX = 1920;
6464
uint64_t baseResolutionCY = 1080;
6565
uint64_t idealResolutionCX = 1280;
@@ -78,7 +78,7 @@ bool qsvAvailable = false;
7878
bool vceAvailable = false;
7979
bool appleHWAvailable = false;
8080

81-
int startingBitrate = 2500;
81+
int startingBitrate = 4500;
8282
bool customServer = false;
8383
bool bandwidthTest = true;
8484
bool testRegions = true;
@@ -1457,7 +1457,7 @@ void autoConfig::SetDefaultSettings(void)
14571457
idealResolutionCY = 720;
14581458
idealFPSNum = 30;
14591459
recordingQuality = Quality::High;
1460-
idealBitrate = 2500;
1460+
idealBitrate = 4500;
14611461
streamingEncoder = Encoder::x264;
14621462
recordingEncoder = Encoder::Stream;
14631463

obs-studio-server/source/nodeobs_configManager.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ void initBasicDefault(config_t *config)
125125
std::string filePath = GetDefaultVideoSavePath();
126126
config_set_default_string(config, "SimpleOutput", "FilePath", filePath.c_str());
127127
config_set_default_string(config, "SimpleOutput", "RecFormat", "mp4");
128-
config_set_default_uint(config, "SimpleOutput", "VBitrate", 2500);
128+
config_set_default_uint(config, "SimpleOutput", "VBitrate", 4500);
129129
config_set_default_string(config, "SimpleOutput", "StreamEncoder", SIMPLE_ENCODER_X264);
130130

131131
config_set_default_uint(config, "SimpleOutput", "ABitrate", 160);
@@ -160,7 +160,7 @@ void initBasicDefault(config_t *config)
160160
config_set_default_bool(config, "AdvOut", "FFOutputToFile", true);
161161
config_set_default_string(config, "AdvOut", "FFFilePath", GetDefaultVideoSavePath().c_str());
162162
config_set_default_string(config, "AdvOut", "FFExtension", "mp4");
163-
config_set_default_uint(config, "AdvOut", "FFVBitrate", 2500);
163+
config_set_default_uint(config, "AdvOut", "FFVBitrate", 4500);
164164
config_set_default_uint(config, "AdvOut", "FFVGOPSize", 250);
165165
config_set_default_bool(config, "AdvOut", "FFUseRescale", false);
166166
config_set_default_bool(config, "AdvOut", "FFIgnoreCompat", false);

obs-studio-server/source/nodeobs_service.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2051,7 +2051,7 @@ void OBS_service::updateVideoStreamingEncoder(bool isSimpleMode, StreamServiceId
20512051
}
20522052

20532053
if (videoBitrate == 0) {
2054-
videoBitrate = 2500;
2054+
videoBitrate = 4500;
20552055
config_set_uint(ConfigManager::getInstance().getBasic(), "SimpleOutput", "VBitrate", videoBitrate);
20562056
config_save_safe(ConfigManager::getInstance().getBasic(), "tmp", nullptr);
20572057
}

0 commit comments

Comments
 (0)