@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,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview MEDIA STAGE: a headless layout model. Participants, placeable surfaces and the user's moves go
|
|
3
|
+
* in; a layout comes out: one stage, a stack of picture-in-picture tiles, tabs, hidden surfaces, the other
|
|
4
|
+
* participants (for a filmstrip or grid), and a screen-share split. It knows nothing about Angular, the DOM,
|
|
5
|
+
* LiveKit or the realtime client, so the realtime overlay and the meeting room lay out the same way.
|
|
6
|
+
*
|
|
7
|
+
* Placement rules:
|
|
8
|
+
* - A surface goes where the user last moved it, if that placement is allowed for it; otherwise to its default.
|
|
9
|
+
* - **One stage.** The surface the user moved to the stage most recently wins it. A surface it displaces goes
|
|
10
|
+
* to its own default placement, or to a PiP when its default is also the stage. With no move, the first
|
|
11
|
+
* surface whose default is the stage keeps it, so a new surface never takes the stage on its own.
|
|
12
|
+
* - **PiPs stack** in one corner, newest first: the latest move first, then surfaces by when they appeared.
|
|
13
|
+
* - When no surface holds the stage, the spotlight participant does: a pin, then the active speaker, then a
|
|
14
|
+
* speaking participant, then the agent, then the first other participant, then the user.
|
|
15
|
+
* - A participant already shown through a surface on the stage or in a PiP (the avatar, the user's camera) is not
|
|
16
|
+
* repeated among the others, and one shown in a PiP does not take the spotlight: the next in line does.
|
|
17
|
+
*
|
|
18
|
+
* A host that lets the user move participants' tiles passes each as a surface ({@link ParticipantTileSurface}), as the
|
|
19
|
+
* meeting room does; a host with channel surfaces passes those, as the realtime call does.
|
|
20
|
+
*
|
|
21
|
+
* @module @memberjunction/ai-realtime-client/media
|
|
22
|
+
*/
|
|
23
|
+
import type { MediaParticipant, MediaPlacement, MediaPlacementMove, MediaSurface } from './model.js';
|
|
24
|
+
/** What the stage is laid out from. */
|
|
25
|
+
export interface MediaStageInput {
|
|
26
|
+
/** Everyone in the session. The local user has `Role: 'self'`. */
|
|
27
|
+
Participants: readonly MediaParticipant[];
|
|
28
|
+
/** Identities the platform reports as speaking, most recent first (a meeting room's active-speaker list). */
|
|
29
|
+
ActiveSpeakers?: readonly string[];
|
|
30
|
+
/** Surfaces that can be placed, in the order they appeared. */
|
|
31
|
+
Surfaces?: readonly MediaSurface[];
|
|
32
|
+
/** The user's moves, oldest first. Only each surface's latest move counts, so a host may keep just those, in order. */
|
|
33
|
+
Moves?: readonly MediaPlacementMove[];
|
|
34
|
+
/** A participant the user pinned to the stage. */
|
|
35
|
+
PinnedIdentity?: string | null;
|
|
36
|
+
/** Whether the user's own tile is among the other participants. Defaults to true. */
|
|
37
|
+
ShowSelfView?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** One tile: a placed surface, or a participant. */
|
|
40
|
+
export type MediaTile = {
|
|
41
|
+
Kind: 'surface';
|
|
42
|
+
Surface: MediaSurface;
|
|
43
|
+
} | {
|
|
44
|
+
Kind: 'participant';
|
|
45
|
+
Participant: MediaParticipant;
|
|
46
|
+
};
|
|
47
|
+
/** Where everything goes. */
|
|
48
|
+
export interface MediaStageLayout {
|
|
49
|
+
/** What fills the stage: a surface placed there, else the spotlight participant; null for an empty session. */
|
|
50
|
+
Stage: MediaTile | null;
|
|
51
|
+
/** Picture-in-picture surfaces, newest first. */
|
|
52
|
+
Pips: readonly MediaSurface[];
|
|
53
|
+
/** Surfaces shown as tabs, in the order they appeared. */
|
|
54
|
+
Tabs: readonly MediaSurface[];
|
|
55
|
+
/** Surfaces the user hid, so the UI can offer them back. */
|
|
56
|
+
Hidden: readonly MediaSurface[];
|
|
57
|
+
/** Participants not already on screen (on the stage or in a PiP), for a filmstrip or grid; the user first when shown. */
|
|
58
|
+
Others: readonly MediaParticipant[];
|
|
59
|
+
/** The screen being shared and the current speaker, for a split view; null when nobody is sharing. */
|
|
60
|
+
Split: {
|
|
61
|
+
Sharer: MediaParticipant;
|
|
62
|
+
Speaker: MediaParticipant | null;
|
|
63
|
+
} | null;
|
|
64
|
+
}
|
|
65
|
+
/** The key a participant's tile is moved under, so it never collides with a channel's surface key. */
|
|
66
|
+
export declare function ParticipantTileKey(identity: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* A participant's tile as a surface the user can move: among the others (`tab`, a filmstrip or grid) until moved,
|
|
69
|
+
* showing the participant's camera, within the places the host offers (every placement when it names none).
|
|
70
|
+
*/
|
|
71
|
+
export declare function ParticipantTileSurface(participant: MediaParticipant, allowed?: readonly MediaPlacement[]): MediaSurface;
|
|
72
|
+
/** Who fills the stage: the participant a surface on it shows (a tile moved there, an avatar), else the spotlight participant. */
|
|
73
|
+
export declare function StageParticipantIdentity(stage: MediaTile | null): string | null;
|
|
74
|
+
/** Lays out the stage. Pure: the same input always gives the same layout. */
|
|
75
|
+
export declare function LayoutMediaStage(input: MediaStageInput): MediaStageLayout;
|
|
76
|
+
/** Each surface's placement after the user's moves, with the one-stage and PiP-order rules applied. */
|
|
77
|
+
export declare function ResolveSurfacePlacements(surfaces: readonly MediaSurface[], moves: readonly MediaPlacementMove[]): {
|
|
78
|
+
Stage: MediaSurface | null;
|
|
79
|
+
Pips: MediaSurface[];
|
|
80
|
+
Tabs: MediaSurface[];
|
|
81
|
+
Hidden: MediaSurface[];
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* The spotlight participant: a pin, then the active speaker, then a speaking participant, then the agent, then
|
|
85
|
+
* the first other participant, then the user.
|
|
86
|
+
*/
|
|
87
|
+
export declare function SelectSpotlight(participants: readonly MediaParticipant[], activeSpeakers: readonly string[], pinnedIdentity: string | null): MediaParticipant | null;
|
|
88
|
+
/** The participants to show in a filmstrip or grid: the user first, when shown. */
|
|
89
|
+
export declare function SelectDisplayParticipants(participants: readonly MediaParticipant[], showSelfView: boolean): MediaParticipant[];
|
|
90
|
+
/** The first participant sharing a screen, if any. */
|
|
91
|
+
export declare function SelectScreenSharer(participants: readonly MediaParticipant[]): MediaParticipant | null;
|
|
92
|
+
/** The speaker pane beside a shared screen: the active speaker other than the sharer, then the agent, then the first other non-sharer, then the user. */
|
|
93
|
+
export declare function SelectSplitSpeaker(participants: readonly MediaParticipant[], activeSpeakers: readonly string[]): MediaParticipant | null;
|
|
94
|
+
/**
|
|
95
|
+
* Where a surface goes when it leaves the stage, displaced by another or sent off it: its default, or the first allowed of
|
|
96
|
+
* PiP, tab, hidden.
|
|
97
|
+
*/
|
|
98
|
+
export declare function PlacementOffStage(surface: MediaSurface): MediaPlacement;
|
|
99
|
+
//# sourceMappingURL=mediaStage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mediaStage.d.ts","sourceRoot":"","sources":["../../src/media/mediaStage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview MEDIA STAGE: a headless layout model. Participants, placeable surfaces and the user's moves go
|
|
3
|
+
* in; a layout comes out: one stage, a stack of picture-in-picture tiles, tabs, hidden surfaces, the other
|
|
4
|
+
* participants (for a filmstrip or grid), and a screen-share split. It knows nothing about Angular, the DOM,
|
|
5
|
+
* LiveKit or the realtime client, so the realtime overlay and the meeting room lay out the same way.
|
|
6
|
+
*
|
|
7
|
+
* Placement rules:
|
|
8
|
+
* - A surface goes where the user last moved it, if that placement is allowed for it; otherwise to its default.
|
|
9
|
+
* - **One stage.** The surface the user moved to the stage most recently wins it. A surface it displaces goes
|
|
10
|
+
* to its own default placement, or to a PiP when its default is also the stage. With no move, the first
|
|
11
|
+
* surface whose default is the stage keeps it, so a new surface never takes the stage on its own.
|
|
12
|
+
* - **PiPs stack** in one corner, newest first: the latest move first, then surfaces by when they appeared.
|
|
13
|
+
* - When no surface holds the stage, the spotlight participant does: a pin, then the active speaker, then a
|
|
14
|
+
* speaking participant, then the agent, then the first other participant, then the user.
|
|
15
|
+
* - A participant already shown through a surface on the stage or in a PiP (the avatar, the user's camera) is not
|
|
16
|
+
* repeated among the others, and one shown in a PiP does not take the spotlight: the next in line does.
|
|
17
|
+
*
|
|
18
|
+
* A host that lets the user move participants' tiles passes each as a surface ({@link ParticipantTileSurface}), as the
|
|
19
|
+
* meeting room does; a host with channel surfaces passes those, as the realtime call does.
|
|
20
|
+
*
|
|
21
|
+
* @module @memberjunction/ai-realtime-client/media
|
|
22
|
+
*/
|
|
23
|
+
import { MEDIA_PLACEMENTS } from './model.js';
|
|
24
|
+
/** The key a participant's tile is moved under, so it never collides with a channel's surface key. */
|
|
25
|
+
export function ParticipantTileKey(identity) {
|
|
26
|
+
return `participant:${identity}`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A participant's tile as a surface the user can move: among the others (`tab`, a filmstrip or grid) until moved,
|
|
30
|
+
* showing the participant's camera, within the places the host offers (every placement when it names none).
|
|
31
|
+
*/
|
|
32
|
+
export function ParticipantTileSurface(participant, allowed) {
|
|
33
|
+
return {
|
|
34
|
+
Key: ParticipantTileKey(participant.Identity),
|
|
35
|
+
Label: participant.DisplayName,
|
|
36
|
+
DefaultPlacement: 'tab',
|
|
37
|
+
...(allowed ? { AllowedPlacements: allowed } : {}),
|
|
38
|
+
Video: { ParticipantIdentity: participant.Identity, Kind: 'camera' },
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Who fills the stage: the participant a surface on it shows (a tile moved there, an avatar), else the spotlight participant. */
|
|
42
|
+
export function StageParticipantIdentity(stage) {
|
|
43
|
+
if (stage?.Kind === 'surface') {
|
|
44
|
+
return stage.Surface.Video?.ParticipantIdentity ?? null;
|
|
45
|
+
}
|
|
46
|
+
return stage?.Participant.Identity ?? null;
|
|
47
|
+
}
|
|
48
|
+
/** Lays out the stage. Pure: the same input always gives the same layout. */
|
|
49
|
+
export function LayoutMediaStage(input) {
|
|
50
|
+
const placed = ResolveSurfacePlacements(input.Surfaces ?? [], input.Moves ?? []);
|
|
51
|
+
const inPips = new Set(placed.Pips.flatMap((s) => (s.Video ? [s.Video.ParticipantIdentity] : [])));
|
|
52
|
+
const candidates = input.Participants.filter((p) => !inPips.has(p.Identity));
|
|
53
|
+
const spotlight = placed.Stage ? null : SelectSpotlight(candidates, input.ActiveSpeakers ?? [], input.PinnedIdentity ?? null);
|
|
54
|
+
const onScreen = new Set([placed.Stage, ...placed.Pips].flatMap((s) => (s?.Video ? [s.Video.ParticipantIdentity] : [])));
|
|
55
|
+
if (spotlight) {
|
|
56
|
+
onScreen.add(spotlight.Identity);
|
|
57
|
+
}
|
|
58
|
+
const shown = SelectDisplayParticipants(input.Participants, input.ShowSelfView ?? true);
|
|
59
|
+
return {
|
|
60
|
+
Stage: placed.Stage ? { Kind: 'surface', Surface: placed.Stage } : spotlight ? { Kind: 'participant', Participant: spotlight } : null,
|
|
61
|
+
Pips: placed.Pips,
|
|
62
|
+
Tabs: placed.Tabs,
|
|
63
|
+
Hidden: placed.Hidden,
|
|
64
|
+
Others: shown.filter((p) => !onScreen.has(p.Identity)),
|
|
65
|
+
Split: selectSplit(input.Participants, input.ActiveSpeakers ?? []),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** Each surface's placement after the user's moves, with the one-stage and PiP-order rules applied. */
|
|
69
|
+
export function ResolveSurfacePlacements(surfaces, moves) {
|
|
70
|
+
const latestMove = latestMoves(surfaces, moves);
|
|
71
|
+
const wanted = new Map(surfaces.map((s) => [s.Key, latestMove.get(s.Key)?.Placement ?? s.DefaultPlacement]));
|
|
72
|
+
const stage = pickStage(surfaces, wanted, latestMove);
|
|
73
|
+
const result = { Stage: stage, Pips: [], Tabs: [], Hidden: [] };
|
|
74
|
+
for (const surface of surfaces) {
|
|
75
|
+
if (surface === stage) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const placement = wanted.get(surface.Key) === 'stage' ? PlacementOffStage(surface) : (wanted.get(surface.Key) ?? surface.DefaultPlacement);
|
|
79
|
+
if (placement === 'pip') {
|
|
80
|
+
result.Pips.push(surface);
|
|
81
|
+
}
|
|
82
|
+
else if (placement === 'tab') {
|
|
83
|
+
result.Tabs.push(surface);
|
|
84
|
+
}
|
|
85
|
+
else if (placement === 'hidden') {
|
|
86
|
+
result.Hidden.push(surface);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
result.Pips.sort((a, b) => recency(b, surfaces, latestMove) - recency(a, surfaces, latestMove));
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The spotlight participant: a pin, then the active speaker, then a speaking participant, then the agent, then
|
|
94
|
+
* the first other participant, then the user.
|
|
95
|
+
*/
|
|
96
|
+
export function SelectSpotlight(participants, activeSpeakers, pinnedIdentity) {
|
|
97
|
+
const pinned = pinnedIdentity ? participants.find((p) => p.Identity === pinnedIdentity) : undefined;
|
|
98
|
+
if (pinned) {
|
|
99
|
+
return pinned;
|
|
100
|
+
}
|
|
101
|
+
const others = participants.filter((p) => p.Role !== 'self');
|
|
102
|
+
const speakerId = activeSpeakers.find((id) => others.some((p) => p.Identity === id));
|
|
103
|
+
// The platform's active-speaker list can miss a server-published agent; a participant's own speaking flag
|
|
104
|
+
// catches it.
|
|
105
|
+
const speaking = (speakerId ? others.find((p) => p.Identity === speakerId) : undefined) ?? others.find((p) => p.IsSpeaking);
|
|
106
|
+
return speaking ?? others.find((p) => p.Role === 'agent') ?? others[0] ?? participants.find((p) => p.Role === 'self') ?? null;
|
|
107
|
+
}
|
|
108
|
+
/** The participants to show in a filmstrip or grid: the user first, when shown. */
|
|
109
|
+
export function SelectDisplayParticipants(participants, showSelfView) {
|
|
110
|
+
const self = participants.filter((p) => p.Role === 'self');
|
|
111
|
+
const others = participants.filter((p) => p.Role !== 'self');
|
|
112
|
+
return showSelfView ? [...self, ...others] : others;
|
|
113
|
+
}
|
|
114
|
+
/** The first participant sharing a screen, if any. */
|
|
115
|
+
export function SelectScreenSharer(participants) {
|
|
116
|
+
return participants.find((p) => p.Video.screen !== undefined) ?? null;
|
|
117
|
+
}
|
|
118
|
+
/** The speaker pane beside a shared screen: the active speaker other than the sharer, then the agent, then the first other non-sharer, then the user. */
|
|
119
|
+
export function SelectSplitSpeaker(participants, activeSpeakers) {
|
|
120
|
+
const sharerId = SelectScreenSharer(participants)?.Identity;
|
|
121
|
+
const speakerId = activeSpeakers.find((id) => id !== sharerId && participants.some((p) => p.Identity === id));
|
|
122
|
+
const speaking = (speakerId ? participants.find((p) => p.Identity === speakerId) : undefined) ??
|
|
123
|
+
participants.find((p) => p.IsSpeaking && p.Identity !== sharerId);
|
|
124
|
+
const others = participants.filter((p) => p.Role !== 'self');
|
|
125
|
+
return speaking ?? others.find((p) => p.Role === 'agent') ?? others.find((p) => p.Identity !== sharerId) ?? participants.find((p) => p.Role === 'self') ?? null;
|
|
126
|
+
}
|
|
127
|
+
function selectSplit(participants, activeSpeakers) {
|
|
128
|
+
const sharer = SelectScreenSharer(participants);
|
|
129
|
+
return sharer ? { Sharer: sharer, Speaker: SelectSplitSpeaker(participants, activeSpeakers) } : null;
|
|
130
|
+
}
|
|
131
|
+
/** Whether a placement is allowed for a surface. */
|
|
132
|
+
function allows(surface, placement) {
|
|
133
|
+
return !surface.AllowedPlacements || surface.AllowedPlacements.includes(placement);
|
|
134
|
+
}
|
|
135
|
+
/** Each live surface's latest allowed move, with its position in the move list (its recency). */
|
|
136
|
+
function latestMoves(surfaces, moves) {
|
|
137
|
+
const byKey = new Map(surfaces.map((s) => [s.Key, s]));
|
|
138
|
+
const latest = new Map();
|
|
139
|
+
moves.forEach((move, order) => {
|
|
140
|
+
const surface = byKey.get(move.SurfaceKey);
|
|
141
|
+
if (surface && allows(surface, move.Placement)) {
|
|
142
|
+
latest.set(move.SurfaceKey, { Placement: move.Placement, Order: order });
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
return latest;
|
|
146
|
+
}
|
|
147
|
+
/** The stage holder: the latest move to the stage, else the first surface whose default is the stage. */
|
|
148
|
+
function pickStage(surfaces, wanted, latestMove) {
|
|
149
|
+
const contenders = surfaces.filter((s) => wanted.get(s.Key) === 'stage');
|
|
150
|
+
const moved = contenders.filter((s) => latestMove.get(s.Key)?.Placement === 'stage');
|
|
151
|
+
if (moved.length > 0) {
|
|
152
|
+
return moved.reduce((a, b) => ((latestMove.get(b.Key)?.Order ?? -1) > (latestMove.get(a.Key)?.Order ?? -1) ? b : a));
|
|
153
|
+
}
|
|
154
|
+
return contenders[0] ?? null;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Where a surface goes when it leaves the stage, displaced by another or sent off it: its default, or the first allowed of
|
|
158
|
+
* PiP, tab, hidden.
|
|
159
|
+
*/
|
|
160
|
+
export function PlacementOffStage(surface) {
|
|
161
|
+
if (surface.DefaultPlacement !== 'stage' && allows(surface, surface.DefaultPlacement)) {
|
|
162
|
+
return surface.DefaultPlacement;
|
|
163
|
+
}
|
|
164
|
+
return MEDIA_PLACEMENTS.slice(1).find((p) => allows(surface, p)) ?? 'hidden';
|
|
165
|
+
}
|
|
166
|
+
/** Higher is newer: a move outranks appearance order, and a later move outranks an earlier one. */
|
|
167
|
+
function recency(surface, surfaces, latestMove) {
|
|
168
|
+
const move = latestMove.get(surface.Key);
|
|
169
|
+
return move ? surfaces.length + move.Order : surfaces.indexOf(surface);
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=mediaStage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mediaStage.js","sourceRoot":"","sources":["../../src/media/mediaStage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAqC3C,sGAAsG;AACtG,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IAC/C,OAAO,eAAe,QAAQ,EAAE,CAAC;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,WAA6B,EAAE,OAAmC;IACrG,OAAO;QACH,GAAG,EAAE,kBAAkB,CAAC,WAAW,CAAC,QAAQ,CAAC;QAC7C,KAAK,EAAE,WAAW,CAAC,WAAW;QAC9B,gBAAgB,EAAE,KAAK;QACvB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,KAAK,EAAE,EAAE,mBAAmB,EAAE,WAAW,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;KACvE,CAAC;AACN,CAAC;AAED,kIAAkI;AAClI,MAAM,UAAU,wBAAwB,CAAC,KAAuB;IAC5D,IAAI,KAAK,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,mBAAmB,IAAI,IAAI,CAAC;IAC5D,CAAC;IACD,OAAO,KAAK,EAAE,WAAW,CAAC,QAAQ,IAAI,IAAI,CAAC;AAC/C,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,gBAAgB,CAAC,KAAsB;IACnD,MAAM,MAAM,GAAG,wBAAwB,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACjF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnG,MAAM,UAAU,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7E,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,IAAI,EAAE,EAAE,KAAK,CAAC,cAAc,IAAI,IAAI,CAAC,CAAC;IAC9H,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACzH,IAAI,SAAS,EAAE,CAAC;QACZ,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IACD,MAAM,KAAK,GAAG,yBAAyB,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC;IACxF,OAAO;QACH,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI;QACrI,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACtD,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,cAAc,IAAI,EAAE,CAAC;KACrE,CAAC;AACN,CAAC;AAED,uGAAuG;AACvG,MAAM,UAAU,wBAAwB,CACpC,QAAiC,EACjC,KAAoC;IAEpC,MAAM,UAAU,GAAG,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,SAAS,IAAI,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC7G,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAoB,EAAE,IAAI,EAAE,EAAoB,EAAE,MAAM,EAAE,EAAoB,EAAE,CAAC;IACtH,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC7B,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;YACpB,SAAS;QACb,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC3I,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;YACtB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;aAAM,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;YAC7B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;aAAM,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;YAChC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;IACL,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;IAChG,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC3B,YAAyC,EACzC,cAAiC,EACjC,cAA6B;IAE7B,MAAM,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpG,IAAI,MAAM,EAAE,CAAC;QACT,OAAO,MAAM,CAAC;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;IAC7D,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC;IACrF,0GAA0G;IAC1G,cAAc;IACd,MAAM,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAC5H,OAAO,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC;AAClI,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,yBAAyB,CAAC,YAAyC,EAAE,YAAqB;IACtG,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;IAC7D,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AACxD,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,kBAAkB,CAAC,YAAyC;IACxE,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,IAAI,IAAI,CAAC;AAC1E,CAAC;AAED,yJAAyJ;AACzJ,MAAM,UAAU,kBAAkB,CAAC,YAAyC,EAAE,cAAiC;IAC3G,MAAM,QAAQ,GAAG,kBAAkB,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC;IAC5D,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC;IAC9G,MAAM,QAAQ,GACV,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5E,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;IAC7D,OAAO,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC;AACpK,CAAC;AAED,SAAS,WAAW,CAAC,YAAyC,EAAE,cAAiC;IAC7F,MAAM,MAAM,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,CAAC,YAAY,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACzG,CAAC;AAED,oDAAoD;AACpD,SAAS,MAAM,CAAC,OAAqB,EAAE,SAAyB;IAC5D,OAAO,CAAC,OAAO,CAAC,iBAAiB,IAAI,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AACvF,CAAC;AAED,iGAAiG;AACjG,SAAS,WAAW,CAAC,QAAiC,EAAE,KAAoC;IACxF,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwD,CAAC;IAC/E,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC1B,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,OAAO,IAAI,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7E,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,yGAAyG;AACzG,SAAS,SAAS,CACd,QAAiC,EACjC,MAAmC,EACnC,UAAqE;IAErE,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,CAAC;IACzE,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,CAAC;IACrF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnB,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzH,CAAC;IACD,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAqB;IACnD,IAAI,OAAO,CAAC,gBAAgB,KAAK,OAAO,IAAI,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACpF,OAAO,OAAO,CAAC,gBAAgB,CAAC;IACpC,CAAC;IACD,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;AACjF,CAAC;AAED,mGAAmG;AACnG,SAAS,OAAO,CAAC,OAAqB,EAAE,QAAiC,EAAE,UAAqE;IAC5I,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACzC,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Shared types for the `/media` entry point: the local devices and capture state that the
|
|
3
|
+
* media controllers and the UI exchange.
|
|
4
|
+
*
|
|
5
|
+
* @module @memberjunction/ai-realtime-client/media
|
|
6
|
+
*/
|
|
7
|
+
/** A kind of local device the user captures from. */
|
|
8
|
+
export type LocalMediaKind = 'camera' | 'microphone';
|
|
9
|
+
/** What a device does: a camera or a microphone the user captures from, or a speaker that plays sound. */
|
|
10
|
+
export type MediaDeviceKind = LocalMediaKind | 'speaker';
|
|
11
|
+
/** One device. */
|
|
12
|
+
export interface MediaDevice {
|
|
13
|
+
/** The browser's id for the device, stable for this site until the user clears its data. */
|
|
14
|
+
DeviceID: string;
|
|
15
|
+
Kind: MediaDeviceKind;
|
|
16
|
+
/** The device's name. Browsers leave it empty until the user has allowed this site that kind of device. */
|
|
17
|
+
Label: string;
|
|
18
|
+
/** Devices on the same physical product (a webcam's camera and microphone) share a group id. */
|
|
19
|
+
GroupID: string;
|
|
20
|
+
}
|
|
21
|
+
/** Why a local device could not be used. */
|
|
22
|
+
export type LocalMediaFailure =
|
|
23
|
+
/** The user, the operating system or the page's permissions policy refused access. */
|
|
24
|
+
'denied'
|
|
25
|
+
/** There is no device of that kind, or not the one asked for. */
|
|
26
|
+
| 'not-found'
|
|
27
|
+
/** The device exists, but another application is using it. */
|
|
28
|
+
| 'in-use'
|
|
29
|
+
/** The browser cannot capture at all (no `getUserMedia`). */
|
|
30
|
+
| 'unsupported'
|
|
31
|
+
/** Anything else; see the message. */
|
|
32
|
+
| 'error';
|
|
33
|
+
/** One kind of local capture. */
|
|
34
|
+
export interface LocalTrackState {
|
|
35
|
+
Status: 'off' | 'starting' | 'on' | 'failed';
|
|
36
|
+
/** The device in use, while `on`. */
|
|
37
|
+
DeviceID?: string;
|
|
38
|
+
/** That device's name, while `on`. */
|
|
39
|
+
Label?: string;
|
|
40
|
+
/** Why capture failed, while `failed`. */
|
|
41
|
+
Failure?: LocalMediaFailure;
|
|
42
|
+
/** The browser's message for the failure. */
|
|
43
|
+
Message?: string;
|
|
44
|
+
}
|
|
45
|
+
/** Everything captured locally, as the `LocalMediaController` reports it. */
|
|
46
|
+
export interface LocalMediaState {
|
|
47
|
+
Camera: LocalTrackState;
|
|
48
|
+
Microphone: LocalTrackState;
|
|
49
|
+
/** The input devices the browser lists now. */
|
|
50
|
+
Devices: MediaDevice[];
|
|
51
|
+
}
|
|
52
|
+
/** The outcome of starting or switching a local device. It always resolves; it never rejects. */
|
|
53
|
+
export type LocalMediaResult = {
|
|
54
|
+
Status: 'started';
|
|
55
|
+
Stream: MediaStream;
|
|
56
|
+
} | {
|
|
57
|
+
Status: 'failed';
|
|
58
|
+
Reason: LocalMediaFailure;
|
|
59
|
+
Message: string;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* A source of video to show: a live `MediaStream` (a camera, a shared screen, a WebRTC track), or a player that
|
|
63
|
+
* must own the `<video>` element (MSE or WebCodecs playout of encoded video, such as an avatar). Renderers show
|
|
64
|
+
* either with `AttachVideoSource`.
|
|
65
|
+
*/
|
|
66
|
+
export type MediaVideoSource =
|
|
67
|
+
/** A live stream, shown muted: its audio is played elsewhere. */
|
|
68
|
+
{
|
|
69
|
+
Kind: 'stream';
|
|
70
|
+
Stream: MediaStream;
|
|
71
|
+
}
|
|
72
|
+
/** A player that takes over the element and returns a function that releases it. */
|
|
73
|
+
| {
|
|
74
|
+
Kind: 'element';
|
|
75
|
+
Attach(element: HTMLVideoElement): () => void;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* What a participant's video shows. Open vocabulary. These are on-screen kinds; the video source arbiter's
|
|
79
|
+
* `VideoSourceKind` is a different list, of what the model is shown.
|
|
80
|
+
*/
|
|
81
|
+
export type MediaSourceKind = 'camera' | 'screen' | 'avatar' | (string & {});
|
|
82
|
+
/** Where a surface appears: the main stage, a picture-in-picture tile, a tab, or nowhere. */
|
|
83
|
+
export type MediaPlacement = 'stage' | 'pip' | 'tab' | 'hidden';
|
|
84
|
+
/** Every placement, in the order a displaced surface falls back through them. */
|
|
85
|
+
export declare const MEDIA_PLACEMENTS: readonly MediaPlacement[];
|
|
86
|
+
/** One person or agent in a session, as the media stage and its tiles see them. */
|
|
87
|
+
export interface MediaParticipant {
|
|
88
|
+
/** Stable identity within the session. */
|
|
89
|
+
Identity: string;
|
|
90
|
+
DisplayName: string;
|
|
91
|
+
/** `'self'` is the local user. */
|
|
92
|
+
Role: 'self' | 'agent' | 'host' | 'participant';
|
|
93
|
+
/** Whether the participant is speaking now. */
|
|
94
|
+
IsSpeaking: boolean;
|
|
95
|
+
/** The participant's videos, by kind: a camera, a shared screen, an avatar. */
|
|
96
|
+
Video: Partial<Record<MediaSourceKind, MediaVideoSource>>;
|
|
97
|
+
/** Which video a tile shows when there are several. Defaults to a shared screen, then the camera, then the avatar. */
|
|
98
|
+
PreferredVideo?: MediaSourceKind;
|
|
99
|
+
/** Whether the participant's microphone is off. */
|
|
100
|
+
IsMuted?: boolean;
|
|
101
|
+
/** The connection's quality, when the platform reports one. */
|
|
102
|
+
ConnectionQuality?: MediaConnectionQuality;
|
|
103
|
+
/** Reads the participant's current audio level, 0..1, for a meter. Called on every animation frame. */
|
|
104
|
+
GetAudioLevel?: () => number;
|
|
105
|
+
/**
|
|
106
|
+
* Whether an agent can see this participant's camera and shared screen: they allowed it, and an agent is there to
|
|
107
|
+
* watch. A tile shows "Agent can see". Absent means no.
|
|
108
|
+
*/
|
|
109
|
+
AgentCanSee?: boolean;
|
|
110
|
+
}
|
|
111
|
+
/** A participant's connection quality. */
|
|
112
|
+
export type MediaConnectionQuality = 'excellent' | 'good' | 'poor' | 'lost' | 'unknown';
|
|
113
|
+
/** The agent's conversational state, for an indicator. */
|
|
114
|
+
export type MediaAgentState = 'idle' | 'listening' | 'thinking' | 'speaking';
|
|
115
|
+
/** The state of a session's connection, for an overlay. */
|
|
116
|
+
export type MediaConnectionStatus = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'disconnected' | 'error';
|
|
117
|
+
/** Why a session ended. */
|
|
118
|
+
export type MediaDisconnectReason = 'client-initiated' | 'server-shutdown' | 'participant-removed' | 'room-deleted' | 'connection-lost' | 'duplicate-identity' | 'unknown';
|
|
119
|
+
/** A device the user picked in a device menu. */
|
|
120
|
+
export interface MediaDeviceSelection {
|
|
121
|
+
Kind: MediaDeviceKind;
|
|
122
|
+
DeviceID: string;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Something that can be placed: a channel's surface (a whiteboard, a remote browser) or a participant's video
|
|
126
|
+
* (the avatar, the user's camera, a shared screen).
|
|
127
|
+
*/
|
|
128
|
+
export interface MediaSurface {
|
|
129
|
+
/** Stable key, usually the channel key. The user's moves are recorded against it. */
|
|
130
|
+
Key: string;
|
|
131
|
+
Label: string;
|
|
132
|
+
/** Where it goes unless the user moved it. */
|
|
133
|
+
DefaultPlacement: MediaPlacement;
|
|
134
|
+
/** Where the user may move it. Defaults to every placement. */
|
|
135
|
+
AllowedPlacements?: readonly MediaPlacement[];
|
|
136
|
+
/** The participant video it shows, when it is one; absent for a component surface such as a whiteboard. */
|
|
137
|
+
Video?: {
|
|
138
|
+
ParticipantIdentity: string;
|
|
139
|
+
Kind: MediaSourceKind;
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/** One move the user made: a surface to a placement. */
|
|
143
|
+
export interface MediaPlacementMove {
|
|
144
|
+
SurfaceKey: string;
|
|
145
|
+
Placement: MediaPlacement;
|
|
146
|
+
}
|
|
147
|
+
/** A picture-in-picture box as fractions of the stage (0 to 1), so it survives a resized window: what a host saves. */
|
|
148
|
+
export interface MediaPipRect {
|
|
149
|
+
X: number;
|
|
150
|
+
Y: number;
|
|
151
|
+
W: number;
|
|
152
|
+
H: number;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/media/model.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Shared types for the `/media` entry point: the local devices and capture state that the
|
|
3
|
+
* media controllers and the UI exchange.
|
|
4
|
+
*
|
|
5
|
+
* @module @memberjunction/ai-realtime-client/media
|
|
6
|
+
*/
|
|
7
|
+
/** Every placement, in the order a displaced surface falls back through them. */
|
|
8
|
+
export const MEDIA_PLACEMENTS = ['stage', 'pip', 'tab', 'hidden'];
|
|
9
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/media/model.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA8EH,iFAAiF;AACjF,MAAM,CAAC,MAAM,gBAAgB,GAA8B,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview PLAYBACK CLOCK: where the voice is, so a video player can show each frame when the voice reaches it and
|
|
3
|
+
* the face moves with the voice.
|
|
4
|
+
*
|
|
5
|
+
* The voice is the master clock, as in the meeting bot: a driver that times both its PCM and its video frames on one media
|
|
6
|
+
* timeline gives the player its PCM playback (`RealtimePcmPlayback`) as `VideoPlayoutOptions.Clock`. The chunk and image
|
|
7
|
+
* decoders then show a frame when the clock reaches its `PresentationTimeMs`. MSE needs no clock: an MP4 that carries the
|
|
8
|
+
* voice plays voice and face together on its own timestamps.
|
|
9
|
+
*
|
|
10
|
+
* @module @memberjunction/ai-realtime-client/media
|
|
11
|
+
*/
|
|
12
|
+
/** Where the voice is: the clock a video player shows frames against, so the face moves with the voice. */
|
|
13
|
+
export interface IPlaybackClock {
|
|
14
|
+
/**
|
|
15
|
+
* The media time, in milliseconds on the stream's timeline, of the audio heard now; `null` while no timed audio plays
|
|
16
|
+
* (nothing is queued, or the audio queued carries no media times).
|
|
17
|
+
*/
|
|
18
|
+
readonly CurrentTimeMs: number | null;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=playbackClock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playbackClock.d.ts","sourceRoot":"","sources":["../../src/media/playbackClock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,2GAA2G;AAC3G,MAAM,WAAW,cAAc;IAC3B;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview PLAYBACK CLOCK: where the voice is, so a video player can show each frame when the voice reaches it and
|
|
3
|
+
* the face moves with the voice.
|
|
4
|
+
*
|
|
5
|
+
* The voice is the master clock, as in the meeting bot: a driver that times both its PCM and its video frames on one media
|
|
6
|
+
* timeline gives the player its PCM playback (`RealtimePcmPlayback`) as `VideoPlayoutOptions.Clock`. The chunk and image
|
|
7
|
+
* decoders then show a frame when the clock reaches its `PresentationTimeMs`. MSE needs no clock: an MP4 that carries the
|
|
8
|
+
* voice plays voice and face together on its own timestamps.
|
|
9
|
+
*
|
|
10
|
+
* @module @memberjunction/ai-realtime-client/media
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=playbackClock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playbackClock.js","sourceRoot":"","sources":["../../src/media/playbackClock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview VIDEO FRAME DECODERS: what plays one kind of `RealtimeVideoFrame` into a `<video>` element for
|
|
3
|
+
* {@link VideoPlayout}, and how a decoder is offered to the player.
|
|
4
|
+
*
|
|
5
|
+
* The player keeps one decoder at a time. For each frame it picks, from the {@link VideoFrameDecoderRegistry}, the first
|
|
6
|
+
* registration of the frame's kind that can play its MIME type, and hands the decoder a {@link VideoFrameDecoderContext}:
|
|
7
|
+
* the player's settings and where to report. A decoder plays into the host's element, whatever it decodes with, so the
|
|
8
|
+
* host shows every kind of video the same way.
|
|
9
|
+
*
|
|
10
|
+
* Built in: `'mse-fmp4'` (fragmented MP4 through Media Source Extensions), `'webcodecs'` (encoded chunks through a
|
|
11
|
+
* WebCodecs `VideoDecoder`) and `'image'` (still images through `createImageBitmap`).
|
|
12
|
+
*
|
|
13
|
+
* @module @memberjunction/ai-realtime-client/media
|
|
14
|
+
*/
|
|
15
|
+
import type { RealtimeVideoFrame, RealtimeVideoFrameKind } from '@memberjunction/ai';
|
|
16
|
+
import type { IPlaybackClock } from './playbackClock.js';
|
|
17
|
+
import type { VideoPlayoutProblem } from './videoPlayout.js';
|
|
18
|
+
/** What a decoder plays with and reports through. The player gives one to each decoder it creates. */
|
|
19
|
+
export interface VideoFrameDecoderContext {
|
|
20
|
+
/**
|
|
21
|
+
* The player's configured type (`VideoPlayoutOptions.MimeType`), with its codecs: what a decoder that opens by type
|
|
22
|
+
* (MSE) opens with until a frame says more.
|
|
23
|
+
*/
|
|
24
|
+
readonly MimeType: string;
|
|
25
|
+
/** Seconds of played media a buffering decoder keeps behind the playhead (`VideoPlayoutOptions.BackBufferSeconds`). */
|
|
26
|
+
readonly BackBufferSeconds: number;
|
|
27
|
+
/** Whether the element plays the media's own audio (an avatar MP4's voice). The player keeps it current. */
|
|
28
|
+
readonly CarriesVoice: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* The element hook from `VideoPlayoutOptions.OnElementAttached`: the voice's route into Web Audio. A decoder whose media
|
|
31
|
+
* carries audio calls it with each element it takes over, before playback starts.
|
|
32
|
+
*/
|
|
33
|
+
OnElementAttached?(element: HTMLVideoElement): void;
|
|
34
|
+
/**
|
|
35
|
+
* The voice's playback clock (`VideoPlayoutOptions.Clock`), when the player has one: a decoder that paces its own
|
|
36
|
+
* frames shows each when the clock reaches its `PresentationTimeMs`. A decoder whose media carries the voice ignores it.
|
|
37
|
+
*/
|
|
38
|
+
readonly Clock?: IPlaybackClock;
|
|
39
|
+
/** Reports a problem. The player passes each kind on once. */
|
|
40
|
+
Report(problem: VideoPlayoutProblem, message: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* The decoder can't go on (its browser decoder closed for good, or the browser can't decode the stream's codec). The
|
|
43
|
+
* player disposes it and picks the next decoder that can play the frame's type; out of decoders, frames of that type are
|
|
44
|
+
* dropped.
|
|
45
|
+
*/
|
|
46
|
+
Failed(message: string): void;
|
|
47
|
+
}
|
|
48
|
+
/** Plays one kind of frame into a `<video>` element. The player creates one at a time and moves it between elements. */
|
|
49
|
+
export interface IVideoFrameDecoder {
|
|
50
|
+
/** Takes the element over and shows its video there, keeping the frames it holds and the last one shown. */
|
|
51
|
+
Attach(element: HTMLVideoElement): void;
|
|
52
|
+
/** Lets the element go (the tile moved or closed). The decoder keeps what it holds for the next element. */
|
|
53
|
+
Detach(): void;
|
|
54
|
+
/** Takes one frame of its kind, in the order they arrived. */
|
|
55
|
+
Append(frame: RealtimeVideoFrame): void;
|
|
56
|
+
/** The turn's last frame has arrived: everything that came plays to the end, then the last frame holds. */
|
|
57
|
+
EndOfTurn(): void;
|
|
58
|
+
/** Barge-in: drops what isn't shown yet. The last frame shown stays on screen. */
|
|
59
|
+
Flush(): void;
|
|
60
|
+
/** Whether the decoder's own audio is audibly playing (an MP4 that carries the voice); `false` for decoders without audio. */
|
|
61
|
+
readonly IsPlaying: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* How many of the frames it took are still to play: waiting, being decoded or appended, or buffered ahead of the
|
|
64
|
+
* playhead. A frame it dropped (a barge-in's flush, an overflow, a decode error) or played past is not counted.
|
|
65
|
+
*/
|
|
66
|
+
readonly FramesAhead: number;
|
|
67
|
+
/** Stops, releases the element and frees what it holds. */
|
|
68
|
+
Dispose(): void;
|
|
69
|
+
}
|
|
70
|
+
/** One decoder the registry can create. */
|
|
71
|
+
export interface VideoFrameDecoderRegistration {
|
|
72
|
+
/** Its name, unique in the registry: registering the same name again replaces it. Built in: `'mse-fmp4'`, `'webcodecs'`, `'image'`. */
|
|
73
|
+
Name: string;
|
|
74
|
+
/** The kind of frame it plays. */
|
|
75
|
+
Kind: RealtimeVideoFrameKind;
|
|
76
|
+
/** Among the decoders that can play a type, a higher priority is tried first. The built-ins have 0. */
|
|
77
|
+
Priority: number;
|
|
78
|
+
/**
|
|
79
|
+
* Whether it can play frames of this MIME type in this browser, answered at once. A decoder whose exact answer needs an
|
|
80
|
+
* asynchronous check answers from what it can see now, and calls `Failed` later if the check says no.
|
|
81
|
+
*/
|
|
82
|
+
CanPlay(mimeType: string): boolean;
|
|
83
|
+
/** A new decoder, for one player. */
|
|
84
|
+
Create(context: VideoFrameDecoderContext): IVideoFrameDecoder;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=videoFrameDecoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"videoFrameDecoder.d.ts","sourceRoot":"","sources":["../../src/media/videoFrameDecoder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,sGAAsG;AACtG,MAAM,WAAW,wBAAwB;IACrC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uHAAuH;IACvH,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,4GAA4G;IAC5G,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B;;;OAGG;IACH,iBAAiB,CAAC,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpD;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC,8DAA8D;IAC9D,MAAM,CAAC,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5D;;;;OAIG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,wHAAwH;AACxH,MAAM,WAAW,kBAAkB;IAC/B,4GAA4G;IAC5G,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACxC,4GAA4G;IAC5G,MAAM,IAAI,IAAI,CAAC;IACf,8DAA8D;IAC9D,MAAM,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACxC,2GAA2G;IAC3G,SAAS,IAAI,IAAI,CAAC;IAClB,kFAAkF;IAClF,KAAK,IAAI,IAAI,CAAC;IACd,8HAA8H;IAC9H,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,OAAO,IAAI,IAAI,CAAC;CACnB;AAED,2CAA2C;AAC3C,MAAM,WAAW,6BAA6B;IAC1C,uIAAuI;IACvI,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,uGAAuG;IACvG,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,qCAAqC;IACrC,MAAM,CAAC,OAAO,EAAE,wBAAwB,GAAG,kBAAkB,CAAC;CACjE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"videoFrameDecoder.js","sourceRoot":"","sources":["../../src/media/videoFrameDecoder.ts"],"names":[],"mappings":""}
|