node-mac-recorder 2.24.9 → 2.24.11

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.
@@ -44,6 +44,15 @@ BOOL MRSyncShouldHoldForPrimary(CMTime timestamp);
44
44
  void MRSyncSetStopLimitSeconds(double seconds);
45
45
  double MRSyncGetStopLimitSeconds(void);
46
46
 
47
+ // Pause/resume the shared media timeline without closing any writers. Samples
48
+ // received while paused are discarded; resumed samples are shifted backwards
49
+ // by the accumulated pause duration so every track remains gap-free.
50
+ void MRSyncPause(void);
51
+ void MRSyncResume(void);
52
+ BOOL MRSyncIsPaused(void);
53
+ CMTime MRSyncAdjustForPauses(CMTime relativeTimestamp);
54
+ double MRSyncGetPausedDurationSeconds(void);
55
+
47
56
  #ifdef __cplusplus
48
57
  }
49
58
  #endif
@@ -17,6 +17,9 @@ static BOOL g_videoHoldLogged = NO;
17
17
  static CMTime g_audioFirstTimestamp = kCMTimeInvalid;
18
18
  static CMTime g_alignmentDelta = kCMTimeInvalid;
19
19
  static double g_stopLimitSeconds = -1.0;
20
+ static BOOL g_isPaused = NO;
21
+ static CFAbsoluteTime g_pauseStartedAt = 0;
22
+ static double g_totalPausedSeconds = 0;
20
23
 
21
24
  // Bidirectional barrier: camera side
22
25
  static BOOL g_expectCamera = NO;
@@ -41,6 +44,9 @@ void MRSyncConfigure(BOOL expectAudio) {
41
44
  g_audioFirstTimestamp = kCMTimeInvalid;
42
45
  g_alignmentDelta = kCMTimeInvalid;
43
46
  g_stopLimitSeconds = -1.0;
47
+ g_isPaused = NO;
48
+ g_pauseStartedAt = 0;
49
+ g_totalPausedSeconds = 0;
44
50
  // Reset camera barrier state
45
51
  g_expectCamera = NO;
46
52
  g_cameraReady = YES;
@@ -55,6 +61,54 @@ void MRSyncConfigure(BOOL expectAudio) {
55
61
  });
56
62
  }
57
63
 
64
+ void MRSyncPause(void) {
65
+ dispatch_sync(MRSyncQueue(), ^{
66
+ if (g_isPaused) return;
67
+ g_isPaused = YES;
68
+ g_pauseStartedAt = CFAbsoluteTimeGetCurrent();
69
+ });
70
+ MRLog(@"⏸️ Recording timeline paused");
71
+ }
72
+
73
+ void MRSyncResume(void) {
74
+ __block BOOL resumed = NO;
75
+ dispatch_sync(MRSyncQueue(), ^{
76
+ if (!g_isPaused) return;
77
+ if (g_pauseStartedAt > 0) {
78
+ g_totalPausedSeconds += MAX(0, CFAbsoluteTimeGetCurrent() - g_pauseStartedAt);
79
+ }
80
+ g_pauseStartedAt = 0;
81
+ g_isPaused = NO;
82
+ resumed = YES;
83
+ });
84
+ if (resumed) MRLog(@"▶️ Recording timeline resumed");
85
+ }
86
+
87
+ BOOL MRSyncIsPaused(void) {
88
+ __block BOOL paused = NO;
89
+ dispatch_sync(MRSyncQueue(), ^{ paused = g_isPaused; });
90
+ return paused;
91
+ }
92
+
93
+ double MRSyncGetPausedDurationSeconds(void) {
94
+ __block double duration = 0;
95
+ dispatch_sync(MRSyncQueue(), ^{
96
+ duration = g_totalPausedSeconds;
97
+ if (g_isPaused && g_pauseStartedAt > 0) {
98
+ duration += MAX(0, CFAbsoluteTimeGetCurrent() - g_pauseStartedAt);
99
+ }
100
+ });
101
+ return duration;
102
+ }
103
+
104
+ CMTime MRSyncAdjustForPauses(CMTime relativeTimestamp) {
105
+ if (!CMTIME_IS_VALID(relativeTimestamp)) return relativeTimestamp;
106
+ double seconds = CMTimeGetSeconds(relativeTimestamp) - MRSyncGetPausedDurationSeconds();
107
+ if (!isfinite(seconds) || seconds <= 0) return kCMTimeZero;
108
+ int32_t timescale = relativeTimestamp.timescale > 0 ? relativeTimestamp.timescale : 600;
109
+ return CMTimeMakeWithSeconds(seconds, timescale);
110
+ }
111
+
58
112
  BOOL MRSyncShouldHoldVideoFrame(CMTime timestamp) {
59
113
  if (!CMTIME_IS_VALID(timestamp)) {
60
114
  return NO;