node-mac-recorder 2.16.1 โ 2.16.2
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/MACOS14_TROUBLESHOOTING.md +111 -0
- package/package.json +1 -1
- package/src/mac_recorder.mm +29 -12
- package/test-macos14.js +56 -0
|
@@ -44,7 +44,9 @@
|
|
|
44
44
|
"Bash(ELECTRON_RUN_AS_NODE=1 node -e \"\nconsole.log(''๐ค Testing microphone only'');\nconst MacRecorder = require(''./index'');\nconst recorder = new MacRecorder();\n\nasync function testMicrophoneOnly() {\n try {\n const outputPath = ''./test-output/microphone-only-test.mov'';\n console.log(''๐น Starting microphone only recording...'');\n \n const success = await recorder.startRecording(outputPath, {\n captureCursor: false,\n includeMicrophone: true, // Sadece mikrofon AรIK\n includeSystemAudio: false // Sistem sesi KAPALI\n });\n \n if (success) {\n console.log(''โ
Microphone recording started - waiting 3 seconds'');\n await new Promise(resolve => setTimeout(resolve, 3000));\n \n console.log(''๐ Stopping microphone recording...'');\n await recorder.stopRecording();\n console.log(''โ
Microphone only test completed!'');\n } else {\n console.log(''โ Recording failed to start'');\n }\n } catch (error) {\n console.log(''โ Error:'', error.message);\n }\n}\n\ntestMicrophoneOnly();\n\")",
|
|
45
45
|
"Bash(ELECTRON_RUN_AS_NODE=1 node -e \"\nconsole.log(''๐ Full stress test - All features + Both audio sources'');\nconst MacRecorder = require(''./index'');\nconst recorder = new MacRecorder();\n\nasync function fullStressTest() {\n try {\n const outputPath = ''./test-output/full-stress-test.mov'';\n console.log(''๐น Starting full featured recording (stress test)...'');\n \n const success = await recorder.startRecording(outputPath, {\n captureCursor: true, // Cursor kayฤฑt\n includeMicrophone: true, // Mikrofon kayฤฑt\n includeSystemAudio: true, // Sistem sesi kayฤฑt\n captureArea: { // Crop area\n x: 300,\n y: 300,\n width: 800,\n height: 500\n }\n });\n \n if (success) {\n console.log(''โ
Full stress test started - waiting 6 seconds'');\n await new Promise(resolve => setTimeout(resolve, 6000));\n \n console.log(''๐ Stopping full stress test...'');\n await recorder.stopRecording();\n console.log(''๐ FULL STRESS TEST COMPLETED WITHOUT CRASH!'');\n } else {\n console.log(''โ Recording failed to start'');\n }\n } catch (error) {\n console.log(''โ Error:'', error.message);\n console.log(''Stack:'', error.stack);\n }\n}\n\nfullStressTest();\n\")",
|
|
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
|
-
"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\")"
|
|
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
|
+
"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\")"
|
|
48
50
|
],
|
|
49
51
|
"deny": []
|
|
50
52
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# macOS 13/14 Recording Troubleshooting Guide
|
|
2
|
+
|
|
3
|
+
## Expected Behavior by macOS Version
|
|
4
|
+
|
|
5
|
+
The system automatically detects macOS version and uses the most compatible recording method:
|
|
6
|
+
|
|
7
|
+
- **macOS 15+**: Uses ScreenCaptureKit (30fps, full features)
|
|
8
|
+
- **macOS 14**: Uses AVFoundation fallback (15fps, stable)
|
|
9
|
+
- **macOS 13**: Uses AVFoundation fallback (15fps, limited features)
|
|
10
|
+
- **macOS < 13**: Not supported
|
|
11
|
+
|
|
12
|
+
## Debug Steps for macOS 13/14 Issues
|
|
13
|
+
|
|
14
|
+
### 1. Check Console Logs
|
|
15
|
+
|
|
16
|
+
When running your application, check for these log messages:
|
|
17
|
+
|
|
18
|
+
**macOS 14:**
|
|
19
|
+
```
|
|
20
|
+
๐ฅ๏ธ macOS Version: 14.x.x
|
|
21
|
+
๐ฏ macOS 14 detected - using AVFoundation for better compatibility
|
|
22
|
+
๐ฅ Using AVFoundation for macOS 14 compatibility
|
|
23
|
+
๐ฅ RECORDING METHOD: AVFoundation (Fallback)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**macOS 13:**
|
|
27
|
+
```
|
|
28
|
+
๐ฅ๏ธ macOS Version: 13.x.x
|
|
29
|
+
๐ฏ macOS 13 detected - using AVFoundation (limited features)
|
|
30
|
+
๐ฅ Using AVFoundation for macOS 13 compatibility (limited features)
|
|
31
|
+
๐ฅ RECORDING METHOD: AVFoundation (Fallback)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 2. Test AVFoundation Directly
|
|
35
|
+
|
|
36
|
+
You can force AVFoundation mode for testing:
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
// Set environment variable before running
|
|
40
|
+
process.env.FORCE_AVFOUNDATION = "1";
|
|
41
|
+
|
|
42
|
+
const MacRecorder = require('node-mac-recorder');
|
|
43
|
+
const recorder = new MacRecorder();
|
|
44
|
+
|
|
45
|
+
async function test() {
|
|
46
|
+
const success = await recorder.startRecording('./test.mov', {
|
|
47
|
+
captureCursor: true,
|
|
48
|
+
includeMicrophone: false,
|
|
49
|
+
includeSystemAudio: true
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (success) {
|
|
53
|
+
console.log('โ
AVFoundation recording started');
|
|
54
|
+
setTimeout(async () => {
|
|
55
|
+
await recorder.stopRecording();
|
|
56
|
+
console.log('โ
Recording completed');
|
|
57
|
+
}, 3000);
|
|
58
|
+
} else {
|
|
59
|
+
console.log('โ Recording failed');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
test();
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 3. Common Issues and Solutions
|
|
67
|
+
|
|
68
|
+
**Issue**: Recording starts but no video file created
|
|
69
|
+
- **Cause**: Permission issues
|
|
70
|
+
- **Solution**: Check Screen Recording permission in System Preferences
|
|
71
|
+
|
|
72
|
+
**Issue**: Audio not recorded
|
|
73
|
+
- **Cause**: Microphone permission missing
|
|
74
|
+
- **Solution**: Check Microphone permission in System Preferences
|
|
75
|
+
|
|
76
|
+
**Issue**: Recording fails silently
|
|
77
|
+
- **Cause**: Invalid display ID or output path
|
|
78
|
+
- **Solution**: Use default display (don't specify displayId) and ensure output directory exists
|
|
79
|
+
|
|
80
|
+
### 4. Permission Requirements
|
|
81
|
+
|
|
82
|
+
macOS 14 requires these permissions:
|
|
83
|
+
- โ
Screen Recording (System Preferences > Privacy & Security)
|
|
84
|
+
- โ
Microphone (if includeMicrophone: true)
|
|
85
|
+
- โ
Accessibility (for cursor tracking)
|
|
86
|
+
|
|
87
|
+
### 5. Technical Details
|
|
88
|
+
|
|
89
|
+
**AVFoundation Implementation (macOS 14):**
|
|
90
|
+
- Video: H.264 encoding at 15fps
|
|
91
|
+
- Audio: AAC encoding at 44.1kHz
|
|
92
|
+
- Screen capture: CGDisplayCreateImage
|
|
93
|
+
- Memory management: Automatic cleanup
|
|
94
|
+
|
|
95
|
+
**Differences from ScreenCaptureKit:**
|
|
96
|
+
- Lower frame rate (15fps vs 30fps) for stability
|
|
97
|
+
- No automatic window exclusion
|
|
98
|
+
- Simpler audio routing
|
|
99
|
+
|
|
100
|
+
**macOS 13 Specific Limitations:**
|
|
101
|
+
- Audio features may have reduced compatibility
|
|
102
|
+
- Some advanced recording options may not work
|
|
103
|
+
- Recommended to test thoroughly on target systems
|
|
104
|
+
|
|
105
|
+
## Contact
|
|
106
|
+
|
|
107
|
+
If recording still fails on macOS 14 after following this guide, please provide:
|
|
108
|
+
1. macOS version (`sw_vers`)
|
|
109
|
+
2. Console logs from the application
|
|
110
|
+
3. Permission status screenshots
|
|
111
|
+
4. Minimal reproduction code
|
package/package.json
CHANGED
package/src/mac_recorder.mm
CHANGED
|
@@ -192,18 +192,23 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
|
|
|
192
192
|
|
|
193
193
|
// Check macOS version for ScreenCaptureKit compatibility
|
|
194
194
|
NSOperatingSystemVersion osVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
|
|
195
|
-
BOOL isM15Plus = (osVersion.majorVersion
|
|
196
|
-
|
|
197
|
-
BOOL
|
|
198
|
-
(osVersion.majorVersion == 14 && osVersion.minorVersion >= 0));
|
|
195
|
+
BOOL isM15Plus = (osVersion.majorVersion >= 15);
|
|
196
|
+
BOOL isM14Plus = (osVersion.majorVersion >= 14);
|
|
197
|
+
BOOL isM13Plus = (osVersion.majorVersion >= 13);
|
|
199
198
|
|
|
200
199
|
NSLog(@"๐ฅ๏ธ macOS Version: %ld.%ld.%ld",
|
|
201
200
|
(long)osVersion.majorVersion, (long)osVersion.minorVersion, (long)osVersion.patchVersion);
|
|
202
201
|
|
|
203
|
-
//
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
202
|
+
// Force AVFoundation for debugging/testing
|
|
203
|
+
BOOL forceAVFoundation = (getenv("FORCE_AVFOUNDATION") != NULL);
|
|
204
|
+
if (forceAVFoundation) {
|
|
205
|
+
NSLog(@"๐ง FORCE_AVFOUNDATION environment variable detected - skipping ScreenCaptureKit");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Use ScreenCaptureKit only on macOS 15+ for maximum stability
|
|
209
|
+
// macOS 14 should use AVFoundation fallback
|
|
210
|
+
if (@available(macOS 12.3, *) && isM15Plus && !forceAVFoundation) {
|
|
211
|
+
NSLog(@"โ
macOS 15+ detected - ScreenCaptureKit available with full compatibility");
|
|
207
212
|
|
|
208
213
|
// Try ScreenCaptureKit with extensive safety measures
|
|
209
214
|
@try {
|
|
@@ -275,20 +280,32 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
|
|
|
275
280
|
NSLog(@"โ Exception during ScreenCaptureKit availability check: %@", availabilityException.reason);
|
|
276
281
|
return Napi::Boolean::New(env, false);
|
|
277
282
|
}
|
|
283
|
+
} else if (isM14Plus) {
|
|
284
|
+
// macOS 14 - directly use AVFoundation for better compatibility
|
|
285
|
+
NSLog(@"๐ฏ macOS 14 detected - using AVFoundation for better compatibility");
|
|
286
|
+
} else if (isM13Plus) {
|
|
287
|
+
// macOS 13 - use AVFoundation (limited features)
|
|
288
|
+
NSLog(@"๐ฏ macOS 13 detected - using AVFoundation (limited features)");
|
|
278
289
|
} else {
|
|
279
|
-
NSLog(@"โ macOS version too old
|
|
290
|
+
NSLog(@"โ macOS version too old (< 13.0) - Recording not supported");
|
|
280
291
|
return Napi::Boolean::New(env, false);
|
|
281
292
|
}
|
|
282
293
|
|
|
283
|
-
//
|
|
294
|
+
// AVFoundation fallback logic
|
|
284
295
|
if (isElectron) {
|
|
285
296
|
NSLog(@"โ ScreenCaptureKit failed in Electron - AVFoundation disabled for stability");
|
|
286
297
|
NSLog(@"โ Recording not available in Electron when ScreenCaptureKit fails");
|
|
287
298
|
return Napi::Boolean::New(env, false);
|
|
288
299
|
}
|
|
289
300
|
|
|
290
|
-
// Try AVFoundation fallback (
|
|
291
|
-
|
|
301
|
+
// Try AVFoundation fallback (ScreenCaptureKit failed or macOS 13/14)
|
|
302
|
+
if (isM15Plus) {
|
|
303
|
+
NSLog(@"๐ ScreenCaptureKit failed on macOS 15+ - attempting AVFoundation fallback");
|
|
304
|
+
} else if (isM14Plus) {
|
|
305
|
+
NSLog(@"๐ฅ Using AVFoundation for macOS 14 compatibility");
|
|
306
|
+
} else if (isM13Plus) {
|
|
307
|
+
NSLog(@"๐ฅ Using AVFoundation for macOS 13 compatibility (limited features)");
|
|
308
|
+
}
|
|
292
309
|
|
|
293
310
|
@try {
|
|
294
311
|
// Import AVFoundation recording functions (if available)
|
package/test-macos14.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const MacRecorder = require('./index');
|
|
2
|
+
|
|
3
|
+
async function testMacOS14Recording() {
|
|
4
|
+
const recorder = new MacRecorder();
|
|
5
|
+
|
|
6
|
+
console.log('๐งช macOS 14 Recording Test');
|
|
7
|
+
console.log('This will test AVFoundation fallback path when ScreenCaptureKit fails or is not available');
|
|
8
|
+
console.log('');
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const outputPath = './test-output/macos14-test.mov';
|
|
12
|
+
|
|
13
|
+
console.log('๐น Starting recording test...');
|
|
14
|
+
console.log('Expected behavior on macOS 14:');
|
|
15
|
+
console.log(' 1. System detects macOS 14.x');
|
|
16
|
+
console.log(' 2. Skips ScreenCaptureKit (only for macOS 15+)');
|
|
17
|
+
console.log(' 3. Uses AVFoundation fallback');
|
|
18
|
+
console.log(' 4. Records at 15fps with H.264 encoding');
|
|
19
|
+
console.log('');
|
|
20
|
+
|
|
21
|
+
const success = await recorder.startRecording(outputPath, {
|
|
22
|
+
captureCursor: true,
|
|
23
|
+
includeMicrophone: false,
|
|
24
|
+
includeSystemAudio: true,
|
|
25
|
+
displayId: null // Use main display
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (success) {
|
|
29
|
+
console.log('โ
Recording started successfully');
|
|
30
|
+
console.log('โฑ๏ธ Recording for 3 seconds...');
|
|
31
|
+
|
|
32
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
33
|
+
|
|
34
|
+
console.log('๐ Stopping recording...');
|
|
35
|
+
await recorder.stopRecording();
|
|
36
|
+
|
|
37
|
+
console.log('โ
macOS 14 test completed successfully!');
|
|
38
|
+
console.log('๐ Output file: ' + outputPath);
|
|
39
|
+
} else {
|
|
40
|
+
console.log('โ Recording failed to start');
|
|
41
|
+
console.log('');
|
|
42
|
+
console.log('Troubleshooting steps:');
|
|
43
|
+
console.log('1. Check Screen Recording permission in System Preferences');
|
|
44
|
+
console.log('2. Ensure macOS version is 14.0 or later');
|
|
45
|
+
console.log('3. Check console logs for detailed error messages');
|
|
46
|
+
}
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.log('โ Error during test:', error.message);
|
|
49
|
+
if (error.stack) {
|
|
50
|
+
console.log('Stack trace:', error.stack);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Run the test
|
|
56
|
+
testMacOS14Recording();
|