@xorgate/react-native 0.1.0 → 0.2.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,122 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.1
4
+
5
+ - **Fix: a replay lane froze for a whole segment at a time on Android.** The
6
+ seam is an opacity flip between two overlapping views, and `expo-video` draws
7
+ into a `SurfaceView` by default — a layer the system composites rather than
8
+ one the view hierarchy draws, so `opacity: 0` does not hide it and `zIndex`
9
+ does not order it against its sibling. The hidden PRELOAD therefore won: it
10
+ parked on the first frame of the next segment, that still frame covered the
11
+ player that was actually running, and the picture held for the whole segment
12
+ while the clock, the map and the readouts carried on. It looked like the
13
+ engine had stalled; the engine was never involved. `ReplayVideo` now renders
14
+ into a `TextureView` on Android (`surfaceType`), which is an ordinary view,
15
+ so alpha and z-order mean what they say. iOS is untouched — `AVPlayerLayer`
16
+ is a real layer and the prop is Android's alone.
17
+
18
+ Measured on an API 36 emulator against a six-segment recording, sampling the
19
+ lane every ~1.5 s for three minutes: **11 distinct frames out of 80 before,
20
+ 79 out of 80 after**, over three segment boundaries either way. Each freeze
21
+ began within ~1.5 s of the hidden player reporting ready, and the LAST
22
+ segment of a replay always played correctly — by then there is nothing left
23
+ to preload on top of it. The engine's own trace was clean throughout, every
24
+ boundary a 0-131 ms seam.
25
+
26
+ ## 0.2.0
27
+
28
+ Replay: the recorded-media player, over `expo-video`.
29
+
30
+ - **`@xorgate/react` `^0.2.1`**, up from `^0.2.0-next.1`. 0.2.1 is where
31
+ `useReplayTelemetry` takes the player CORE rather than the browser wrapper —
32
+ the change that lets a React Native player drive replay telemetry at all. The
33
+ 0.2.0 tarball shipped with the looser `^0.2.0-next.1`, which resolves to 0.2.1
34
+ on any fresh install and is wrong only for a lockfile pinned at the
35
+ pre-release; the range was tightened as soon as 0.2.1 existed to be named.
36
+ - **`expo-video` is a new required peer.** It is the native player; there is no
37
+ way to play a recorded segment without it, and an optional peer whose absence
38
+ fails deep inside a lane is worse than one line of install (the same call
39
+ `expo-crypto` got in 0.1.0). Installing it moves the native fingerprint.
40
+ - `useReplayPlayer(manifest, options)` — `@xorgate/react`'s
41
+ `useReplayPlayerCore` with native media bound to every lane. The transport,
42
+ the clock, the lanes and `laneState` are the web package's; what is added is
43
+ `lanePlayer(streamKey)` and `laneMedia(streamKey)`, and the pool of players
44
+ behind them. `createVideoPlayer` is manual memory, so the hook creates a
45
+ pair per lane lazily and releases it when the lane goes or the hook unmounts.
46
+ - `<ReplayVideo player streamKey />` — both of a lane's views, the hidden one
47
+ at zero opacity, `nativeControls` off.
48
+ - `ExpoVideoReplayEngine` — one lane over two players, implementing
49
+ `@xorgate/react`'s `ReplayEngine`. A phone has no Media Source Extensions:
50
+ `AVPlayer` and `ExoPlayer` play a FILE, and a recorded segment is a
51
+ self-contained fMP4 that cannot be concatenated at runtime. So a lane is two
52
+ players and a boundary is an opacity flip. Four decisions the real segments
53
+ forced, all measured before the code was written:
54
+ - **The boundary is the manifest's** `effectiveDurationMs`, not the file's
55
+ end — a segment's file runs past the next one's start and playing that tail
56
+ would show the same wall clock twice. `playToEnd` is the fallback for the
57
+ opposite case, a file shorter than the manifest claims.
58
+ - **Readiness is the `statusChange` event, never the `replaceAsync`
59
+ promise**, which resolves with `status` still `loading`; `bufferedPosition`
60
+ can answer for the previous item until then.
61
+ - **Prepare early, promote on time.** The next segment is loaded and parked
62
+ on its first frame half a second out, and played only when the outgoing
63
+ player actually reaches the boundary — swapping at the lead would silently
64
+ drop it, once per segment.
65
+ - **A cross-segment seek always loads onto the hidden player**, so the
66
+ outgoing picture stays up for the 1.3-5.3 s the download takes instead of
67
+ going black.
68
+ - A failed segment load is probed with a one-byte ranged GET on the same
69
+ presigned URL, because a native player never reports the HTTP status: 403
70
+ becomes `onAuthError` (the manifest refresh, as in the browser engine) and
71
+ 404/410 becomes a media error. Anything else retries.
72
+ - `useReplayPlayer(manifest, { debug })` — every decision a lane makes, as one
73
+ line, off by default. A seam is tens of milliseconds wide and the native
74
+ player is the half you cannot step through, so a boundary that did NOT
75
+ happen has to be able to leave evidence. It is what found the four defects
76
+ below, none of which any test had caught.
77
+
78
+ **Four things the device corrected, all at the same place: a segment boundary.**
79
+ On the first real 3-segment session a whole 60 s segment vanished — 57.7 s of a
80
+ 145.6 s replay, silently — and it took all four lining up:
81
+
82
+ 1. **A preloaded player is not parked at 0.** One was caught at 15.68 s, and
83
+ promoting it would have started that segment a quarter of the way in. On
84
+ iOS a playback RATE is the transport, so setting the rate on a paused
85
+ preload starts it playing. The rate now goes only on the player that is
86
+ about to play, and the incoming player is seeked unconditionally rather
87
+ than only for a non-zero offset.
88
+ 2. **Promoting does not move the playhead.** The clock is paced BY the lane
89
+ and only learns the new position on its next tick, so the very next
90
+ `ensureAt` arrives with a timestamp a few milliseconds BEFORE the boundary
91
+ — which dragged the lane back into the segment it had just left, which the
92
+ next tick undid, and so on. A move back into a just-crossed segment is now
93
+ ignored for a second.
94
+ 3. **The boundary must be released whether or not the player says so.** The
95
+ last `timeUpdate` of a segment lands 60-80 ms short of the file's end, and
96
+ `playToEnd` / `playingChange` follow a beat later. A timer armed when the
97
+ lead-in is prepared — for the expected end plus 120 ms — closes that, and
98
+ deliberately fires LATE: early skips real video, late only holds a frame.
99
+ A segment's end is `min(manifest, file)`, because a file can fall short of
100
+ what the manifest claims (60.000 s claimed, 59.987 s of media).
101
+ 4. **A lane waiting on a prepared lead-in must not report itself stalled.**
102
+ It did, so the player core's stall recovery ran — and with the playhead
103
+ already inside the NEXT segment, that recovery seeks to the END of it.
104
+ That is the line that actually ate the 57.7 s.
105
+
106
+ Two more it showed, away from the boundary:
107
+
108
+ - **A seek holds the outgoing picture STILL**, not merely on screen. The
109
+ outgoing player used to keep playing for the seconds a cross-segment
110
+ download takes — six of them, on one measured seek — while the transport bar
111
+ already read the seek target, so the picture and the clock were describing
112
+ different moments. A boundary lead-in is deliberately exempt: there the
113
+ outgoing segment is still the right one, right up to its last frame.
114
+ - **A torn-down lane dies quietly.** The players belong to the hook, and one
115
+ that has been released throws `NotFoundException` on every access; the hook
116
+ now destroys engines before releasing players rather than trusting React's
117
+ cleanup order, and an engine handed a dead pair goes inert instead of
118
+ throwing into the tree.
119
+
3
120
  ## 0.1.0
4
121
 
5
122
  First release: live telemetry and live video on React Native, over
package/dist/index.d.ts CHANGED
@@ -5,14 +5,17 @@
5
5
  * re-exported here, so an app imports from ONE package: the data hooks, live
6
6
  * telemetry, the live-block policy, the replay timeline and clock, the
7
7
  * telemetry math, the types. What this package adds is the runtime underneath
8
- * them (`nativePlatform`, `XorgateNativeProvider`) and the two pieces that
9
- * cannot be neutral because they are pixels: `useLiveVideo` / `LiveVideo` over
10
- * react-native-webrtc's `RTCView`.
8
+ * them (`nativePlatform`, `XorgateNativeProvider`) and the pieces that cannot
9
+ * be neutral because they are pixels: `useLiveVideo` / `LiveVideo` over
10
+ * react-native-webrtc's `RTCView`, and `useReplayPlayer` / `ReplayVideo` over
11
+ * expo-video.
11
12
  *
12
13
  * The browser-only exports of `@xorgate/react` — its `useLiveVideo`,
13
14
  * `LiveVideo`, `useReplayPlayer`, `ReplayVideo` and the `browser*` platform
14
15
  * helpers — are deliberately NOT re-exported: they need `HTMLVideoElement`,
15
- * `window` or Media Source Extensions, none of which exist here. Importing
16
+ * `window` or Media Source Extensions, none of which exist here. The four
17
+ * names are SHADOWED by the native implementations above, so an app that
18
+ * imports from this package gets the one that works on a phone; importing
16
19
  * `@xorgate/react` directly still works and is how you reach them on web.
17
20
  */
18
21
  export { nativePlatform, type NativePlatformOptions } from "./platform.js";
@@ -21,5 +24,8 @@ export { appStateWake, composeWake, type WakeSource } from "./wake.js";
21
24
  export { XorgateNativeProvider, type XorgateNativeProviderProps, } from "./provider.js";
22
25
  export { useLiveVideo, type UseLiveVideo, type UseLiveVideoOptions, } from "./use-live-video.js";
23
26
  export { LiveVideo, type LiveVideoProps } from "./live-video.js";
27
+ export { ExpoVideoReplayEngine, type ExpoVideoReplayEngineOptions, } from "./replay-engine.js";
28
+ export { useReplayPlayer, type UseReplayPlayer, type UseReplayPlayerNativeOptions, type ReplayLaneMedia, type ReplayLaneState, type ReplayLaneStatus, type UseReplayPlayerOptions, } from "./use-replay-player.js";
29
+ export { ReplayVideo, type ReplayVideoProps } from "./replay-video.js";
24
30
  export { XorgateProvider, useXorgate, useXorgateTenancy, DEFAULT_BASE_URL, type XorgateProviderProps, type XorgateConfig, type XorgateAuth, type FirstPartyAuth, type SessionTokenAuth, type ApiKeyAuth, type LiveCredentialsAuth, type LiveCredentials, type LiveUnavailableReason, type Awaitable, type XorgatePlatform, XorgateError, isXorgateError, type Device, type DeviceModel, type LatestByMetric, type LatestReading, type MediaSession, type Me, type MetricName, type Organization, type PageMeta, type RecordingRun, type ReplayGap, type ReplayManifest, type ReplaySegment, type ReplaySession, type StreamKey, type TelemetryHistory, type TelemetryReading, type VideoChannel, type Workspace, type XorgateClient, useMe, useOrganizations, useWorkspaces, useDevices, useDevice, useDeviceModel, useTelemetryLatest, useTelemetryHistory, useVideoChannels, useRecordingRuns, useSessions, type QueryResult, type QueryOptions, type UseDevicesParams, type UseDevicesResult, type UseTelemetryHistoryParams, type UseSessionsParams, type UseRunsResult, type UseSessionsResult, useLiveTelemetry, useLivePlane, useLiveCredentials, parseTelemetryPayload, presignIotWssUrl, type UseLiveTelemetry, type UseLiveTelemetryOptions, type LiveStatus, type TelemetryPoint, type TelemetrySnapshot, type TelemetryFeedDeps, type MqttLikeClient, type MqttConnectionSpec, type ResolvedLiveCredentials, type ParsedTelemetryPayload, type TelemetryRecordingStatus, type TelemetryMediaStatus, type TelemetryStreamStatus, type LiveBlockPayload, useLiveBlock, resolveLiveBlock, liveBlockElapsedMs, LIVE_BLOCK_STALE_MS, type LiveBlockReason, type LiveBlockOpenReason, type LiveBlockState, type ResolveLiveBlockInput, useLiveVideoSession, type UseLiveVideoSession, type UseLiveVideoSessionOptions, type LiveVideoStatus, type LiveVideoStats, type WebRtcPlatform, type PeerConnectionLike, type SignalingLike, type TimerHost, useReplayManifest, useReplayPlayerCore, useReplayTelemetry, buildTimeline, segmentEnd, segmentAt, hasCoverageAt, gapAt, nextSegmentAfter, prevBoundary, nextBoundary, clampTs, buildLanes, buildClockTimeline, segmentUrlKey, ReplayClock, REPLAY_RATES, parseSegmentMediaInfo, seriesFromReadings, floorIndex, latestWithin, metricGroup, stalenessMs, overviewStalenessMs, chooseIntervalSeconds, windowBoundsFor, windowNeedsRefetch, buildTrace, traceLines, traveledLines, positionAt, GROUP_STALENESS_MS, DEFAULT_STALENESS_MS, WINDOW_SPAN_MS, WINDOW_MIN_SPAN_MS, type UseReplayManifestParams, type UseReplayManifestResult, type UseReplayPlayerCore, type UseReplayTelemetry, type UseReplayTelemetryOptions, type ReplayEngine, type ReplayEngineOptions, type ReplayEngineFactory, type ReplayTimeline, type ReplayLane, type LaneSegment, type ReplayClockState, type ReplayRate, type PacerCandidate, type GapSkipEvent, type SegmentMediaInfo, type MetricSeries, type GpsTrace, type WindowBounds, type PositionResolution, } from "@xorgate/react";
25
31
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -5,14 +5,17 @@
5
5
  * re-exported here, so an app imports from ONE package: the data hooks, live
6
6
  * telemetry, the live-block policy, the replay timeline and clock, the
7
7
  * telemetry math, the types. What this package adds is the runtime underneath
8
- * them (`nativePlatform`, `XorgateNativeProvider`) and the two pieces that
9
- * cannot be neutral because they are pixels: `useLiveVideo` / `LiveVideo` over
10
- * react-native-webrtc's `RTCView`.
8
+ * them (`nativePlatform`, `XorgateNativeProvider`) and the pieces that cannot
9
+ * be neutral because they are pixels: `useLiveVideo` / `LiveVideo` over
10
+ * react-native-webrtc's `RTCView`, and `useReplayPlayer` / `ReplayVideo` over
11
+ * expo-video.
11
12
  *
12
13
  * The browser-only exports of `@xorgate/react` — its `useLiveVideo`,
13
14
  * `LiveVideo`, `useReplayPlayer`, `ReplayVideo` and the `browser*` platform
14
15
  * helpers — are deliberately NOT re-exported: they need `HTMLVideoElement`,
15
- * `window` or Media Source Extensions, none of which exist here. Importing
16
+ * `window` or Media Source Extensions, none of which exist here. The four
17
+ * names are SHADOWED by the native implementations above, so an app that
18
+ * imports from this package gets the one that works on a phone; importing
16
19
  * `@xorgate/react` directly still works and is how you reach them on web.
17
20
  */
18
21
  // ---------------------------------------------------------------------------
@@ -28,6 +31,12 @@ export { XorgateNativeProvider, } from "./provider.js";
28
31
  export { useLiveVideo, } from "./use-live-video.js";
29
32
  export { LiveVideo } from "./live-video.js";
30
33
  // ---------------------------------------------------------------------------
34
+ // Replay (expo-video)
35
+ // ---------------------------------------------------------------------------
36
+ export { ExpoVideoReplayEngine, } from "./replay-engine.js";
37
+ export { useReplayPlayer, } from "./use-replay-player.js";
38
+ export { ReplayVideo } from "./replay-video.js";
39
+ // ---------------------------------------------------------------------------
31
40
  // Re-exported unchanged from `@xorgate/react`
32
41
  // ---------------------------------------------------------------------------
33
42
  export {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,8EAA8E;AAC9E,2BAA2B;AAC3B,8EAA8E;AAE9E,OAAO,EAAE,cAAc,EAA8B,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAmB,MAAM,WAAW,CAAC;AACvE,OAAO,EACL,qBAAqB,GAEtB,MAAM,eAAe,CAAC;AAEvB,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,OAAO,EACL,YAAY,GAGb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAuB,MAAM,iBAAiB,CAAC;AAEjE,8EAA8E;AAC9E,8CAA8C;AAC9C,8EAA8E;AAE9E,OAAO;AACL,uBAAuB;AACvB,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,gBAAgB;AAahB,oCAAoC;AACpC,YAAY,EACZ,cAAc;AAsBd,aAAa;AACb,KAAK,EACL,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,SAAS,EACT,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,WAAW;AAUX,oCAAoC;AACpC,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB;AAgBhB,oBAAoB;AACpB,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB;AAMnB,mDAAmD;AACnD,mBAAmB;AAUnB,4EAA4E;AAC5E,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,UAAU,EACV,SAAS,EACT,aAAa,EACb,KAAK,EACL,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,OAAO,EACP,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,aAAa,EACb,UAAU,EACV,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EACd,kBAAkB,GAqBnB,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,8EAA8E;AAC9E,2BAA2B;AAC3B,8EAA8E;AAE9E,OAAO,EAAE,cAAc,EAA8B,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAmB,MAAM,WAAW,CAAC;AACvE,OAAO,EACL,qBAAqB,GAEtB,MAAM,eAAe,CAAC;AAEvB,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,OAAO,EACL,YAAY,GAGb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAuB,MAAM,iBAAiB,CAAC;AAEjE,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E,OAAO,EACL,qBAAqB,GAEtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,eAAe,GAOhB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,WAAW,EAAyB,MAAM,mBAAmB,CAAC;AAEvE,8EAA8E;AAC9E,8CAA8C;AAC9C,8EAA8E;AAE9E,OAAO;AACL,uBAAuB;AACvB,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,gBAAgB;AAahB,oCAAoC;AACpC,YAAY,EACZ,cAAc;AAsBd,aAAa;AACb,KAAK,EACL,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,SAAS,EACT,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,WAAW;AAUX,oCAAoC;AACpC,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB;AAgBhB,oBAAoB;AACpB,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB;AAMnB,mDAAmD;AACnD,mBAAmB;AAUnB,4EAA4E;AAC5E,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,UAAU,EACV,SAAS,EACT,aAAa,EACb,KAAK,EACL,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,OAAO,EACP,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,aAAa,EACb,UAAU,EACV,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EACd,kBAAkB,GAqBnB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,193 @@
1
+ import { type ReplayEngine, type ReplayEngineOptions } from "@xorgate/react";
2
+ import type { VideoPlayer } from "expo-video";
3
+ export interface ExpoVideoReplayEngineOptions extends ReplayEngineOptions {
4
+ /**
5
+ * The lane's two players. The engine drives them but does not own them:
6
+ * `useReplayPlayer` creates and releases the pair, the same way the browser
7
+ * engine is handed a `<video>` it did not create.
8
+ */
9
+ players: readonly [VideoPlayer, VideoPlayer];
10
+ /** The player on screen changed. The hook re-renders so the views swap. */
11
+ onActivePlayerChange?: () => void;
12
+ /**
13
+ * Every decision this lane makes, as one line. Off by default and costing
14
+ * nothing when unset. A replay seam is tens of milliseconds wide and the
15
+ * native player is the half you cannot step through, so the only way to
16
+ * find out why a boundary did or did not happen is to have the engine say
17
+ * so at the time.
18
+ */
19
+ onDebug?: (message: string) => void;
20
+ }
21
+ /**
22
+ * One replay lane over two `expo-video` players (replay option A).
23
+ *
24
+ * The browser plays a lane as ONE `<video>` fed by Media Source Extensions:
25
+ * segments are appended into a single continuous buffer and there is no seam
26
+ * to manage. A phone has no MSE. `AVPlayer` and `ExoPlayer` play a FILE, and
27
+ * every recorded segment is a self-contained fMP4 (own `ftyp`+`moov`, `tfdt`
28
+ * from 0) — an ordinary playable MP4, and nothing that can be concatenated at
29
+ * runtime. So a lane is two players: one showing segment N while the other
30
+ * already holds N+1, and a boundary is an opacity swap between two views that
31
+ * are both mounted.
32
+ *
33
+ * Four things shape the code, all measured on real segments before it was
34
+ * written (SPIKES.md §4):
35
+ *
36
+ * - **The boundary is the MANIFEST's** (`effectiveDurationMs`), not the file's
37
+ * end: a segment's file routinely runs past the next segment's start
38
+ * (`fstat` anchors), and playing that tail would show the same wall clock
39
+ * twice. `playToEnd` is the fallback for the opposite case, a file SHORTER
40
+ * than the manifest claims.
41
+ * - **Readiness is an event, not a promise.** `replaceAsync` resolves with
42
+ * `status` still `loading`, and `bufferedPosition` can report the previous
43
+ * item's value for a beat afterwards. Nothing here trusts a player until
44
+ * `statusChange → readyToPlay`.
45
+ * - **Prepare early, promote on time.** The incoming player is loaded and
46
+ * parked on its first frame half a second before the boundary, but it is
47
+ * not played until the outgoing one actually reaches the boundary. That is
48
+ * what makes the seam a picture change with no playhead jump — swapping
49
+ * early would silently skip the lead, once per segment.
50
+ * - **A cross-segment seek is download-bound** (1.3-5.3 s for a 6-13 MB
51
+ * segment), so it always loads onto the HIDDEN player and the outgoing
52
+ * picture stays up until the new one has a frame. Replacing the visible
53
+ * player's source instead is seconds of black.
54
+ *
55
+ * Positions are lane-local seconds, as `ReplayEngine` requires; the wall clock
56
+ * stays the player core's business.
57
+ */
58
+ export declare class ExpoVideoReplayEngine implements ReplayEngine {
59
+ private readonly timeline;
60
+ private readonly getUrl;
61
+ private readonly onError;
62
+ private readonly onUpdate;
63
+ private readonly onAuthError;
64
+ private readonly onActivePlayerChange;
65
+ private readonly onDebug;
66
+ private readonly slots;
67
+ private activeIdx;
68
+ private activation;
69
+ private boundaryTimer;
70
+ private wantPlay;
71
+ private rate;
72
+ private destroyed;
73
+ private firstFrameFired;
74
+ /** Lane-local seconds, kept so `position` is honest while nothing is ready. */
75
+ private lastPos;
76
+ /** The last position the active player was seen at, and when — see `watchStall`. */
77
+ private stalledAt;
78
+ private stalledSince;
79
+ /** The segment most recently left at a boundary, and when. See `activate`. */
80
+ private crossed;
81
+ private readonly failedAt;
82
+ private readonly probing;
83
+ private readonly abort;
84
+ private readonly waitingCbs;
85
+ private readonly firstFrameCbs;
86
+ constructor(opts: ExpoVideoReplayEngineOptions);
87
+ private makeSlot;
88
+ get position(): number;
89
+ get paused(): boolean;
90
+ /** The player whose picture belongs on screen. */
91
+ get activePlayer(): VideoPlayer;
92
+ /** Which of the two players `activePlayer` is. */
93
+ get activeIndex(): 0 | 1;
94
+ buffered(): Array<{
95
+ start: number;
96
+ end: number;
97
+ }>;
98
+ isBufferedAt(posSec: number): boolean;
99
+ isStalled(): boolean;
100
+ seek(posSec: number): void;
101
+ play(): void;
102
+ pause(): void;
103
+ setRate(rate: number): void;
104
+ /**
105
+ * Keep the media around `ts` — and the segment after it — loaded. Called at
106
+ * clock-notify rate and from the core's 500 ms pump, so every path is
107
+ * guarded: steady state does no work.
108
+ */
109
+ ensureAt(ts: number): void;
110
+ on(event: "waiting" | "firstFrame", cb: () => void): () => void;
111
+ destroy(): void;
112
+ private debug;
113
+ /** One line of state, for a debug message that has to explain a decision. */
114
+ private snapshot;
115
+ private segPos;
116
+ private slotHolding;
117
+ /**
118
+ * Only the player on screen ever plays; the other one is preload.
119
+ *
120
+ * Every write below goes through JSI to a native object the hook owns, and
121
+ * a call on one that has been released throws `NotFoundException` rather
122
+ * than returning — so nothing here may run after `destroy()`.
123
+ */
124
+ private applyTransport;
125
+ /**
126
+ * Bring `seg` to the front at `offsetSec`, always through the HIDDEN player
127
+ * so the picture on screen survives the load.
128
+ */
129
+ private activate;
130
+ private cancelActivation;
131
+ /** Park the incoming player on the frame it will be promoted with. */
132
+ private prepare;
133
+ private maybePromote;
134
+ /** One segment of look-ahead on the hidden player — what makes a boundary free. */
135
+ /**
136
+ * Cross the boundary on time even if the outgoing player never says it is
137
+ * finished. Armed when the lead-in is prepared, for the moment the segment
138
+ * is expected to run out plus a short grace, and re-armed rather than fired
139
+ * if the player is somehow still behind that (a pause, a slower rate). An
140
+ * event almost always beats it; what it buys is that none of them has to,
141
+ * and that the swap lands AFTER the end rather than before it — a timer
142
+ * that fires early skips real video, one that fires late holds a frame.
143
+ */
144
+ private armBoundaryTimer;
145
+ private onBoundaryTimer;
146
+ private clearBoundaryTimer;
147
+ private prefetchAfter;
148
+ private load;
149
+ /**
150
+ * The player on screen has stopped advancing while the transport says play.
151
+ * That is a segment that has run out of file without saying so — and it is
152
+ * the state that must never be left alone, because the player core's stall
153
+ * recovery reads the playhead (already inside the NEXT segment) rather than
154
+ * the media, and jumps to the end of a segment that was never shown.
155
+ */
156
+ private watchStall;
157
+ private markReady;
158
+ /**
159
+ * The one case `statusChange` cannot report: a player that was already
160
+ * `readyToPlay` and whose new item loaded without the status ever leaving
161
+ * that value. Runs off the core's pump, so it costs nothing in steady state.
162
+ */
163
+ private reconcileReady;
164
+ private onTimeUpdate;
165
+ private onPlayToEnd;
166
+ /**
167
+ * The outgoing segment is finished, however we found out. With a lead-in
168
+ * already prepared this swaps; without one — the file ran out well before
169
+ * the manifest said it would, which `fstat`-anchored rows do — it starts
170
+ * the next segment now rather than leave the clock on a player that will
171
+ * never advance again.
172
+ */
173
+ private releaseBoundary;
174
+ /**
175
+ * Where this player's segment really ends, in its own seconds: the manifest
176
+ * duration, or the file's if the file is shorter. A file that outruns the
177
+ * manifest must be cut at the manifest (its tail is the next segment's wall
178
+ * clock); a file that falls short can only be played to its own end, and
179
+ * waiting for a boundary it can never reach is what freezes a lane.
180
+ */
181
+ private endOf;
182
+ private contiguousNext;
183
+ private onStatusChange;
184
+ /**
185
+ * A native player reports that a source would not load, and never why: the
186
+ * HTTP status is not on the error. A one-byte ranged GET against the same
187
+ * presigned URL is the cheapest way to tell an expired signature (403 —
188
+ * refresh the manifest, exactly as the browser engine does) from a network
189
+ * blip (retry), and it only ever runs on a failure.
190
+ */
191
+ private onLoadFailure;
192
+ }
193
+ //# sourceMappingURL=replay-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-engine.d.ts","sourceRoot":"","sources":["../src/replay-engine.ts"],"names":[],"mappings":"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"}