node-mac-recorder 2.4.5 โ†’ 2.4.7

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.4.5",
3
+ "version": "2.4.7",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -26,6 +26,7 @@ API_AVAILABLE(macos(12.3))
26
26
  @property (nonatomic, strong) AVAssetWriter *assetWriter;
27
27
  @property (nonatomic, strong) AVAssetWriterInput *videoInput;
28
28
  @property (nonatomic, strong) AVAssetWriterInput *audioInput;
29
+ @property (nonatomic, strong) AVAssetWriterInputPixelBufferAdaptor *pixelBufferAdaptor;
29
30
  @property (nonatomic, strong) NSURL *outputURL;
30
31
  @property (nonatomic, assign) BOOL isWriting;
31
32
  @property (nonatomic, assign) CMTime startTime;
@@ -63,6 +64,13 @@ API_AVAILABLE(macos(12.3))
63
64
  return;
64
65
  }
65
66
 
67
+ // Check asset writer status before processing
68
+ if (self.assetWriter.status == AVAssetWriterStatusFailed) {
69
+ NSLog(@"โŒ Asset writer has failed status: %@", self.assetWriter.error.localizedDescription);
70
+ self.startFailed = YES;
71
+ return;
72
+ }
73
+
66
74
  // Start asset writer on first sample buffer
67
75
  if (!self.hasStartTime) {
68
76
  NSLog(@"๐Ÿš€ Starting asset writer with first sample buffer");
@@ -88,10 +96,62 @@ API_AVAILABLE(macos(12.3))
88
96
  case SCStreamOutputTypeScreen: {
89
97
  NSLog(@"๐Ÿ“บ Processing screen sample buffer");
90
98
  if (self.videoInput && self.videoInput.isReadyForMoreMediaData) {
91
- BOOL success = [self.videoInput appendSampleBuffer:sampleBuffer];
92
- NSLog(@"๐Ÿ“บ Video sample buffer appended: %@", success ? @"SUCCESS" : @"FAILED");
99
+ // Check sample buffer validity
100
+ if (!CMSampleBufferIsValid(sampleBuffer)) {
101
+ NSLog(@"โš ๏ธ Invalid sample buffer received");
102
+ return;
103
+ }
104
+
105
+ // Check timing - ensure presentation time is advancing
106
+ CMTime currentTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
107
+ NSLog(@"๐Ÿ“บ Sample buffer PTS: %lld", currentTime.value);
108
+
109
+ BOOL success = NO;
110
+
111
+ // Try using pixel buffer adaptor for better compatibility
112
+ if (self.pixelBufferAdaptor && self.pixelBufferAdaptor.assetWriterInput.isReadyForMoreMediaData) {
113
+ // Extract pixel buffer from sample buffer
114
+ CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
115
+ if (pixelBuffer) {
116
+ success = [self.pixelBufferAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:currentTime];
117
+ NSLog(@"๐Ÿ“บ Pixel buffer appended via adaptor: %@", success ? @"SUCCESS" : @"FAILED");
118
+ } else {
119
+ // Fallback to direct sample buffer append
120
+ success = [self.videoInput appendSampleBuffer:sampleBuffer];
121
+ NSLog(@"๐Ÿ“บ Sample buffer appended directly: %@", success ? @"SUCCESS" : @"FAILED");
122
+ }
123
+ } else {
124
+ // Fallback to direct sample buffer append
125
+ success = [self.videoInput appendSampleBuffer:sampleBuffer];
126
+ NSLog(@"๐Ÿ“บ Video sample buffer appended (fallback): %@", success ? @"SUCCESS" : @"FAILED");
127
+ }
128
+
129
+ if (!success) {
130
+ // Log detailed error information
131
+ NSLog(@"โŒ Video input append failed - Asset Writer Status: %ld", (long)self.assetWriter.status);
132
+ if (self.assetWriter.error) {
133
+ NSLog(@"โŒ Asset Writer Error: %@", self.assetWriter.error.localizedDescription);
134
+ }
135
+
136
+ // Check if asset writer has failed and mark for cleanup
137
+ if (self.assetWriter.status == AVAssetWriterStatusFailed) {
138
+ self.startFailed = YES;
139
+ }
140
+ }
93
141
  } else {
94
- NSLog(@"โš ๏ธ Video input not ready for more data");
142
+ NSLog(@"โš ๏ธ Video input not ready for more data - isReadyForMoreMediaData: %@",
143
+ self.videoInput.isReadyForMoreMediaData ? @"YES" : @"NO");
144
+
145
+ // Also check pixel buffer adaptor readiness
146
+ if (self.pixelBufferAdaptor) {
147
+ NSLog(@"๐Ÿ“Š Pixel buffer adaptor ready: %@",
148
+ self.pixelBufferAdaptor.assetWriterInput.isReadyForMoreMediaData ? @"YES" : @"NO");
149
+ }
150
+
151
+ // Log asset writer input status
152
+ NSLog(@"๐Ÿ“Š Asset Writer Status: %ld, Video Input Status: readyForMoreMediaData=%@",
153
+ (long)self.assetWriter.status,
154
+ self.videoInput.isReadyForMoreMediaData ? @"YES" : @"NO");
95
155
  }
96
156
  break;
97
157
  }
@@ -100,6 +160,10 @@ API_AVAILABLE(macos(12.3))
100
160
  if (self.audioInput && self.audioInput.isReadyForMoreMediaData) {
101
161
  BOOL success = [self.audioInput appendSampleBuffer:sampleBuffer];
102
162
  NSLog(@"๐Ÿ”Š Audio sample buffer appended: %@", success ? @"SUCCESS" : @"FAILED");
163
+
164
+ if (!success && self.assetWriter.error) {
165
+ NSLog(@"โŒ Audio append error: %@", self.assetWriter.error.localizedDescription);
166
+ }
103
167
  } else {
104
168
  NSLog(@"โš ๏ธ Audio input not ready for more data (or no audio input)");
105
169
  }
@@ -110,6 +174,10 @@ API_AVAILABLE(macos(12.3))
110
174
  if (self.audioInput && self.audioInput.isReadyForMoreMediaData) {
111
175
  BOOL success = [self.audioInput appendSampleBuffer:sampleBuffer];
112
176
  NSLog(@"๐ŸŽค Microphone sample buffer appended: %@", success ? @"SUCCESS" : @"FAILED");
177
+
178
+ if (!success && self.assetWriter.error) {
179
+ NSLog(@"โŒ Microphone append error: %@", self.assetWriter.error.localizedDescription);
180
+ }
113
181
  } else {
114
182
  NSLog(@"โš ๏ธ Microphone input not ready for more data (or no audio input)");
115
183
  }
@@ -474,15 +542,30 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
474
542
  NSDictionary *videoSettings = @{
475
543
  AVVideoCodecKey: AVVideoCodecTypeH264,
476
544
  AVVideoWidthKey: @((NSInteger)videoSize.width),
477
- AVVideoHeightKey: @((NSInteger)videoSize.height)
545
+ AVVideoHeightKey: @((NSInteger)videoSize.height),
546
+ AVVideoCompressionPropertiesKey: @{
547
+ AVVideoAverageBitRateKey: @(2000000), // 2 Mbps
548
+ AVVideoMaxKeyFrameIntervalKey: @30
549
+ }
478
550
  };
479
551
 
480
552
  g_scDelegate.videoInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
481
553
  g_scDelegate.videoInput.expectsMediaDataInRealTime = YES;
482
554
 
555
+ // Create pixel buffer adaptor for more robust handling
556
+ NSDictionary *pixelBufferAttributes = @{
557
+ (NSString*)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
558
+ (NSString*)kCVPixelBufferWidthKey: @((NSInteger)videoSize.width),
559
+ (NSString*)kCVPixelBufferHeightKey: @((NSInteger)videoSize.height),
560
+ };
561
+
562
+ g_scDelegate.pixelBufferAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc]
563
+ initWithAssetWriterInput:g_scDelegate.videoInput
564
+ sourcePixelBufferAttributes:pixelBufferAttributes];
565
+
483
566
  if ([g_scDelegate.assetWriter canAddInput:g_scDelegate.videoInput]) {
484
567
  [g_scDelegate.assetWriter addInput:g_scDelegate.videoInput];
485
- NSLog(@"โœ… Video input added to asset writer");
568
+ NSLog(@"โœ… Video input added to asset writer with pixel buffer adaptor");
486
569
  } else {
487
570
  NSLog(@"โŒ Cannot add video input to asset writer");
488
571
  }
@@ -566,6 +566,8 @@ void cleanupWindowSelector() {
566
566
  dispatch_async(dispatch_get_main_queue(), ^{ cleanupWindowSelector(); });
567
567
  return;
568
568
  }
569
+
570
+ NSLog(@"๐Ÿงน Cleaning up window selector resources");
569
571
  g_isWindowSelecting = false;
570
572
 
571
573
  // Stop tracking timer
@@ -973,8 +975,8 @@ Napi::Value StartWindowSelection(const Napi::CallbackInfo& info) {
973
975
  Napi::Env env = info.Env();
974
976
 
975
977
  if (g_isWindowSelecting) {
976
- Napi::TypeError::New(env, "Window selection already in progress").ThrowAsJavaScriptException();
977
- return env.Null();
978
+ NSLog(@"โš ๏ธ Window selection already in progress");
979
+ return Napi::Boolean::New(env, false);
978
980
  }
979
981
 
980
982
  @try {
@@ -1272,13 +1274,13 @@ Napi::Value ShowRecordingPreview(const Napi::CallbackInfo& info) {
1272
1274
  Napi::Env env = info.Env();
1273
1275
 
1274
1276
  if (info.Length() < 1) {
1275
- Napi::TypeError::New(env, "Window info object required").ThrowAsJavaScriptException();
1276
- return env.Null();
1277
+ NSLog(@"โš ๏ธ Window info object required");
1278
+ return Napi::Boolean::New(env, false);
1277
1279
  }
1278
1280
 
1279
1281
  if (!info[0].IsObject()) {
1280
- Napi::TypeError::New(env, "Window info must be an object").ThrowAsJavaScriptException();
1281
- return env.Null();
1282
+ NSLog(@"โš ๏ธ Window info must be an object");
1283
+ return Napi::Boolean::New(env, false);
1282
1284
  }
1283
1285
 
1284
1286
  @try {
@@ -1341,6 +1343,7 @@ Napi::Value StartScreenSelection(const Napi::CallbackInfo& info) {
1341
1343
  return Napi::Boolean::New(env, success);
1342
1344
 
1343
1345
  } @catch (NSException *exception) {
1346
+ NSLog(@"โŒ Screen selection error: %@", exception);
1344
1347
  return Napi::Boolean::New(env, false);
1345
1348
  }
1346
1349
  }
@@ -32,6 +32,15 @@ class WindowSelector extends EventEmitter {
32
32
  this.selectionTimer = null;
33
33
  this.selectedWindow = null;
34
34
  this.lastStatus = null;
35
+
36
+ // Electron environment detection (for logging only)
37
+ this.isElectron = !!(process.versions && process.versions.electron) ||
38
+ !!(process.env.ELECTRON_VERSION) ||
39
+ !!(process.env.ELECTRON_RUN_AS_NODE);
40
+
41
+ if (this.isElectron) {
42
+ console.log("๐Ÿ” WindowSelector: Detected Electron environment");
43
+ }
35
44
  }
36
45
 
37
46
  /**