@memberjunction/ai-realtime-client 6.2.0-edge.3 → 6.2.0-edge.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/README.md +156 -29
- package/dist/audio/audioMeter.d.ts +71 -0
- package/dist/audio/audioMeter.d.ts.map +1 -1
- package/dist/audio/audioMeter.js +83 -0
- package/dist/audio/audioMeter.js.map +1 -1
- package/dist/audio/mediaElementAudioRouter.d.ts +41 -0
- package/dist/audio/mediaElementAudioRouter.d.ts.map +1 -0
- package/dist/audio/mediaElementAudioRouter.js +82 -0
- package/dist/audio/mediaElementAudioRouter.js.map +1 -0
- package/dist/audio/micCapture.d.ts +12 -3
- package/dist/audio/micCapture.d.ts.map +1 -1
- package/dist/audio/micCapture.js +15 -1
- package/dist/audio/micCapture.js.map +1 -1
- package/dist/audio/pcmPlayback.d.ts +72 -4
- package/dist/audio/pcmPlayback.d.ts.map +1 -1
- package/dist/audio/pcmPlayback.js +101 -1
- package/dist/audio/pcmPlayback.js.map +1 -1
- package/dist/drivers/assemblyAIRealtimeClient.d.ts +2 -0
- package/dist/drivers/assemblyAIRealtimeClient.d.ts.map +1 -1
- package/dist/drivers/assemblyAIRealtimeClient.js +14 -0
- package/dist/drivers/assemblyAIRealtimeClient.js.map +1 -1
- package/dist/drivers/elevenLabsRealtimeClient.d.ts +2 -0
- package/dist/drivers/elevenLabsRealtimeClient.d.ts.map +1 -1
- package/dist/drivers/elevenLabsRealtimeClient.js +14 -0
- package/dist/drivers/elevenLabsRealtimeClient.js.map +1 -1
- package/dist/drivers/geminiAvatarOutput.d.ts +132 -0
- package/dist/drivers/geminiAvatarOutput.d.ts.map +1 -0
- package/dist/drivers/geminiAvatarOutput.js +310 -0
- package/dist/drivers/geminiAvatarOutput.js.map +1 -0
- package/dist/drivers/geminiEnterpriseRealtimeClient.d.ts +38 -0
- package/dist/drivers/geminiEnterpriseRealtimeClient.d.ts.map +1 -0
- package/dist/drivers/geminiEnterpriseRealtimeClient.js +107 -0
- package/dist/drivers/geminiEnterpriseRealtimeClient.js.map +1 -0
- package/dist/drivers/geminiRealtimeClient.d.ts +314 -48
- package/dist/drivers/geminiRealtimeClient.d.ts.map +1 -1
- package/dist/drivers/geminiRealtimeClient.js +759 -176
- package/dist/drivers/geminiRealtimeClient.js.map +1 -1
- package/dist/drivers/openAILiveClient.d.ts +5 -8
- package/dist/drivers/openAILiveClient.d.ts.map +1 -1
- package/dist/drivers/openAILiveClient.js +19 -32
- package/dist/drivers/openAILiveClient.js.map +1 -1
- package/dist/drivers/openAIRealtimeClient.d.ts +13 -26
- package/dist/drivers/openAIRealtimeClient.d.ts.map +1 -1
- package/dist/drivers/openAIRealtimeClient.js +28 -55
- package/dist/drivers/openAIRealtimeClient.js.map +1 -1
- package/dist/generic/baseRealtimeClient.d.ts +173 -29
- package/dist/generic/baseRealtimeClient.d.ts.map +1 -1
- package/dist/generic/baseRealtimeClient.js +233 -14
- package/dist/generic/baseRealtimeClient.js.map +1 -1
- package/dist/generic/openAIProtocolClient.d.ts +2 -0
- package/dist/generic/openAIProtocolClient.d.ts.map +1 -1
- package/dist/generic/openAIProtocolClient.js +14 -0
- package/dist/generic/openAIProtocolClient.js.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/media/attachVideoSource.d.ts +23 -0
- package/dist/media/attachVideoSource.d.ts.map +1 -0
- package/dist/media/attachVideoSource.js +49 -0
- package/dist/media/attachVideoSource.js.map +1 -0
- package/dist/media/channelVideoSource.d.ts +110 -14
- package/dist/media/channelVideoSource.d.ts.map +1 -1
- package/dist/media/channelVideoSource.js +183 -18
- package/dist/media/channelVideoSource.js.map +1 -1
- package/dist/media/decoders/frameScheduler.d.ts +119 -0
- package/dist/media/decoders/frameScheduler.d.ts.map +1 -0
- package/dist/media/decoders/frameScheduler.js +238 -0
- package/dist/media/decoders/frameScheduler.js.map +1 -0
- package/dist/media/decoders/imageFrameDecoder.d.ts +58 -0
- package/dist/media/decoders/imageFrameDecoder.d.ts.map +1 -0
- package/dist/media/decoders/imageFrameDecoder.js +110 -0
- package/dist/media/decoders/imageFrameDecoder.js.map +1 -0
- package/dist/media/decoders/mseFmp4Decoder.d.ts +130 -0
- package/dist/media/decoders/mseFmp4Decoder.d.ts.map +1 -0
- package/dist/media/decoders/mseFmp4Decoder.js +402 -0
- package/dist/media/decoders/mseFmp4Decoder.js.map +1 -0
- package/dist/media/decoders/streamCanvas.d.ts +46 -0
- package/dist/media/decoders/streamCanvas.d.ts.map +1 -0
- package/dist/media/decoders/streamCanvas.js +163 -0
- package/dist/media/decoders/streamCanvas.js.map +1 -0
- package/dist/media/decoders/videoMimeTypes.d.ts +29 -0
- package/dist/media/decoders/videoMimeTypes.d.ts.map +1 -0
- package/dist/media/decoders/videoMimeTypes.js +50 -0
- package/dist/media/decoders/videoMimeTypes.js.map +1 -0
- package/dist/media/decoders/webCodecsChunkDecoder.d.ts +99 -0
- package/dist/media/decoders/webCodecsChunkDecoder.d.ts.map +1 -0
- package/dist/media/decoders/webCodecsChunkDecoder.js +265 -0
- package/dist/media/decoders/webCodecsChunkDecoder.js.map +1 -0
- package/dist/media/displayCapture.d.ts +128 -0
- package/dist/media/displayCapture.d.ts.map +1 -0
- package/dist/media/displayCapture.js +245 -0
- package/dist/media/displayCapture.js.map +1 -0
- package/dist/media/frameCapture.d.ts +25 -8
- package/dist/media/frameCapture.d.ts.map +1 -1
- package/dist/media/frameCapture.js +42 -72
- package/dist/media/frameCapture.js.map +1 -1
- package/dist/media/frameSampler.d.ts +94 -0
- package/dist/media/frameSampler.d.ts.map +1 -0
- package/dist/media/frameSampler.js +134 -0
- package/dist/media/frameSampler.js.map +1 -0
- package/dist/media/index.d.ts +32 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media/index.js +32 -0
- package/dist/media/index.js.map +1 -0
- package/dist/media/localMediaController.d.ts +116 -0
- package/dist/media/localMediaController.d.ts.map +1 -0
- package/dist/media/localMediaController.js +281 -0
- package/dist/media/localMediaController.js.map +1 -0
- package/dist/media/mediaLayout.d.ts +93 -0
- package/dist/media/mediaLayout.d.ts.map +1 -0
- package/dist/media/mediaLayout.js +187 -0
- package/dist/media/mediaLayout.js.map +1 -0
- package/dist/media/mediaPreview.d.ts +94 -0
- package/dist/media/mediaPreview.d.ts.map +1 -0
- package/dist/media/mediaPreview.js +154 -0
- package/dist/media/mediaPreview.js.map +1 -0
- package/dist/media/mediaStage.d.ts +99 -0
- package/dist/media/mediaStage.d.ts.map +1 -0
- package/dist/media/mediaStage.js +171 -0
- package/dist/media/mediaStage.js.map +1 -0
- package/dist/media/model.d.ts +154 -0
- package/dist/media/model.d.ts.map +1 -0
- package/dist/media/model.js +9 -0
- package/dist/media/model.js.map +1 -0
- package/dist/media/playbackClock.d.ts +20 -0
- package/dist/media/playbackClock.d.ts.map +1 -0
- package/dist/media/playbackClock.js +13 -0
- package/dist/media/playbackClock.js.map +1 -0
- package/dist/media/videoFrameDecoder.d.ts +86 -0
- package/dist/media/videoFrameDecoder.d.ts.map +1 -0
- package/dist/media/videoFrameDecoder.js +2 -0
- package/dist/media/videoFrameDecoder.js.map +1 -0
- package/dist/media/videoFrameDecoderRegistry.d.ts +40 -0
- package/dist/media/videoFrameDecoderRegistry.d.ts.map +1 -0
- package/dist/media/videoFrameDecoderRegistry.js +69 -0
- package/dist/media/videoFrameDecoderRegistry.js.map +1 -0
- package/dist/media/videoPacing.d.ts +32 -0
- package/dist/media/videoPacing.d.ts.map +1 -0
- package/dist/media/videoPacing.js +37 -0
- package/dist/media/videoPacing.js.map +1 -0
- package/dist/media/videoPlayout.d.ts +168 -0
- package/dist/media/videoPlayout.d.ts.map +1 -0
- package/dist/media/videoPlayout.js +217 -0
- package/dist/media/videoPlayout.js.map +1 -0
- package/dist/media/videoSourceArbiter.d.ts +250 -0
- package/dist/media/videoSourceArbiter.d.ts.map +1 -0
- package/dist/media/videoSourceArbiter.js +423 -0
- package/dist/media/videoSourceArbiter.js.map +1 -0
- package/dist/testing/conformanceAssertions.d.ts +25 -0
- package/dist/testing/conformanceAssertions.d.ts.map +1 -0
- package/dist/testing/conformanceAssertions.js +64 -0
- package/dist/testing/conformanceAssertions.js.map +1 -0
- package/dist/testing/conformanceFixtures.d.ts +76 -0
- package/dist/testing/conformanceFixtures.d.ts.map +1 -0
- package/dist/testing/conformanceFixtures.js +169 -0
- package/dist/testing/conformanceFixtures.js.map +1 -0
- package/dist/testing/conformanceGates.d.ts +32 -0
- package/dist/testing/conformanceGates.d.ts.map +1 -0
- package/dist/testing/conformanceGates.js +35 -0
- package/dist/testing/conformanceGates.js.map +1 -0
- package/dist/testing/conformanceMicrophone.d.ts +10 -0
- package/dist/testing/conformanceMicrophone.d.ts.map +1 -0
- package/dist/testing/conformanceMicrophone.js +71 -0
- package/dist/testing/conformanceMicrophone.js.map +1 -0
- package/dist/testing/conformanceTimeline.d.ts +128 -0
- package/dist/testing/conformanceTimeline.d.ts.map +1 -0
- package/dist/testing/conformanceTimeline.js +32 -0
- package/dist/testing/conformanceTimeline.js.map +1 -0
- package/dist/testing/conformanceVideoStream.d.ts +29 -0
- package/dist/testing/conformanceVideoStream.d.ts.map +1 -0
- package/dist/testing/conformanceVideoStream.js +39 -0
- package/dist/testing/conformanceVideoStream.js.map +1 -0
- package/dist/testing/index.d.ts +29 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +28 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/realtimeVideoConformance.d.ts +23 -0
- package/dist/testing/realtimeVideoConformance.d.ts.map +1 -0
- package/dist/testing/realtimeVideoConformance.js +139 -0
- package/dist/testing/realtimeVideoConformance.js.map +1 -0
- package/dist/testing/realtimeVideoConformanceChecks.d.ts +4 -0
- package/dist/testing/realtimeVideoConformanceChecks.d.ts.map +1 -0
- package/dist/testing/realtimeVideoConformanceChecks.js +164 -0
- package/dist/testing/realtimeVideoConformanceChecks.js.map +1 -0
- package/dist/testing/realtimeVideoConformanceFrameChecks.d.ts +4 -0
- package/dist/testing/realtimeVideoConformanceFrameChecks.d.ts.map +1 -0
- package/dist/testing/realtimeVideoConformanceFrameChecks.js +63 -0
- package/dist/testing/realtimeVideoConformanceFrameChecks.js.map +1 -0
- package/dist/testing/realtimeVideoConformanceSession.d.ts +108 -0
- package/dist/testing/realtimeVideoConformanceSession.d.ts.map +1 -0
- package/dist/testing/realtimeVideoConformanceSession.js +270 -0
- package/dist/testing/realtimeVideoConformanceSession.js.map +1 -0
- package/dist/testing/realtimeVideoConformanceTurnChecks.d.ts +4 -0
- package/dist/testing/realtimeVideoConformanceTurnChecks.d.ts.map +1 -0
- package/dist/testing/realtimeVideoConformanceTurnChecks.js +248 -0
- package/dist/testing/realtimeVideoConformanceTurnChecks.js.map +1 -0
- package/dist/testing/realtimeVideoConformanceTypes.d.ts +155 -0
- package/dist/testing/realtimeVideoConformanceTypes.d.ts.map +1 -0
- package/dist/testing/realtimeVideoConformanceTypes.js +2 -0
- package/dist/testing/realtimeVideoConformanceTypes.js.map +1 -0
- package/dist/testing/recordingPlayout.d.ts +84 -0
- package/dist/testing/recordingPlayout.d.ts.map +1 -0
- package/dist/testing/recordingPlayout.js +120 -0
- package/dist/testing/recordingPlayout.js.map +1 -0
- package/package.json +29 -4
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview STREAM CANVAS: turns decoded pictures (WebCodecs `VideoFrame`s, `ImageBitmap`s) into a live
|
|
3
|
+
* `MediaStream` that the host's `<video>` element shows, so a decoder that isn't MSE still plays into the element: the
|
|
4
|
+
* tile, its stall watch (`requestVideoFrameCallback` fires once per picture) and its placements work as for any video.
|
|
5
|
+
*
|
|
6
|
+
* - **Chromium:** a `MediaStreamTrackGenerator` takes each picture as a `VideoFrame`, with no copy.
|
|
7
|
+
* - **Elsewhere:** a canvas captured at 0 fps (`captureStream(0)`) is drawn on, and a frame is requested after each draw.
|
|
8
|
+
* - **The last picture holds.** Between pictures the element keeps showing the last one, and an element attached later
|
|
9
|
+
* is shown it: the generator is written a copy again, or the canvas is captured again. A picture that reaches an element
|
|
10
|
+
* before its media pipeline is connected is lost (in Chromium that takes a task or two), so the copy is offered every
|
|
11
|
+
* {@link REPLAY_INTERVAL_MS} until the element has a frame, at most {@link MAX_REPLAYS} times.
|
|
12
|
+
* - **Time moves forward.** Each picture written to the generator is stamped with the wall clock, after the one before, so a
|
|
13
|
+
* stream that restarts its media time doesn't feed the track frames that go back in time.
|
|
14
|
+
*
|
|
15
|
+
* @module @memberjunction/ai-realtime-client/media
|
|
16
|
+
*/
|
|
17
|
+
/** How often the last picture is offered again to an element just attached, until it has a frame, in milliseconds. */
|
|
18
|
+
export const REPLAY_INTERVAL_MS = 50;
|
|
19
|
+
/** How many times the last picture is offered to an element just attached. */
|
|
20
|
+
export const MAX_REPLAYS = 20;
|
|
21
|
+
/** `HTMLMediaElement.HAVE_CURRENT_DATA`: the element has a frame to show. */
|
|
22
|
+
const HAVE_CURRENT_DATA = 2;
|
|
23
|
+
/** The generator class, when this browser exposes one on the page. */
|
|
24
|
+
function generatorClass() {
|
|
25
|
+
return globalThis.MediaStreamTrackGenerator ?? null;
|
|
26
|
+
}
|
|
27
|
+
/** Whether a canvas can be captured as a stream here. */
|
|
28
|
+
function canvasCaptureAvailable() {
|
|
29
|
+
return typeof HTMLCanvasElement === 'function' && typeof HTMLCanvasElement.prototype.captureStream === 'function';
|
|
30
|
+
}
|
|
31
|
+
/** A picture's size in pixels. */
|
|
32
|
+
function sizeOf(picture) {
|
|
33
|
+
return 'displayWidth' in picture ? { Width: picture.displayWidth, Height: picture.displayHeight } : { Width: picture.width, Height: picture.height };
|
|
34
|
+
}
|
|
35
|
+
/** Writes each picture to a `MediaStreamTrackGenerator` as a `VideoFrame`, keeping a copy of the last one. */
|
|
36
|
+
class GeneratorSink {
|
|
37
|
+
constructor(track) {
|
|
38
|
+
this.track = track;
|
|
39
|
+
this.last = null;
|
|
40
|
+
/** The timestamp of the last frame written, in microseconds. */
|
|
41
|
+
this.timestampUs = 0;
|
|
42
|
+
this.writer = track.writable.getWriter();
|
|
43
|
+
this.Stream = new MediaStream([track]);
|
|
44
|
+
}
|
|
45
|
+
get HasPicture() {
|
|
46
|
+
return this.last !== null;
|
|
47
|
+
}
|
|
48
|
+
Show(picture) {
|
|
49
|
+
const frame = this.stamped(picture);
|
|
50
|
+
picture.close();
|
|
51
|
+
this.last?.close();
|
|
52
|
+
this.last = frame.clone();
|
|
53
|
+
this.write(frame);
|
|
54
|
+
}
|
|
55
|
+
Replay() {
|
|
56
|
+
if (this.last) {
|
|
57
|
+
this.write(this.stamped(this.last));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
Dispose() {
|
|
61
|
+
this.last?.close();
|
|
62
|
+
this.last = null;
|
|
63
|
+
this.writer.releaseLock();
|
|
64
|
+
this.track.stop();
|
|
65
|
+
}
|
|
66
|
+
/** A frame of the picture, stamped with the wall clock and after the last frame written. */
|
|
67
|
+
stamped(picture) {
|
|
68
|
+
this.timestampUs = Math.max(this.timestampUs + 1, Math.round(performance.now() * 1000));
|
|
69
|
+
return new VideoFrame(picture, { timestamp: this.timestampUs });
|
|
70
|
+
}
|
|
71
|
+
write(frame) {
|
|
72
|
+
this.writer.write(frame).catch(() => frame.close());
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** Draws each picture on a canvas captured at 0 fps, requesting a frame after each draw. */
|
|
76
|
+
class CanvasSink {
|
|
77
|
+
constructor() {
|
|
78
|
+
this.HasPicture = false;
|
|
79
|
+
this.canvas = document.createElement('canvas');
|
|
80
|
+
this.Stream = this.canvas.captureStream(0);
|
|
81
|
+
this.track = this.Stream.getVideoTracks()[0];
|
|
82
|
+
}
|
|
83
|
+
Show(picture) {
|
|
84
|
+
const { Width, Height } = sizeOf(picture);
|
|
85
|
+
if (this.canvas.width !== Width || this.canvas.height !== Height) {
|
|
86
|
+
this.canvas.width = Width;
|
|
87
|
+
this.canvas.height = Height;
|
|
88
|
+
}
|
|
89
|
+
this.canvas.getContext('2d')?.drawImage(picture, 0, 0, Width, Height);
|
|
90
|
+
picture.close();
|
|
91
|
+
this.HasPicture = true;
|
|
92
|
+
this.Replay();
|
|
93
|
+
}
|
|
94
|
+
Replay() {
|
|
95
|
+
this.track?.requestFrame?.();
|
|
96
|
+
}
|
|
97
|
+
Dispose() {
|
|
98
|
+
this.track?.stop();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/** Shows decoded pictures in `<video>` elements through one live stream. */
|
|
102
|
+
export class StreamCanvas {
|
|
103
|
+
/** Whether this browser can turn pictures into a stream: a track generator, or a canvas it can capture. */
|
|
104
|
+
static IsAvailable() {
|
|
105
|
+
return generatorClass() !== null || canvasCaptureAvailable();
|
|
106
|
+
}
|
|
107
|
+
constructor() {
|
|
108
|
+
this.element = null;
|
|
109
|
+
this.replayTimer = null;
|
|
110
|
+
const Generator = generatorClass();
|
|
111
|
+
this.sink = Generator ? new GeneratorSink(new Generator({ kind: 'video' })) : new CanvasSink();
|
|
112
|
+
}
|
|
113
|
+
/** Shows a picture in the attached element (and any attached later), and closes it. */
|
|
114
|
+
Show(picture) {
|
|
115
|
+
this.sink.Show(picture);
|
|
116
|
+
}
|
|
117
|
+
/** Shows the stream in an element, with the last picture. The element plays muted: the stream has no audio. */
|
|
118
|
+
Attach(element) {
|
|
119
|
+
this.Detach();
|
|
120
|
+
this.element = element;
|
|
121
|
+
element.muted = true;
|
|
122
|
+
element.playsInline = true;
|
|
123
|
+
element.srcObject = this.sink.Stream;
|
|
124
|
+
void element.play().catch(() => {
|
|
125
|
+
// A hidden or not-yet-allowed element starts later; the stream keeps its last picture until then.
|
|
126
|
+
});
|
|
127
|
+
this.replayUntilShown(element, 0);
|
|
128
|
+
}
|
|
129
|
+
/** Takes the stream out of the element it was attached to, unless another source replaced it there. */
|
|
130
|
+
Detach() {
|
|
131
|
+
this.cancelReplay();
|
|
132
|
+
const element = this.element;
|
|
133
|
+
this.element = null;
|
|
134
|
+
if (element && element.srcObject === this.sink.Stream) {
|
|
135
|
+
element.pause();
|
|
136
|
+
element.srcObject = null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/** Detaches, stops the stream's track and closes the last picture. */
|
|
140
|
+
Dispose() {
|
|
141
|
+
this.Detach();
|
|
142
|
+
this.sink.Dispose();
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Offers the last picture to a just-attached element until it has a frame, every {@link REPLAY_INTERVAL_MS}. Letting
|
|
146
|
+
* the element go cancels the offers.
|
|
147
|
+
*/
|
|
148
|
+
replayUntilShown(element, attempt) {
|
|
149
|
+
this.replayTimer = null;
|
|
150
|
+
if (!this.sink.HasPicture || element.readyState >= HAVE_CURRENT_DATA || attempt >= MAX_REPLAYS) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
this.sink.Replay();
|
|
154
|
+
this.replayTimer = setTimeout(() => this.replayUntilShown(element, attempt + 1), REPLAY_INTERVAL_MS);
|
|
155
|
+
}
|
|
156
|
+
cancelReplay() {
|
|
157
|
+
if (this.replayTimer !== null) {
|
|
158
|
+
clearTimeout(this.replayTimer);
|
|
159
|
+
this.replayTimer = null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=streamCanvas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamCanvas.js","sourceRoot":"","sources":["../../../src/media/decoders/streamCanvas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview VIDEO MIME TYPES: what `VideoPlayout` and its decoders read from a frame's MIME type: its essence
|
|
3
|
+
* (`type/subtype`), its `codecs` parameter, the frame kind it names, and an encoded chunk's WebCodecs codec string.
|
|
4
|
+
*
|
|
5
|
+
* Chunk types follow the `RealtimeChunkVideoFrame` contract: `video/h264`, `video/vp9` and `video/av1` carry the WebCodecs
|
|
6
|
+
* codec string in their `codecs` parameter (`video/h264; codecs="avc1.42e01f"`); `video/vp8` needs none.
|
|
7
|
+
*
|
|
8
|
+
* @module @memberjunction/ai-realtime-client/media
|
|
9
|
+
*/
|
|
10
|
+
import type { RealtimeVideoFrameKind } from '@memberjunction/ai';
|
|
11
|
+
/** The image types `createImageBitmap` decodes in every browser that has it. */
|
|
12
|
+
export declare const IMAGE_FRAME_TYPES: ReadonlySet<string>;
|
|
13
|
+
/** A MIME type's essence: `type/subtype` in lower case, without parameters. */
|
|
14
|
+
export declare function MimeEssence(mimeType: string): string;
|
|
15
|
+
/** The first entry of a MIME type's `codecs` parameter, unquoted; `undefined` when it has none. */
|
|
16
|
+
export declare function MimeCodec(mimeType: string): string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* The frame kind a MIME type names: `video/mp4` is fragmented MP4, the chunk types above are encoded chunks, and any
|
|
19
|
+
* `image/*` is an image. `null` for anything else.
|
|
20
|
+
*/
|
|
21
|
+
export declare function FrameKindOfMimeType(mimeType: string): RealtimeVideoFrameKind | null;
|
|
22
|
+
/**
|
|
23
|
+
* The WebCodecs codec string for an encoded chunk type: its `codecs` parameter, or `'vp8'` for `video/vp8` without one.
|
|
24
|
+
* `null` for another type, or a `codecs` parameter of another codec family.
|
|
25
|
+
*/
|
|
26
|
+
export declare function WebCodecsCodecOf(mimeType: string): string | null;
|
|
27
|
+
/** A frame's type as the player tells decoders apart: its kind and its MIME essence. */
|
|
28
|
+
export declare function FrameTypeKey(kind: RealtimeVideoFrameKind, mimeType: string): string;
|
|
29
|
+
//# sourceMappingURL=videoMimeTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"videoMimeTypes.d.ts","sourceRoot":"","sources":["../../../src/media/decoders/videoMimeTypes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAgBjE,gFAAgF;AAChF,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAAsD,CAAC;AAEzG,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,mGAAmG;AACnG,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAI9D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI,CASnF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOhE;AAED,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,IAAI,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** The chunk types a WebCodecs decoder can be configured for, by MIME essence. */
|
|
2
|
+
const CHUNK_CODEC_FAMILIES = new Map([
|
|
3
|
+
['video/h264', { Prefixes: ['avc1.', 'avc3.'] }],
|
|
4
|
+
['video/vp8', { Prefixes: ['vp8'], Default: 'vp8' }],
|
|
5
|
+
['video/vp9', { Prefixes: ['vp09.'] }],
|
|
6
|
+
['video/av1', { Prefixes: ['av01.'] }],
|
|
7
|
+
]);
|
|
8
|
+
/** The image types `createImageBitmap` decodes in every browser that has it. */
|
|
9
|
+
export const IMAGE_FRAME_TYPES = new Set(['image/jpeg', 'image/png', 'image/webp']);
|
|
10
|
+
/** A MIME type's essence: `type/subtype` in lower case, without parameters. */
|
|
11
|
+
export function MimeEssence(mimeType) {
|
|
12
|
+
return mimeType.split(';')[0].trim().toLowerCase();
|
|
13
|
+
}
|
|
14
|
+
/** The first entry of a MIME type's `codecs` parameter, unquoted; `undefined` when it has none. */
|
|
15
|
+
export function MimeCodec(mimeType) {
|
|
16
|
+
const match = /;\s*codecs\s*=\s*(?:"([^"]*)"|([^;\s]+))/i.exec(mimeType);
|
|
17
|
+
const codec = (match?.[1] ?? match?.[2])?.split(',')[0].trim();
|
|
18
|
+
return codec || undefined;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The frame kind a MIME type names: `video/mp4` is fragmented MP4, the chunk types above are encoded chunks, and any
|
|
22
|
+
* `image/*` is an image. `null` for anything else.
|
|
23
|
+
*/
|
|
24
|
+
export function FrameKindOfMimeType(mimeType) {
|
|
25
|
+
const essence = MimeEssence(mimeType);
|
|
26
|
+
if (essence === 'video/mp4') {
|
|
27
|
+
return 'fmp4';
|
|
28
|
+
}
|
|
29
|
+
if (CHUNK_CODEC_FAMILIES.has(essence)) {
|
|
30
|
+
return 'chunk';
|
|
31
|
+
}
|
|
32
|
+
return essence.startsWith('image/') ? 'image' : null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The WebCodecs codec string for an encoded chunk type: its `codecs` parameter, or `'vp8'` for `video/vp8` without one.
|
|
36
|
+
* `null` for another type, or a `codecs` parameter of another codec family.
|
|
37
|
+
*/
|
|
38
|
+
export function WebCodecsCodecOf(mimeType) {
|
|
39
|
+
const family = CHUNK_CODEC_FAMILIES.get(MimeEssence(mimeType));
|
|
40
|
+
const codec = MimeCodec(mimeType) ?? family?.Default;
|
|
41
|
+
if (!family || !codec) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return family.Prefixes.some((prefix) => codec.toLowerCase().startsWith(prefix)) ? codec : null;
|
|
45
|
+
}
|
|
46
|
+
/** A frame's type as the player tells decoders apart: its kind and its MIME essence. */
|
|
47
|
+
export function FrameTypeKey(kind, mimeType) {
|
|
48
|
+
return `${kind} ${MimeEssence(mimeType)}`;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=videoMimeTypes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"videoMimeTypes.js","sourceRoot":"","sources":["../../../src/media/decoders/videoMimeTypes.ts"],"names":[],"mappings":"AAiBA,kFAAkF;AAClF,MAAM,oBAAoB,GAA0C,IAAI,GAAG,CAAC;IACxE,CAAC,YAAY,EAAE,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;IAChD,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACpD,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACtC,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;CACzC,CAAC,CAAC;AAEH,gFAAgF;AAChF,MAAM,CAAC,MAAM,iBAAiB,GAAwB,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;AAEzG,+EAA+E;AAC/E,MAAM,UAAU,WAAW,CAAC,QAAgB;IACxC,OAAO,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACvD,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,SAAS,CAAC,QAAgB;IACtC,MAAM,KAAK,GAAG,2CAA2C,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzE,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/D,OAAO,KAAK,IAAI,SAAS,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAChD,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACtC,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;QAC1B,OAAO,MAAM,CAAC;IAClB,CAAC;IACD,IAAI,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,OAAO,CAAC;IACnB,CAAC;IACD,OAAO,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC7C,MAAM,MAAM,GAAG,oBAAoB,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,MAAM,EAAE,OAAO,CAAC;IACrD,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACnG,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,YAAY,CAAC,IAA4B,EAAE,QAAgB;IACvE,OAAO,GAAG,IAAI,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview WEBCODECS CHUNK DECODER: plays encoded video chunks (`Kind: 'chunk'`: H.264 in Annex B form, VP8, VP9,
|
|
3
|
+
* AV1) through a WebCodecs `VideoDecoder`, into the host's `<video>` element through a {@link StreamCanvas}. The
|
|
4
|
+
* `'webcodecs'` decoder of `VideoPlayout`.
|
|
5
|
+
*
|
|
6
|
+
* - **Configured at a key frame.** The decoder is configured from the chunk's MIME type (its `codecs` parameter is the
|
|
7
|
+
* WebCodecs codec string; H.264 in Annex B needs no `description`) at the first key frame, after the browser confirms
|
|
8
|
+
* it decodes the codec (`VideoDecoder.isConfigSupported`, asynchronous). A "no" reports `'unsupported'` and gives up,
|
|
9
|
+
* so the player tries the next decoder. Until a key frame, delta chunks are dropped.
|
|
10
|
+
* - **Paced by presentation time.** Decoded frames show on the {@link FrameScheduler} by their `PresentationTimeMs`: on
|
|
11
|
+
* the voice's clock when the player has one (`VideoPlayoutOptions.Clock`), else by their own times.
|
|
12
|
+
* Chunks wait, encoded, while {@link MAX_FRAMES_AHEAD} frames are decoding or waiting to show: a browser decoder stalls
|
|
13
|
+
* when its output frames aren't closed.
|
|
14
|
+
* - **End of turn** flushes the decoder once the waiting chunks are decoded, so the turn's last frames show; a chunk
|
|
15
|
+
* that arrives first continues the turn instead. After the flush the next chunk must be a key frame (WebCodecs requires
|
|
16
|
+
* one). **Barge-in** resets the decoder, drops what is waiting and what hasn't shown, and waits for the next key frame;
|
|
17
|
+
* the last frame shown stays.
|
|
18
|
+
* - **Errors.** A decode error is reported (`'append-failed'`); the browser has closed that decoder, so a new one starts
|
|
19
|
+
* at the next key frame. {@link MAX_DECODE_ERRORS} errors within {@link DECODE_ERROR_WINDOW_MS} give up.
|
|
20
|
+
*
|
|
21
|
+
* @module @memberjunction/ai-realtime-client/media
|
|
22
|
+
*/
|
|
23
|
+
import type { RealtimeVideoFrame } from '@memberjunction/ai';
|
|
24
|
+
import type { IVideoFrameDecoder, VideoFrameDecoderContext, VideoFrameDecoderRegistration } from '../videoFrameDecoder.js';
|
|
25
|
+
/** Frames decoding or waiting to show, at most; further chunks wait encoded. */
|
|
26
|
+
export declare const MAX_FRAMES_AHEAD = 6;
|
|
27
|
+
/** Encoded chunks waiting to be decoded, at most; beyond this they are dropped and decoding restarts at a key frame. */
|
|
28
|
+
export declare const MAX_WAITING_CHUNKS = 600;
|
|
29
|
+
/** Decode errors within {@link DECODE_ERROR_WINDOW_MS} that make the decoder give up. */
|
|
30
|
+
export declare const MAX_DECODE_ERRORS = 3;
|
|
31
|
+
/** The window decode errors are counted in, in milliseconds. */
|
|
32
|
+
export declare const DECODE_ERROR_WINDOW_MS = 60000;
|
|
33
|
+
/** Plays encoded chunks through a WebCodecs `VideoDecoder`. */
|
|
34
|
+
export declare class WebCodecsChunkDecoder implements IVideoFrameDecoder {
|
|
35
|
+
private readonly context;
|
|
36
|
+
private readonly canvas;
|
|
37
|
+
private readonly scheduler;
|
|
38
|
+
/** Chunks from a key frame on, waiting to be decoded. */
|
|
39
|
+
private readonly waiting;
|
|
40
|
+
/** Codecs this browser said it decodes. */
|
|
41
|
+
private readonly supported;
|
|
42
|
+
/** When the recent decode errors happened, for the give-up rule. */
|
|
43
|
+
private readonly errors;
|
|
44
|
+
private decoder;
|
|
45
|
+
/** The codec the decoder is configured for; `null` until a key frame configures it, and after a reset. */
|
|
46
|
+
private configured;
|
|
47
|
+
/** The codec whose support check is under way. */
|
|
48
|
+
private checking;
|
|
49
|
+
/** Delta chunks are dropped until a key frame. */
|
|
50
|
+
private awaitingKeyFrame;
|
|
51
|
+
/** Set by EndOfTurn: flush the decoder once nothing waits. */
|
|
52
|
+
private endPending;
|
|
53
|
+
/** Whether a key frame ever arrived: a stream that starts on a delta chunk is reported once. */
|
|
54
|
+
private started;
|
|
55
|
+
private disposed;
|
|
56
|
+
/** Whether this browser can decode chunks of `mimeType` with WebCodecs and show them, as far as it can tell at once. */
|
|
57
|
+
static CanPlay(mimeType: string): boolean;
|
|
58
|
+
/** @param context The player this decoder plays for. */
|
|
59
|
+
constructor(context: VideoFrameDecoderContext);
|
|
60
|
+
/** Always `false`: a chunk carries no voice. */
|
|
61
|
+
get IsPlaying(): boolean;
|
|
62
|
+
/** Frames still to show: chunks waiting to be decoded, chunks the decoder is decoding, and frames waiting for their time. */
|
|
63
|
+
get FramesAhead(): number;
|
|
64
|
+
Attach(element: HTMLVideoElement): void;
|
|
65
|
+
Detach(): void;
|
|
66
|
+
/** Takes one chunk: from a key frame on, it waits its turn to be decoded. */
|
|
67
|
+
Append(frame: RealtimeVideoFrame): void;
|
|
68
|
+
/** The turn's last chunk has arrived: the decoder is flushed once the waiting chunks are decoded, so its last frames show. */
|
|
69
|
+
EndOfTurn(): void;
|
|
70
|
+
/** Barge-in: resets the decoder and drops what is waiting and what hasn't shown. The last frame shown stays. */
|
|
71
|
+
Flush(): void;
|
|
72
|
+
Dispose(): void;
|
|
73
|
+
/**
|
|
74
|
+
* A key frame: decoding starts here, configured for its codec (after the browser confirms it, the first time).
|
|
75
|
+
* Returns `false` when the chunk names no codec WebCodecs knows: it is dropped.
|
|
76
|
+
*/
|
|
77
|
+
private startAt;
|
|
78
|
+
private dropBeforeKeyFrame;
|
|
79
|
+
private enqueue;
|
|
80
|
+
/** Asks the browser whether it decodes `codec`; a "yes" configures the decoder, a "no" gives up. */
|
|
81
|
+
private checkSupport;
|
|
82
|
+
private supportChecked;
|
|
83
|
+
/** Configures the decoder for `codec`, creating one when none is open. */
|
|
84
|
+
private configure;
|
|
85
|
+
private createDecoder;
|
|
86
|
+
/** Decodes waiting chunks while fewer than {@link MAX_FRAMES_AHEAD} frames are ahead, then flushes a finished turn. */
|
|
87
|
+
private feed;
|
|
88
|
+
/** Flushes the decoder for a finished turn once nothing waits. WebCodecs then needs a key frame to go on. */
|
|
89
|
+
private flushWhenDrained;
|
|
90
|
+
private decode;
|
|
91
|
+
/** A decoded frame: it waits on the scheduler for its time. A frame from a decoder since replaced is closed. */
|
|
92
|
+
private decoded;
|
|
93
|
+
/** A decode error: the browser closed the decoder. A new one starts at the next key frame, unless errors keep coming. */
|
|
94
|
+
private decodeFailed;
|
|
95
|
+
private closeDecoder;
|
|
96
|
+
}
|
|
97
|
+
/** The `'webcodecs'` decoder: encoded chunks whose codec this browser's WebCodecs decodes. */
|
|
98
|
+
export declare const WEBCODECS_CHUNK_DECODER: VideoFrameDecoderRegistration;
|
|
99
|
+
//# sourceMappingURL=webCodecsChunkDecoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webCodecsChunkDecoder.d.ts","sourceRoot":"","sources":["../../../src/media/decoders/webCodecsChunkDecoder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAA2B,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,KAAK,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAKxH,gFAAgF;AAChF,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,wHAAwH;AACxH,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,yFAAyF;AACzF,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,gEAAgE;AAChE,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAE7C,+DAA+D;AAC/D,qBAAa,qBAAsB,YAAW,kBAAkB;IA6BhD,OAAO,CAAC,QAAQ,CAAC,OAAO;IA5BpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,yDAAyD;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,2CAA2C;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAC/C,oEAAoE;IACpE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,OAAO,CAA6B;IAC5C,0GAA0G;IAC1G,OAAO,CAAC,UAAU,CAAuB;IACzC,kDAAkD;IAClD,OAAO,CAAC,QAAQ,CAAuB;IACvC,kDAAkD;IAClD,OAAO,CAAC,gBAAgB,CAAQ;IAChC,8DAA8D;IAC9D,OAAO,CAAC,UAAU,CAAS;IAC3B,gGAAgG;IAChG,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;IAEzB,wHAAwH;WAC1G,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAKhD,wDAAwD;gBAC3B,OAAO,EAAE,wBAAwB;IAI9D,gDAAgD;IAChD,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,6HAA6H;IAC7H,IAAW,WAAW,IAAI,MAAM,CAG/B;IAEM,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAMvC,MAAM,IAAI,IAAI;IAIrB,6EAA6E;IACtE,MAAM,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAkB9C,8HAA8H;IACvH,SAAS,IAAI,IAAI;IAKxB,gHAAgH;IACzG,KAAK,IAAI,IAAI;IAWb,OAAO,IAAI,IAAI;IAQtB;;;OAGG;IACH,OAAO,CAAC,OAAO;IAwBf,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,OAAO;IAUf,oGAAoG;IACpG,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,cAAc;IAetB,0EAA0E;IAC1E,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,aAAa;IASrB,uHAAuH;IACvH,OAAO,CAAC,IAAI;IAWZ,6GAA6G;IAC7G,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,MAAM;IASd,gHAAgH;IAChH,OAAO,CAAC,OAAO;IASf,yHAAyH;IACzH,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,YAAY;CAQvB;AAOD,8FAA8F;AAC9F,eAAO,MAAM,uBAAuB,EAAE,6BAMrC,CAAC"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { FrameScheduler } from './frameScheduler.js';
|
|
2
|
+
import { StreamCanvas } from './streamCanvas.js';
|
|
3
|
+
import { WebCodecsCodecOf } from './videoMimeTypes.js';
|
|
4
|
+
/** Frames decoding or waiting to show, at most; further chunks wait encoded. */
|
|
5
|
+
export const MAX_FRAMES_AHEAD = 6;
|
|
6
|
+
/** Encoded chunks waiting to be decoded, at most; beyond this they are dropped and decoding restarts at a key frame. */
|
|
7
|
+
export const MAX_WAITING_CHUNKS = 600;
|
|
8
|
+
/** Decode errors within {@link DECODE_ERROR_WINDOW_MS} that make the decoder give up. */
|
|
9
|
+
export const MAX_DECODE_ERRORS = 3;
|
|
10
|
+
/** The window decode errors are counted in, in milliseconds. */
|
|
11
|
+
export const DECODE_ERROR_WINDOW_MS = 60_000;
|
|
12
|
+
/** Plays encoded chunks through a WebCodecs `VideoDecoder`. */
|
|
13
|
+
export class WebCodecsChunkDecoder {
|
|
14
|
+
/** Whether this browser can decode chunks of `mimeType` with WebCodecs and show them, as far as it can tell at once. */
|
|
15
|
+
static CanPlay(mimeType) {
|
|
16
|
+
const canDecode = typeof VideoDecoder === 'function' && typeof EncodedVideoChunk === 'function';
|
|
17
|
+
return canDecode && StreamCanvas.IsAvailable() && WebCodecsCodecOf(mimeType) !== null;
|
|
18
|
+
}
|
|
19
|
+
/** @param context The player this decoder plays for. */
|
|
20
|
+
constructor(context) {
|
|
21
|
+
this.context = context;
|
|
22
|
+
this.canvas = new StreamCanvas();
|
|
23
|
+
/** Chunks from a key frame on, waiting to be decoded. */
|
|
24
|
+
this.waiting = [];
|
|
25
|
+
/** Codecs this browser said it decodes. */
|
|
26
|
+
this.supported = new Set();
|
|
27
|
+
/** When the recent decode errors happened, for the give-up rule. */
|
|
28
|
+
this.errors = [];
|
|
29
|
+
this.decoder = null;
|
|
30
|
+
/** The codec the decoder is configured for; `null` until a key frame configures it, and after a reset. */
|
|
31
|
+
this.configured = null;
|
|
32
|
+
/** The codec whose support check is under way. */
|
|
33
|
+
this.checking = null;
|
|
34
|
+
/** Delta chunks are dropped until a key frame. */
|
|
35
|
+
this.awaitingKeyFrame = true;
|
|
36
|
+
/** Set by EndOfTurn: flush the decoder once nothing waits. */
|
|
37
|
+
this.endPending = false;
|
|
38
|
+
/** Whether a key frame ever arrived: a stream that starts on a delta chunk is reported once. */
|
|
39
|
+
this.started = false;
|
|
40
|
+
this.disposed = false;
|
|
41
|
+
this.scheduler = new FrameScheduler(this.canvas, () => this.feed(), { Clock: context.Clock });
|
|
42
|
+
}
|
|
43
|
+
/** Always `false`: a chunk carries no voice. */
|
|
44
|
+
get IsPlaying() {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
/** Frames still to show: chunks waiting to be decoded, chunks the decoder is decoding, and frames waiting for their time. */
|
|
48
|
+
get FramesAhead() {
|
|
49
|
+
const decoding = this.decoder && this.decoder.state !== 'closed' ? this.decoder.decodeQueueSize : 0;
|
|
50
|
+
return this.waiting.length + decoding + this.scheduler.Size;
|
|
51
|
+
}
|
|
52
|
+
Attach(element) {
|
|
53
|
+
if (!this.disposed) {
|
|
54
|
+
this.canvas.Attach(element);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
Detach() {
|
|
58
|
+
this.canvas.Detach();
|
|
59
|
+
}
|
|
60
|
+
/** Takes one chunk: from a key frame on, it waits its turn to be decoded. */
|
|
61
|
+
Append(frame) {
|
|
62
|
+
if (this.disposed || frame.Kind !== 'chunk') {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// More media is coming, so a turn that was about to end continues instead.
|
|
66
|
+
this.endPending = false;
|
|
67
|
+
if (frame.KeyFrame) {
|
|
68
|
+
if (!this.startAt(frame) || this.disposed) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else if (this.awaitingKeyFrame) {
|
|
73
|
+
this.dropBeforeKeyFrame();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
this.enqueue(frame);
|
|
77
|
+
this.feed();
|
|
78
|
+
}
|
|
79
|
+
/** The turn's last chunk has arrived: the decoder is flushed once the waiting chunks are decoded, so its last frames show. */
|
|
80
|
+
EndOfTurn() {
|
|
81
|
+
this.endPending = true;
|
|
82
|
+
this.flushWhenDrained();
|
|
83
|
+
}
|
|
84
|
+
/** Barge-in: resets the decoder and drops what is waiting and what hasn't shown. The last frame shown stays. */
|
|
85
|
+
Flush() {
|
|
86
|
+
this.waiting.length = 0;
|
|
87
|
+
this.endPending = false;
|
|
88
|
+
this.awaitingKeyFrame = true;
|
|
89
|
+
this.scheduler.Clear();
|
|
90
|
+
if (this.decoder && this.decoder.state !== 'closed') {
|
|
91
|
+
this.decoder.reset();
|
|
92
|
+
}
|
|
93
|
+
this.configured = null;
|
|
94
|
+
}
|
|
95
|
+
Dispose() {
|
|
96
|
+
this.disposed = true;
|
|
97
|
+
this.waiting.length = 0;
|
|
98
|
+
this.scheduler.Dispose();
|
|
99
|
+
this.closeDecoder();
|
|
100
|
+
this.canvas.Dispose();
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A key frame: decoding starts here, configured for its codec (after the browser confirms it, the first time).
|
|
104
|
+
* Returns `false` when the chunk names no codec WebCodecs knows: it is dropped.
|
|
105
|
+
*/
|
|
106
|
+
startAt(frame) {
|
|
107
|
+
const codec = WebCodecsCodecOf(frame.MimeType);
|
|
108
|
+
if (codec === null) {
|
|
109
|
+
this.context.Report('unsupported', `A video chunk of type ${frame.MimeType} names no codec WebCodecs knows; it was dropped.`);
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
this.awaitingKeyFrame = false;
|
|
113
|
+
this.started = true;
|
|
114
|
+
if (codec === this.configured || codec === this.checking) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
// A new codec: chunks of the old one still waiting can't be decoded with it, nothing decodes until it is configured,
|
|
118
|
+
// and a check under way for another codec no longer applies.
|
|
119
|
+
this.waiting.length = 0;
|
|
120
|
+
this.configured = null;
|
|
121
|
+
this.checking = null;
|
|
122
|
+
if (this.supported.has(codec)) {
|
|
123
|
+
this.configure(codec);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
this.checkSupport(codec);
|
|
127
|
+
}
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
dropBeforeKeyFrame() {
|
|
131
|
+
if (!this.started) {
|
|
132
|
+
this.context.Report('fragment-before-init', 'An encoded video chunk arrived before any key frame and was dropped.');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
enqueue(frame) {
|
|
136
|
+
this.waiting.push(frame);
|
|
137
|
+
if (this.waiting.length > MAX_WAITING_CHUNKS) {
|
|
138
|
+
this.waiting.length = 0;
|
|
139
|
+
this.awaitingKeyFrame = true;
|
|
140
|
+
const message = 'Encoded video chunks piled up faster than they could be decoded; they were dropped until the next key frame.';
|
|
141
|
+
this.context.Report('pending-overflow', message);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** Asks the browser whether it decodes `codec`; a "yes" configures the decoder, a "no" gives up. */
|
|
145
|
+
checkSupport(codec) {
|
|
146
|
+
this.checking = codec;
|
|
147
|
+
const canCheck = typeof VideoDecoder.isConfigSupported === 'function';
|
|
148
|
+
const check = canCheck ? VideoDecoder.isConfigSupported({ codec }) : Promise.resolve({ supported: true });
|
|
149
|
+
check.then((result) => this.supportChecked(codec, result.supported === true), () => this.supportChecked(codec, false));
|
|
150
|
+
}
|
|
151
|
+
supportChecked(codec, supported) {
|
|
152
|
+
if (this.disposed || this.checking !== codec) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
this.checking = null;
|
|
156
|
+
if (!supported) {
|
|
157
|
+
this.context.Report('unsupported', `This browser cannot decode ${codec} video with WebCodecs.`);
|
|
158
|
+
this.context.Failed(`the browser does not decode ${codec}`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
this.supported.add(codec);
|
|
162
|
+
this.configure(codec);
|
|
163
|
+
this.feed();
|
|
164
|
+
}
|
|
165
|
+
/** Configures the decoder for `codec`, creating one when none is open. */
|
|
166
|
+
configure(codec) {
|
|
167
|
+
try {
|
|
168
|
+
const decoder = this.decoder && this.decoder.state !== 'closed' ? this.decoder : this.createDecoder();
|
|
169
|
+
decoder.configure({ codec, optimizeForLatency: true });
|
|
170
|
+
this.configured = codec;
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
this.context.Report('unsupported', `This browser cannot decode ${codec} video with WebCodecs: ${messageOf(error)}`);
|
|
174
|
+
this.context.Failed(`the decoder could not be configured for ${codec}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
createDecoder() {
|
|
178
|
+
const decoder = new VideoDecoder({
|
|
179
|
+
output: (frame) => this.decoded(decoder, frame),
|
|
180
|
+
error: (error) => this.decodeFailed(decoder, error.message),
|
|
181
|
+
});
|
|
182
|
+
this.decoder = decoder;
|
|
183
|
+
return decoder;
|
|
184
|
+
}
|
|
185
|
+
/** Decodes waiting chunks while fewer than {@link MAX_FRAMES_AHEAD} frames are ahead, then flushes a finished turn. */
|
|
186
|
+
feed() {
|
|
187
|
+
const decoder = this.decoder;
|
|
188
|
+
while (decoder && this.decoder === decoder && this.configured !== null && this.waiting.length > 0) {
|
|
189
|
+
if (decoder.decodeQueueSize + this.scheduler.Size >= MAX_FRAMES_AHEAD) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
this.decode(decoder, this.waiting.shift());
|
|
193
|
+
}
|
|
194
|
+
this.flushWhenDrained();
|
|
195
|
+
}
|
|
196
|
+
/** Flushes the decoder for a finished turn once nothing waits. WebCodecs then needs a key frame to go on. */
|
|
197
|
+
flushWhenDrained() {
|
|
198
|
+
const decoder = this.decoder;
|
|
199
|
+
if (!this.endPending || this.waiting.length > 0 || !decoder || this.configured === null) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
this.endPending = false;
|
|
203
|
+
this.awaitingKeyFrame = true;
|
|
204
|
+
decoder.flush().catch(() => {
|
|
205
|
+
// A reset or an error since: what the flush waited for was dropped.
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
decode(decoder, frame) {
|
|
209
|
+
try {
|
|
210
|
+
const timestamp = Math.round(frame.PresentationTimeMs * 1000);
|
|
211
|
+
decoder.decode(new EncodedVideoChunk({ type: frame.KeyFrame ? 'key' : 'delta', timestamp, data: frame.Data }));
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
this.decodeFailed(decoder, messageOf(error));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/** A decoded frame: it waits on the scheduler for its time. A frame from a decoder since replaced is closed. */
|
|
218
|
+
decoded(decoder, frame) {
|
|
219
|
+
if (this.disposed || this.decoder !== decoder) {
|
|
220
|
+
frame.close();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
this.scheduler.Push(frame, frame.timestamp / 1000);
|
|
224
|
+
this.feed();
|
|
225
|
+
}
|
|
226
|
+
/** A decode error: the browser closed the decoder. A new one starts at the next key frame, unless errors keep coming. */
|
|
227
|
+
decodeFailed(decoder, message) {
|
|
228
|
+
if (this.disposed || this.decoder !== decoder) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
this.context.Report('append-failed', `The browser could not decode a video chunk: ${message}`);
|
|
232
|
+
this.closeDecoder();
|
|
233
|
+
this.waiting.length = 0;
|
|
234
|
+
this.awaitingKeyFrame = true;
|
|
235
|
+
const now = Date.now();
|
|
236
|
+
this.errors.push(now);
|
|
237
|
+
while (this.errors.length > 0 && now - this.errors[0] > DECODE_ERROR_WINDOW_MS) {
|
|
238
|
+
this.errors.shift();
|
|
239
|
+
}
|
|
240
|
+
if (this.errors.length >= MAX_DECODE_ERRORS) {
|
|
241
|
+
this.context.Failed(`${this.errors.length} decode errors within ${DECODE_ERROR_WINDOW_MS / 1000} s; the last: ${message}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
closeDecoder() {
|
|
245
|
+
const decoder = this.decoder;
|
|
246
|
+
this.decoder = null;
|
|
247
|
+
this.configured = null;
|
|
248
|
+
if (decoder && decoder.state !== 'closed') {
|
|
249
|
+
decoder.close();
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/** An error's message, whatever was thrown. */
|
|
254
|
+
function messageOf(error) {
|
|
255
|
+
return error instanceof Error ? error.message : String(error);
|
|
256
|
+
}
|
|
257
|
+
/** The `'webcodecs'` decoder: encoded chunks whose codec this browser's WebCodecs decodes. */
|
|
258
|
+
export const WEBCODECS_CHUNK_DECODER = {
|
|
259
|
+
Name: 'webcodecs',
|
|
260
|
+
Kind: 'chunk',
|
|
261
|
+
Priority: 0,
|
|
262
|
+
CanPlay: (mimeType) => WebCodecsChunkDecoder.CanPlay(mimeType),
|
|
263
|
+
Create: (context) => new WebCodecsChunkDecoder(context),
|
|
264
|
+
};
|
|
265
|
+
//# sourceMappingURL=webCodecsChunkDecoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webCodecsChunkDecoder.js","sourceRoot":"","sources":["../../../src/media/decoders/webCodecsChunkDecoder.ts"],"names":[],"mappings":"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"}
|