@memberjunction/ai-realtime-client 6.2.0-edge.2 → 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 +23 -26
- package/dist/drivers/openAIRealtimeClient.d.ts.map +1 -1
- package/dist/drivers/openAIRealtimeClient.js +42 -57
- package/dist/drivers/openAIRealtimeClient.js.map +1 -1
- package/dist/generic/baseRealtimeClient.d.ts +188 -30
- package/dist/generic/baseRealtimeClient.d.ts.map +1 -1
- package/dist/generic/baseRealtimeClient.js +250 -14
- package/dist/generic/baseRealtimeClient.js.map +1 -1
- package/dist/generic/openAIProtocolClient.d.ts +57 -1
- package/dist/generic/openAIProtocolClient.d.ts.map +1 -1
- package/dist/generic/openAIProtocolClient.js +89 -4
- 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,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":"AAwBA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,gFAAgF;AAChF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAElC,wHAAwH;AACxH,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAEtC,yFAAyF;AACzF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAEnC,gEAAgE;AAChE,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAE7C,+DAA+D;AAC/D,MAAM,OAAO,qBAAqB;IAsB9B,wHAAwH;IACjH,MAAM,CAAC,OAAO,CAAC,QAAgB;QAClC,MAAM,SAAS,GAAG,OAAO,YAAY,KAAK,UAAU,IAAI,OAAO,iBAAiB,KAAK,UAAU,CAAC;QAChG,OAAO,SAAS,IAAI,YAAY,CAAC,WAAW,EAAE,IAAI,gBAAgB,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAC1F,CAAC;IAED,wDAAwD;IACxD,YAA6B,OAAiC;QAAjC,YAAO,GAAP,OAAO,CAA0B;QA5B7C,WAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAE7C,yDAAyD;QACxC,YAAO,GAA8B,EAAE,CAAC;QACzD,2CAA2C;QAC1B,cAAS,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/C,oEAAoE;QACnD,WAAM,GAAa,EAAE,CAAC;QAC/B,YAAO,GAAwB,IAAI,CAAC;QAC5C,0GAA0G;QAClG,eAAU,GAAkB,IAAI,CAAC;QACzC,kDAAkD;QAC1C,aAAQ,GAAkB,IAAI,CAAC;QACvC,kDAAkD;QAC1C,qBAAgB,GAAG,IAAI,CAAC;QAChC,8DAA8D;QACtD,eAAU,GAAG,KAAK,CAAC;QAC3B,gGAAgG;QACxF,YAAO,GAAG,KAAK,CAAC;QAChB,aAAQ,GAAG,KAAK,CAAC;QAUrB,IAAI,CAAC,SAAS,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,gDAAgD;IAChD,IAAW,SAAS;QAChB,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,6HAA6H;IAC7H,IAAW,WAAW;QAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;QACpG,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;IAChE,CAAC;IAEM,MAAM,CAAC,OAAyB;QACnC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACjB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;IACL,CAAC;IAEM,MAAM;QACT,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;IACzB,CAAC;IAED,6EAA6E;IACtE,MAAM,CAAC,KAAyB;QACnC,IAAI,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC1C,OAAO;QACX,CAAC;QACD,2EAA2E;QAC3E,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACjB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACxC,OAAO;YACX,CAAC;QACL,CAAC;aAAM,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC/B,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC1B,OAAO;QACX,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACpB,IAAI,CAAC,IAAI,EAAE,CAAC;IAChB,CAAC;IAED,8HAA8H;IACvH,SAAS;QACZ,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC5B,CAAC;IAED,gHAAgH;IACzG,KAAK;QACR,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YAClD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;IAC3B,CAAC;IAEM,OAAO;QACV,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACzB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACK,OAAO,CAAC,KAA8B;QAC1C,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACjB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,yBAAyB,KAAK,CAAC,QAAQ,kDAAkD,CAAC,CAAC;YAC9H,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;QAC9B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,KAAK,KAAK,IAAI,CAAC,UAAU,IAAI,KAAK,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;YACvD,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,qHAAqH;QACrH,6DAA6D;QAC7D,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAEO,kBAAkB;QACtB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAChB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,sBAAsB,EAAE,sEAAsE,CAAC,CAAC;QACxH,CAAC;IACL,CAAC;IAEO,OAAO,CAAC,KAA8B;QAC1C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;YAC3C,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;YACxB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;YAC7B,MAAM,OAAO,GAAG,8GAA8G,CAAC;YAC/H,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;QACrD,CAAC;IACL,CAAC;IAED,oGAAoG;IAC5F,YAAY,CAAC,KAAa;QAC9B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,MAAM,QAAQ,GAAG,OAAO,YAAY,CAAC,iBAAiB,KAAK,UAAU,CAAC;QACtE,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,iBAAiB,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1G,KAAK,CAAC,IAAI,CACN,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,KAAK,IAAI,CAAC,EACjE,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAC1C,CAAC;IACN,CAAC;IAEO,cAAc,CAAC,KAAa,EAAE,SAAkB;QACpD,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;YAC3C,OAAO;QACX,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,SAAS,EAAE,CAAC;YACb,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,8BAA8B,KAAK,wBAAwB,CAAC,CAAC;YAChG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,+BAA+B,KAAK,EAAE,CAAC,CAAC;YAC5D,OAAO;QACX,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,EAAE,CAAC;IAChB,CAAC;IAED,0EAA0E;IAClE,SAAS,CAAC,KAAa;QAC3B,IAAI,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACtG,OAAO,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;YACvD,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,8BAA8B,KAAK,0BAA0B,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACpH,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,2CAA2C,KAAK,EAAE,CAAC,CAAC;QAC5E,CAAC;IACL,CAAC;IAEO,aAAa;QACjB,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC;YAC7B,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC;YAC/C,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC;SAC9D,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,OAAO,OAAO,CAAC;IACnB,CAAC;IAED,uHAAuH;IAC/G,IAAI;QACR,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,OAAO,OAAO,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChG,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,gBAAgB,EAAE,CAAC;gBACpE,OAAO;YACX,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,EAA6B,CAAC,CAAC;QAC1E,CAAC;QACD,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC5B,CAAC;IAED,6GAA6G;IACrG,gBAAgB;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YACtF,OAAO;QACX,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;YACvB,oEAAoE;QACxE,CAAC,CAAC,CAAC;IACP,CAAC;IAEO,MAAM,CAAC,OAAqB,EAAE,KAA8B;QAChE,IAAI,CAAC;YACD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;YAC9D,OAAO,CAAC,MAAM,CAAC,IAAI,iBAAiB,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACnH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QACjD,CAAC;IACL,CAAC;IAED,gHAAgH;IACxG,OAAO,CAAC,OAAqB,EAAE,KAAiB;QACpD,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YAC5C,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,OAAO;QACX,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;QACnD,IAAI,CAAC,IAAI,EAAE,CAAC;IAChB,CAAC;IAED,yHAAyH;IACjH,YAAY,CAAC,OAAqB,EAAE,OAAe;QACvD,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YAC5C,OAAO;QACX,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,+CAA+C,OAAO,EAAE,CAAC,CAAC;QAC/F,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtB,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,sBAAsB,EAAE,CAAC;YAC7E,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,iBAAiB,EAAE,CAAC;YAC1C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,yBAAyB,sBAAsB,GAAG,IAAI,iBAAiB,OAAO,EAAE,CAAC,CAAC;QAC/H,CAAC;IACL,CAAC;IAEO,YAAY;QAChB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,OAAO,IAAI,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,OAAO,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;IACL,CAAC;CACJ;AAED,+CAA+C;AAC/C,SAAS,SAAS,CAAC,KAAc;IAC7B,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED,8FAA8F;AAC9F,MAAM,CAAC,MAAM,uBAAuB,GAAkC;IAClE,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,QAAQ,CAAC;IAC9D,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,qBAAqB,CAAC,OAAO,CAAC;CAC1D,CAAC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview DISPLAY CAPTURE: asks the browser to share a screen, a window, a tab or one panel of this
|
|
3
|
+
* page, and reports what the user actually shared.
|
|
4
|
+
*
|
|
5
|
+
* Sharing works wherever `getDisplayMedia` exists: desktop Chrome, Edge, Firefox and Safari (no mobile browser
|
|
6
|
+
* has it). The picker hints sent with it (`displaySurface`, `selfBrowserSurface`, `surfaceSwitching`,
|
|
7
|
+
* `preferCurrentTab`, `monitorTypeSurfaces`, `systemAudio`) are read only by Chromium browsers; others ignore
|
|
8
|
+
* them.
|
|
9
|
+
*
|
|
10
|
+
* A PANEL capture shares one element of this page. The user picks this tab in the picker, and the stream is
|
|
11
|
+
* then narrowed to the element with Element Capture (`restrictTo`, Chromium 132+: the element alone, without
|
|
12
|
+
* anything drawn over it) or, failing that, Region Capture (`cropTo`, Chromium 104+: the element's rectangle,
|
|
13
|
+
* including anything over it). Element Capture emits frames only while the element is its own stacking
|
|
14
|
+
* context, so the element gets `isolation: isolate` for the share and its own value back when the share ends.
|
|
15
|
+
* Firefox and Safari have neither; {@link GetDisplayCaptureSupport} says so, and the caller shows the panel to
|
|
16
|
+
* the agent another way (its channel frames). If the user shares something other than this tab, the capture is
|
|
17
|
+
* stopped rather than sharing more than the panel.
|
|
18
|
+
*
|
|
19
|
+
* The browser's picker is the user's consent: it opens on every request, with no remembered grant. Like the
|
|
20
|
+
* picker itself, {@link RequestDisplayCapture} must be called from a user gesture (a click handler).
|
|
21
|
+
*
|
|
22
|
+
* Capture runs at the surface's native frame rate; pace what the model receives with a `FrameSampler`.
|
|
23
|
+
*
|
|
24
|
+
* @module @memberjunction/ai-realtime-client/media
|
|
25
|
+
*/
|
|
26
|
+
/** What the user is asked to share. */
|
|
27
|
+
export type DisplayCaptureSurface = 'screen' | 'window' | 'tab';
|
|
28
|
+
/** What a capture turned out to be; `'unknown'` when the browser doesn't say. */
|
|
29
|
+
export type CapturedDisplaySurface = DisplayCaptureSurface | 'unknown';
|
|
30
|
+
/** How a panel capture was narrowed to its element. */
|
|
31
|
+
export type PanelCaptureMethod = 'element' | 'region';
|
|
32
|
+
/** What this browser can capture. */
|
|
33
|
+
export interface DisplayCaptureSupport {
|
|
34
|
+
/** A screen, window or tab can be shared (`getDisplayMedia`). */
|
|
35
|
+
Display: boolean;
|
|
36
|
+
/** Element Capture (`RestrictionTarget`, Chromium 132+). */
|
|
37
|
+
ElementCapture: boolean;
|
|
38
|
+
/** Region Capture (`CropTarget`, Chromium 104+). */
|
|
39
|
+
RegionCapture: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface DisplayCaptureOptions {
|
|
42
|
+
/**
|
|
43
|
+
* The kind of surface the picker offers first. A hint: the user can still pick another kind, and only
|
|
44
|
+
* Chromium browsers read it. Ignored for a panel capture, which asks for this tab.
|
|
45
|
+
*/
|
|
46
|
+
PreferredSurface?: DisplayCaptureSurface;
|
|
47
|
+
/**
|
|
48
|
+
* Share only this element of the page. Needs Element or Region Capture (see
|
|
49
|
+
* {@link GetDisplayCaptureSupport}); Element Capture is used where the browser has it. Element Capture emits
|
|
50
|
+
* frames only while the element is its own stacking context, so unless it already is one, the element's
|
|
51
|
+
* inline style gets `isolation: isolate` while it is shared and its own inline value back when the share
|
|
52
|
+
* ends. Meanwhile its descendants stack inside it: one with a high `z-index` no longer paints over content
|
|
53
|
+
* outside the panel.
|
|
54
|
+
*/
|
|
55
|
+
Panel?: Element;
|
|
56
|
+
/**
|
|
57
|
+
* The panel's name, such as "Whiteboard", carried on the capture ({@link DisplayCapture.PanelLabel}) so the
|
|
58
|
+
* UI and the agent can name what is shared. Read only with {@link Panel}.
|
|
59
|
+
*/
|
|
60
|
+
PanelLabel?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Also capture the shared surface's audio, where the browser offers it (Chromium: tab or system audio).
|
|
63
|
+
* Defaults to `false`: the agent already hears the microphone.
|
|
64
|
+
*/
|
|
65
|
+
IncludeAudio?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/** A live share. */
|
|
68
|
+
export interface DisplayCapture {
|
|
69
|
+
readonly Stream: MediaStream;
|
|
70
|
+
/** The shared video track. */
|
|
71
|
+
readonly Track: MediaStreamTrack;
|
|
72
|
+
/** What is being shared now. It can change if the user switches surfaces mid-share. */
|
|
73
|
+
readonly Surface: CapturedDisplaySurface;
|
|
74
|
+
/** The browser's label for the shared surface, such as a window or tab title. */
|
|
75
|
+
readonly Label: string;
|
|
76
|
+
/** How the stream was narrowed, for a panel capture. */
|
|
77
|
+
readonly PanelMethod?: PanelCaptureMethod;
|
|
78
|
+
/** The shared panel's name, for a panel capture that was given one ({@link DisplayCaptureOptions.PanelLabel}). */
|
|
79
|
+
readonly PanelLabel?: string;
|
|
80
|
+
/**
|
|
81
|
+
* Calls `handler` once when the share ends: the user pressed the browser's "Stop sharing", the shared
|
|
82
|
+
* surface closed, or {@link DisplayCapture.Stop} was called. If the share has already ended, `handler` is
|
|
83
|
+
* called at once.
|
|
84
|
+
*
|
|
85
|
+
* @returns A function that removes the handler.
|
|
86
|
+
*/
|
|
87
|
+
OnEnded(handler: () => void): () => void;
|
|
88
|
+
/** Stops sharing. Calling it again does nothing. */
|
|
89
|
+
Stop(): void;
|
|
90
|
+
}
|
|
91
|
+
/** Why a capture failed. */
|
|
92
|
+
export type DisplayCaptureFailure =
|
|
93
|
+
/** The browser cannot share a screen at all (mobile browsers, or no DOM). */
|
|
94
|
+
'unsupported'
|
|
95
|
+
/** A panel was asked for, but the browser has neither Element nor Region Capture (Firefox, Safari). */
|
|
96
|
+
| 'panel-unsupported'
|
|
97
|
+
/** A panel was asked for, but the user shared a screen, a window or another tab. The capture was stopped. */
|
|
98
|
+
| 'panel-wrong-surface'
|
|
99
|
+
/** The operating system or the page's permissions policy blocked sharing. */
|
|
100
|
+
| 'denied'
|
|
101
|
+
/** Anything else; see the message. */
|
|
102
|
+
| 'error';
|
|
103
|
+
/** The outcome of {@link RequestDisplayCapture}. It always resolves; it never rejects. */
|
|
104
|
+
export type DisplayCaptureResult = {
|
|
105
|
+
Status: 'started';
|
|
106
|
+
Capture: DisplayCapture;
|
|
107
|
+
} | {
|
|
108
|
+
Status: 'cancelled';
|
|
109
|
+
} | {
|
|
110
|
+
Status: 'failed';
|
|
111
|
+
Reason: DisplayCaptureFailure;
|
|
112
|
+
Message: string;
|
|
113
|
+
};
|
|
114
|
+
/** What this browser can capture. */
|
|
115
|
+
export declare function GetDisplayCaptureSupport(): DisplayCaptureSupport;
|
|
116
|
+
/**
|
|
117
|
+
* Opens the browser's share picker and starts sharing what the user picks. Call it from a user gesture.
|
|
118
|
+
*
|
|
119
|
+
* @param options What to offer, whether to share only a panel, and whether to include audio.
|
|
120
|
+
* @returns `started` with the live capture, `cancelled` when the user closed the picker, or `failed` with a reason.
|
|
121
|
+
*/
|
|
122
|
+
export declare function RequestDisplayCapture(options?: DisplayCaptureOptions): Promise<DisplayCaptureResult>;
|
|
123
|
+
/**
|
|
124
|
+
* The kind of surface a captured track shows, from the browser's `displaySurface` setting. It reads any display
|
|
125
|
+
* track, including one captured elsewhere, such as a LiveKit screen share.
|
|
126
|
+
*/
|
|
127
|
+
export declare function CapturedSurfaceOf(track: MediaStreamTrack): CapturedDisplaySurface;
|
|
128
|
+
//# sourceMappingURL=displayCapture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"displayCapture.d.ts","sourceRoot":"","sources":["../../src/media/displayCapture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,uCAAuC;AACvC,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEhE,iFAAiF;AACjF,MAAM,MAAM,sBAAsB,GAAG,qBAAqB,GAAG,SAAS,CAAC;AAEvE,uDAAuD;AACvD,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEtD,qCAAqC;AACrC,MAAM,WAAW,qBAAqB;IAClC,iEAAiE;IACjE,OAAO,EAAE,OAAO,CAAC;IACjB,4DAA4D;IAC5D,cAAc,EAAE,OAAO,CAAC;IACxB,oDAAoD;IACpD,aAAa,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IAClC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,qBAAqB,CAAC;IACzC;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,oBAAoB;AACpB,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,8BAA8B;IAC9B,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,uFAAuF;IACvF,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,QAAQ,CAAC,WAAW,CAAC,EAAE,kBAAkB,CAAC;IAC1C,kHAAkH;IAClH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;;OAMG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IACzC,oDAAoD;IACpD,IAAI,IAAI,IAAI,CAAC;CAChB;AAED,4BAA4B;AAC5B,MAAM,MAAM,qBAAqB;AAC7B,6EAA6E;AAC3E,aAAa;AACf,uGAAuG;GACrG,mBAAmB;AACrB,6GAA6G;GAC3G,qBAAqB;AACvB,6EAA6E;GAC3E,QAAQ;AACV,sCAAsC;GACpC,OAAO,CAAC;AAEd,0FAA0F;AAC1F,MAAM,MAAM,oBAAoB,GAC1B;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC9C;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AA0C3E,qCAAqC;AACrC,wBAAgB,wBAAwB,IAAI,qBAAqB,CAOhE;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA6B9G;AAoHD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,sBAAsB,CAWjF"}
|