node-mac-recorder 2.21.28 → 2.21.30
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/camera_recorder.mm +20 -10
- package/src/mac_recorder.mm +33 -15
package/package.json
CHANGED
package/src/camera_recorder.mm
CHANGED
|
@@ -754,31 +754,41 @@ static BOOL MRIsContinuityCamera(AVCaptureDevice *device) {
|
|
|
754
754
|
return YES; // Success - nothing to finish
|
|
755
755
|
}
|
|
756
756
|
|
|
757
|
-
|
|
758
|
-
|
|
757
|
+
AVAssetWriter *writer = self.assetWriter;
|
|
758
|
+
AVAssetWriterInput *writerInput = self.assetWriterInput;
|
|
759
|
+
|
|
760
|
+
if (writerInput) {
|
|
761
|
+
[writerInput markAsFinished];
|
|
759
762
|
}
|
|
760
763
|
|
|
761
764
|
__block BOOL finished = NO;
|
|
762
765
|
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
763
766
|
|
|
764
|
-
[
|
|
767
|
+
[writer finishWritingWithCompletionHandler:^{
|
|
765
768
|
finished = YES;
|
|
766
769
|
dispatch_semaphore_signal(semaphore);
|
|
767
770
|
}];
|
|
768
771
|
|
|
769
|
-
//
|
|
770
|
-
|
|
772
|
+
// Allow generous flush time so final frames are preserved.
|
|
773
|
+
const int64_t primaryWaitSeconds = 3;
|
|
774
|
+
dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(primaryWaitSeconds * NSEC_PER_SEC));
|
|
771
775
|
long result = dispatch_semaphore_wait(semaphore, timeout);
|
|
772
776
|
|
|
773
777
|
if (result != 0 || !finished) {
|
|
774
|
-
MRLog(@"⚠️ CameraRecorder:
|
|
775
|
-
|
|
776
|
-
|
|
778
|
+
MRLog(@"⚠️ CameraRecorder: Writer still finishing after %ds – waiting longer", (int)primaryWaitSeconds);
|
|
779
|
+
const int64_t extendedWaitSeconds = 5;
|
|
780
|
+
dispatch_time_t extendedTimeout = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(extendedWaitSeconds * NSEC_PER_SEC));
|
|
781
|
+
result = dispatch_semaphore_wait(semaphore, extendedTimeout);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
if (result != 0 || !finished) {
|
|
785
|
+
MRLog(@"⚠️ CameraRecorder: Writer did not finish after extended wait – forcing cancel");
|
|
786
|
+
[writer cancelWriting];
|
|
777
787
|
}
|
|
778
788
|
|
|
779
|
-
BOOL success = (
|
|
789
|
+
BOOL success = (writer.status == AVAssetWriterStatusCompleted);
|
|
780
790
|
if (!success) {
|
|
781
|
-
MRLog(@"⚠️ CameraRecorder: Writer finished with status %ld error %@", (long)
|
|
791
|
+
MRLog(@"⚠️ CameraRecorder: Writer finished with status %ld error %@", (long)writer.status, writer.error);
|
|
782
792
|
} else {
|
|
783
793
|
MRLog(@"✅ CameraRecorder writer finished successfully");
|
|
784
794
|
}
|
package/src/mac_recorder.mm
CHANGED
|
@@ -630,33 +630,51 @@ Napi::Value StopRecording(const Napi::CallbackInfo& info) {
|
|
|
630
630
|
if (isAVFoundationRecording()) {
|
|
631
631
|
MRLog(@"🛑 Stopping AVFoundation recording");
|
|
632
632
|
|
|
633
|
-
|
|
634
|
-
|
|
633
|
+
BOOL cameraWasRecording = isCameraRecording();
|
|
634
|
+
__block BOOL cameraStopResult = YES;
|
|
635
|
+
dispatch_group_t cameraStopGroup = NULL;
|
|
636
|
+
|
|
637
|
+
if (cameraWasRecording) {
|
|
635
638
|
MRLog(@"🛑 Stopping camera recording...");
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
639
|
+
cameraStopResult = NO;
|
|
640
|
+
cameraStopGroup = dispatch_group_create();
|
|
641
|
+
dispatch_group_enter(cameraStopGroup);
|
|
642
|
+
// Stop camera on a background queue so audio/screen shutdown can proceed immediately.
|
|
643
|
+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
|
644
|
+
cameraStopResult = stopCameraRecording() ? YES : NO;
|
|
645
|
+
dispatch_group_leave(cameraStopGroup);
|
|
646
|
+
});
|
|
642
647
|
}
|
|
643
648
|
|
|
644
|
-
// Stop standalone audio if used
|
|
649
|
+
// Stop standalone audio if used (ScreenCaptureKit fallback)
|
|
645
650
|
if (g_usingStandaloneAudio && isStandaloneAudioRecording()) {
|
|
646
651
|
MRLog(@"🛑 Stopping standalone audio...");
|
|
647
652
|
stopStandaloneAudioRecording();
|
|
648
653
|
}
|
|
649
654
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
655
|
+
bool avFoundationStopped = stopAVFoundationRecording();
|
|
656
|
+
|
|
657
|
+
if (cameraStopGroup) {
|
|
658
|
+
dispatch_time_t waitTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC));
|
|
659
|
+
long waitResult = dispatch_group_wait(cameraStopGroup, waitTime);
|
|
660
|
+
if (waitResult != 0) {
|
|
661
|
+
MRLog(@"⚠️ Camera stop did not finish within 2 seconds (AVFoundation)");
|
|
662
|
+
cameraStopResult = NO;
|
|
663
|
+
} else if (cameraStopResult) {
|
|
664
|
+
MRLog(@"✅ Camera stopped successfully");
|
|
665
|
+
} else {
|
|
666
|
+
MRLog(@"⚠️ Camera stop reported failure");
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
g_isRecording = false;
|
|
671
|
+
g_usingStandaloneAudio = false;
|
|
672
|
+
|
|
673
|
+
if (avFoundationStopped && (!cameraWasRecording || cameraStopResult)) {
|
|
654
674
|
MRLog(@"✅ AVFoundation recording stopped");
|
|
655
675
|
return Napi::Boolean::New(env, true);
|
|
656
676
|
} else {
|
|
657
677
|
NSLog(@"❌ Failed to stop AVFoundation recording");
|
|
658
|
-
g_isRecording = false;
|
|
659
|
-
g_usingStandaloneAudio = false;
|
|
660
678
|
return Napi::Boolean::New(env, false);
|
|
661
679
|
}
|
|
662
680
|
}
|