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 +1 -1
- package/src/mac_recorder.mm +88 -5
- package/src/window_selector.mm +9 -6
- package/window-selector.js +9 -0
package/package.json
CHANGED
package/src/mac_recorder.mm
CHANGED
|
@@ -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
|
-
|
|
92
|
-
|
|
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
|
}
|
package/src/window_selector.mm
CHANGED
|
@@ -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
|
-
|
|
977
|
-
return env
|
|
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
|
-
|
|
1276
|
-
return env
|
|
1277
|
+
NSLog(@"โ ๏ธ Window info object required");
|
|
1278
|
+
return Napi::Boolean::New(env, false);
|
|
1277
1279
|
}
|
|
1278
1280
|
|
|
1279
1281
|
if (!info[0].IsObject()) {
|
|
1280
|
-
|
|
1281
|
-
return env
|
|
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
|
}
|
package/window-selector.js
CHANGED
|
@@ -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
|
/**
|