@vindral/web-sdk 4.1.10 → 4.2.0

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/legacy.d.ts CHANGED
@@ -66,6 +66,10 @@ declare class Emitter<TEvents, TEmits = TEvents, ArgLessEvents extends VoidKeys<
66
66
  */
67
67
  once<T extends ArgLessEvents>(eventName: T, fn: () => void): void;
68
68
  once<T extends ArgEvents>(eventName: T, fn: (args: TEvents[T]) => void): void;
69
+ /**
70
+ * Check whether there are any listeners registered for the given event.
71
+ */
72
+ hasListeners<T extends keyof TEvents | keyof TEmits>(eventName: T): boolean;
69
73
  /**
70
74
  * Reset the event emitter
71
75
  */
@@ -141,53 +145,6 @@ export interface ReconnectState {
141
145
  */
142
146
  reconnectRetries: number;
143
147
  }
144
- interface RenditionProps {
145
- id: number;
146
- /** */
147
- bitRate: number;
148
- /** */
149
- codecString?: string;
150
- /** */
151
- language?: string;
152
- /** */
153
- meta?: Record<string, string>;
154
- }
155
- interface VideoRenditionProps {
156
- /** */
157
- codec: VideoCodec;
158
- /** */
159
- frameRate: [
160
- number,
161
- number
162
- ];
163
- /** */
164
- width: number;
165
- /** */
166
- height: number;
167
- }
168
- interface AudioRenditionProps {
169
- /** */
170
- codec: AudioCodec;
171
- /** */
172
- channels: number;
173
- /** */
174
- sampleRate: number;
175
- }
176
- interface TextRenditionProps {
177
- codec: "webvtt";
178
- kind: "subtitles" | "captions";
179
- label?: string;
180
- }
181
- /**
182
- * @interface
183
- */
184
- export type VideoRendition = VideoRenditionProps & RenditionProps;
185
- /**
186
- * @interface
187
- */
188
- export type AudioRendition = AudioRenditionProps & RenditionProps;
189
- type TextRendition = TextRenditionProps & RenditionProps;
190
- type Rendition = VideoRendition | AudioRendition | TextRendition;
191
148
  /**
192
149
  * Represents a size with a width and height.
193
150
  */
@@ -197,28 +154,10 @@ export interface Size {
197
154
  /** */
198
155
  height: number;
199
156
  }
200
- export interface VideoConstraint {
201
- /** */
202
- width: number;
203
- /** */
204
- height: number;
205
- /** */
206
- bitRate: number;
207
- /** */
208
- codec?: VideoCodec;
209
- /** */
210
- codecString?: string;
211
- }
212
157
  /**
213
158
  * Advanced options to override default behaviour.
214
159
  */
215
160
  export interface AdvancedOptions {
216
- /**
217
- * Constrains wasm decoding to this resolution.
218
- * By default it is set to 1280 in width and height.
219
- * This guarantees better performance on older devices and reduces battery drain in general.
220
- */
221
- wasmDecodingConstraint: Partial<VideoConstraint>;
222
161
  }
223
162
  /**
224
163
  * DRM options to provide to the Vindral instance
@@ -252,6 +191,7 @@ export interface DrmOptions {
252
191
  */
253
192
  export type Media = "audio" | "video" | "audio+video";
254
193
  type WebCodecsHardwareAccelerationPreference = "no-preference" | "prefer-hardware" | "prefer-software";
194
+ type DecoderType = "mse" | "webcodecs" | "wasm";
255
195
  /**
256
196
  * Options for the Vindral instance
257
197
  *
@@ -322,11 +262,9 @@ export interface Options {
322
262
  */
323
263
  burstEnabled?: boolean;
324
264
  /**
325
- * Enable usage of the MediaSource API on supported browsers.
326
- *
327
- * Is enabled by default.
328
- *
329
- * Note: We recommend to keep this at the default value unless you have very specific needs.
265
+ * @deprecated Use `decoders` instead.
266
+ * Setting `mseEnabled: false` is equivalent to `decoders: ["wasm"]`.
267
+ * When both `mseEnabled` and `decoders` are provided, `decoders` takes precedence.
330
268
  */
331
269
  mseEnabled?: boolean;
332
270
  /**
@@ -443,7 +381,7 @@ export interface Options {
443
381
  * The wake lock requires that the audio has been activated at least once for the instance, othwerwise it will not work.
444
382
  * Other devices already provide wake lock by default.
445
383
  *
446
- * This option is redundant and has no effect if iosMediaElementEnabled is enabled since that automatically enables wake lock.
384
+ * This option is redundant and has no effect if streamToMediaElementEnabled is enabled since that automatically enables wake lock.
447
385
  *
448
386
  * Disabled by default.
449
387
  */
@@ -453,26 +391,20 @@ export interface Options {
453
391
  */
454
392
  pauseSupportEnabled?: boolean;
455
393
  /**
456
- * Enables iOS devices to use a media element for playback. This enables fullscreen and picture in picture support on iOS.
457
- */
458
- iosMediaElementEnabled?: boolean;
459
- /**
460
- * Enable WebCodecs API for hardware-accelerated decoding.
394
+ * Stream canvas-rendered video/audio to a media element via captureStream.
461
395
  *
462
- * When enabled, the browser's native VideoDecoder and AudioDecoder APIs will be used instead
463
- * of WASM decoding on supported browsers (Chrome 94+, Edge 94+, Safari 16.4+). This provides:
464
- * - Hardware-accelerated decoding (uses GPU for video)
465
- * - Better performance at higher resolutions
466
- * - Lower CPU usage and battery consumption
396
+ * This enables platform media features such as fullscreen and picture-in-picture
397
+ * for non-MSE playback by routing the canvas output through a `<video>` element.
467
398
  *
468
- * Disabled by default to allow gradual rollout and testing.
399
+ * Disabled by default.
400
+ */
401
+ streamToMediaElementEnabled?: boolean;
402
+ /**
403
+ * @deprecated Use `streamToMediaElementEnabled` instead.
469
404
  *
470
- * Note: Automatically falls back to WASM decoding if:
471
- * - The browser doesn't support WebCodecs
472
- * - WebCodecs initialization fails
473
- * - This option is set to false or undefined
405
+ * Legacy alias kept for backwards compatibility.
474
406
  */
475
- webcodecsEnabled?: boolean;
407
+ iosMediaElementEnabled?: boolean;
476
408
  /**
477
409
  * Hardware acceleration preference for WebCodecs video decoding.
478
410
  *
@@ -480,14 +412,29 @@ export interface Options {
480
412
  */
481
413
  webcodecsHardwareAcceleration?: WebCodecsHardwareAccelerationPreference;
482
414
  /**
483
- * Enable OffscreenCanvas rendering in worker thread (requires webcodecsEnabled: true).
415
+ * Enable OffscreenCanvas rendering in worker thread.
484
416
  *
485
417
  * When enabled, video rendering happens in the worker thread using OffscreenCanvas.
486
- * Disabled by default to allow gradual rollout and testing.
418
+ * Automatically enabled when `decoders` resolves to WebCodecs. Set to `false`
419
+ * to explicitly disable even when WebCodecs is active.
487
420
  *
488
- * Note: Requires browser support for OffscreenCanvas and webcodecsEnabled must be true, and iosMediaElementEnabled must be false.
421
+ * Requires browser support for OffscreenCanvas and WebCodecs.
422
+ * Works with `streamToMediaElementEnabled` for fullscreen/PiP support.
489
423
  */
490
424
  offscreenCanvasEnabled?: boolean;
425
+ /**
426
+ * Ordered list of decoders to try.
427
+ *
428
+ * The runtime walks the list and uses the first decoder that is available on the
429
+ * current platform. When DRM is active, MSE is forced regardless of order.
430
+ *
431
+ * When omitted, the platform default order is used (`["mse", "wasm"]`).
432
+ *
433
+ * @example
434
+ * // Prefer WebCodecs over MSE
435
+ * decoders: ["webcodecs", "mse", "wasm"]
436
+ */
437
+ decoders?: DecoderType[];
491
438
  /**
492
439
  * Advanced options to override default behaviour.
493
440
  */
@@ -506,7 +453,6 @@ interface ClientOverrides {
506
453
  burstEnabled?: boolean;
507
454
  sizeBasedResolutionCapEnabled?: boolean;
508
455
  separateVideoSocketEnabled?: boolean;
509
- webcodecsEnabled?: boolean;
510
456
  webcodecsHardwareAcceleration?: WebCodecsHardwareAccelerationPreference;
511
457
  offscreenCanvasEnabled?: boolean;
512
458
  videoCodecs?: string[];
@@ -550,6 +496,53 @@ interface TracksCatalog extends CatalogRoot {
550
496
  namespace: Namespace;
551
497
  tracks: Array<TrackObject>;
552
498
  }
499
+ interface RenditionProps {
500
+ id: number;
501
+ /** */
502
+ bitRate: number;
503
+ /** */
504
+ codecString?: string;
505
+ /** */
506
+ language?: string;
507
+ /** */
508
+ meta?: Record<string, string>;
509
+ }
510
+ interface VideoRenditionProps {
511
+ /** */
512
+ codec: VideoCodec;
513
+ /** */
514
+ frameRate: [
515
+ number,
516
+ number
517
+ ];
518
+ /** */
519
+ width: number;
520
+ /** */
521
+ height: number;
522
+ }
523
+ interface AudioRenditionProps {
524
+ /** */
525
+ codec: AudioCodec;
526
+ /** */
527
+ channels: number;
528
+ /** */
529
+ sampleRate: number;
530
+ }
531
+ interface TextRenditionProps {
532
+ codec: "webvtt";
533
+ kind: "subtitles" | "captions";
534
+ label?: string;
535
+ }
536
+ /**
537
+ * @interface
538
+ */
539
+ export type VideoRendition = VideoRenditionProps & RenditionProps;
540
+ /**
541
+ * @interface
542
+ */
543
+ export type AudioRendition = AudioRenditionProps & RenditionProps;
544
+ type TextRendition = TextRenditionProps & RenditionProps;
545
+ type Rendition = VideoRendition | AudioRendition | TextRendition;
553
546
  interface Telemetry {
554
547
  url: string;
555
548
  probability?: number;
@@ -641,6 +634,18 @@ export interface RenditionLevelChanged {
641
634
  /** */
642
635
  reason: RenditionLevelChangedReason;
643
636
  }
637
+ export interface VideoConstraint {
638
+ /** */
639
+ width: number;
640
+ /** */
641
+ height: number;
642
+ /** */
643
+ bitRate: number;
644
+ /** */
645
+ codec?: VideoCodec;
646
+ /** */
647
+ codecString?: string;
648
+ }
644
649
  interface VindralErrorProps {
645
650
  isFatal: boolean;
646
651
  type?: ErrorType;
@@ -864,6 +869,13 @@ interface DecoderStatistics {
864
869
  videoDecodeTime: MinMaxAverage;
865
870
  audioDecodeTime: MinMaxAverage;
866
871
  videoTransportTime: MinMaxAverage;
872
+ videoKeyframeIntervalMs?: number;
873
+ renderedFrameCount?: number;
874
+ rendererDroppedFrameCount?: number;
875
+ videoRenderer?: "OffscreenCanvas" | "Canvas" | "MSE";
876
+ videoDecoder?: "WebCodecs" | "WASM" | "MSE";
877
+ audioRenderer?: "AudioContext" | "MSE";
878
+ audioDecoder?: "WebCodecs" | "WASM" | "MSE";
867
879
  }
868
880
  interface DocumentStateModulesStatistics {
869
881
  isVisible: boolean;
@@ -913,6 +925,11 @@ interface MseModuleStatistics {
913
925
  droppedVideoFrames?: number;
914
926
  successfulVideoAppendCalls?: number;
915
927
  successfulAudioAppendsCalls?: number;
928
+ videoKeyframeIntervalMs?: number;
929
+ videoRenderer?: "OffscreenCanvas" | "Canvas" | "MSE";
930
+ videoDecoder?: "WebCodecs" | "WASM" | "MSE";
931
+ audioRenderer?: "AudioContext" | "MSE";
932
+ audioDecoder?: "WebCodecs" | "WASM" | "MSE";
916
933
  }
917
934
  interface QualityOfServiceModuleStatistics {
918
935
  /**
@@ -993,8 +1010,6 @@ interface SyncModuleStatistics {
993
1010
  interface VideoPlayerStatistics {
994
1011
  renderedFrameCount: number;
995
1012
  rendererDroppedFrameCount: number;
996
- contextLostCount: number;
997
- contextRestoredCount: number;
998
1013
  }
999
1014
  type ModuleStatistics = AdaptivityStatistics & BufferTimeStatistics & ConnectionStatistics & ConstraintCapStatistics & DecoderStatistics & DocumentStateModulesStatistics & IncomingDataModuleStatistics & JitterModuleStatistics & MseModuleStatistics & PlaybackModuleStatistics & QualityOfServiceModuleStatistics & RenditionsModuleStatistics & SyncModuleStatistics & TelemetryModuleStatistics & VideoPlayerStatistics;
1000
1015
  /**
@@ -1045,6 +1060,8 @@ export type Statistics = ModuleStatistics & ReturnType<UserAgentInformation["get
1045
1060
  * Note that an actual frame render often happens much quicker, but that is not counted as TTFF.
1046
1061
  */
1047
1062
  timeToFirstFrame?: number;
1063
+ streamToMediaElementEnabled?: boolean;
1064
+ /** @deprecated */
1048
1065
  iosMediaElementEnabled?: boolean;
1049
1066
  /**
1050
1067
  * Average bitrate for the entire session in bits/second.
@@ -1147,6 +1164,8 @@ export declare class Vindral extends Emitter<PublicVindralEvents> {
1147
1164
  private clientId;
1148
1165
  private _channels;
1149
1166
  private createdAt;
1167
+ private offscreenCanvasElement?;
1168
+ private webCodecsRenditionSupport;
1150
1169
  private hasCalledConnect;
1151
1170
  private latestEmittedLanguages;
1152
1171
  private wakeLock;
@@ -1157,6 +1176,7 @@ export declare class Vindral extends Emitter<PublicVindralEvents> {
1157
1176
  private sizes;
1158
1177
  private isSuspended;
1159
1178
  private disconnectTimeout;
1179
+ private offscreenSubtitleInterval?;
1160
1180
  constructor(options: Options);
1161
1181
  /**
1162
1182
  * Attaches the video view to a DOM element. The Vindral video view will be sized to fill this element while
@@ -1165,6 +1185,7 @@ export declare class Vindral extends Emitter<PublicVindralEvents> {
1165
1185
  * @returns
1166
1186
  */
1167
1187
  attach: (container: HTMLElement) => void;
1188
+ private setElement;
1168
1189
  /**
1169
1190
  * Set the current volume.
1170
1191
  * Setting this to 0 is not equivalent to muting the audio.
@@ -1385,6 +1406,10 @@ export declare class Vindral extends Emitter<PublicVindralEvents> {
1385
1406
  * The ranges are specified in milliseconds.
1386
1407
  */
1387
1408
  get audioBufferedRanges(): ReadonlyArray<TimeRange>;
1409
+ /**
1410
+ * The timestamps (in milliseconds) of video keyframes currently in the buffer.
1411
+ */
1412
+ get videoKeyframeTimestamps(): ReadonlyArray<number>;
1388
1413
  /**
1389
1414
  * The API client for calls to the public available endpoints of the Vindral Live CDN.
1390
1415
  */
@@ -1444,9 +1469,16 @@ export declare class Vindral extends Emitter<PublicVindralEvents> {
1444
1469
  private isSupportedVideoCodecProfile;
1445
1470
  private supportedAudioCodecs;
1446
1471
  private initializeDecodingModule;
1472
+ /**
1473
+ * Set up a polling interval that forwards subtitle cues to the decoder worker
1474
+ * when OffscreenCanvas rendering is active. This is needed because the canvas modules'
1475
+ * own subtitle intervals either get killed (LegacyCanvasModule) or don't have the
1476
+ * OffscreenCanvas reference at construction time (ModernCanvasModule).
1477
+ */
1478
+ private setupOffscreenSubtitleRouting;
1447
1479
  /**
1448
1480
  * Fully unloads the instance. This disconnects the clients and stops any background tasks.
1449
- * This client instance can not be used after this has been called.
1481
+ * This client instance cannot be used after this has been called.
1450
1482
  */
1451
1483
  unload: () => Promise<void>;
1452
1484
  /**
@@ -1510,7 +1542,17 @@ export declare class Vindral extends Emitter<PublicVindralEvents> {
1510
1542
  private get currentSubscription();
1511
1543
  private get targetSubscription();
1512
1544
  private timeToFirstFrame;
1545
+ private resolvedDecoder;
1513
1546
  private willUseMediaSource;
1547
+ private shouldUseWebCodecs;
1548
+ private isWebCodecsVideoAvailable;
1549
+ private isWebCodecsAudioAvailable;
1550
+ /**
1551
+ * Returns true if OffscreenCanvas should be used.
1552
+ * Implicitly enabled when the resolved decoder is WebCodecs, since OffscreenCanvas
1553
+ * is the optimal rendering path for WebCodecs (worker renders VideoFrames directly).
1554
+ */
1555
+ private shouldUseOffscreenCanvas;
1514
1556
  }
1515
1557
  interface TelemetryModuleStatistics {
1516
1558
  /**
@@ -1590,6 +1632,12 @@ interface TimeShiftInfo {
1590
1632
  urls: string[];
1591
1633
  duration: string;
1592
1634
  }
1635
+ interface CmafFragmentEvent {
1636
+ mediaType: "video" | "audio";
1637
+ initSegment: Readonly<Uint8Array<ArrayBuffer>>;
1638
+ fragment: Readonly<Uint8Array<ArrayBuffer>>;
1639
+ isKeyframe: boolean;
1640
+ }
1593
1641
  /**
1594
1642
  * The events that can be emitted from the Vindral instance
1595
1643
  */
@@ -1693,6 +1741,13 @@ export interface PublicVindralEvents {
1693
1741
  * Emitted when the timeshift URLs are updated.
1694
1742
  */
1695
1743
  ["timeshift info"]: Readonly<TimeShiftInfo>;
1744
+ /**
1745
+ * Emitted for each CMAF fragment received via the MoQ/VoQ path.
1746
+ * Contains raw fMP4 bytes suitable for recording.
1747
+ *
1748
+ * @internal Not part of the public API — may change without notice.
1749
+ */
1750
+ ["cmaf fragment"]: Readonly<CmafFragmentEvent>;
1696
1751
  ["buffer state event"]: Readonly<BufferStateEvent>;
1697
1752
  ["initialized media"]: void;
1698
1753
  }