node-mac-recorder 2.13.3 → 2.13.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.13.3",
3
+ "version": "2.13.5",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -168,9 +168,12 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
168
168
  }
169
169
 
170
170
  @try {
171
- // Phase 4: Pure ScreenCaptureKit with memory-optimized implementation
172
- NSLog(@"🔍 Phase 4: Pure ScreenCaptureKit with Electron-safe memory optimization");
173
- if (@available(macOS 12.3, *)) {
171
+ // Phase 4: DISABLED ScreenCaptureKit due to Electron crashes (Thread 52 crash confirmed)
172
+ NSLog(@"⚠️ ScreenCaptureKit DISABLED: Causes consistent Electron crashes in ElectronSafeOutput");
173
+ NSLog(@"📋 Crash Report: Thread 52 crash in stream:didOutputSampleBuffer:ofType: method");
174
+ NSLog(@"🎯 Using AVFoundation instead - stable in Electron environment");
175
+
176
+ if (false) { // Permanently disabled ScreenCaptureKit
174
177
  NSLog(@"✅ macOS 12.3+ detected - ScreenCaptureKit should be available");
175
178
  if ([ScreenCaptureKitRecorder isScreenCaptureKitAvailable]) {
176
179
  NSLog(@"✅ ScreenCaptureKit availability check passed");
@@ -57,45 +57,45 @@ static BOOL g_writerStarted = NO;
57
57
  NSLog(@"✅ Electron-safe video writer started");
58
58
  }
59
59
 
60
- // Write sample buffer with improved pixel buffer validation
61
- if (g_writerStarted && g_assetWriterInput.isReadyForMoreMediaData) {
62
- CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
60
+ // Ultra-conservative Electron-safe sample buffer processing
61
+ @autoreleasepool {
62
+ if (!g_writerStarted || !g_assetWriterInput || !g_pixelBufferAdaptor) {
63
+ return; // Skip if not ready
64
+ }
65
+
66
+ // Rate limiting for Electron stability
67
+ static NSTimeInterval lastProcessTime = 0;
68
+ NSTimeInterval currentTime = [NSDate timeIntervalSinceReferenceDate];
69
+ if (currentTime - lastProcessTime < 0.1) { // Max 10 FPS for stability
70
+ return;
71
+ }
72
+ lastProcessTime = currentTime;
63
73
 
64
- // Validate pixel buffer more thoroughly
65
- if (pixelBuffer && g_pixelBufferAdaptor) {
66
- // Check if pixel buffer has valid dimensions
67
- size_t width = CVPixelBufferGetWidth(pixelBuffer);
68
- size_t height = CVPixelBufferGetHeight(pixelBuffer);
74
+ if (g_assetWriterInput.isReadyForMoreMediaData) {
75
+ CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
69
76
 
70
- if (width > 0 && height > 0) {
71
- CMTime presentationTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
72
- CMTime relativeTime = CMTimeSubtract(presentationTime, g_startTime);
77
+ if (pixelBuffer && g_pixelBufferAdaptor) {
78
+ // Ultra-conservative validation
79
+ size_t width = CVPixelBufferGetWidth(pixelBuffer);
80
+ size_t height = CVPixelBufferGetHeight(pixelBuffer);
73
81
 
74
- BOOL success = [g_pixelBufferAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:relativeTime];
75
- if (success) {
76
- g_currentTime = relativeTime;
77
- static int validFrameCount = 0;
78
- validFrameCount++;
79
- if (validFrameCount % 30 == 0) {
80
- NSLog(@"✅ Successfully wrote %d valid frames (%dx%d)", validFrameCount, (int)width, (int)height);
82
+ if (width == 1280 && height == 720) { // Exact match only
83
+ CMTime presentationTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
84
+ CMTime relativeTime = CMTimeSubtract(presentationTime, g_startTime);
85
+
86
+ // Conservative time validation
87
+ if (CMTimeGetSeconds(relativeTime) >= 0 && CMTimeGetSeconds(relativeTime) < 30) {
88
+ BOOL success = [g_pixelBufferAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:relativeTime];
89
+ if (success) {
90
+ g_currentTime = relativeTime;
91
+ static int safeFrameCount = 0;
92
+ safeFrameCount++;
93
+ if (safeFrameCount % 10 == 0) {
94
+ NSLog(@"✅ Electron-safe: %d frames", safeFrameCount);
95
+ }
96
+ }
81
97
  }
82
- } else {
83
- NSLog(@"⚠️ Failed to append valid pixel buffer (%dx%d) at time %f", (int)width, (int)height, CMTimeGetSeconds(relativeTime));
84
- NSLog(@"Asset writer status: %ld, error: %@", (long)g_assetWriter.status, g_assetWriter.error);
85
98
  }
86
- } else {
87
- static int invalidSizeCount = 0;
88
- invalidSizeCount++;
89
- if (invalidSizeCount % 50 == 0) {
90
- NSLog(@"⚠️ Invalid pixel buffer dimensions: %dx%d (%d times)", (int)width, (int)height, invalidSizeCount);
91
- }
92
- }
93
- } else {
94
- // Only log occasionally to avoid spam
95
- static int nullBufferCount = 0;
96
- nullBufferCount++;
97
- if (nullBufferCount % 100 == 0) {
98
- NSLog(@"⚠️ Null pixel buffer (%d times) - adaptor: %p", nullBufferCount, g_pixelBufferAdaptor);
99
99
  }
100
100
  }
101
101
  }
@@ -137,12 +137,14 @@ static BOOL g_writerStarted = NO;
137
137
  // Simple content filter - no exclusions for now
138
138
  SCContentFilter *filter = [[SCContentFilter alloc] initWithDisplay:targetDisplay excludingWindows:@[]];
139
139
 
140
- // Stream configuration
140
+ // Electron-optimized stream configuration (lower resource usage)
141
141
  SCStreamConfiguration *streamConfig = [[SCStreamConfiguration alloc] init];
142
142
  streamConfig.width = 1280;
143
143
  streamConfig.height = 720;
144
- streamConfig.minimumFrameInterval = CMTimeMake(1, 30);
144
+ streamConfig.minimumFrameInterval = CMTimeMake(1, 10); // 10 FPS for stability
145
145
  streamConfig.pixelFormat = kCVPixelFormatType_32BGRA;
146
+ streamConfig.capturesAudio = NO; // Disable audio for simplicity
147
+ streamConfig.excludesCurrentProcessAudio = YES;
146
148
 
147
149
  // Create Electron-safe delegates
148
150
  g_streamDelegate = [[ElectronSafeDelegate alloc] init];
@@ -211,19 +213,20 @@ static BOOL g_writerStarted = NO;
211
213
  return;
212
214
  }
213
215
 
214
- // Electron-safe video settings
216
+ // Ultra-conservative Electron video settings
215
217
  NSDictionary *videoSettings = @{
216
218
  AVVideoCodecKey: AVVideoCodecTypeH264,
217
219
  AVVideoWidthKey: @1280,
218
220
  AVVideoHeightKey: @720,
219
221
  AVVideoCompressionPropertiesKey: @{
220
- AVVideoAverageBitRateKey: @(1280 * 720 * 2),
221
- AVVideoMaxKeyFrameIntervalKey: @30
222
+ AVVideoAverageBitRateKey: @(1280 * 720 * 1), // Lower bitrate
223
+ AVVideoMaxKeyFrameIntervalKey: @10,
224
+ AVVideoProfileLevelKey: AVVideoProfileLevelH264BaselineAutoLevel
222
225
  }
223
226
  };
224
227
 
225
228
  g_assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
226
- g_assetWriterInput.expectsMediaDataInRealTime = YES; // Important for live capture
229
+ g_assetWriterInput.expectsMediaDataInRealTime = NO; // Safer for Electron
227
230
 
228
231
  // Pixel buffer attributes matching ScreenCaptureKit format
229
232
  NSDictionary *pixelBufferAttributes = @{