node-mac-recorder 2.16.23 โ 2.16.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +1 -1
- package/package.json +1 -1
- package/src/mac_recorder.mm +11 -37
- package/src/screen_capture_kit.mm +23 -0
- package/src/window_selector.mm +5 -23
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"permissions": {
|
|
3
3
|
"allow": [
|
|
4
|
-
"Bash(FORCE_AVFOUNDATION=1 node -e \"\nconsole.log(''๐งช Testing
|
|
4
|
+
"Bash(FORCE_AVFOUNDATION=1 node -e \"\nconsole.log(''๐งช Testing external display recording WITH AUDIO - debug version...'');\nconst MacRecorder = require(''./index.js'');\nconst recorder = new MacRecorder();\n\nrecorder.startRecording(''/tmp/external-audio-debug.mov'', {\n displayId: 3, // External display\n includeMicrophone: true,\n includeSystemAudio: true,\n captureCursor: true\n})\n .then(success => {\n console.log(''Start result:'', success ? ''โ
SUCCESS'' : ''โ FAILED'');\n if (success) {\n setTimeout(() => {\n console.log(''โน๏ธ Stopping recording...'');\n recorder.stopRecording().then(() => {\n console.log(''โ
Recording stopped'');\n const fs = require(''fs'');\n if (fs.existsSync(''/tmp/external-audio-debug.mov'')) {\n const size = Math.round(fs.statSync(''/tmp/external-audio-debug.mov'').size/1024);\n console.log(''๐น File size:'', size + ''KB'');\n if (size > 100) {\n console.log(''๐ External display recording with audio SUCCESS!'');\n } else {\n console.log(''โ ๏ธ File too small, may have failed'');\n }\n } else {\n console.log(''โ No output file created'');\n }\n });\n }, 4000); // 4 seconds recording\n }\n })\n .catch(console.error);\n\")"
|
|
5
5
|
],
|
|
6
6
|
"deny": [],
|
|
7
7
|
"ask": []
|
package/package.json
CHANGED
package/src/mac_recorder.mm
CHANGED
|
@@ -567,50 +567,24 @@ Napi::Value GetDisplays(const Napi::CallbackInfo& info) {
|
|
|
567
567
|
Napi::Env env = info.Env();
|
|
568
568
|
|
|
569
569
|
@try {
|
|
570
|
-
// Get displays using
|
|
571
|
-
NSArray *screens = [NSScreen screens];
|
|
570
|
+
// Get active displays directly using CGDirectDisplayID
|
|
572
571
|
NSMutableArray *displays = [NSMutableArray array];
|
|
573
|
-
|
|
574
|
-
// Get real CGDirectDisplayIDs first
|
|
575
572
|
CGDirectDisplayID activeDisplays[32];
|
|
576
573
|
uint32_t displayCount;
|
|
577
574
|
CGGetActiveDisplayList(32, activeDisplays, &displayCount);
|
|
578
575
|
|
|
579
|
-
for (
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
// Find matching CGDirectDisplayID
|
|
584
|
-
CGDirectDisplayID displayID = 0;
|
|
585
|
-
bool isPrimary = false;
|
|
586
|
-
|
|
587
|
-
for (uint32_t j = 0; j < displayCount; j++) {
|
|
588
|
-
CGDirectDisplayID candidateID = activeDisplays[j];
|
|
589
|
-
CGRect displayBounds = CGDisplayBounds(candidateID);
|
|
590
|
-
|
|
591
|
-
if (fabs(frame.origin.x - displayBounds.origin.x) < 1.0 &&
|
|
592
|
-
fabs(frame.origin.y - displayBounds.origin.y) < 1.0 &&
|
|
593
|
-
fabs(frame.size.width - displayBounds.size.width) < 1.0 &&
|
|
594
|
-
fabs(frame.size.height - displayBounds.size.height) < 1.0) {
|
|
595
|
-
displayID = candidateID;
|
|
596
|
-
isPrimary = (candidateID == CGMainDisplayID());
|
|
597
|
-
break;
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// Fallback if no match found
|
|
602
|
-
if (displayID == 0 && i < displayCount) {
|
|
603
|
-
displayID = activeDisplays[i];
|
|
604
|
-
isPrimary = (displayID == CGMainDisplayID());
|
|
605
|
-
}
|
|
576
|
+
for (uint32_t i = 0; i < displayCount; i++) {
|
|
577
|
+
CGDirectDisplayID displayID = activeDisplays[i];
|
|
578
|
+
CGRect displayBounds = CGDisplayBounds(displayID);
|
|
579
|
+
bool isPrimary = (displayID == CGMainDisplayID());
|
|
606
580
|
|
|
607
581
|
NSDictionary *displayInfo = @{
|
|
608
|
-
@"id": @(displayID), //
|
|
609
|
-
@"name": [NSString stringWithFormat:@"Display %
|
|
610
|
-
@"width": @((int)
|
|
611
|
-
@"height": @((int)
|
|
612
|
-
@"x": @((int)
|
|
613
|
-
@"y": @((int)
|
|
582
|
+
@"id": @(displayID), // Direct CGDirectDisplayID
|
|
583
|
+
@"name": [NSString stringWithFormat:@"Display %u", (unsigned int)(i + 1)],
|
|
584
|
+
@"width": @((int)displayBounds.size.width),
|
|
585
|
+
@"height": @((int)displayBounds.size.height),
|
|
586
|
+
@"x": @((int)displayBounds.origin.x),
|
|
587
|
+
@"y": @((int)displayBounds.origin.y),
|
|
614
588
|
@"isPrimary": @(isPrimary)
|
|
615
589
|
};
|
|
616
590
|
[displays addObject:displayInfo];
|
|
@@ -77,6 +77,10 @@ static NSString *g_outputPath = nil;
|
|
|
77
77
|
NSLog(@"๐ง Config: cursor=%@ mic=%@ system=%@ display=%@ window=%@ crop=%@",
|
|
78
78
|
captureCursor, includeMicrophone, includeSystemAudio, displayId, windowId, captureRect);
|
|
79
79
|
|
|
80
|
+
// CRITICAL DEBUG: Log EXACT audio parameter values
|
|
81
|
+
NSLog(@"๐ AUDIO DEBUG: includeMicrophone type=%@ value=%d", [includeMicrophone class], [includeMicrophone boolValue]);
|
|
82
|
+
NSLog(@"๐ AUDIO DEBUG: includeSystemAudio type=%@ value=%d", [includeSystemAudio class], [includeSystemAudio boolValue]);
|
|
83
|
+
|
|
80
84
|
// Get shareable content
|
|
81
85
|
[SCShareableContent getShareableContentWithCompletionHandler:^(SCShareableContent *content, NSError *contentError) {
|
|
82
86
|
if (contentError) {
|
|
@@ -87,6 +91,15 @@ static NSString *g_outputPath = nil;
|
|
|
87
91
|
NSLog(@"โ
Got %lu displays, %lu windows for pure recording",
|
|
88
92
|
content.displays.count, content.windows.count);
|
|
89
93
|
|
|
94
|
+
// CRITICAL DEBUG: List all available displays in ScreenCaptureKit
|
|
95
|
+
NSLog(@"๐ ScreenCaptureKit available displays:");
|
|
96
|
+
for (SCDisplay *display in content.displays) {
|
|
97
|
+
NSLog(@" Display ID=%u, Size=%dx%d, Frame=(%.0f,%.0f,%.0fx%.0f)",
|
|
98
|
+
display.displayID, (int)display.width, (int)display.height,
|
|
99
|
+
display.frame.origin.x, display.frame.origin.y,
|
|
100
|
+
display.frame.size.width, display.frame.size.height);
|
|
101
|
+
}
|
|
102
|
+
|
|
90
103
|
SCContentFilter *filter = nil;
|
|
91
104
|
NSInteger recordingWidth = 0;
|
|
92
105
|
NSInteger recordingHeight = 0;
|
|
@@ -121,12 +134,20 @@ static NSString *g_outputPath = nil;
|
|
|
121
134
|
|
|
122
135
|
if (displayId && [displayId integerValue] != 0) {
|
|
123
136
|
// Find specific display
|
|
137
|
+
NSLog(@"๐ฏ Looking for display ID=%@ in ScreenCaptureKit list", displayId);
|
|
124
138
|
for (SCDisplay *display in content.displays) {
|
|
139
|
+
NSLog(@" Checking display ID=%u vs requested=%u", display.displayID, [displayId unsignedIntValue]);
|
|
125
140
|
if (display.displayID == [displayId unsignedIntValue]) {
|
|
126
141
|
targetDisplay = display;
|
|
142
|
+
NSLog(@"โ
FOUND matching display ID=%u", display.displayID);
|
|
127
143
|
break;
|
|
128
144
|
}
|
|
129
145
|
}
|
|
146
|
+
|
|
147
|
+
if (!targetDisplay) {
|
|
148
|
+
NSLog(@"โ Display ID=%@ NOT FOUND in ScreenCaptureKit - using first display as fallback", displayId);
|
|
149
|
+
targetDisplay = content.displays.firstObject;
|
|
150
|
+
}
|
|
130
151
|
} else {
|
|
131
152
|
// Use first display
|
|
132
153
|
targetDisplay = content.displays.firstObject;
|
|
@@ -188,8 +209,10 @@ static NSString *g_outputPath = nil;
|
|
|
188
209
|
recordingWidth, recordingHeight, shouldShowCursor);
|
|
189
210
|
|
|
190
211
|
// AUDIO SUPPORT - Enable both microphone and system audio
|
|
212
|
+
NSLog(@"๐ AUDIO PROCESSING: includeMicrophone=%@ includeSystemAudio=%@", includeMicrophone, includeSystemAudio);
|
|
191
213
|
BOOL shouldCaptureMic = includeMicrophone ? [includeMicrophone boolValue] : NO;
|
|
192
214
|
BOOL shouldCaptureSystemAudio = includeSystemAudio ? [includeSystemAudio boolValue] : NO;
|
|
215
|
+
NSLog(@"๐ AUDIO COMPUTED: shouldCaptureMic=%d shouldCaptureSystemAudio=%d", shouldCaptureMic, shouldCaptureSystemAudio);
|
|
193
216
|
|
|
194
217
|
// Enable audio if either microphone or system audio is requested
|
|
195
218
|
if (@available(macOS 13.0, *)) {
|
package/src/window_selector.mm
CHANGED
|
@@ -2360,33 +2360,15 @@ Napi::Value GetSelectedWindowInfo(const Napi::CallbackInfo& info) {
|
|
|
2360
2360
|
windowScreen = mainScreen;
|
|
2361
2361
|
}
|
|
2362
2362
|
|
|
2363
|
-
//
|
|
2363
|
+
// Simple screen information - no complex mapping
|
|
2364
2364
|
NSRect screenFrame = [windowScreen frame];
|
|
2365
|
+
NSNumber *screenNumber = [windowScreen deviceDescription][@"NSScreenNumber"];
|
|
2365
2366
|
|
|
2366
|
-
|
|
2367
|
-
CGDirectDisplayID realDisplayID = 0;
|
|
2368
|
-
CGDirectDisplayID activeDisplays[32];
|
|
2369
|
-
uint32_t displayCount;
|
|
2370
|
-
CGGetActiveDisplayList(32, activeDisplays, &displayCount);
|
|
2371
|
-
|
|
2372
|
-
for (uint32_t j = 0; j < displayCount; j++) {
|
|
2373
|
-
CGDirectDisplayID candidateID = activeDisplays[j];
|
|
2374
|
-
CGRect displayBounds = CGDisplayBounds(candidateID);
|
|
2375
|
-
|
|
2376
|
-
if (fabs(screenFrame.origin.x - displayBounds.origin.x) < 1.0 &&
|
|
2377
|
-
fabs(screenFrame.origin.y - displayBounds.origin.y) < 1.0 &&
|
|
2378
|
-
fabs(screenFrame.size.width - displayBounds.size.width) < 1.0 &&
|
|
2379
|
-
fabs(screenFrame.size.height - displayBounds.size.height) < 1.0) {
|
|
2380
|
-
realDisplayID = candidateID;
|
|
2381
|
-
break;
|
|
2382
|
-
}
|
|
2383
|
-
}
|
|
2384
|
-
|
|
2385
|
-
NSLog(@"๐ Window screen mapping: Frame=(%.0f,%.0f,%.0fx%.0f) โ CGDirectDisplayID=%u",
|
|
2367
|
+
NSLog(@"๐ Window screen: Frame=(%.0f,%.0f,%.0fx%.0f) ScreenNumber=%@",
|
|
2386
2368
|
screenFrame.origin.x, screenFrame.origin.y,
|
|
2387
|
-
screenFrame.size.width, screenFrame.size.height,
|
|
2369
|
+
screenFrame.size.width, screenFrame.size.height, screenNumber);
|
|
2388
2370
|
|
|
2389
|
-
result.Set("screenId", Napi::Number::New(env,
|
|
2371
|
+
result.Set("screenId", Napi::Number::New(env, [screenNumber unsignedIntValue]));
|
|
2390
2372
|
result.Set("screenX", Napi::Number::New(env, (int)screenFrame.origin.x));
|
|
2391
2373
|
result.Set("screenY", Napi::Number::New(env, (int)screenFrame.origin.y));
|
|
2392
2374
|
result.Set("screenWidth", Napi::Number::New(env, (int)screenFrame.size.width));
|