@stinkycomputing/web-live-player 0.1.15 → 0.1.16

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.
@@ -1093,6 +1093,7 @@ const G = class G extends lU {
1093
1093
  l(this, "audioPlayer", null);
1094
1094
  l(this, "ownsAudioContext", !1);
1095
1095
  l(this, "audioCodecData", null);
1096
+ l(this, "volume", 1);
1096
1097
  // Timing tracking: maps frame timestamp to arrival time
1097
1098
  l(this, "arrivalTimes", /* @__PURE__ */ new Map());
1098
1099
  // Track keyframe status per timestamp
@@ -1137,15 +1138,20 @@ const G = class G extends lU {
1137
1138
  }
1138
1139
  /**
1139
1140
  * Set audio volume (0-1)
1141
+ *
1142
+ * The value is remembered and re-applied whenever a new audio player is
1143
+ * created, so calls made before audio arrives (or across codec changes)
1144
+ * are not lost.
1140
1145
  */
1141
1146
  setVolume(U) {
1142
- this.audioPlayer && this.audioPlayer.setVolume(U);
1147
+ var Q;
1148
+ this.volume = Math.max(0, Math.min(1, U)), (Q = this.audioPlayer) == null || Q.setVolume(this.volume);
1143
1149
  }
1144
1150
  /**
1145
1151
  * Get current audio volume (0-1)
1146
1152
  */
1147
1153
  getVolume() {
1148
- return 1;
1154
+ return this.volume;
1149
1155
  }
1150
1156
  /**
1151
1157
  * Set the stream source (dependency injection)
@@ -1329,11 +1335,11 @@ const G = class G extends lU {
1329
1335
  this.currentCodecData = (W = Q.header.media) == null ? void 0 : W.codecData, this.isConfiguring = !0, this.pendingDuringConfig = [Q], await this.configureDecoder((Z = Q.header.media) == null ? void 0 : Z.codecData), this.isConfiguring = !1, this.waitingForKeyframe = !0;
1330
1336
  const a = this.pendingDuringConfig;
1331
1337
  this.pendingDuringConfig = [], this.logger.info(`Processing ${a.length} frames queued during configuration`);
1332
- for (const M of a)
1338
+ for (const m of a)
1333
1339
  await this.handleStreamData({
1334
1340
  trackName: U.trackName,
1335
1341
  streamType: U.streamType,
1336
- data: M
1342
+ data: m
1337
1343
  });
1338
1344
  return;
1339
1345
  }
@@ -1355,18 +1361,18 @@ const G = class G extends lU {
1355
1361
  this.logger.debug("Keyframe received, resuming decode"), this.waitingForKeyframe = !1, this.lastWaitingForKeyframeLog = 0;
1356
1362
  }
1357
1363
  try {
1358
- const a = performance.now(), M = (i = (C = Q.header.media) == null ? void 0 : C.codecData) != null && i.timebaseDen && ((I = (E = Q.header.media) == null ? void 0 : E.codecData) != null && I.timebaseNum) ? { num: Q.header.media.codecData.timebaseNum, den: Q.header.media.codecData.timebaseDen } : { num: 1, den: 1e6 }, b = { num: 1, den: 1e6 }, g = P(((c = Q.header.media) == null ? void 0 : c.pts) ?? 0, M, b);
1364
+ const a = performance.now(), m = (i = (C = Q.header.media) == null ? void 0 : C.codecData) != null && i.timebaseDen && ((I = (E = Q.header.media) == null ? void 0 : E.codecData) != null && I.timebaseNum) ? { num: Q.header.media.codecData.timebaseNum, den: Q.header.media.codecData.timebaseDen } : { num: 1, den: 1e6 }, b = { num: 1, den: 1e6 }, g = P(((c = Q.header.media) == null ? void 0 : c.pts) ?? 0, m, b);
1359
1365
  if (this.arrivalTimes.set(g, a), this.keyframeStatus.set(g, V), this.lastVideoTimestampUs >= 0 && g > this.lastVideoTimestampUs) {
1360
1366
  const D = g - this.lastVideoTimestampUs;
1361
1367
  if (D > 5e3 && D < 1e6 && (this.fpsEstimateSamples.push(D), this.fpsEstimateSamples.length > G.FPS_SAMPLE_COUNT && this.fpsEstimateSamples.shift(), this.fpsEstimateSamples.length >= 3)) {
1362
- const m = this.fpsEstimateSamples.reduce((x, w) => x + w, 0) / this.fpsEstimateSamples.length;
1363
- this.estimatedFrameRate = Math.round(1e6 / m);
1368
+ const M = this.fpsEstimateSamples.reduce((x, w) => x + w, 0) / this.fpsEstimateSamples.length;
1369
+ this.estimatedFrameRate = Math.round(1e6 / M);
1364
1370
  }
1365
1371
  }
1366
1372
  if (this.lastVideoTimestampUs = g, this.arrivalTimes.size > 100) {
1367
1373
  const D = [...this.arrivalTimes.entries()];
1368
- for (let m = 0; m < D.length - 100; m++)
1369
- this.arrivalTimes.delete(D[m][0]), this.keyframeStatus.delete(D[m][0]);
1374
+ for (let M = 0; M < D.length - 100; M++)
1375
+ this.arrivalTimes.delete(D[M][0]), this.keyframeStatus.delete(D[M][0]);
1370
1376
  }
1371
1377
  this.decoder.decodeBinary(Q);
1372
1378
  } catch (a) {
@@ -1383,7 +1389,7 @@ const G = class G extends lU {
1383
1389
  const Q = this.audioCodecData ?? void 0;
1384
1390
  (R = (B = U.header) == null ? void 0 : B.media) != null && R.codecData && _(Q, U.header.media.codecData) && (this.audioCodecData = U.header.media.codecData, this.audioPlayer && (this.audioPlayer.dispose(), this.audioPlayer = null), this.audioContext || (this.config.audioContext ? (this.audioContext = this.config.audioContext, this.ownsAudioContext = !1) : (this.audioContext = new AudioContext(), this.ownsAudioContext = !0)), this.audioPlayer = new hU(this.audioContext, {
1385
1391
  bufferDelayMs: this.config.bufferDelayMs ?? 100
1386
- }), await this.audioPlayer.init((d = U.header.media) == null ? void 0 : d.codecData), this.audioPlayer.start(), this.logger.info(`Audio player started: ${(J = (V = U.header.media) == null ? void 0 : V.codecData) == null ? void 0 : J.codecType}, ${(S = (n = U.header.media) == null ? void 0 : n.codecData) == null ? void 0 : S.sampleRate}Hz, ${(W = (t = U.header.media) == null ? void 0 : t.codecData) == null ? void 0 : W.channels}ch`)), this.audioPlayer && U.payload && U.header && this.audioPlayer.decode(U.payload, (Z = U.header.media) == null ? void 0 : Z.pts);
1392
+ }), await this.audioPlayer.init((d = U.header.media) == null ? void 0 : d.codecData), this.audioPlayer.setVolume(this.volume), this.audioPlayer.start(), this.logger.info(`Audio player started: ${(J = (V = U.header.media) == null ? void 0 : V.codecData) == null ? void 0 : J.codecType}, ${(S = (n = U.header.media) == null ? void 0 : n.codecData) == null ? void 0 : S.sampleRate}Hz, ${(W = (t = U.header.media) == null ? void 0 : t.codecData) == null ? void 0 : W.channels}ch`)), this.audioPlayer && U.payload && U.header && this.audioPlayer.decode(U.payload, (Z = U.header.media) == null ? void 0 : Z.pts);
1387
1393
  }
1388
1394
  /**
1389
1395
  * Configure the decoder for a specific codec
@@ -1613,8 +1619,8 @@ class FU {
1613
1619
  });
1614
1620
  if (!a.ok && a.status !== 206)
1615
1621
  throw new Error(`Failed to fetch chunk: ${a.status} ${a.statusText}`);
1616
- const M = await a.arrayBuffer(), b = M;
1617
- if (b.fileStart = Q, Q += M.byteLength, this.loadedBytes = Q, (o = (T = this.events).onProgress) == null || o.call(T, this.loadedBytes, this.fileSize), (r = this.mp4File) == null || r.appendBuffer(b), B && V) {
1622
+ const m = await a.arrayBuffer(), b = m;
1623
+ if (b.fileStart = Q, Q += m.byteLength, this.loadedBytes = Q, (o = (T = this.events).onProgress) == null || o.call(T, this.loadedBytes, this.fileSize), (r = this.mp4File) == null || r.appendBuffer(b), B && V) {
1618
1624
  this.continueLoadingInBackground(F, Q, U), R(this.fileInfo);
1619
1625
  return;
1620
1626
  }
@@ -1726,7 +1732,7 @@ class FU {
1726
1732
  * Handle file ready event
1727
1733
  */
1728
1734
  handleFileReady(F) {
1729
- var U, Q, B, R, d, V, J, n, S, t, W, Z, s, h, k, T, o, r, C, i, E, I, c, a, M, b, g, D, m, x;
1735
+ var U, Q, B, R, d, V, J, n, S, t, W, Z, s, h, k, T, o, r, C, i, E, I, c, a, m, b, g, D, M, x;
1730
1736
  if (F.videoTracks.length > 0) {
1731
1737
  this.videoTrack = F.videoTracks[0], this.videoTrackId = this.videoTrack.id, this.totalVideoSamples = this.videoTrack.nb_samples;
1732
1738
  const w = (U = this.mp4File) == null ? void 0 : U.getTrackById(this.videoTrackId);
@@ -1776,12 +1782,12 @@ class FU {
1776
1782
  duration: this.videoTrack.duration / this.videoTrack.timescale,
1777
1783
  timescale: this.videoTrack.timescale,
1778
1784
  width: ((a = this.videoTrack.video) == null ? void 0 : a.width) ?? 0,
1779
- height: ((M = this.videoTrack.video) == null ? void 0 : M.height) ?? 0,
1785
+ height: ((m = this.videoTrack.video) == null ? void 0 : m.height) ?? 0,
1780
1786
  videoCodec: this.videoTrack.codec,
1781
1787
  frameRate: this.videoTrack.nb_samples / (this.videoTrack.duration / this.videoTrack.timescale),
1782
1788
  bitrate: this.videoTrack.bitrate,
1783
1789
  isMoovAtStart: ((b = this.mp4File) == null ? void 0 : b.isProgressive) ?? void 0
1784
- }, this.audioTrack && (this.fileInfo.audioCodec = this.audioTrack.codec, this.fileInfo.audioChannels = (g = this.audioTrack.audio) == null ? void 0 : g.channel_count, this.fileInfo.audioSampleRate = (D = this.audioTrack.audio) == null ? void 0 : D.sample_rate), this.requestSamples(), (x = (m = this.events).onReady) == null || x.call(m, this.fileInfo);
1790
+ }, this.audioTrack && (this.fileInfo.audioCodec = this.audioTrack.codec, this.fileInfo.audioChannels = (g = this.audioTrack.audio) == null ? void 0 : g.channel_count, this.fileInfo.audioSampleRate = (D = this.audioTrack.audio) == null ? void 0 : D.sample_rate), this.requestSamples(), (x = (M = this.events).onReady) == null || x.call(M, this.fileInfo);
1785
1791
  }
1786
1792
  /**
1787
1793
  * Request samples to be extracted
@@ -2195,6 +2201,7 @@ class rU extends lU {
2195
2201
  l(this, "audioPlayer", null);
2196
2202
  l(this, "ownsAudioContext", !1);
2197
2203
  l(this, "audioInitialized", !1);
2204
+ l(this, "volume", 1);
2198
2205
  // File info
2199
2206
  l(this, "fileInfo", null);
2200
2207
  // Frame buffer - sorted by timestamp
@@ -2292,15 +2299,19 @@ class rU extends lU {
2292
2299
  }
2293
2300
  /**
2294
2301
  * Set audio volume (0-1)
2302
+ *
2303
+ * The value is remembered and re-applied whenever the audio decoder is
2304
+ * (re)initialized, so calls made before the decoder is ready are not lost.
2295
2305
  */
2296
2306
  setVolume(U) {
2297
- this.audioPlayer && this.audioPlayer.setVolume(U);
2307
+ var Q;
2308
+ this.volume = Math.max(0, Math.min(1, U)), (Q = this.audioPlayer) == null || Q.setVolume(this.volume);
2298
2309
  }
2299
2310
  /**
2300
2311
  * Get current audio volume (0-1)
2301
2312
  */
2302
2313
  getVolume() {
2303
- return 1;
2314
+ return this.volume;
2304
2315
  }
2305
2316
  /**
2306
2317
  * Load a video file from URL
@@ -2391,7 +2402,7 @@ class rU extends lU {
2391
2402
  this.fileInfo.audioSampleRate ?? 48e3,
2392
2403
  this.fileInfo.audioChannels ?? 2,
2393
2404
  U ?? void 0
2394
- ), this.audioInitialized = !0, this.logger.info(`Audio decoder configured: ${this.fileInfo.audioCodec}`), this.feedAudioDecoder();
2405
+ ), this.audioPlayer.setVolume(this.volume), this.audioInitialized = !0, this.logger.info(`Audio decoder configured: ${this.fileInfo.audioCodec}`), this.feedAudioDecoder();
2395
2406
  } catch (U) {
2396
2407
  this.logger.warn(`Failed to initialize audio: ${U}`), this.audioPlayer = null;
2397
2408
  }
@@ -2820,11 +2831,11 @@ class pU extends RU {
2820
2831
  function yU(e) {
2821
2832
  return new pU(e);
2822
2833
  }
2823
- function MU(e) {
2834
+ function mU(e) {
2824
2835
  return e instanceof VideoFrame;
2825
2836
  }
2826
2837
  function HU(e) {
2827
- return !MU(e) && "y" in e && "u" in e && "v" in e;
2838
+ return !mU(e) && "y" in e && "u" in e && "v" in e;
2828
2839
  }
2829
2840
  const y = {
2830
2841
  video: {
@@ -2881,7 +2892,7 @@ function xU(e) {
2881
2892
  function vU(e) {
2882
2893
  return e >= N.CODEC_TYPE_AUDIO_OPUS && e <= N.CODEC_TYPE_AUDIO_PCM;
2883
2894
  }
2884
- class mU {
2895
+ class MU {
2885
2896
  constructor(F, U, Q, B) {
2886
2897
  l(this, "audioWorker");
2887
2898
  l(this, "videoWorker");
@@ -3391,7 +3402,7 @@ class v {
3391
3402
  channels: (Q = this.audioMetadata) == null ? void 0 : Q.channels,
3392
3403
  sampleRate: (B = this.audioMetadata) == null ? void 0 : B.sampleRate
3393
3404
  } : void 0;
3394
- this.encoder = new mU(
3405
+ this.encoder = new MU(
3395
3406
  this.mediaStream,
3396
3407
  J,
3397
3408
  n,
@@ -3508,7 +3519,7 @@ export {
3508
3519
  A as LiveVideoPlayer,
3509
3520
  FU as MP4FileSource,
3510
3521
  v as MediaCapture,
3511
- mU as MediaStreamEncoder,
3522
+ MU as MediaStreamEncoder,
3512
3523
  K as MoQCaptureSink,
3513
3524
  VU as MoQSource,
3514
3525
  UU as WasmDecoder,
@@ -3526,7 +3537,7 @@ export {
3526
3537
  yU as createWebSocketSource,
3527
3538
  vU as isAudioCodec,
3528
3539
  xU as isVideoCodec,
3529
- MU as isVideoFrame,
3540
+ mU as isVideoFrame,
3530
3541
  HU as isYUVFrame,
3531
3542
  WU as silentLogger
3532
3543
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stinkycomputing/web-live-player",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "A Player library for Sesame video streams using WebCodecs and MoQ",
5
5
  "type": "module",
6
6
  "main": "./dist/web-live-player.cjs",