@mebius-io/web 0.5.2 → 0.5.4

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/dist/index.js CHANGED
@@ -429,7 +429,7 @@ var LIVE_FLV_CONFIG = {
429
429
  var MAX_DRIFT_S = 2;
430
430
  var EDGE_MARGIN_S = 0.4;
431
431
  var AUDIO_RETRY_MS = 2500;
432
- var ESTIMATED_LATENCY_MS = 3e3;
432
+ var UPSTREAM_LATENCY_MS = 800;
433
433
  function stalledWithData(video, ms) {
434
434
  if (video.currentTime > 0) return Promise.resolve(false);
435
435
  return new Promise((resolve) => {
@@ -559,13 +559,24 @@ var FlvViewTransport = class {
559
559
  return { bitrateKbps, framesPerSecond, latencyMs: void 0 };
560
560
  }
561
561
  /**
562
- * Estimate only see {@link ESTIMATED_LATENCY_MS}. Without this, captions
563
- * never render on the FLV route at all: {@link MebiusCaptions} withholds
564
- * every segment until the playhead reaches its `epochMs`, and a transport
565
- * returning `null` here means the playhead comparison never runs.
562
+ * Estimate — FLV carries no wall clock, so this is measured where possible
563
+ * and assumed where not (see {@link UPSTREAM_LATENCY_MS}).
564
+ *
565
+ * The measurable half is the decoded media queued ahead of the playhead:
566
+ * whatever is buffered but not yet shown is, by definition, how far behind
567
+ * the newest received frame this viewer is watching. A flat guess for the
568
+ * whole delay was previously used, and being too generous costs real time —
569
+ * every millisecond of over-estimate is a caption withheld for no reason,
570
+ * on top of the STT latency the viewer already pays.
566
571
  */
567
572
  playheadEpochMs() {
568
- return Date.now() - ESTIMATED_LATENCY_MS;
573
+ let bufferedAheadMs = 0;
574
+ const ranges = this.video?.buffered;
575
+ if (ranges && ranges.length > 0 && this.video) {
576
+ const ahead = ranges.end(ranges.length - 1) - this.video.currentTime;
577
+ if (Number.isFinite(ahead) && ahead > 0) bufferedAheadMs = ahead * 1e3;
578
+ }
579
+ return Date.now() - UPSTREAM_LATENCY_MS - bufferedAheadMs;
569
580
  }
570
581
  };
571
582
 
@@ -798,6 +809,7 @@ function normalize(c, fallback) {
798
809
  // src/captions.ts
799
810
  var TICK_MS = 100;
800
811
  var STALE_MS = 5e3;
812
+ var MAX_QUEUE_MS = 1500;
801
813
  var MebiusCaptions = class extends TypedEmitter {
802
814
  /** @internal */
803
815
  constructor(signaling, player, opts) {
@@ -839,22 +851,27 @@ var MebiusCaptions = class extends TypedEmitter {
839
851
  if (frame.type !== "caption" || !frame.segmentId) return;
840
852
  const prev = this.pending.get(frame.segmentId);
841
853
  if (prev && (frame.rev ?? 0) < (prev.rev ?? 0)) return;
854
+ frame.receivedAtMs = Date.now();
842
855
  this.pending.set(frame.segmentId, frame);
843
856
  }
844
857
  tick() {
845
858
  const now = this.player.currentEpochMs();
846
- if (now == null) return;
847
859
  for (const [id, frame] of this.pending) {
848
860
  const due = frame.epochMs ?? 0;
849
- if (due > now) continue;
850
- if (due < now - STALE_MS) {
861
+ const waitedMs = Date.now() - (frame.receivedAtMs ?? 0);
862
+ const dueNow = now == null ? true : due <= now;
863
+ if (!dueNow) {
864
+ if (waitedMs < MAX_QUEUE_MS) continue;
865
+ }
866
+ if (waitedMs > STALE_MS && this.shown.has(id)) {
851
867
  this.pending.delete(id);
852
- if (this.shown.delete(id)) this.emit("cleared", { segmentId: id });
868
+ this.shown.delete(id);
869
+ this.emit("cleared", { segmentId: id });
853
870
  continue;
854
871
  }
872
+ if (this.shown.has(id) && frame.state === "final") continue;
855
873
  this.shown.add(id);
856
874
  this.emit("segment", toSegment(id, frame, this.opts.lang));
857
- if (frame.state === "final") this.pending.delete(id);
858
875
  }
859
876
  }
860
877
  };