node-mac-recorder 2.16.1 โ†’ 2.16.3

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.
@@ -44,7 +44,10 @@
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\")",
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\")"
48
51
  ],
49
52
  "deny": []
50
53
  }
@@ -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
@@ -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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.16.1",
3
+ "version": "2.16.3",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -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
- [[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
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 = @{
@@ -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 > 15 ||
196
- (osVersion.majorVersion == 15 && osVersion.minorVersion >= 0));
197
- BOOL isM14Plus = (osVersion.majorVersion > 14 ||
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
- // Try ScreenCaptureKit on macOS 14+ (with better compatibility on 15+)
204
- if (@available(macOS 12.3, *) && isM14Plus) {
205
- NSLog(@"โœ… macOS 14+ detected - ScreenCaptureKit available with %@ compatibility",
206
- isM15Plus ? @"full" : @"limited");
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,22 +280,42 @@ 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 for ScreenCaptureKit (< 12.3) - Recording not supported");
290
+ NSLog(@"โŒ macOS version too old (< 13.0) - Recording not supported");
280
291
  return Napi::Boolean::New(env, false);
281
292
  }
282
293
 
283
- // If we get here, ScreenCaptureKit failed
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 (only in non-Electron environments)
291
- NSLog(@"๐Ÿ”„ ScreenCaptureKit failed - attempting AVFoundation fallback");
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 {
311
+ NSLog(@"๐Ÿ”ง Attempting AVFoundation recording...");
312
+ NSLog(@"๐Ÿ”ง Output path: %s", outputPath.c_str());
313
+ NSLog(@"๐Ÿ”ง Display ID: %u", displayID);
314
+ NSLog(@"๐Ÿ”ง Cursor: %s, Mic: %s, System Audio: %s",
315
+ captureCursor ? "YES" : "NO",
316
+ includeMicrophone ? "YES" : "NO",
317
+ includeSystemAudio ? "YES" : "NO");
318
+
294
319
  // Import AVFoundation recording functions (if available)
295
320
  extern bool startAVFoundationRecording(const std::string& outputPath,
296
321
  CGDirectDisplayID displayID,
@@ -301,17 +326,23 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
301
326
  bool includeSystemAudio,
302
327
  NSString* audioDeviceId);
303
328
 
304
- if (startAVFoundationRecording(outputPath, displayID, windowID, captureRect,
305
- captureCursor, includeMicrophone, includeSystemAudio, audioDeviceId)) {
329
+ NSLog(@"๐Ÿ”ง Calling startAVFoundationRecording...");
330
+ bool avResult = startAVFoundationRecording(outputPath, displayID, windowID, captureRect,
331
+ captureCursor, includeMicrophone, includeSystemAudio, audioDeviceId);
332
+ NSLog(@"๐Ÿ”ง AVFoundation result: %s", avResult ? "SUCCESS" : "FAILED");
333
+
334
+ if (avResult) {
306
335
  NSLog(@"๐ŸŽฅ RECORDING METHOD: AVFoundation (Fallback)");
307
336
  NSLog(@"โœ… AVFoundation recording started successfully");
308
337
  g_isRecording = true;
309
338
  return Napi::Boolean::New(env, true);
310
339
  } else {
311
- NSLog(@"โŒ AVFoundation recording also failed to start");
340
+ NSLog(@"โŒ AVFoundation recording failed to start");
341
+ NSLog(@"โŒ Check permissions and output path validity");
312
342
  }
313
343
  } @catch (NSException *avException) {
314
344
  NSLog(@"โŒ Exception during AVFoundation startup: %@", avException.reason);
345
+ NSLog(@"โŒ Stack trace: %@", [avException callStackSymbols]);
315
346
  }
316
347
 
317
348
  // Both ScreenCaptureKit and AVFoundation failed
@@ -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();