node-mac-recorder 2.21.54 → 2.22.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 +2 -1
- package/index.js +4 -1
- package/package.json +1 -1
- package/src/camera_recorder.mm +46 -4
- package/src/mac_recorder.mm +10 -1
package/index.js
CHANGED
|
@@ -1119,12 +1119,15 @@ class MacRecorder extends EventEmitter {
|
|
|
1119
1119
|
try {
|
|
1120
1120
|
console.log('🛑 SYNC: Stopping screen recording');
|
|
1121
1121
|
const stopLimit = elapsedSeconds > 0 ? elapsedSeconds : 0;
|
|
1122
|
+
console.log(`📊 DEBUG: elapsedSeconds=${elapsedSeconds.toFixed(3)}, stopLimit=${stopLimit.toFixed(3)}`);
|
|
1123
|
+
console.log(`📊 DEBUG: typeof nativeBinding.stopRecording = ${typeof nativeBinding.stopRecording}`);
|
|
1124
|
+
console.log(`📊 DEBUG: nativeBinding.stopRecording = ${nativeBinding.stopRecording}`);
|
|
1122
1125
|
success = nativeBinding.stopRecording(stopLimit);
|
|
1123
1126
|
if (success) {
|
|
1124
1127
|
console.log('✅ SYNC: Screen recording stopped');
|
|
1125
1128
|
}
|
|
1126
1129
|
} catch (nativeError) {
|
|
1127
|
-
|
|
1130
|
+
console.log('⚠️ Native stop failed:', nativeError.message);
|
|
1128
1131
|
success = true; // Assume success to avoid throwing
|
|
1129
1132
|
}
|
|
1130
1133
|
|
package/package.json
CHANGED
package/src/camera_recorder.mm
CHANGED
|
@@ -451,10 +451,11 @@ static void MRCameraRemoveFileIfExists(NSString *path) {
|
|
|
451
451
|
|
|
452
452
|
MRLog(@"🎥 Camera recording dimensions: %zux%zu", width, height);
|
|
453
453
|
|
|
454
|
-
// H.264 video settings
|
|
455
|
-
|
|
456
|
-
bitrate =
|
|
457
|
-
bitrate =
|
|
454
|
+
// H.264 video settings - optimized for smaller file size
|
|
455
|
+
// Using lower bitrate multiplier for camera (2x instead of 24x) to reduce file size
|
|
456
|
+
NSInteger bitrate = (NSInteger)(width * height * 2);
|
|
457
|
+
bitrate = MAX(bitrate, 1 * 1000 * 1000); // Min 1 Mbps
|
|
458
|
+
bitrate = MIN(bitrate, 6 * 1000 * 1000); // Max 6 Mbps (significantly reduced from 30)
|
|
458
459
|
|
|
459
460
|
NSDictionary *compressionProps = @{
|
|
460
461
|
AVVideoAverageBitRateKey: @(bitrate),
|
|
@@ -586,6 +587,39 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
|
|
586
587
|
adjustedTimestamp = kCMTimeZero;
|
|
587
588
|
}
|
|
588
589
|
|
|
590
|
+
// LIP SYNC FIX: Check stopLimit OR elapsed time to drop frames after recording duration
|
|
591
|
+
// This prevents camera from recording longer than audio
|
|
592
|
+
double frameTime = CMTimeGetSeconds(adjustedTimestamp);
|
|
593
|
+
double stopLimit = MRSyncGetStopLimitSeconds();
|
|
594
|
+
double videoTolerance = 0.05; // 50ms tolerance for video frames (larger than audio's 20ms)
|
|
595
|
+
|
|
596
|
+
// CRITICAL FIX: Also check elapsed time since recording started
|
|
597
|
+
// This works even if stopLimit hasn't been set yet
|
|
598
|
+
double elapsedTime = (g_cameraStartTimestamp > 0) ? (CFAbsoluteTimeGetCurrent() - g_cameraStartTimestamp) : 0;
|
|
599
|
+
double maxDuration = (stopLimit > 0) ? stopLimit : elapsedTime + 1.0; // Use stopLimit if available, else allow 1s more
|
|
600
|
+
|
|
601
|
+
// DEBUG: Log every 30th frame
|
|
602
|
+
static int frameCounter = 0;
|
|
603
|
+
frameCounter++;
|
|
604
|
+
if (frameCounter % 30 == 0) {
|
|
605
|
+
MRLog(@"📹 Camera frame #%d: frameTime=%.3fs, elapsedTime=%.3fs, stopLimit=%.3fs, maxDuration=%.3fs",
|
|
606
|
+
frameCounter, frameTime, elapsedTime, stopLimit, maxDuration);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Drop frame if it exceeds stopLimit (when set) or if elapsed time is suspiciously long
|
|
610
|
+
if (stopLimit > 0 && frameTime > stopLimit + videoTolerance) {
|
|
611
|
+
MRLog(@"🛑 Camera dropping frame #%d: frameTime %.3fs > stopLimit %.3fs + tolerance",
|
|
612
|
+
frameCounter, frameTime, stopLimit);
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// Safety check: Drop frames if recording has been going for too long (failsafe)
|
|
617
|
+
if (elapsedTime > maxDuration + 1.0) { // Allow 1s grace period
|
|
618
|
+
MRLog(@"🛑 Camera dropping frame #%d: elapsed %.3fs > maxDuration %.3fs (failsafe)",
|
|
619
|
+
frameCounter, elapsedTime, maxDuration);
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
|
|
589
623
|
// Get pixel buffer from sample
|
|
590
624
|
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
|
591
625
|
if (!pixelBuffer) {
|
|
@@ -872,6 +906,14 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
|
|
872
906
|
|
|
873
907
|
// Finalize writer (audio_recorder.mm pattern)
|
|
874
908
|
if (self.writer && self.writerStarted) {
|
|
909
|
+
// LIP SYNC FIX: End session at stopLimit to trim excess frames
|
|
910
|
+
double stopLimit = MRSyncGetStopLimitSeconds();
|
|
911
|
+
if (stopLimit > 0) {
|
|
912
|
+
CMTime endTime = CMTimeMakeWithSeconds(stopLimit, 600);
|
|
913
|
+
[self.writer endSessionAtSourceTime:endTime];
|
|
914
|
+
MRLog(@"🎯 Camera writer session ended at %.3fs (stopLimit)", stopLimit);
|
|
915
|
+
}
|
|
916
|
+
|
|
875
917
|
if (self.writerInput) {
|
|
876
918
|
[self.writerInput markAsFinished];
|
|
877
919
|
}
|
package/src/mac_recorder.mm
CHANGED
|
@@ -786,14 +786,23 @@ Napi::Value StopRecording(const Napi::CallbackInfo& info) {
|
|
|
786
786
|
}
|
|
787
787
|
|
|
788
788
|
if (requestedStopLimit > 0) {
|
|
789
|
+
MRLog(@"🎯 SYNC FIX: Setting stopLimit = %.3f seconds", requestedStopLimit);
|
|
789
790
|
MRStoreActiveStopLimit(requestedStopLimit);
|
|
790
791
|
MRSyncSetStopLimitSeconds(requestedStopLimit);
|
|
791
792
|
} else {
|
|
793
|
+
MRLog(@"⚠️ SYNC FIX: stopLimit NOT set (requestedStopLimit = %.3f)", requestedStopLimit);
|
|
792
794
|
MRStoreActiveStopLimit(-1.0);
|
|
793
795
|
MRSyncSetStopLimitSeconds(-1.0);
|
|
794
796
|
}
|
|
795
797
|
MRResetRecordingStartTimestamp();
|
|
796
|
-
|
|
798
|
+
|
|
799
|
+
// LIP SYNC FIX: Wait 150ms for camera/audio delegates to see stopLimit and drop excess frames
|
|
800
|
+
if (requestedStopLimit > 0 && (isCameraRecording() || isStandaloneAudioRecording())) {
|
|
801
|
+
MRLog(@"⏳ LIP SYNC: Waiting 150ms for delegates to process stopLimit...");
|
|
802
|
+
[NSThread sleepForTimeInterval:0.15];
|
|
803
|
+
MRLog(@"✅ LIP SYNC: Delegate processing time complete");
|
|
804
|
+
}
|
|
805
|
+
|
|
797
806
|
// Try ScreenCaptureKit first
|
|
798
807
|
if (@available(macOS 12.3, *)) {
|
|
799
808
|
if ([ScreenCaptureKitRecorder isRecording]) {
|