Skip to content

Commit

Permalink
capture source crash
Browse files Browse the repository at this point in the history
  • Loading branch information
summeroff committed Oct 24, 2024
1 parent 57e195b commit 76de4e9
Showing 1 changed file with 151 additions and 101 deletions.
252 changes: 151 additions & 101 deletions plugins/mac-capture/mac-screen-capture.m
Original file line number Diff line number Diff line change
Expand Up @@ -362,43 +362,49 @@ static bool init_screen_stream(struct screen_capture *sc)
dispatch_async(dispatch_get_main_queue(), ^{
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:@"Screen Recording Permission Required"];
[alert setInformativeText:@"Please grant Screen Recording permission in System Preferences > Security & Privacy > Privacy > Screen Recording, then restart the application."];
[alert setInformativeText:
@"Please grant Screen Recording permission in System "
@"Preferences > Security & Privacy > Privacy > Screen "
@"Recording, then restart the application."];
[alert addButtonWithTitle:@"OK"];
[alert runModal];
[alert release];

// Open the Security & Privacy preferences pane
NSURL *url = [NSURL fileURLWithPath:@"/System/Library/PreferencePanes/Security.prefPane"];
NSURL *url = [NSURL
fileURLWithPath:@"/System/Library/PreferencePanes/"
@"Security.prefPane"];
[[NSWorkspace sharedWorkspace] openURL:url];
});

// Since permissions are not granted, return false
return false;
}

SCContentFilter *content_filter = nil;

sc->frame = CGRectZero;
sc->stream_properties = [[SCStreamConfiguration alloc] init];
os_sem_wait(sc->shareable_content_available);

SCDisplay * (^get_target_display)() = ^SCDisplay *()
{
SCDisplay *(^get_target_display)() = ^SCDisplay *() {
__block SCDisplay *target_display = nil;
[sc->shareable_content.displays
indexOfObjectPassingTest:^BOOL(
SCDisplay *_Nonnull display, NSUInteger idx,
SCDisplay *_Nonnull display,
NSUInteger idx,
BOOL *_Nonnull stop) {
if (display.displayID == sc->display) {
target_display = sc->shareable_content.displays[idx];
target_display =
sc->shareable_content
.displays[idx];
*stop = TRUE;
}
return *stop;
}];
return target_display;
};

void (^set_display_mode)(struct screen_capture *, SCDisplay *) = ^void(
void (^set_display_mode)(struct screen_capture *,
SCDisplay *) = ^void(
struct screen_capture *capture_data,
SCDisplay *target_display) {
CGDisplayModeRef display_mode =
Expand All @@ -414,41 +420,46 @@ static bool init_screen_stream(struct screen_capture *sc)
case ScreenCaptureDisplayStream: {
SCDisplay *target_display = get_target_display();
if (!target_display) {
MACCAP_ERR("init_screen_stream: Target display not found\n");
MACCAP_ERR(
"init_screen_stream: Target display not found\n");
os_sem_post(sc->shareable_content_available);
return false;
}

NSArray *empty = [[NSArray alloc] init];
content_filter = [[SCContentFilter alloc]
initWithDisplay:target_display
excludingWindows:empty];
content_filter =
[[SCContentFilter alloc] initWithDisplay:target_display
excludingWindows:empty];
[empty release];

set_display_mode(sc, target_display);
} break;

case ScreenCaptureWindowStream: {
__block SCWindow *target_window = nil;
if (sc->window != 0) {
[sc->shareable_content.windows
indexOfObjectPassingTest:^BOOL(
SCWindow *_Nonnull window,
NSUInteger idx, BOOL *_Nonnull stop) {
if (window.windowID == sc->window) {
target_window = sc->shareable_content.windows[idx];
*stop = TRUE;
}
return *stop;
}];
} else {
if ([sc->shareable_content.windows count] > 0) {
target_window = [sc->shareable_content.windows objectAtIndex:0];
sc->window = target_window.windowID;
}
[sc->shareable_content.windows
indexOfObjectPassingTest:^BOOL(
SCWindow *_Nonnull window,
NSUInteger idx,
BOOL *_Nonnull stop) {
if (window.windowID == sc->window) {
target_window =
sc->shareable_content
.windows[idx];
*stop = TRUE;
}
return *stop;
}];

if (!target_window && [sc->shareable_content.windows count] > 0) {
target_window =
[sc->shareable_content.windows objectAtIndex:0];
sc->window = target_window.windowID;
}

if (!target_window) {
MACCAP_ERR("init_screen_stream: Target window not found\n");
MACCAP_ERR(
"init_screen_stream: Target window not found\n");
os_sem_post(sc->shareable_content_available);
return false;
}
Expand All @@ -460,12 +471,13 @@ static bool init_screen_stream(struct screen_capture *sc)
setWidth:(size_t)target_window.frame.size.width];
[sc->stream_properties
setHeight:(size_t)target_window.frame.size.height];

} break;

case ScreenCaptureApplicationStream: {
SCDisplay *target_display = get_target_display();
if (!target_display) {
MACCAP_ERR("init_screen_stream: Target display not found\n");
MACCAP_ERR(
"init_screen_stream: Target display not found\n");
os_sem_post(sc->shareable_content_available);
return false;
}
Expand All @@ -474,44 +486,50 @@ static bool init_screen_stream(struct screen_capture *sc)
[sc->shareable_content.applications
indexOfObjectPassingTest:^BOOL(
SCRunningApplication *_Nonnull application,
NSUInteger idx, BOOL *_Nonnull stop) {
NSUInteger idx,
BOOL *_Nonnull stop) {
if ([application.bundleIdentifier
isEqualToString:sc->application_id]) {
target_application = sc->shareable_content.applications[idx];
isEqualToString:sc->application_id]) {
target_application =
sc->shareable_content
.applications[idx];
*stop = TRUE;
}
return *stop;
}];

if (!target_application) {
MACCAP_ERR("init_screen_stream: Target application not found\n");
MACCAP_ERR(
"init_screen_stream: Target application not found\n");
os_sem_post(sc->shareable_content_available);
return false;
}

NSArray *target_application_array = [[NSArray alloc]
initWithObjects:target_application, nil];

NSArray *target_application_array =
[[NSArray alloc] initWithObjects:target_application, nil];
NSArray *empty_array = [[NSArray alloc] init];

content_filter = [[SCContentFilter alloc]
initWithDisplay:target_display
initWithDisplay:target_display
includingApplications:target_application_array
exceptingWindows:empty_array];
exceptingWindows:empty_array];

[target_application_array release];
[empty_array release];

set_display_mode(sc, target_display);
} break;
}

os_sem_post(sc->shareable_content_available);

CGColorRef background = CGColorGetConstantColor(kCGColorClear);
[sc->stream_properties setQueueDepth:8];
[sc->stream_properties setShowsCursor:!sc->hide_cursor];
[sc->stream_properties setColorSpaceName:kCGColorSpaceDisplayP3];
[sc->stream_properties setBackgroundColor:background];
FourCharCode l10r_type = 0;
l10r_type = ('l' << 24) | ('1' << 16) | ('0' << 8) | 'r';

FourCharCode l10r_type = ('l' << 24) | ('1' << 16) | ('0' << 8) | 'r';
[sc->stream_properties setPixelFormat:l10r_type];

if (@available(macOS 13.0, *)) {
Expand All @@ -520,92 +538,124 @@ static bool init_screen_stream(struct screen_capture *sc)
[sc->stream_properties setExcludesCurrentProcessAudio:TRUE];
[sc->stream_properties setChannelCount:2];
#endif
} else {
if (sc->capture_type != ScreenCaptureWindowStream) {
sc->disp = NULL;
[content_filter release];
os_event_init(&sc->disp_finished, OS_EVENT_TYPE_MANUAL);
os_event_init(&sc->stream_start_completed, OS_EVENT_TYPE_MANUAL);
return true;
}
} else if (sc->capture_type != ScreenCaptureWindowStream) {
sc->disp = NULL;
[content_filter release];
os_event_init(&sc->disp_finished, OS_EVENT_TYPE_MANUAL);
os_event_init(&sc->stream_start_completed,
OS_EVENT_TYPE_MANUAL);
return true;
}

sc->disp = [[SCStream alloc] initWithFilter:content_filter
configuration:sc->stream_properties
delegate:nil];

configuration:sc->stream_properties
delegate:nil];
[content_filter release];

NSError *addStreamOutputError = nil;
BOOL did_add_output = [sc->disp addStreamOutput:sc->capture_delegate
type:SCStreamOutputTypeScreen
sampleHandlerQueue:nil
error:&addStreamOutputError];
BOOL did_add_output = [sc->disp
addStreamOutput:sc->capture_delegate
type:SCStreamOutputTypeScreen
sampleHandlerQueue:nil
error:&addStreamOutputError];

if (!did_add_output) {
NSString *errorDescription = addStreamOutputError ? [addStreamOutputError localizedDescription] : @"Unknown error";
MACCAP_ERR(
"init_screen_stream: Failed to add stream output with error: %s\n",
[errorDescription cStringUsingEncoding:NSUTF8StringEncoding]);
NSString *errorDescription =
addStreamOutputError
? [addStreamOutputError localizedDescription]
: @"Unknown error";
MACCAP_ERR("init_screen_stream: Failed to add stream output "
"with error: %s\n",
[errorDescription
cStringUsingEncoding:NSUTF8StringEncoding]);
[addStreamOutputError release];
return false;
}

#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130000
if (@available(macOS 13.0, *)) {
did_add_output = [sc->disp addStreamOutput:sc->capture_delegate
type:SCStreamOutputTypeAudio
sampleHandlerQueue:nil
error:&addStreamOutputError];
did_add_output = [sc->disp
addStreamOutput:sc->capture_delegate
type:SCStreamOutputTypeAudio
sampleHandlerQueue:nil
error:&addStreamOutputError];

if (!did_add_output) {
NSString *errorDescription = addStreamOutputError ? [addStreamOutputError localizedDescription] : @"Unknown error";
NSString *errorDescription =
addStreamOutputError
? [addStreamOutputError
localizedDescription]
: @"Unknown error";
MACCAP_ERR(
"init_screen_stream: Failed to add audio stream output with error: %s\n",
[errorDescription cStringUsingEncoding:NSUTF8StringEncoding]);
"init_screen_stream: Failed to add audio stream "
"output with error: %s\n",
[errorDescription
cStringUsingEncoding:NSUTF8StringEncoding]);
[addStreamOutputError release];
return false;
}
}
#endif

os_event_init(&sc->disp_finished, OS_EVENT_TYPE_MANUAL);
os_event_init(&sc->stream_start_completed, OS_EVENT_TYPE_MANUAL);

__block BOOL did_stream_start = false;
[sc->disp startCaptureWithCompletionHandler:^(NSError *_Nullable error) {
did_stream_start = (error == nil);
if (!did_stream_start) {
NSString *errorDescription = error ? [error localizedDescription] : @"Unknown error";
MACCAP_ERR(
"init_screen_stream: Failed to start capture with error: %s\n",
[errorDescription cStringUsingEncoding:NSUTF8StringEncoding]);

// Check for permission error
if ([error.domain isEqualToString:@"com.apple.ScreenCaptureKit.ErrorDomain"]) {
NSInteger permissionDeniedErrorCode = -3801; // Replace with the actual error code if known
if (error.code == permissionDeniedErrorCode) {
// Inform the user and guide them to grant permission
dispatch_async(dispatch_get_main_queue(), ^{
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:@"Screen Recording Permission Denied"];
[alert setInformativeText:@"Please grant Screen Recording permission in System Preferences > Security & Privacy > Privacy > Screen Recording, then restart the application."];
[alert addButtonWithTitle:@"OK"];
[alert runModal];
[alert release];

// Open the Security & Privacy preferences pane
NSURL *url = [NSURL fileURLWithPath:@"/System/Library/PreferencePanes/Security.prefPane"];
[[NSWorkspace sharedWorkspace] openURL:url];
});
[sc->disp
startCaptureWithCompletionHandler:^(NSError *_Nullable error) {
did_stream_start = (error == nil);
if (!did_stream_start) {
NSString *errorDescription =
error ? [error localizedDescription]
: @"Unknown error";
MACCAP_ERR("init_screen_stream: Failed to start "
"capture with error: %s\n",
[errorDescription
cStringUsingEncoding:
NSUTF8StringEncoding]);

// Check for permission error
if ([error.domain
isEqualToString:
@"com.apple.ScreenCaptureKit.ErrorDomain"]) {
NSInteger permissionDeniedErrorCode =
-3801; // Replace with actual error code if known
if (error.code ==
permissionDeniedErrorCode) {
// Inform the user and guide them to grant permission
dispatch_async(
dispatch_get_main_queue(),
^{
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:@"Screen Recording Permission Denied"];
[alert setInformativeText:
@"Please grant Screen Recording permission in "
@"System Preferences > Security & Privacy > "
@"Privacy > Screen Recording, then restart "
@"the application."];
[alert addButtonWithTitle:@"OK"];
[alert runModal];
[alert release];

// Open the Security & Privacy preferences pane
NSURL *url = [NSURL
fileURLWithPath:@"/System/Library/PreferencePanes/"
@"Security.prefPane"];
[[NSWorkspace
sharedWorkspace]
openURL:url];
});
}
}

// Clean up disp so it isn't stopped
[sc->disp release];
sc->disp = NULL;
}
os_event_signal(sc->stream_start_completed);
}];

// Clean up disp so it isn't stopped
[sc->disp release];
sc->disp = NULL;
}
os_event_signal(sc->stream_start_completed);
}];
os_event_wait(sc->stream_start_completed);

return did_stream_start;
}

Expand Down

0 comments on commit 76de4e9

Please sign in to comment.