@memberjunction/ai-realtime-client 6.2.0-edge.3 → 6.2.0-edge.5
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 +99 -0
- package/dist/drivers/geminiEnterpriseRealtimeClient.js.map +1 -0
- package/dist/drivers/geminiRealtimeClient.d.ts +325 -50
- package/dist/drivers/geminiRealtimeClient.d.ts.map +1 -1
- package/dist/drivers/geminiRealtimeClient.js +782 -184
- 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/drivers/xaiRealtimeClient.d.ts.map +1 -1
- package/dist/drivers/xaiRealtimeClient.js +19 -14
- package/dist/drivers/xaiRealtimeClient.js.map +1 -1
- package/dist/generic/baseRealtimeClient.d.ts +183 -29
- package/dist/generic/baseRealtimeClient.d.ts.map +1 -1
- package/dist/generic/baseRealtimeClient.js +246 -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 +17 -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,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview FRAME SCHEDULER: shows decoded pictures on a {@link StreamCanvas} when their presentation time comes,
|
|
3
|
+
* for the decoders that aren't MSE (WebCodecs chunks, images). MSE paces itself on the element's clock.
|
|
4
|
+
*
|
|
5
|
+
* - **On the voice's clock, when the player has one** ({@link FrameSchedulerOptions.Clock}): the meeting bot's rules, on
|
|
6
|
+
* media time. A picture shows when the clock reaches its time; one more than {@link MAX_CLOCK_LATE_MS} behind the clock
|
|
7
|
+
* is dropped, never shown; one ahead of it waits, and one more than {@link MAX_LEAD_MS} ahead is dropped (it belongs to
|
|
8
|
+
* a stream the voice has left). A picture timed before the last one shown starts a new stream: it waits while the clock
|
|
9
|
+
* still plays the old stream, instead of counting as late.
|
|
10
|
+
* - **When the clock reads nothing.** After a reading, pictures carry on by their own times from the clock's last reading,
|
|
11
|
+
* as if the voice went on (the tail of a turn whose video outlasts its voice, or idle video between turns); a new stream
|
|
12
|
+
* then waits for its voice. Before any reading (at the start, or after a barge-in) pictures wait up to
|
|
13
|
+
* {@link CLOCK_WAIT_MS} for the voice to start, then go by their own times.
|
|
14
|
+
* - **By their own times, without a clock.** The first timed picture after a start, a flush or a new stream anchors media
|
|
15
|
+
* time to the wall clock; each later picture shows when its time comes. When several are due, the newest shows and the
|
|
16
|
+
* older ones are dropped. A picture shown more than {@link MAX_LATE_MS} late anchors the pacing again; so does a
|
|
17
|
+
* picture timed before the last one shown, or more than {@link MAX_LEAD_MS} ahead.
|
|
18
|
+
* - **Untimed pictures** (an image that carries no time) show as soon as they arrive.
|
|
19
|
+
* - **Bounded.** The decoders hold encoded frames back while {@link FrameScheduler.Size} pictures wait, and the scheduler
|
|
20
|
+
* calls back each time it shows one, so a decoder never holds many decoded pictures (a browser decoder stalls when its
|
|
21
|
+
* output frames aren't closed).
|
|
22
|
+
*
|
|
23
|
+
* @module @memberjunction/ai-realtime-client/media
|
|
24
|
+
*/
|
|
25
|
+
import type { IPlaybackClock } from '../playbackClock.js';
|
|
26
|
+
import type { StreamCanvas, StreamPicture } from './streamCanvas.js';
|
|
27
|
+
/** Without a clock, a picture shown this much later than its time anchors the pacing again, in milliseconds. */
|
|
28
|
+
export declare const MAX_LATE_MS = 250;
|
|
29
|
+
/** A picture due this much ahead starts a new stream (without a clock) or is dropped (on the clock), in milliseconds. */
|
|
30
|
+
export declare const MAX_LEAD_MS = 2000;
|
|
31
|
+
/** On the voice's clock, a picture this far behind it is dropped rather than shown, in milliseconds. */
|
|
32
|
+
export declare const MAX_CLOCK_LATE_MS = 500;
|
|
33
|
+
/** How long pictures wait for a clock that has read nothing yet before they go by their own times, in milliseconds. */
|
|
34
|
+
export declare const CLOCK_WAIT_MS = 500;
|
|
35
|
+
/** How often waiting pictures look at the clock again, at most, in milliseconds. */
|
|
36
|
+
export declare const CLOCK_POLL_MS = 20;
|
|
37
|
+
/** What a scheduler paces by, besides the pictures' own times. */
|
|
38
|
+
export interface FrameSchedulerOptions {
|
|
39
|
+
/** The voice's playback clock: pictures show when it reaches their times. */
|
|
40
|
+
Clock?: IPlaybackClock;
|
|
41
|
+
/** The wall clock in milliseconds; injectable for tests. */
|
|
42
|
+
Now?: () => number;
|
|
43
|
+
}
|
|
44
|
+
/** Shows pictures on a stream canvas at their presentation times: on the voice's clock when there is one. */
|
|
45
|
+
export declare class FrameScheduler {
|
|
46
|
+
private readonly canvas;
|
|
47
|
+
private readonly onShown;
|
|
48
|
+
private readonly queue;
|
|
49
|
+
private readonly clock;
|
|
50
|
+
private readonly now;
|
|
51
|
+
/** Own-time pacing: where the current stream's media time sits on the wall clock. */
|
|
52
|
+
private anchor;
|
|
53
|
+
/** The time of the last timed picture shown, to see a stream restart. */
|
|
54
|
+
private lastShownMs;
|
|
55
|
+
/** The clock's last reading and when it was taken, until the clock stops reading. */
|
|
56
|
+
private lastReading;
|
|
57
|
+
/** Whether own-time pacing carries on from the clock's last reading (the voice stopped). */
|
|
58
|
+
private continuing;
|
|
59
|
+
/** When the pictures began waiting for the voice's clock to read. */
|
|
60
|
+
private waitingSince;
|
|
61
|
+
private timer;
|
|
62
|
+
private disposed;
|
|
63
|
+
/**
|
|
64
|
+
* @param canvas Where pictures show.
|
|
65
|
+
* @param onShown Called after each picture shown, so the decoder can decode more.
|
|
66
|
+
* @param options The voice's clock, and a wall clock for tests.
|
|
67
|
+
*/
|
|
68
|
+
constructor(canvas: StreamCanvas, onShown: () => void, options?: FrameSchedulerOptions);
|
|
69
|
+
/** How many pictures wait to be shown. */
|
|
70
|
+
get Size(): number;
|
|
71
|
+
/**
|
|
72
|
+
* Queues a picture: it shows when its time comes, or at once when it has no time.
|
|
73
|
+
*
|
|
74
|
+
* @param picture The decoded picture; the scheduler closes it, shown or dropped.
|
|
75
|
+
* @param timeMs Its presentation time on the stream's timeline, when it has one.
|
|
76
|
+
*/
|
|
77
|
+
Push(picture: StreamPicture, timeMs?: number): void;
|
|
78
|
+
/** Drops every waiting picture and forgets both clocks: the pacing starts over. The last picture shown stays. */
|
|
79
|
+
Clear(): void;
|
|
80
|
+
/** Clears, and closes every picture pushed later. */
|
|
81
|
+
Dispose(): void;
|
|
82
|
+
/** Shows the picture that is due now, if any, by the voice's clock or by the pictures' own times; then waits for the next. */
|
|
83
|
+
private tick;
|
|
84
|
+
/**
|
|
85
|
+
* Whether the pictures wait for the voice's clock, which reads nothing now. A clock that read before stopped: pacing
|
|
86
|
+
* carries on from its last reading, but a picture that starts a new stream waits for its voice. Pictures wait up to
|
|
87
|
+
* {@link CLOCK_WAIT_MS}, then go by their own times. Never without a clock.
|
|
88
|
+
*/
|
|
89
|
+
private holdForClock;
|
|
90
|
+
/** Whether the next picture is timed before the last one shown: it starts a new stream. */
|
|
91
|
+
private headStartsNewStream;
|
|
92
|
+
/** Shows the newest picture the clock has reached, dropping the stale ones before it ({@link clockVerdict}). */
|
|
93
|
+
private showByClock;
|
|
94
|
+
/**
|
|
95
|
+
* What the clock says about a picture: it waits when it starts a new stream whose voice hasn't started, or is ahead of
|
|
96
|
+
* the clock; it is dropped when more than {@link MAX_CLOCK_LATE_MS} behind the clock or more than {@link MAX_LEAD_MS}
|
|
97
|
+
* ahead of it; otherwise it is due. An untimed picture is due at once.
|
|
98
|
+
*/
|
|
99
|
+
private clockVerdict;
|
|
100
|
+
/**
|
|
101
|
+
* Whether a picture starts a new stream whose voice hasn't started: it is timed before the last picture shown, and the
|
|
102
|
+
* clock still reads the old stream (at or after that picture).
|
|
103
|
+
*/
|
|
104
|
+
private awaitsNewStream;
|
|
105
|
+
/** Shows the newest picture whose own time has come (dropping older due ones). */
|
|
106
|
+
private showByOwnTime;
|
|
107
|
+
/** When a picture is due on the wall clock. A first picture, or one that starts a new stream, anchors the pacing to now. */
|
|
108
|
+
private dueAt;
|
|
109
|
+
/** A picture timed before the last one shown, or far ahead of the pacing, belongs to a new stream. */
|
|
110
|
+
private startsNewStream;
|
|
111
|
+
private show;
|
|
112
|
+
/** By own time: until the next picture is due. */
|
|
113
|
+
private ownTimeDelay;
|
|
114
|
+
/** On the clock: until the clock should reach the next picture, but never longer than {@link CLOCK_POLL_MS}. */
|
|
115
|
+
private clockDelay;
|
|
116
|
+
private schedule;
|
|
117
|
+
private cancelTimer;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=frameScheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frameScheduler.d.ts","sourceRoot":"","sources":["../../../src/media/decoders/frameScheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAElE,gHAAgH;AAChH,eAAO,MAAM,WAAW,MAAM,CAAC;AAE/B,yHAAyH;AACzH,eAAO,MAAM,WAAW,OAAO,CAAC;AAEhC,wGAAwG;AACxG,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC,uHAAuH;AACvH,eAAO,MAAM,aAAa,MAAM,CAAC;AAEjC,oFAAoF;AACpF,eAAO,MAAM,aAAa,KAAK,CAAC;AAchC,kEAAkE;AAClE,MAAM,WAAW,qBAAqB;IAClC,6EAA6E;IAC7E,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,4DAA4D;IAC5D,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB;AAED,6GAA6G;AAC7G,qBAAa,cAAc;IAuBnB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAvB5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;IACnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,qFAAqF;IACrF,OAAO,CAAC,MAAM,CAA4B;IAC1C,yEAAyE;IACzE,OAAO,CAAC,WAAW,CAAuB;IAC1C,qFAAqF;IACrF,OAAO,CAAC,WAAW,CAA4B;IAC/C,4FAA4F;IAC5F,OAAO,CAAC,UAAU,CAAS;IAC3B,qEAAqE;IACrE,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,KAAK,CAA8C;IAC3D,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;OAIG;gBAEkB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,MAAM,IAAI,EACpC,OAAO,GAAE,qBAA0B;IAMvC,0CAA0C;IAC1C,IAAW,IAAI,IAAI,MAAM,CAExB;IAED;;;;;OAKG;IACI,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAW1D,iHAAiH;IAC1G,KAAK,IAAI,IAAI;IAYpB,qDAAqD;IAC9C,OAAO,IAAI,IAAI;IAKtB,8HAA8H;IAC9H,OAAO,CAAC,IAAI;IAsBZ;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAqBpB,2FAA2F;IAC3F,OAAO,CAAC,mBAAmB;IAK3B,gHAAgH;IAChH,OAAO,CAAC,WAAW;IAqBnB;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAapB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAIvB,kFAAkF;IAClF,OAAO,CAAC,aAAa;IAqBrB,4HAA4H;IAC5H,OAAO,CAAC,KAAK;IAWb,sGAAsG;IACtG,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,IAAI;IAOZ,kDAAkD;IAClD,OAAO,CAAC,YAAY;IAIpB,gHAAgH;IAChH,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,WAAW;CAMtB"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/** Without a clock, a picture shown this much later than its time anchors the pacing again, in milliseconds. */
|
|
2
|
+
export const MAX_LATE_MS = 250;
|
|
3
|
+
/** A picture due this much ahead starts a new stream (without a clock) or is dropped (on the clock), in milliseconds. */
|
|
4
|
+
export const MAX_LEAD_MS = 2000;
|
|
5
|
+
/** On the voice's clock, a picture this far behind it is dropped rather than shown, in milliseconds. */
|
|
6
|
+
export const MAX_CLOCK_LATE_MS = 500;
|
|
7
|
+
/** How long pictures wait for a clock that has read nothing yet before they go by their own times, in milliseconds. */
|
|
8
|
+
export const CLOCK_WAIT_MS = 500;
|
|
9
|
+
/** How often waiting pictures look at the clock again, at most, in milliseconds. */
|
|
10
|
+
export const CLOCK_POLL_MS = 20;
|
|
11
|
+
/** Shows pictures on a stream canvas at their presentation times: on the voice's clock when there is one. */
|
|
12
|
+
export class FrameScheduler {
|
|
13
|
+
/**
|
|
14
|
+
* @param canvas Where pictures show.
|
|
15
|
+
* @param onShown Called after each picture shown, so the decoder can decode more.
|
|
16
|
+
* @param options The voice's clock, and a wall clock for tests.
|
|
17
|
+
*/
|
|
18
|
+
constructor(canvas, onShown, options = {}) {
|
|
19
|
+
this.canvas = canvas;
|
|
20
|
+
this.onShown = onShown;
|
|
21
|
+
this.queue = [];
|
|
22
|
+
/** Own-time pacing: where the current stream's media time sits on the wall clock. */
|
|
23
|
+
this.anchor = null;
|
|
24
|
+
/** The time of the last timed picture shown, to see a stream restart. */
|
|
25
|
+
this.lastShownMs = null;
|
|
26
|
+
/** The clock's last reading and when it was taken, until the clock stops reading. */
|
|
27
|
+
this.lastReading = null;
|
|
28
|
+
/** Whether own-time pacing carries on from the clock's last reading (the voice stopped). */
|
|
29
|
+
this.continuing = false;
|
|
30
|
+
/** When the pictures began waiting for the voice's clock to read. */
|
|
31
|
+
this.waitingSince = null;
|
|
32
|
+
this.timer = null;
|
|
33
|
+
this.disposed = false;
|
|
34
|
+
this.clock = options.Clock;
|
|
35
|
+
this.now = options.Now ?? (() => performance.now());
|
|
36
|
+
}
|
|
37
|
+
/** How many pictures wait to be shown. */
|
|
38
|
+
get Size() {
|
|
39
|
+
return this.queue.length;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Queues a picture: it shows when its time comes, or at once when it has no time.
|
|
43
|
+
*
|
|
44
|
+
* @param picture The decoded picture; the scheduler closes it, shown or dropped.
|
|
45
|
+
* @param timeMs Its presentation time on the stream's timeline, when it has one.
|
|
46
|
+
*/
|
|
47
|
+
Push(picture, timeMs) {
|
|
48
|
+
if (this.disposed) {
|
|
49
|
+
picture.close();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.queue.push({ Picture: picture, TimeMs: timeMs });
|
|
53
|
+
if (this.timer === null) {
|
|
54
|
+
this.tick();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Drops every waiting picture and forgets both clocks: the pacing starts over. The last picture shown stays. */
|
|
58
|
+
Clear() {
|
|
59
|
+
this.cancelTimer();
|
|
60
|
+
for (const scheduled of this.queue.splice(0)) {
|
|
61
|
+
scheduled.Picture.close();
|
|
62
|
+
}
|
|
63
|
+
this.anchor = null;
|
|
64
|
+
this.lastShownMs = null;
|
|
65
|
+
this.lastReading = null;
|
|
66
|
+
this.continuing = false;
|
|
67
|
+
this.waitingSince = null;
|
|
68
|
+
}
|
|
69
|
+
/** Clears, and closes every picture pushed later. */
|
|
70
|
+
Dispose() {
|
|
71
|
+
this.disposed = true;
|
|
72
|
+
this.Clear();
|
|
73
|
+
}
|
|
74
|
+
/** Shows the picture that is due now, if any, by the voice's clock or by the pictures' own times; then waits for the next. */
|
|
75
|
+
tick() {
|
|
76
|
+
this.timer = null;
|
|
77
|
+
const now = this.now();
|
|
78
|
+
const clockMs = this.clock?.CurrentTimeMs ?? null;
|
|
79
|
+
let shown = false;
|
|
80
|
+
if (clockMs !== null) {
|
|
81
|
+
this.lastReading = { WallMs: now, MediaMs: clockMs };
|
|
82
|
+
shown = this.showByClock(clockMs);
|
|
83
|
+
}
|
|
84
|
+
else if (this.holdForClock(now)) {
|
|
85
|
+
this.schedule(CLOCK_POLL_MS);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
shown = this.showByOwnTime(now);
|
|
90
|
+
}
|
|
91
|
+
if (this.queue.length > 0) {
|
|
92
|
+
this.schedule(clockMs === null ? this.ownTimeDelay(now) : this.clockDelay(clockMs));
|
|
93
|
+
}
|
|
94
|
+
if (shown) {
|
|
95
|
+
this.onShown();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Whether the pictures wait for the voice's clock, which reads nothing now. A clock that read before stopped: pacing
|
|
100
|
+
* carries on from its last reading, but a picture that starts a new stream waits for its voice. Pictures wait up to
|
|
101
|
+
* {@link CLOCK_WAIT_MS}, then go by their own times. Never without a clock.
|
|
102
|
+
*/
|
|
103
|
+
holdForClock(now) {
|
|
104
|
+
if (!this.clock) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
if (this.lastReading) {
|
|
108
|
+
this.anchor = this.lastReading;
|
|
109
|
+
this.lastReading = null;
|
|
110
|
+
this.continuing = true;
|
|
111
|
+
}
|
|
112
|
+
if (this.continuing && this.headStartsNewStream()) {
|
|
113
|
+
this.anchor = null;
|
|
114
|
+
this.continuing = false;
|
|
115
|
+
this.waitingSince = now;
|
|
116
|
+
}
|
|
117
|
+
if (this.anchor) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
this.waitingSince ??= now;
|
|
121
|
+
return now - this.waitingSince < CLOCK_WAIT_MS;
|
|
122
|
+
}
|
|
123
|
+
/** Whether the next picture is timed before the last one shown: it starts a new stream. */
|
|
124
|
+
headStartsNewStream() {
|
|
125
|
+
const time = this.queue[0]?.TimeMs;
|
|
126
|
+
return time !== undefined && this.lastShownMs !== null && time < this.lastShownMs;
|
|
127
|
+
}
|
|
128
|
+
/** Shows the newest picture the clock has reached, dropping the stale ones before it ({@link clockVerdict}). */
|
|
129
|
+
showByClock(clockMs) {
|
|
130
|
+
let due = null;
|
|
131
|
+
while (this.queue.length > 0) {
|
|
132
|
+
const verdict = this.clockVerdict(this.queue[0].TimeMs, clockMs);
|
|
133
|
+
if (verdict === 'wait') {
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
const head = this.queue.shift();
|
|
137
|
+
if (verdict === 'drop') {
|
|
138
|
+
head.Picture.close();
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
due?.Picture.close();
|
|
142
|
+
due = head;
|
|
143
|
+
}
|
|
144
|
+
if (due) {
|
|
145
|
+
this.show(due);
|
|
146
|
+
}
|
|
147
|
+
return due !== null;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* What the clock says about a picture: it waits when it starts a new stream whose voice hasn't started, or is ahead of
|
|
151
|
+
* the clock; it is dropped when more than {@link MAX_CLOCK_LATE_MS} behind the clock or more than {@link MAX_LEAD_MS}
|
|
152
|
+
* ahead of it; otherwise it is due. An untimed picture is due at once.
|
|
153
|
+
*/
|
|
154
|
+
clockVerdict(timeMs, clockMs) {
|
|
155
|
+
if (timeMs === undefined) {
|
|
156
|
+
return 'show';
|
|
157
|
+
}
|
|
158
|
+
if (this.awaitsNewStream(timeMs, clockMs)) {
|
|
159
|
+
return 'wait';
|
|
160
|
+
}
|
|
161
|
+
if (clockMs - timeMs > MAX_CLOCK_LATE_MS || timeMs - clockMs > MAX_LEAD_MS) {
|
|
162
|
+
return 'drop';
|
|
163
|
+
}
|
|
164
|
+
return timeMs > clockMs ? 'wait' : 'show';
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Whether a picture starts a new stream whose voice hasn't started: it is timed before the last picture shown, and the
|
|
168
|
+
* clock still reads the old stream (at or after that picture).
|
|
169
|
+
*/
|
|
170
|
+
awaitsNewStream(timeMs, clockMs) {
|
|
171
|
+
return this.lastShownMs !== null && timeMs < this.lastShownMs && clockMs >= this.lastShownMs;
|
|
172
|
+
}
|
|
173
|
+
/** Shows the newest picture whose own time has come (dropping older due ones). */
|
|
174
|
+
showByOwnTime(now) {
|
|
175
|
+
let due = null;
|
|
176
|
+
while (this.queue.length > 0) {
|
|
177
|
+
const dueMs = this.dueAt(this.queue[0], now);
|
|
178
|
+
if (dueMs > now) {
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
due?.Scheduled.Picture.close();
|
|
182
|
+
due = { Scheduled: this.queue.shift(), DueMs: dueMs };
|
|
183
|
+
}
|
|
184
|
+
if (!due) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
this.show(due.Scheduled);
|
|
188
|
+
const time = due.Scheduled.TimeMs;
|
|
189
|
+
if (time !== undefined && now - due.DueMs > MAX_LATE_MS) {
|
|
190
|
+
this.anchor = { WallMs: now, MediaMs: time };
|
|
191
|
+
}
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
/** When a picture is due on the wall clock. A first picture, or one that starts a new stream, anchors the pacing to now. */
|
|
195
|
+
dueAt(scheduled, now) {
|
|
196
|
+
const time = scheduled.TimeMs;
|
|
197
|
+
if (time === undefined) {
|
|
198
|
+
return now;
|
|
199
|
+
}
|
|
200
|
+
if (!this.anchor || this.startsNewStream(time, now)) {
|
|
201
|
+
this.anchor = { WallMs: now, MediaMs: time };
|
|
202
|
+
}
|
|
203
|
+
return this.anchor.WallMs + (time - this.anchor.MediaMs);
|
|
204
|
+
}
|
|
205
|
+
/** A picture timed before the last one shown, or far ahead of the pacing, belongs to a new stream. */
|
|
206
|
+
startsNewStream(timeMs, now) {
|
|
207
|
+
const anchor = this.anchor;
|
|
208
|
+
const backwards = this.lastShownMs !== null && timeMs < this.lastShownMs;
|
|
209
|
+
return backwards || anchor.WallMs + (timeMs - anchor.MediaMs) - now > MAX_LEAD_MS;
|
|
210
|
+
}
|
|
211
|
+
show(scheduled) {
|
|
212
|
+
this.canvas.Show(scheduled.Picture);
|
|
213
|
+
if (scheduled.TimeMs !== undefined) {
|
|
214
|
+
this.lastShownMs = scheduled.TimeMs;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/** By own time: until the next picture is due. */
|
|
218
|
+
ownTimeDelay(now) {
|
|
219
|
+
return Math.max(0, this.dueAt(this.queue[0], now) - now);
|
|
220
|
+
}
|
|
221
|
+
/** On the clock: until the clock should reach the next picture, but never longer than {@link CLOCK_POLL_MS}. */
|
|
222
|
+
clockDelay(clockMs) {
|
|
223
|
+
const time = this.queue[0].TimeMs;
|
|
224
|
+
return time !== undefined && time > clockMs ? Math.min(CLOCK_POLL_MS, time - clockMs) : CLOCK_POLL_MS;
|
|
225
|
+
}
|
|
226
|
+
schedule(delayMs) {
|
|
227
|
+
if (this.timer === null && !this.disposed) {
|
|
228
|
+
this.timer = setTimeout(() => this.tick(), delayMs);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
cancelTimer() {
|
|
232
|
+
if (this.timer !== null) {
|
|
233
|
+
clearTimeout(this.timer);
|
|
234
|
+
this.timer = null;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=frameScheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frameScheduler.js","sourceRoot":"","sources":["../../../src/media/decoders/frameScheduler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview IMAGE FRAME DECODER: plays still images (`Kind: 'image'`: JPEG, PNG, WebP) through `createImageBitmap`,
|
|
3
|
+
* into the host's `<video>` element through a {@link StreamCanvas}. The `'image'` decoder of `VideoPlayout`.
|
|
4
|
+
*
|
|
5
|
+
* - **In order.** Images are decoded one at a time, in the order they arrived, while fewer than {@link MAX_IMAGES_AHEAD}
|
|
6
|
+
* decoded images wait to show; the rest wait encoded.
|
|
7
|
+
* - **Paced by presentation time when an image has one**, on the {@link FrameScheduler}: on the voice's clock when the
|
|
8
|
+
* player has one (`VideoPlayoutOptions.Clock`), else by its own time. An image without a time shows as soon as it is
|
|
9
|
+
* decoded.
|
|
10
|
+
* - **End of turn** needs nothing: every image stands alone. **Barge-in** drops the images waiting, decoded or not, and a
|
|
11
|
+
* decode under way; the last image shown stays.
|
|
12
|
+
* - An image the browser can't decode is dropped and reported (`'append-failed'`); the next one plays.
|
|
13
|
+
*
|
|
14
|
+
* @module @memberjunction/ai-realtime-client/media
|
|
15
|
+
*/
|
|
16
|
+
import type { RealtimeVideoFrame } from '@memberjunction/ai';
|
|
17
|
+
import type { IVideoFrameDecoder, VideoFrameDecoderContext, VideoFrameDecoderRegistration } from '../videoFrameDecoder.js';
|
|
18
|
+
/** Decoded images waiting to show, at most; further images wait encoded. */
|
|
19
|
+
export declare const MAX_IMAGES_AHEAD = 4;
|
|
20
|
+
/** Encoded images waiting to be decoded, at most; beyond this the oldest are dropped. */
|
|
21
|
+
export declare const MAX_WAITING_IMAGES = 120;
|
|
22
|
+
/** Plays still images through `createImageBitmap`. */
|
|
23
|
+
export declare class ImageFrameDecoder implements IVideoFrameDecoder {
|
|
24
|
+
private readonly context;
|
|
25
|
+
private readonly canvas;
|
|
26
|
+
private readonly scheduler;
|
|
27
|
+
/** Images waiting to be decoded, in arrival order. */
|
|
28
|
+
private readonly waiting;
|
|
29
|
+
/** Whether a decode is under way: images decode one at a time, so they show in order. */
|
|
30
|
+
private decoding;
|
|
31
|
+
/** Bumped by Flush and Dispose: a decode that finishes after it is dropped. */
|
|
32
|
+
private generation;
|
|
33
|
+
private disposed;
|
|
34
|
+
/** Whether this browser can decode images of `mimeType` and show them. */
|
|
35
|
+
static CanPlay(mimeType: string): boolean;
|
|
36
|
+
/** @param context The player this decoder plays for. */
|
|
37
|
+
constructor(context: VideoFrameDecoderContext);
|
|
38
|
+
/** Always `false`: an image carries no voice. */
|
|
39
|
+
get IsPlaying(): boolean;
|
|
40
|
+
/** Images still to show: waiting to be decoded, decoding, or decoded and waiting for their time. */
|
|
41
|
+
get FramesAhead(): number;
|
|
42
|
+
Attach(element: HTMLVideoElement): void;
|
|
43
|
+
Detach(): void;
|
|
44
|
+
/** Takes one image: it is decoded in its turn and shown at its time, or at once when it has none. */
|
|
45
|
+
Append(frame: RealtimeVideoFrame): void;
|
|
46
|
+
/** Nothing to drain: every image stands alone, and those waiting still show. */
|
|
47
|
+
EndOfTurn(): void;
|
|
48
|
+
/** Barge-in: drops the images waiting, decoded or not, and the decode under way. The last image shown stays. */
|
|
49
|
+
Flush(): void;
|
|
50
|
+
Dispose(): void;
|
|
51
|
+
/** Decodes the next waiting image, when none is decoding and fewer than {@link MAX_IMAGES_AHEAD} wait to show. */
|
|
52
|
+
private feed;
|
|
53
|
+
private decoded;
|
|
54
|
+
private decodeFailed;
|
|
55
|
+
}
|
|
56
|
+
/** The `'image'` decoder: JPEG, PNG and WebP images, where this browser has `createImageBitmap`. */
|
|
57
|
+
export declare const IMAGE_FRAME_DECODER: VideoFrameDecoderRegistration;
|
|
58
|
+
//# sourceMappingURL=imageFrameDecoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imageFrameDecoder.d.ts","sourceRoot":"","sources":["../../../src/media/decoders/imageFrameDecoder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAA2B,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,KAAK,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAKxH,4EAA4E;AAC5E,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,yFAAyF;AACzF,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,sDAAsD;AACtD,qBAAa,iBAAkB,YAAW,kBAAkB;IAkB5C,OAAO,CAAC,QAAQ,CAAC,OAAO;IAjBpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,sDAAsD;IACtD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,yFAAyF;IACzF,OAAO,CAAC,QAAQ,CAAS;IACzB,+EAA+E;IAC/E,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,QAAQ,CAAS;IAEzB,0EAA0E;WAC5D,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAKhD,wDAAwD;gBAC3B,OAAO,EAAE,wBAAwB;IAI9D,iDAAiD;IACjD,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,oGAAoG;IACpG,IAAW,WAAW,IAAI,MAAM,CAE/B;IAEM,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAMvC,MAAM,IAAI,IAAI;IAIrB,qGAAqG;IAC9F,MAAM,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAY9C,gFAAgF;IACzE,SAAS,IAAI,IAAI;IAIxB,gHAAgH;IACzG,KAAK,IAAI,IAAI;IAOb,OAAO,IAAI,IAAI;IAOtB,kHAAkH;IAClH,OAAO,CAAC,IAAI;IAaZ,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,YAAY;CASvB;AAED,oGAAoG;AACpG,eAAO,MAAM,mBAAmB,EAAE,6BAMjC,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { FrameScheduler } from './frameScheduler.js';
|
|
2
|
+
import { StreamCanvas } from './streamCanvas.js';
|
|
3
|
+
import { IMAGE_FRAME_TYPES, MimeEssence } from './videoMimeTypes.js';
|
|
4
|
+
/** Decoded images waiting to show, at most; further images wait encoded. */
|
|
5
|
+
export const MAX_IMAGES_AHEAD = 4;
|
|
6
|
+
/** Encoded images waiting to be decoded, at most; beyond this the oldest are dropped. */
|
|
7
|
+
export const MAX_WAITING_IMAGES = 120;
|
|
8
|
+
/** Plays still images through `createImageBitmap`. */
|
|
9
|
+
export class ImageFrameDecoder {
|
|
10
|
+
/** Whether this browser can decode images of `mimeType` and show them. */
|
|
11
|
+
static CanPlay(mimeType) {
|
|
12
|
+
const canDecode = typeof createImageBitmap === 'function' && typeof Blob === 'function';
|
|
13
|
+
return canDecode && StreamCanvas.IsAvailable() && IMAGE_FRAME_TYPES.has(MimeEssence(mimeType));
|
|
14
|
+
}
|
|
15
|
+
/** @param context The player this decoder plays for. */
|
|
16
|
+
constructor(context) {
|
|
17
|
+
this.context = context;
|
|
18
|
+
this.canvas = new StreamCanvas();
|
|
19
|
+
/** Images waiting to be decoded, in arrival order. */
|
|
20
|
+
this.waiting = [];
|
|
21
|
+
/** Whether a decode is under way: images decode one at a time, so they show in order. */
|
|
22
|
+
this.decoding = false;
|
|
23
|
+
/** Bumped by Flush and Dispose: a decode that finishes after it is dropped. */
|
|
24
|
+
this.generation = 0;
|
|
25
|
+
this.disposed = false;
|
|
26
|
+
this.scheduler = new FrameScheduler(this.canvas, () => this.feed(), { Clock: context.Clock });
|
|
27
|
+
}
|
|
28
|
+
/** Always `false`: an image carries no voice. */
|
|
29
|
+
get IsPlaying() {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
/** Images still to show: waiting to be decoded, decoding, or decoded and waiting for their time. */
|
|
33
|
+
get FramesAhead() {
|
|
34
|
+
return this.waiting.length + (this.decoding ? 1 : 0) + this.scheduler.Size;
|
|
35
|
+
}
|
|
36
|
+
Attach(element) {
|
|
37
|
+
if (!this.disposed) {
|
|
38
|
+
this.canvas.Attach(element);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
Detach() {
|
|
42
|
+
this.canvas.Detach();
|
|
43
|
+
}
|
|
44
|
+
/** Takes one image: it is decoded in its turn and shown at its time, or at once when it has none. */
|
|
45
|
+
Append(frame) {
|
|
46
|
+
if (this.disposed || frame.Kind !== 'image') {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this.waiting.push(frame);
|
|
50
|
+
if (this.waiting.length > MAX_WAITING_IMAGES) {
|
|
51
|
+
this.waiting.splice(0, this.waiting.length - MAX_WAITING_IMAGES);
|
|
52
|
+
this.context.Report('pending-overflow', 'Images arrived faster than they could be decoded; the oldest were dropped.');
|
|
53
|
+
}
|
|
54
|
+
this.feed();
|
|
55
|
+
}
|
|
56
|
+
/** Nothing to drain: every image stands alone, and those waiting still show. */
|
|
57
|
+
EndOfTurn() {
|
|
58
|
+
// Images need no flush.
|
|
59
|
+
}
|
|
60
|
+
/** Barge-in: drops the images waiting, decoded or not, and the decode under way. The last image shown stays. */
|
|
61
|
+
Flush() {
|
|
62
|
+
this.generation++;
|
|
63
|
+
this.decoding = false;
|
|
64
|
+
this.waiting.length = 0;
|
|
65
|
+
this.scheduler.Clear();
|
|
66
|
+
}
|
|
67
|
+
Dispose() {
|
|
68
|
+
this.Flush();
|
|
69
|
+
this.disposed = true;
|
|
70
|
+
this.scheduler.Dispose();
|
|
71
|
+
this.canvas.Dispose();
|
|
72
|
+
}
|
|
73
|
+
/** Decodes the next waiting image, when none is decoding and fewer than {@link MAX_IMAGES_AHEAD} wait to show. */
|
|
74
|
+
feed() {
|
|
75
|
+
if (this.disposed || this.decoding || this.waiting.length === 0 || this.scheduler.Size >= MAX_IMAGES_AHEAD) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const frame = this.waiting.shift();
|
|
79
|
+
const generation = this.generation;
|
|
80
|
+
this.decoding = true;
|
|
81
|
+
createImageBitmap(new Blob([frame.Data], { type: frame.MimeType })).then((image) => this.decoded(generation, image, frame.PresentationTimeMs), (error) => this.decodeFailed(generation, frame, error));
|
|
82
|
+
}
|
|
83
|
+
decoded(generation, image, timeMs) {
|
|
84
|
+
if (generation !== this.generation) {
|
|
85
|
+
image.close();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.decoding = false;
|
|
89
|
+
this.scheduler.Push(image, timeMs);
|
|
90
|
+
this.feed();
|
|
91
|
+
}
|
|
92
|
+
decodeFailed(generation, frame, error) {
|
|
93
|
+
if (generation !== this.generation) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
this.decoding = false;
|
|
97
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
98
|
+
this.context.Report('append-failed', `The browser could not decode an image of type ${frame.MimeType}: ${reason}`);
|
|
99
|
+
this.feed();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** The `'image'` decoder: JPEG, PNG and WebP images, where this browser has `createImageBitmap`. */
|
|
103
|
+
export const IMAGE_FRAME_DECODER = {
|
|
104
|
+
Name: 'image',
|
|
105
|
+
Kind: 'image',
|
|
106
|
+
Priority: 0,
|
|
107
|
+
CanPlay: (mimeType) => ImageFrameDecoder.CanPlay(mimeType),
|
|
108
|
+
Create: (context) => new ImageFrameDecoder(context),
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=imageFrameDecoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imageFrameDecoder.js","sourceRoot":"","sources":["../../../src/media/decoders/imageFrameDecoder.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAElE,4EAA4E;AAC5E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAElC,yFAAyF;AACzF,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAEtC,sDAAsD;AACtD,MAAM,OAAO,iBAAiB;IAW1B,0EAA0E;IACnE,MAAM,CAAC,OAAO,CAAC,QAAgB;QAClC,MAAM,SAAS,GAAG,OAAO,iBAAiB,KAAK,UAAU,IAAI,OAAO,IAAI,KAAK,UAAU,CAAC;QACxF,OAAO,SAAS,IAAI,YAAY,CAAC,WAAW,EAAE,IAAI,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnG,CAAC;IAED,wDAAwD;IACxD,YAA6B,OAAiC;QAAjC,YAAO,GAAP,OAAO,CAA0B;QAjB7C,WAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAE7C,sDAAsD;QACrC,YAAO,GAA8B,EAAE,CAAC;QACzD,yFAAyF;QACjF,aAAQ,GAAG,KAAK,CAAC;QACzB,+EAA+E;QACvE,eAAU,GAAG,CAAC,CAAC;QACf,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,iDAAiD;IACjD,IAAW,SAAS;QAChB,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,oGAAoG;IACpG,IAAW,WAAW;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;IAC/E,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,qGAAqG;IAC9F,MAAM,CAAC,KAAyB;QACnC,IAAI,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC1C,OAAO;QACX,CAAC;QACD,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,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,kBAAkB,CAAC,CAAC;YACjE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,4EAA4E,CAAC,CAAC;QAC1H,CAAC;QACD,IAAI,CAAC,IAAI,EAAE,CAAC;IAChB,CAAC;IAED,gFAAgF;IACzE,SAAS;QACZ,wBAAwB;IAC5B,CAAC;IAED,gHAAgH;IACzG,KAAK;QACR,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAEM,OAAO;QACV,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IAC1B,CAAC;IAED,kHAAkH;IAC1G,IAAI;QACR,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,gBAAgB,EAAE,CAAC;YACzG,OAAO;QACX,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAA6B,CAAC;QAC9D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACnC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,iBAAiB,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CACpE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,kBAAkB,CAAC,EACpE,CAAC,KAAc,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,CAClE,CAAC;IACN,CAAC;IAEO,OAAO,CAAC,UAAkB,EAAE,KAAkB,EAAE,MAA0B;QAC9E,IAAI,UAAU,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;YACjC,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,OAAO;QACX,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,EAAE,CAAC;IAChB,CAAC;IAEO,YAAY,CAAC,UAAkB,EAAE,KAA8B,EAAE,KAAc;QACnF,IAAI,UAAU,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;YACjC,OAAO;QACX,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,iDAAiD,KAAK,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC,CAAC;QACnH,IAAI,CAAC,IAAI,EAAE,CAAC;IAChB,CAAC;CACJ;AAED,oGAAoG;AACpG,MAAM,CAAC,MAAM,mBAAmB,GAAkC;IAC9D,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,QAAQ,CAAC;IAC1D,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,iBAAiB,CAAC,OAAO,CAAC;CACtD,CAAC"}
|