node-mac-recorder 2.16.2 โ 2.16.4
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 +3 -1
- package/debug-macos14.js +110 -0
- package/index.js +1 -1
- package/package.json +1 -1
- package/src/avfoundation_recorder.mm +18 -2
- package/src/mac_recorder.mm +26 -7
|
@@ -46,7 +46,9 @@
|
|
|
46
46
|
"Bash(ELECTRON_RUN_AS_NODE=1 node -e \"\nconsole.log(''๐งช Testing version detection and fallback system'');\nconst MacRecorder = require(''./index'');\nconst recorder = new MacRecorder();\n\nasync function testVersionDetection() {\n try {\n const outputPath = ''./test-output/version-detection-test.mov'';\n console.log(''๐น Starting recording with version detection...'');\n \n const success = await recorder.startRecording(outputPath, {\n captureCursor: true,\n includeMicrophone: false,\n includeSystemAudio: true\n });\n \n if (success) {\n console.log(''โ
Recording started - waiting 3 seconds'');\n await new Promise(resolve => setTimeout(resolve, 3000));\n \n console.log(''๐ Stopping recording...'');\n await recorder.stopRecording();\n console.log(''โ
Version detection test completed successfully!'');\n } else {\n console.log(''โ Recording failed to start'');\n }\n } catch (error) {\n console.log(''โ Error:'', error.message);\n }\n}\n\ntestVersionDetection();\n\")",
|
|
47
47
|
"Bash(ELECTRON_RUN_AS_NODE=1 node -e \"\nconsole.log(''๐งช Testing Electron safety measures'');\nconst MacRecorder = require(''./index'');\nconst recorder = new MacRecorder();\n\nasync function testElectronSafety() {\n try {\n const outputPath = ''./test-output/electron-safe-test.mov'';\n console.log(''๐น Starting recording in Electron environment...'');\n \n const success = await recorder.startRecording(outputPath, {\n captureCursor: true,\n includeMicrophone: false,\n includeSystemAudio: true\n });\n \n if (success) {\n console.log(''โ
Recording started safely in Electron - waiting 3 seconds'');\n await new Promise(resolve => setTimeout(resolve, 3000));\n \n console.log(''๐ Stopping recording...'');\n await recorder.stopRecording();\n console.log(''โ
Electron safety test completed successfully!'');\n } else {\n console.log(''โ ๏ธ Recording failed to start (expected in some cases)'');\n }\n } catch (error) {\n console.log(''โ Error:'', error.message);\n }\n}\n\ntestElectronSafety();\n\")",
|
|
48
48
|
"Bash(FORCE_AVFOUNDATION=1 node -e \"\nconsole.log(''๐งช Testing AVFoundation fallback path'');\nconst MacRecorder = require(''./index'');\nconst recorder = new MacRecorder();\n\nasync function testAVFoundationPath() {\n try {\n const outputPath = ''./test-output/force-avfoundation-test.mov'';\n console.log(''๐น Testing AVFoundation (force mode)...'');\n \n const success = await recorder.startRecording(outputPath, {\n captureCursor: true,\n includeMicrophone: false,\n includeSystemAudio: true\n });\n \n if (success) {\n console.log(''โ
Recording started'');\n await new Promise(resolve => setTimeout(resolve, 2000));\n \n await recorder.stopRecording();\n console.log(''โ
AVFoundation test completed!'');\n } else {\n console.log(''โ Recording failed'');\n }\n } catch (error) {\n console.log(''โ Error:'', error.message);\n }\n}\n\ntestAVFoundationPath();\n\")",
|
|
49
|
-
"Bash(FORCE_AVFOUNDATION=1 node -e \"\nconsole.log(''๐งช Testing AVFoundation fallback path (macOS 14 simulation)'');\nconst MacRecorder = require(''./index'');\nconst recorder = new MacRecorder();\n\nasync function testAVFoundationPath() {\n try {\n const outputPath = ''./test-output/force-avfoundation-test.mov'';\n console.log(''๐น Testing AVFoundation (simulating macOS 14)...'');\n \n const success = await recorder.startRecording(outputPath, {\n captureCursor: true,\n includeMicrophone: false,\n includeSystemAudio: true\n });\n \n if (success) {\n console.log(''โ
Recording started with AVFoundation'');\n await new Promise(resolve => setTimeout(resolve, 3000));\n \n await recorder.stopRecording();\n console.log(''โ
AVFoundation test completed successfully!'');\n console.log(''This is how it should work on macOS 14'');\n } else {\n console.log(''โ Recording failed to start'');\n }\n } catch (error) {\n console.log(''โ Error:'', error.message);\n }\n}\n\ntestAVFoundationPath();\n\")"
|
|
49
|
+
"Bash(FORCE_AVFOUNDATION=1 node -e \"\nconsole.log(''๐งช Testing AVFoundation fallback path (macOS 14 simulation)'');\nconst MacRecorder = require(''./index'');\nconst recorder = new MacRecorder();\n\nasync function testAVFoundationPath() {\n try {\n const outputPath = ''./test-output/force-avfoundation-test.mov'';\n console.log(''๐น Testing AVFoundation (simulating macOS 14)...'');\n \n const success = await recorder.startRecording(outputPath, {\n captureCursor: true,\n includeMicrophone: false,\n includeSystemAudio: true\n });\n \n if (success) {\n console.log(''โ
Recording started with AVFoundation'');\n await new Promise(resolve => setTimeout(resolve, 3000));\n \n await recorder.stopRecording();\n console.log(''โ
AVFoundation test completed successfully!'');\n console.log(''This is how it should work on macOS 14'');\n } else {\n console.log(''โ Recording failed to start'');\n }\n } catch (error) {\n console.log(''โ Error:'', error.message);\n }\n}\n\ntestAVFoundationPath();\n\")",
|
|
50
|
+
"Bash(FORCE_AVFOUNDATION=1 node -e \"\nconsole.log(''๐งช Testing AVFoundation with detailed debugging'');\nconst MacRecorder = require(''./index'');\nconst recorder = new MacRecorder();\n\nasync function testWithDebugging() {\n try {\n const outputPath = ''./test-output/debug-test.mov'';\n console.log(''๐น Starting AVFoundation test with debugging...'');\n console.log(''Expected to see detailed AVFoundation logs in console'');\n \n const success = await recorder.startRecording(outputPath, {\n captureCursor: true,\n includeMicrophone: false,\n includeSystemAudio: true\n });\n \n if (success) {\n console.log(''โ
Recording started'');\n await new Promise(resolve => setTimeout(resolve, 2000));\n \n await recorder.stopRecording();\n console.log(''โ
Test completed'');\n } else {\n console.log(''โ Recording failed - check console logs for AVFoundation details'');\n }\n } catch (error) {\n console.log(''โ Error:'', error.message);\n }\n}\n\ntestWithDebugging();\n\")",
|
|
51
|
+
"Bash(FORCE_AVFOUNDATION=1 node -e \"\nconsole.log(''๐งช Testing macOS 13/14 path (forced AVFoundation)'');\nconst MacRecorder = require(''./index'');\nconst recorder = new MacRecorder();\n\nasync function testMacOS1314Path() {\n try {\n const outputPath = ''./test-output/macos1314-test.mov'';\n console.log(''๐น Starting test for macOS 13/14 path...'');\n console.log(''This simulates the exact path macOS 13/14 users will take'');\n console.log('''');\n \n const success = await recorder.startRecording(outputPath, {\n captureCursor: true,\n includeMicrophone: false,\n includeSystemAudio: true\n });\n \n if (success) {\n console.log(''โ
SUCCESS: Recording started on macOS 13/14 path!'');\n await new Promise(resolve => setTimeout(resolve, 3000));\n \n await recorder.stopRecording();\n console.log(''โ
Recording completed successfully!'');\n console.log(''๐ Output:'', outputPath);\n } else {\n console.log(''โ Recording failed to start'');\n }\n } catch (error) {\n console.log(''โ Error:'', error.message);\n console.log(''This error would be what macOS 13/14 users see'');\n }\n}\n\ntestMacOS1314Path();\n\")"
|
|
50
52
|
],
|
|
51
53
|
"deny": []
|
|
52
54
|
}
|
package/debug-macos14.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
const MacRecorder = require('./index');
|
|
2
|
+
|
|
3
|
+
console.log('๐งช macOS 14/13 Debug Test');
|
|
4
|
+
console.log('=========================================');
|
|
5
|
+
console.log('');
|
|
6
|
+
console.log('This script helps debug recording issues on macOS 14 and earlier.');
|
|
7
|
+
console.log('Please run this and share the complete console output.');
|
|
8
|
+
console.log('');
|
|
9
|
+
|
|
10
|
+
async function debugMacOS14() {
|
|
11
|
+
const recorder = new MacRecorder();
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
// Create test output directory
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
if (!fs.existsSync('./test-output')) {
|
|
17
|
+
fs.mkdirSync('./test-output');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
console.log('๐ System Information:');
|
|
21
|
+
const os = require('os');
|
|
22
|
+
console.log(' OS:', os.type(), os.release());
|
|
23
|
+
console.log(' Architecture:', os.arch());
|
|
24
|
+
console.log(' Platform:', os.platform());
|
|
25
|
+
|
|
26
|
+
// Check permissions first
|
|
27
|
+
console.log('');
|
|
28
|
+
console.log('๐ Checking Permissions...');
|
|
29
|
+
try {
|
|
30
|
+
const permissions = await recorder.checkPermissions();
|
|
31
|
+
console.log(' Screen Recording Permission:', permissions.screenRecording ? 'โ
GRANTED' : 'โ DENIED');
|
|
32
|
+
console.log(' Accessibility Permission:', permissions.accessibility ? 'โ
GRANTED' : 'โ DENIED');
|
|
33
|
+
|
|
34
|
+
if (!permissions.screenRecording) {
|
|
35
|
+
console.log('');
|
|
36
|
+
console.log('โ CRITICAL: Screen Recording permission is DENIED');
|
|
37
|
+
console.log(' Please grant permission in System Preferences > Security & Privacy > Privacy > Screen Recording');
|
|
38
|
+
console.log(' Then restart this test.');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
} catch (permError) {
|
|
42
|
+
console.log(' Permission check failed:', permError.message);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log('');
|
|
46
|
+
console.log('๐ฏ Starting Recording Test...');
|
|
47
|
+
console.log('Expected behavior:');
|
|
48
|
+
console.log(' โข System should detect macOS version');
|
|
49
|
+
console.log(' โข macOS 15+ uses ScreenCaptureKit');
|
|
50
|
+
console.log(' โข macOS 14/13 uses AVFoundation fallback');
|
|
51
|
+
console.log(' โข You should see detailed logs below');
|
|
52
|
+
console.log('');
|
|
53
|
+
|
|
54
|
+
const outputPath = './test-output/debug-test.mov';
|
|
55
|
+
|
|
56
|
+
const success = await recorder.startRecording(outputPath, {
|
|
57
|
+
captureCursor: true,
|
|
58
|
+
includeMicrophone: false,
|
|
59
|
+
includeSystemAudio: true,
|
|
60
|
+
displayId: null // Use primary display
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (success) {
|
|
64
|
+
console.log('โ
Recording started successfully');
|
|
65
|
+
console.log('โฑ๏ธ Recording for 3 seconds...');
|
|
66
|
+
|
|
67
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
68
|
+
|
|
69
|
+
console.log('๐ Stopping recording...');
|
|
70
|
+
await recorder.stopRecording();
|
|
71
|
+
|
|
72
|
+
// Check if file was created
|
|
73
|
+
const fs = require('fs');
|
|
74
|
+
if (fs.existsSync(outputPath)) {
|
|
75
|
+
const stats = fs.statSync(outputPath);
|
|
76
|
+
console.log('โ
Recording file created:', outputPath);
|
|
77
|
+
console.log(' File size:', Math.round(stats.size / 1024), 'KB');
|
|
78
|
+
console.log('');
|
|
79
|
+
console.log('๐ SUCCESS: Recording works on your system!');
|
|
80
|
+
} else {
|
|
81
|
+
console.log('โ Recording file was not created');
|
|
82
|
+
console.log(' Expected:', outputPath);
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
console.log('โ Recording failed to start');
|
|
86
|
+
console.log('');
|
|
87
|
+
console.log('๐ Troubleshooting Steps:');
|
|
88
|
+
console.log('1. Check console logs above for specific error messages');
|
|
89
|
+
console.log('2. Verify Screen Recording permission is granted');
|
|
90
|
+
console.log('3. Try restarting your application');
|
|
91
|
+
console.log('4. Check if output directory exists and is writable');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.log('โ Error during test:', error.message);
|
|
96
|
+
if (error.stack) {
|
|
97
|
+
console.log('Stack trace:', error.stack);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log('');
|
|
102
|
+
console.log('๐ Support Information:');
|
|
103
|
+
console.log('If recording still fails, please share:');
|
|
104
|
+
console.log('1. Complete console output from this test');
|
|
105
|
+
console.log('2. Your macOS version (System Settings > About)');
|
|
106
|
+
console.log('3. Permission screenshots from System Settings');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Run the debug test
|
|
110
|
+
debugMacOS14();
|
package/index.js
CHANGED
|
@@ -406,7 +406,7 @@ class MacRecorder extends EventEmitter {
|
|
|
406
406
|
} else {
|
|
407
407
|
reject(
|
|
408
408
|
new Error(
|
|
409
|
-
"
|
|
409
|
+
"Recording failed to start. Check permissions, output path, and system compatibility."
|
|
410
410
|
)
|
|
411
411
|
);
|
|
412
412
|
}
|
package/package.json
CHANGED
|
@@ -32,24 +32,40 @@ bool startAVFoundationRecording(const std::string& outputPath,
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
@try {
|
|
35
|
+
NSLog(@"๐ฌ AVFoundation: Starting recording initialization");
|
|
36
|
+
|
|
35
37
|
// Create output URL
|
|
36
38
|
NSString *outputPathStr = [NSString stringWithUTF8String:outputPath.c_str()];
|
|
39
|
+
NSLog(@"๐ฌ AVFoundation: Output path string: %@", outputPathStr);
|
|
40
|
+
|
|
37
41
|
NSURL *outputURL = [NSURL fileURLWithPath:outputPathStr];
|
|
42
|
+
NSLog(@"๐ฌ AVFoundation: Output URL: %@", outputURL);
|
|
38
43
|
|
|
39
44
|
// Remove existing file
|
|
40
|
-
|
|
45
|
+
NSError *removeError = nil;
|
|
46
|
+
[[NSFileManager defaultManager] removeItemAtURL:outputURL error:&removeError];
|
|
47
|
+
if (removeError && removeError.code != NSFileNoSuchFileError) {
|
|
48
|
+
NSLog(@"โ ๏ธ AVFoundation: Warning removing existing file: %@", removeError);
|
|
49
|
+
}
|
|
41
50
|
|
|
42
51
|
// Create asset writer
|
|
52
|
+
NSLog(@"๐ฌ AVFoundation: Creating AVAssetWriter...");
|
|
43
53
|
NSError *error = nil;
|
|
44
54
|
g_avWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeQuickTimeMovie error:&error];
|
|
45
55
|
if (!g_avWriter || error) {
|
|
46
|
-
NSLog(@"โ Failed to create AVAssetWriter: %@", error);
|
|
56
|
+
NSLog(@"โ AVFoundation: Failed to create AVAssetWriter: %@", error);
|
|
57
|
+
NSLog(@"โ AVFoundation: Output URL was: %@", outputURL);
|
|
47
58
|
return false;
|
|
48
59
|
}
|
|
60
|
+
NSLog(@"โ
AVFoundation: AVAssetWriter created successfully");
|
|
49
61
|
|
|
50
62
|
// Get display dimensions
|
|
63
|
+
NSLog(@"๐ฌ AVFoundation: Getting display dimensions for display ID %u", displayID);
|
|
51
64
|
CGRect displayBounds = CGDisplayBounds(displayID);
|
|
65
|
+
NSLog(@"๐ฌ AVFoundation: Display bounds: %.0f x %.0f", displayBounds.size.width, displayBounds.size.height);
|
|
66
|
+
|
|
52
67
|
CGSize recordingSize = captureRect.size.width > 0 ? captureRect.size : displayBounds.size;
|
|
68
|
+
NSLog(@"๐ฌ AVFoundation: Recording size: %.0f x %.0f", recordingSize.width, recordingSize.height);
|
|
53
69
|
|
|
54
70
|
// Video settings
|
|
55
71
|
NSDictionary *videoSettings = @{
|
package/src/mac_recorder.mm
CHANGED
|
@@ -282,10 +282,12 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
|
|
|
282
282
|
}
|
|
283
283
|
} else if (isM14Plus) {
|
|
284
284
|
// macOS 14 - directly use AVFoundation for better compatibility
|
|
285
|
-
NSLog(@"๐ฏ macOS 14 detected - using AVFoundation for better compatibility");
|
|
285
|
+
NSLog(@"๐ฏ macOS 14 detected - directly using AVFoundation for better compatibility");
|
|
286
|
+
// Skip ScreenCaptureKit completely and go directly to AVFoundation
|
|
286
287
|
} else if (isM13Plus) {
|
|
287
288
|
// macOS 13 - use AVFoundation (limited features)
|
|
288
|
-
NSLog(@"๐ฏ macOS 13 detected - using AVFoundation (limited features)");
|
|
289
|
+
NSLog(@"๐ฏ macOS 13 detected - directly using AVFoundation (limited features)");
|
|
290
|
+
// Skip ScreenCaptureKit completely and go directly to AVFoundation
|
|
289
291
|
} else {
|
|
290
292
|
NSLog(@"โ macOS version too old (< 13.0) - Recording not supported");
|
|
291
293
|
return Napi::Boolean::New(env, false);
|
|
@@ -302,12 +304,23 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
|
|
|
302
304
|
if (isM15Plus) {
|
|
303
305
|
NSLog(@"๐ ScreenCaptureKit failed on macOS 15+ - attempting AVFoundation fallback");
|
|
304
306
|
} else if (isM14Plus) {
|
|
305
|
-
NSLog(@"๐ฅ Using AVFoundation for macOS 14 compatibility");
|
|
307
|
+
NSLog(@"๐ฅ Using AVFoundation for macOS 14 compatibility (primary method)");
|
|
306
308
|
} else if (isM13Plus) {
|
|
307
|
-
NSLog(@"๐ฅ Using AVFoundation for macOS 13 compatibility (limited features)");
|
|
309
|
+
NSLog(@"๐ฅ Using AVFoundation for macOS 13 compatibility (primary method, limited features)");
|
|
310
|
+
} else {
|
|
311
|
+
NSLog(@"โ Unsupported macOS version for AVFoundation");
|
|
312
|
+
return Napi::Boolean::New(env, false);
|
|
308
313
|
}
|
|
309
314
|
|
|
310
315
|
@try {
|
|
316
|
+
NSLog(@"๐ง Attempting AVFoundation recording...");
|
|
317
|
+
NSLog(@"๐ง Output path: %s", outputPath.c_str());
|
|
318
|
+
NSLog(@"๐ง Display ID: %u", displayID);
|
|
319
|
+
NSLog(@"๐ง Cursor: %s, Mic: %s, System Audio: %s",
|
|
320
|
+
captureCursor ? "YES" : "NO",
|
|
321
|
+
includeMicrophone ? "YES" : "NO",
|
|
322
|
+
includeSystemAudio ? "YES" : "NO");
|
|
323
|
+
|
|
311
324
|
// Import AVFoundation recording functions (if available)
|
|
312
325
|
extern bool startAVFoundationRecording(const std::string& outputPath,
|
|
313
326
|
CGDirectDisplayID displayID,
|
|
@@ -318,17 +331,23 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
|
|
|
318
331
|
bool includeSystemAudio,
|
|
319
332
|
NSString* audioDeviceId);
|
|
320
333
|
|
|
321
|
-
|
|
322
|
-
|
|
334
|
+
NSLog(@"๐ง Calling startAVFoundationRecording...");
|
|
335
|
+
bool avResult = startAVFoundationRecording(outputPath, displayID, windowID, captureRect,
|
|
336
|
+
captureCursor, includeMicrophone, includeSystemAudio, audioDeviceId);
|
|
337
|
+
NSLog(@"๐ง AVFoundation result: %s", avResult ? "SUCCESS" : "FAILED");
|
|
338
|
+
|
|
339
|
+
if (avResult) {
|
|
323
340
|
NSLog(@"๐ฅ RECORDING METHOD: AVFoundation (Fallback)");
|
|
324
341
|
NSLog(@"โ
AVFoundation recording started successfully");
|
|
325
342
|
g_isRecording = true;
|
|
326
343
|
return Napi::Boolean::New(env, true);
|
|
327
344
|
} else {
|
|
328
|
-
NSLog(@"โ AVFoundation recording
|
|
345
|
+
NSLog(@"โ AVFoundation recording failed to start");
|
|
346
|
+
NSLog(@"โ Check permissions and output path validity");
|
|
329
347
|
}
|
|
330
348
|
} @catch (NSException *avException) {
|
|
331
349
|
NSLog(@"โ Exception during AVFoundation startup: %@", avException.reason);
|
|
350
|
+
NSLog(@"โ Stack trace: %@", [avException callStackSymbols]);
|
|
332
351
|
}
|
|
333
352
|
|
|
334
353
|
// Both ScreenCaptureKit and AVFoundation failed
|