@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.
Files changed (206) hide show
  1. package/README.md +156 -29
  2. package/dist/audio/audioMeter.d.ts +71 -0
  3. package/dist/audio/audioMeter.d.ts.map +1 -1
  4. package/dist/audio/audioMeter.js +83 -0
  5. package/dist/audio/audioMeter.js.map +1 -1
  6. package/dist/audio/mediaElementAudioRouter.d.ts +41 -0
  7. package/dist/audio/mediaElementAudioRouter.d.ts.map +1 -0
  8. package/dist/audio/mediaElementAudioRouter.js +82 -0
  9. package/dist/audio/mediaElementAudioRouter.js.map +1 -0
  10. package/dist/audio/micCapture.d.ts +12 -3
  11. package/dist/audio/micCapture.d.ts.map +1 -1
  12. package/dist/audio/micCapture.js +15 -1
  13. package/dist/audio/micCapture.js.map +1 -1
  14. package/dist/audio/pcmPlayback.d.ts +72 -4
  15. package/dist/audio/pcmPlayback.d.ts.map +1 -1
  16. package/dist/audio/pcmPlayback.js +101 -1
  17. package/dist/audio/pcmPlayback.js.map +1 -1
  18. package/dist/drivers/assemblyAIRealtimeClient.d.ts +2 -0
  19. package/dist/drivers/assemblyAIRealtimeClient.d.ts.map +1 -1
  20. package/dist/drivers/assemblyAIRealtimeClient.js +14 -0
  21. package/dist/drivers/assemblyAIRealtimeClient.js.map +1 -1
  22. package/dist/drivers/elevenLabsRealtimeClient.d.ts +2 -0
  23. package/dist/drivers/elevenLabsRealtimeClient.d.ts.map +1 -1
  24. package/dist/drivers/elevenLabsRealtimeClient.js +14 -0
  25. package/dist/drivers/elevenLabsRealtimeClient.js.map +1 -1
  26. package/dist/drivers/geminiAvatarOutput.d.ts +132 -0
  27. package/dist/drivers/geminiAvatarOutput.d.ts.map +1 -0
  28. package/dist/drivers/geminiAvatarOutput.js +310 -0
  29. package/dist/drivers/geminiAvatarOutput.js.map +1 -0
  30. package/dist/drivers/geminiEnterpriseRealtimeClient.d.ts +38 -0
  31. package/dist/drivers/geminiEnterpriseRealtimeClient.d.ts.map +1 -0
  32. package/dist/drivers/geminiEnterpriseRealtimeClient.js +107 -0
  33. package/dist/drivers/geminiEnterpriseRealtimeClient.js.map +1 -0
  34. package/dist/drivers/geminiRealtimeClient.d.ts +314 -48
  35. package/dist/drivers/geminiRealtimeClient.d.ts.map +1 -1
  36. package/dist/drivers/geminiRealtimeClient.js +759 -176
  37. package/dist/drivers/geminiRealtimeClient.js.map +1 -1
  38. package/dist/drivers/openAILiveClient.d.ts +5 -8
  39. package/dist/drivers/openAILiveClient.d.ts.map +1 -1
  40. package/dist/drivers/openAILiveClient.js +19 -32
  41. package/dist/drivers/openAILiveClient.js.map +1 -1
  42. package/dist/drivers/openAIRealtimeClient.d.ts +23 -26
  43. package/dist/drivers/openAIRealtimeClient.d.ts.map +1 -1
  44. package/dist/drivers/openAIRealtimeClient.js +42 -57
  45. package/dist/drivers/openAIRealtimeClient.js.map +1 -1
  46. package/dist/generic/baseRealtimeClient.d.ts +188 -30
  47. package/dist/generic/baseRealtimeClient.d.ts.map +1 -1
  48. package/dist/generic/baseRealtimeClient.js +250 -14
  49. package/dist/generic/baseRealtimeClient.js.map +1 -1
  50. package/dist/generic/openAIProtocolClient.d.ts +57 -1
  51. package/dist/generic/openAIProtocolClient.d.ts.map +1 -1
  52. package/dist/generic/openAIProtocolClient.js +89 -4
  53. package/dist/generic/openAIProtocolClient.js.map +1 -1
  54. package/dist/index.d.ts +2 -3
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +3 -3
  57. package/dist/index.js.map +1 -1
  58. package/dist/media/attachVideoSource.d.ts +23 -0
  59. package/dist/media/attachVideoSource.d.ts.map +1 -0
  60. package/dist/media/attachVideoSource.js +49 -0
  61. package/dist/media/attachVideoSource.js.map +1 -0
  62. package/dist/media/channelVideoSource.d.ts +110 -14
  63. package/dist/media/channelVideoSource.d.ts.map +1 -1
  64. package/dist/media/channelVideoSource.js +183 -18
  65. package/dist/media/channelVideoSource.js.map +1 -1
  66. package/dist/media/decoders/frameScheduler.d.ts +119 -0
  67. package/dist/media/decoders/frameScheduler.d.ts.map +1 -0
  68. package/dist/media/decoders/frameScheduler.js +238 -0
  69. package/dist/media/decoders/frameScheduler.js.map +1 -0
  70. package/dist/media/decoders/imageFrameDecoder.d.ts +58 -0
  71. package/dist/media/decoders/imageFrameDecoder.d.ts.map +1 -0
  72. package/dist/media/decoders/imageFrameDecoder.js +110 -0
  73. package/dist/media/decoders/imageFrameDecoder.js.map +1 -0
  74. package/dist/media/decoders/mseFmp4Decoder.d.ts +130 -0
  75. package/dist/media/decoders/mseFmp4Decoder.d.ts.map +1 -0
  76. package/dist/media/decoders/mseFmp4Decoder.js +402 -0
  77. package/dist/media/decoders/mseFmp4Decoder.js.map +1 -0
  78. package/dist/media/decoders/streamCanvas.d.ts +46 -0
  79. package/dist/media/decoders/streamCanvas.d.ts.map +1 -0
  80. package/dist/media/decoders/streamCanvas.js +163 -0
  81. package/dist/media/decoders/streamCanvas.js.map +1 -0
  82. package/dist/media/decoders/videoMimeTypes.d.ts +29 -0
  83. package/dist/media/decoders/videoMimeTypes.d.ts.map +1 -0
  84. package/dist/media/decoders/videoMimeTypes.js +50 -0
  85. package/dist/media/decoders/videoMimeTypes.js.map +1 -0
  86. package/dist/media/decoders/webCodecsChunkDecoder.d.ts +99 -0
  87. package/dist/media/decoders/webCodecsChunkDecoder.d.ts.map +1 -0
  88. package/dist/media/decoders/webCodecsChunkDecoder.js +265 -0
  89. package/dist/media/decoders/webCodecsChunkDecoder.js.map +1 -0
  90. package/dist/media/displayCapture.d.ts +128 -0
  91. package/dist/media/displayCapture.d.ts.map +1 -0
  92. package/dist/media/displayCapture.js +245 -0
  93. package/dist/media/displayCapture.js.map +1 -0
  94. package/dist/media/frameCapture.d.ts +25 -8
  95. package/dist/media/frameCapture.d.ts.map +1 -1
  96. package/dist/media/frameCapture.js +42 -72
  97. package/dist/media/frameCapture.js.map +1 -1
  98. package/dist/media/frameSampler.d.ts +94 -0
  99. package/dist/media/frameSampler.d.ts.map +1 -0
  100. package/dist/media/frameSampler.js +134 -0
  101. package/dist/media/frameSampler.js.map +1 -0
  102. package/dist/media/index.d.ts +32 -0
  103. package/dist/media/index.d.ts.map +1 -0
  104. package/dist/media/index.js +32 -0
  105. package/dist/media/index.js.map +1 -0
  106. package/dist/media/localMediaController.d.ts +116 -0
  107. package/dist/media/localMediaController.d.ts.map +1 -0
  108. package/dist/media/localMediaController.js +281 -0
  109. package/dist/media/localMediaController.js.map +1 -0
  110. package/dist/media/mediaLayout.d.ts +93 -0
  111. package/dist/media/mediaLayout.d.ts.map +1 -0
  112. package/dist/media/mediaLayout.js +187 -0
  113. package/dist/media/mediaLayout.js.map +1 -0
  114. package/dist/media/mediaPreview.d.ts +94 -0
  115. package/dist/media/mediaPreview.d.ts.map +1 -0
  116. package/dist/media/mediaPreview.js +154 -0
  117. package/dist/media/mediaPreview.js.map +1 -0
  118. package/dist/media/mediaStage.d.ts +99 -0
  119. package/dist/media/mediaStage.d.ts.map +1 -0
  120. package/dist/media/mediaStage.js +171 -0
  121. package/dist/media/mediaStage.js.map +1 -0
  122. package/dist/media/model.d.ts +154 -0
  123. package/dist/media/model.d.ts.map +1 -0
  124. package/dist/media/model.js +9 -0
  125. package/dist/media/model.js.map +1 -0
  126. package/dist/media/playbackClock.d.ts +20 -0
  127. package/dist/media/playbackClock.d.ts.map +1 -0
  128. package/dist/media/playbackClock.js +13 -0
  129. package/dist/media/playbackClock.js.map +1 -0
  130. package/dist/media/videoFrameDecoder.d.ts +86 -0
  131. package/dist/media/videoFrameDecoder.d.ts.map +1 -0
  132. package/dist/media/videoFrameDecoder.js +2 -0
  133. package/dist/media/videoFrameDecoder.js.map +1 -0
  134. package/dist/media/videoFrameDecoderRegistry.d.ts +40 -0
  135. package/dist/media/videoFrameDecoderRegistry.d.ts.map +1 -0
  136. package/dist/media/videoFrameDecoderRegistry.js +69 -0
  137. package/dist/media/videoFrameDecoderRegistry.js.map +1 -0
  138. package/dist/media/videoPacing.d.ts +32 -0
  139. package/dist/media/videoPacing.d.ts.map +1 -0
  140. package/dist/media/videoPacing.js +37 -0
  141. package/dist/media/videoPacing.js.map +1 -0
  142. package/dist/media/videoPlayout.d.ts +168 -0
  143. package/dist/media/videoPlayout.d.ts.map +1 -0
  144. package/dist/media/videoPlayout.js +217 -0
  145. package/dist/media/videoPlayout.js.map +1 -0
  146. package/dist/media/videoSourceArbiter.d.ts +250 -0
  147. package/dist/media/videoSourceArbiter.d.ts.map +1 -0
  148. package/dist/media/videoSourceArbiter.js +423 -0
  149. package/dist/media/videoSourceArbiter.js.map +1 -0
  150. package/dist/testing/conformanceAssertions.d.ts +25 -0
  151. package/dist/testing/conformanceAssertions.d.ts.map +1 -0
  152. package/dist/testing/conformanceAssertions.js +64 -0
  153. package/dist/testing/conformanceAssertions.js.map +1 -0
  154. package/dist/testing/conformanceFixtures.d.ts +76 -0
  155. package/dist/testing/conformanceFixtures.d.ts.map +1 -0
  156. package/dist/testing/conformanceFixtures.js +169 -0
  157. package/dist/testing/conformanceFixtures.js.map +1 -0
  158. package/dist/testing/conformanceGates.d.ts +32 -0
  159. package/dist/testing/conformanceGates.d.ts.map +1 -0
  160. package/dist/testing/conformanceGates.js +35 -0
  161. package/dist/testing/conformanceGates.js.map +1 -0
  162. package/dist/testing/conformanceMicrophone.d.ts +10 -0
  163. package/dist/testing/conformanceMicrophone.d.ts.map +1 -0
  164. package/dist/testing/conformanceMicrophone.js +71 -0
  165. package/dist/testing/conformanceMicrophone.js.map +1 -0
  166. package/dist/testing/conformanceTimeline.d.ts +128 -0
  167. package/dist/testing/conformanceTimeline.d.ts.map +1 -0
  168. package/dist/testing/conformanceTimeline.js +32 -0
  169. package/dist/testing/conformanceTimeline.js.map +1 -0
  170. package/dist/testing/conformanceVideoStream.d.ts +29 -0
  171. package/dist/testing/conformanceVideoStream.d.ts.map +1 -0
  172. package/dist/testing/conformanceVideoStream.js +39 -0
  173. package/dist/testing/conformanceVideoStream.js.map +1 -0
  174. package/dist/testing/index.d.ts +29 -0
  175. package/dist/testing/index.d.ts.map +1 -0
  176. package/dist/testing/index.js +28 -0
  177. package/dist/testing/index.js.map +1 -0
  178. package/dist/testing/realtimeVideoConformance.d.ts +23 -0
  179. package/dist/testing/realtimeVideoConformance.d.ts.map +1 -0
  180. package/dist/testing/realtimeVideoConformance.js +139 -0
  181. package/dist/testing/realtimeVideoConformance.js.map +1 -0
  182. package/dist/testing/realtimeVideoConformanceChecks.d.ts +4 -0
  183. package/dist/testing/realtimeVideoConformanceChecks.d.ts.map +1 -0
  184. package/dist/testing/realtimeVideoConformanceChecks.js +164 -0
  185. package/dist/testing/realtimeVideoConformanceChecks.js.map +1 -0
  186. package/dist/testing/realtimeVideoConformanceFrameChecks.d.ts +4 -0
  187. package/dist/testing/realtimeVideoConformanceFrameChecks.d.ts.map +1 -0
  188. package/dist/testing/realtimeVideoConformanceFrameChecks.js +63 -0
  189. package/dist/testing/realtimeVideoConformanceFrameChecks.js.map +1 -0
  190. package/dist/testing/realtimeVideoConformanceSession.d.ts +108 -0
  191. package/dist/testing/realtimeVideoConformanceSession.d.ts.map +1 -0
  192. package/dist/testing/realtimeVideoConformanceSession.js +270 -0
  193. package/dist/testing/realtimeVideoConformanceSession.js.map +1 -0
  194. package/dist/testing/realtimeVideoConformanceTurnChecks.d.ts +4 -0
  195. package/dist/testing/realtimeVideoConformanceTurnChecks.d.ts.map +1 -0
  196. package/dist/testing/realtimeVideoConformanceTurnChecks.js +248 -0
  197. package/dist/testing/realtimeVideoConformanceTurnChecks.js.map +1 -0
  198. package/dist/testing/realtimeVideoConformanceTypes.d.ts +155 -0
  199. package/dist/testing/realtimeVideoConformanceTypes.d.ts.map +1 -0
  200. package/dist/testing/realtimeVideoConformanceTypes.js +2 -0
  201. package/dist/testing/realtimeVideoConformanceTypes.js.map +1 -0
  202. package/dist/testing/recordingPlayout.d.ts +84 -0
  203. package/dist/testing/recordingPlayout.d.ts.map +1 -0
  204. package/dist/testing/recordingPlayout.js +120 -0
  205. package/dist/testing/recordingPlayout.js.map +1 -0
  206. package/package.json +29 -4
@@ -0,0 +1,164 @@
1
+ /**
2
+ * @fileoverview Checks VC01-VC07: what a session hands the host and where the model's parts go. An audio-only session
3
+ * shows no video and still plays the voice; a granted avatar is handed over once, or not at all when the host doesn't
4
+ * show it or the browser can't play it; video goes to its player in order and never to the voice; a part of an unknown
5
+ * type goes nowhere and is reported once.
6
+ *
7
+ * @module @memberjunction/ai-realtime-client/testing
8
+ */
9
+ import { AssertCount, AssertSameBytes, AssertTrue, AssertValue } from './conformanceAssertions.js';
10
+ import { ConformanceFmp4InitSegment, ConformanceFmp4VideoFragment, ConformancePcm } from './conformanceFixtures.js';
11
+ import { AllOf, NeedsAgentVideo, NeedsGrant, NeedsHarnessMethod, NeedsPlayout, NoGate } from './conformanceGates.js';
12
+ import { WithConformanceSession } from './realtimeVideoConformanceSession.js';
13
+ /** The MIME type of a part no realtime driver plays. */
14
+ const UNKNOWN_PART_TYPE = 'application/x-unknown';
15
+ const VC01 = {
16
+ Id: 'VC01',
17
+ Title: 'An audio-only session hands over no agent video and still works',
18
+ Gate: NoGate,
19
+ Run: (harness) => WithConformanceSession(harness, { Grant: { Avatar: false } }, async (s) => {
20
+ AssertValue(s.LastState(), 'listening', 'an audio-only session listens after Connect');
21
+ AssertCount(s.Count('error'), 0, 'errors reported by an audio-only session');
22
+ assertAgentVideoTrackNotLive(s, 'unsupported');
23
+ await assertVoicePlays(s, ConformancePcm(1));
24
+ await harness.TurnComplete();
25
+ AssertCount(s.RemoteVideos().length, 0, 'agent video handed over in an audio-only session');
26
+ AssertCount(s.Players.length, 0, 'video players created in an audio-only session');
27
+ }),
28
+ };
29
+ const VC02 = {
30
+ Id: 'VC02',
31
+ Title: 'In an audio-only session, a video part never plays as audio',
32
+ Gate: NeedsHarnessMethod('SendPart'),
33
+ Run: (harness) => WithConformanceSession(harness, { Grant: { Avatar: false } }, async (s) => {
34
+ const mark = s.Timeline.Mark();
35
+ await harness.SendPart?.('video/mp4', ConformanceFmp4InitSegment());
36
+ await harness.SendPart?.('video/mp4', ConformanceFmp4VideoFragment());
37
+ AssertCount(s.Count('voice-enqueue', mark), 0, 'video/mp4 parts played as audio');
38
+ AssertCount(s.Players.length, 0, 'video players created in an audio-only session');
39
+ AssertCount(s.RemoteVideos().length, 0, 'agent video handed over in an audio-only session');
40
+ AssertCount(s.Warnings('video/mp4', mark), 1, 'warnings naming the dropped video/mp4 parts (once per type)');
41
+ }),
42
+ };
43
+ const VC03 = {
44
+ Id: 'VC03',
45
+ Title: 'A granted avatar is handed over once, and its track is live',
46
+ Gate: AllOf(NeedsAgentVideo, NeedsGrant),
47
+ Run: (harness) => WithConformanceSession(harness, { Grant: { Avatar: true } }, async (s) => {
48
+ AssertValue(s.OutboundVideoTrack()?.State ?? 'absent', 'live', 'the outbound video track of a granted avatar the host shows');
49
+ if (harness.AskedProviderForVideo) {
50
+ AssertValue(harness.AskedProviderForVideo(), true, 'the provider was asked for the avatar the host shows');
51
+ }
52
+ AssertTrue(s.RemoteVideos().length <= 1, 'the agent video is handed over once', `handed over ${s.RemoteVideos().length} times by Connect`);
53
+ await s.StartVideo();
54
+ await s.SendFrames(2);
55
+ await s.SendVoice(ConformancePcm(1));
56
+ await s.EndTurn();
57
+ AssertCount(s.RemoteVideos().length, 1, 'agent video hand-overs through a full turn');
58
+ assertHandedOverItsVideo(s);
59
+ }),
60
+ };
61
+ const VC04 = {
62
+ Id: 'VC04',
63
+ Title: "A granted avatar the host doesn't show stays audio only",
64
+ Gate: AllOf(NeedsAgentVideo, NeedsGrant),
65
+ Run: (harness) => WithConformanceSession(harness, { Grant: { Avatar: true }, ShowAgentVideo: false }, async (s) => {
66
+ assertAgentVideoTrackNotLive(s, null);
67
+ await assertVoicePlays(s, ConformancePcm(1));
68
+ AssertCount(s.RemoteVideos().length, 0, 'agent video handed over to a host that shows none');
69
+ assertNoPlayerKept(s);
70
+ assertAskedForAudioOnly(s);
71
+ }),
72
+ };
73
+ const VC05 = {
74
+ Id: 'VC05',
75
+ Title: "A granted avatar this browser can't play stays audio only",
76
+ Gate: AllOf(NeedsPlayout, NeedsGrant, NeedsHarnessMethod('RefusePlayback')),
77
+ Run: async (harness) => {
78
+ const undo = harness.RefusePlayback?.() ?? (() => undefined);
79
+ try {
80
+ await WithConformanceSession(harness, { Grant: { Avatar: true } }, async (s) => {
81
+ assertAgentVideoTrackNotLive(s, 'unsupported');
82
+ AssertCount(s.RemoteVideos().length, 0, "agent video handed over when the browser can't play it");
83
+ assertNoPlayerKept(s);
84
+ await assertVoicePlays(s, ConformancePcm(1));
85
+ assertAskedForAudioOnly(s);
86
+ });
87
+ }
88
+ finally {
89
+ undo();
90
+ }
91
+ },
92
+ };
93
+ const VC06 = {
94
+ Id: 'VC06',
95
+ Title: 'The avatar\'s video goes to its player in order, never to the voice',
96
+ Gate: AllOf(NeedsPlayout, NeedsGrant),
97
+ Run: (harness) => WithConformanceSession(harness, { Grant: { Avatar: true } }, async (s) => {
98
+ const mark = s.Timeline.Mark();
99
+ const sent = [await s.StartVideo(), ...(await s.SendFrames(3))];
100
+ AssertCount(s.Players.length, 1, 'video players created for one avatar');
101
+ const appended = s.AppendedFrames(0, mark).map((frame) => frame.Data);
102
+ AssertSameBytes(appended, sent.map((frame) => frame.Data), 'every frame of video reaches the player once, in order, unchanged');
103
+ AssertCount(s.Count('voice-enqueue', mark), 0, 'frames of video played as the voice');
104
+ }),
105
+ };
106
+ const VC07 = {
107
+ Id: 'VC07',
108
+ Title: 'A part of an unknown type is dropped and reported once',
109
+ Gate: AllOf(NeedsPlayout, NeedsGrant, NeedsHarnessMethod('SendPart')),
110
+ Run: (harness) => WithConformanceSession(harness, { Grant: { Avatar: true } }, async (s) => {
111
+ const mark = s.Timeline.Mark();
112
+ // Bytes with no format of their own, as PCM has none: the type the part names is all a driver has to go by.
113
+ await harness.SendPart?.(UNKNOWN_PART_TYPE, ConformancePcm(7));
114
+ await harness.SendPart?.(UNKNOWN_PART_TYPE, ConformancePcm(8));
115
+ AssertCount(s.Count('player-append', mark), 0, `${UNKNOWN_PART_TYPE} parts played as video`);
116
+ AssertCount(s.Count('voice-enqueue', mark), 0, `${UNKNOWN_PART_TYPE} parts played as the voice`);
117
+ AssertCount(s.Warnings(UNKNOWN_PART_TYPE, mark), 1, `warnings naming the dropped ${UNKNOWN_PART_TYPE} parts (once per type)`);
118
+ }),
119
+ };
120
+ /** VC01-VC07, in order. */
121
+ export const REALTIME_VIDEO_SESSION_CHECKS = [VC01, VC02, VC03, VC04, VC05, VC06, VC07];
122
+ /**
123
+ * The agent's video track is not live. A driver that negotiates tracks and was asked for it reports it `expected`
124
+ * (`'unsupported'`), so the host can say why; `null` accepts any state but live, or no track.
125
+ */
126
+ function assertAgentVideoTrackNotLive(s, expected) {
127
+ const state = s.OutboundVideoTrack()?.State ?? 'absent';
128
+ AssertTrue(state !== 'live', 'the outbound video track of a session that shows no avatar is not live', 'it is live');
129
+ if (expected !== null && s.Client.AllTracks.length > 0) {
130
+ AssertValue(state, expected, 'the requested outbound video track a driver negotiated and could not grant');
131
+ }
132
+ }
133
+ /** The model's voice plays: a PCM driver queues these bytes, and the client says the agent is audible. */
134
+ async function assertVoicePlays(s, pcm) {
135
+ const mark = s.Timeline.Mark();
136
+ await s.SendVoice(pcm);
137
+ if (s.Harness.Traits.Voice === 'pcm') {
138
+ AssertSameBytes(s.VoiceEnqueued(mark), [pcm], "the model's voice reaches the voice playback");
139
+ }
140
+ AssertValue(s.Client.IsAudioPlaying, true, "IsAudioPlaying while the model's voice plays");
141
+ }
142
+ /** The handed-over video is the driver's own: its player's source (playout), or a live stream. */
143
+ function assertHandedOverItsVideo(s) {
144
+ const video = s.RemoteVideos()[0];
145
+ if (s.Harness.Traits.AgentVideo === 'playout') {
146
+ AssertCount(s.Players.length, 1, 'video players created for one avatar');
147
+ AssertTrue(video === s.Players[0].Source, "the handed-over video is the player's video", `it is another '${video.Kind}' source`);
148
+ return;
149
+ }
150
+ AssertValue(video.Kind, 'stream', 'the kind of video a stream driver hands over');
151
+ AssertTrue(video.Kind === 'stream' && !!video.Stream, 'a stream driver hands over its stream', 'the stream is missing');
152
+ }
153
+ /** No video player outlives the connect: none was created, or each was released. */
154
+ function assertNoPlayerKept(s) {
155
+ const kept = s.Players.filter((player) => s.PlayerEvents('player-dispose', player.Index).length === 0);
156
+ AssertCount(kept.length, 0, 'video players kept by a session that shows no avatar');
157
+ }
158
+ /** When the harness can tell, the provider was asked for audio only: an avatar nobody sees is still generated and billed. */
159
+ function assertAskedForAudioOnly(s) {
160
+ if (s.Harness.AskedProviderForVideo) {
161
+ AssertValue(s.Harness.AskedProviderForVideo(), false, 'the provider was asked for video that nobody sees');
162
+ }
163
+ }
164
+ //# sourceMappingURL=realtimeVideoConformanceChecks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtimeVideoConformanceChecks.js","sourceRoot":"","sources":["../../src/testing/realtimeVideoConformanceChecks.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAChG,OAAO,EAAE,0BAA0B,EAAE,4BAA4B,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACjH,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAClH,OAAO,EAAE,sBAAsB,EAA2B,MAAM,mCAAmC,CAAC;AAGpG,wDAAwD;AACxD,MAAM,iBAAiB,GAAG,uBAAuB,CAAC;AAElD,MAAM,IAAI,GAAkC;IACxC,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,iEAAiE;IACxE,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,CACb,sBAAsB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACtE,WAAW,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,6CAA6C,CAAC,CAAC;QACvF,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,0CAA0C,CAAC,CAAC;QAC7E,4BAA4B,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;QAC/C,MAAM,gBAAgB,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC;QAC7B,WAAW,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,kDAAkD,CAAC,CAAC;QAC5F,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,gDAAgD,CAAC,CAAC;IACvF,CAAC,CAAC;CACT,CAAC;AAEF,MAAM,IAAI,GAAkC;IACxC,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,6DAA6D;IACpE,IAAI,EAAE,kBAAkB,CAAC,UAAU,CAAC;IACpC,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,CACb,sBAAsB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACtE,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,0BAA0B,EAAE,CAAC,CAAC;QACpE,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,4BAA4B,EAAE,CAAC,CAAC;QACtE,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,iCAAiC,CAAC,CAAC;QAClF,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,gDAAgD,CAAC,CAAC;QACnF,WAAW,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,kDAAkD,CAAC,CAAC;QAC5F,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,6DAA6D,CAAC,CAAC;IACjH,CAAC,CAAC;CACT,CAAC;AAEF,MAAM,IAAI,GAAkC;IACxC,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,6DAA6D;IACpE,IAAI,EAAE,KAAK,CAAC,eAAe,EAAE,UAAU,CAAC;IACxC,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,CACb,sBAAsB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACrE,WAAW,CAAC,CAAC,CAAC,kBAAkB,EAAE,EAAE,KAAK,IAAI,QAAQ,EAAE,MAAM,EAAE,6DAA6D,CAAC,CAAC;QAC9H,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC;YAChC,WAAW,CAAC,OAAO,CAAC,qBAAqB,EAAE,EAAE,IAAI,EAAE,sDAAsD,CAAC,CAAC;QAC/G,CAAC;QACD,UAAU,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,MAAM,IAAI,CAAC,EAAE,qCAAqC,EAAE,eAAe,CAAC,CAAC,YAAY,EAAE,CAAC,MAAM,mBAAmB,CAAC,CAAC;QAC3I,MAAM,CAAC,CAAC,UAAU,EAAE,CAAC;QACrB,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC;QAClB,WAAW,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,4CAA4C,CAAC,CAAC;QACtF,wBAAwB,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC,CAAC;CACT,CAAC;AAEF,MAAM,IAAI,GAAkC;IACxC,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,yDAAyD;IAChE,IAAI,EAAE,KAAK,CAAC,eAAe,EAAE,UAAU,CAAC;IACxC,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,CACb,sBAAsB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC5F,4BAA4B,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACtC,MAAM,gBAAgB,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7C,WAAW,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,mDAAmD,CAAC,CAAC;QAC7F,kBAAkB,CAAC,CAAC,CAAC,CAAC;QACtB,uBAAuB,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC,CAAC;CACT,CAAC;AAEF,MAAM,IAAI,GAAkC;IACxC,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,2DAA2D;IAClE,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,UAAU,EAAE,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;IAC3E,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACnB,MAAM,IAAI,GAAG,OAAO,CAAC,cAAc,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC7D,IAAI,CAAC;YACD,MAAM,sBAAsB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;gBAC3E,4BAA4B,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;gBAC/C,WAAW,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,wDAAwD,CAAC,CAAC;gBAClG,kBAAkB,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,gBAAgB,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC7C,uBAAuB,CAAC,CAAC,CAAC,CAAC;YAC/B,CAAC,CAAC,CAAC;QACP,CAAC;gBAAS,CAAC;YACP,IAAI,EAAE,CAAC;QACX,CAAC;IACL,CAAC;CACJ,CAAC;AAEF,MAAM,IAAI,GAAkC;IACxC,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,qEAAqE;IAC5E,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,UAAU,CAAC;IACrC,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,CACb,sBAAsB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACrE,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,sCAAsC,CAAC,CAAC;QACzE,MAAM,QAAQ,GAAG,CAAC,CAAC,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtE,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,mEAAmE,CAAC,CAAC;QAChI,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,qCAAqC,CAAC,CAAC;IAC1F,CAAC,CAAC;CACT,CAAC;AAEF,MAAM,IAAI,GAAkC;IACxC,EAAE,EAAE,MAAM;IACV,KAAK,EAAE,wDAAwD;IAC/D,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,UAAU,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAC;IACrE,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,CACb,sBAAsB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACrE,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC/B,4GAA4G;QAC5G,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,iBAAiB,wBAAwB,CAAC,CAAC;QAC7F,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,iBAAiB,4BAA4B,CAAC,CAAC;QACjG,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,+BAA+B,iBAAiB,wBAAwB,CAAC,CAAC;IAClI,CAAC,CAAC;CACT,CAAC;AAEF,2BAA2B;AAC3B,MAAM,CAAC,MAAM,6BAA6B,GAA6C,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAElI;;;GAGG;AACH,SAAS,4BAA4B,CAAC,CAAqB,EAAE,QAA8B;IACvF,MAAM,KAAK,GAAG,CAAC,CAAC,kBAAkB,EAAE,EAAE,KAAK,IAAI,QAAQ,CAAC;IACxD,UAAU,CAAC,KAAK,KAAK,MAAM,EAAE,wEAAwE,EAAE,YAAY,CAAC,CAAC;IACrH,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrD,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,4EAA4E,CAAC,CAAC;IAC/G,CAAC;AACL,CAAC;AAED,0GAA0G;AAC1G,KAAK,UAAU,gBAAgB,CAAC,CAAqB,EAAE,GAAgB;IACnE,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/B,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACvB,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QACnC,eAAe,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,8CAA8C,CAAC,CAAC;IAClG,CAAC;IACD,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,IAAI,EAAE,8CAA8C,CAAC,CAAC;AAC/F,CAAC;AAED,kGAAkG;AAClG,SAAS,wBAAwB,CAAC,CAAqB;IACnD,MAAM,KAAK,GAAG,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;IAClC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QAC5C,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,sCAAsC,CAAC,CAAC;QACzE,UAAU,CAAC,KAAK,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,6CAA6C,EAAE,kBAAkB,KAAK,CAAC,IAAI,UAAU,CAAC,CAAC;QACjI,OAAO;IACX,CAAC;IACD,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,8CAA8C,CAAC,CAAC;IAClF,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,uCAAuC,EAAE,uBAAuB,CAAC,CAAC;AAC5H,CAAC;AAED,oFAAoF;AACpF,SAAS,kBAAkB,CAAC,CAAqB;IAC7C,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;IACvG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,sDAAsD,CAAC,CAAC;AACxF,CAAC;AAED,6HAA6H;AAC7H,SAAS,uBAAuB,CAAC,CAAqB;IAClD,IAAI,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC;QAClC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,mDAAmD,CAAC,CAAC;IAC/G,CAAC;AACL,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { RealtimeVideoConformanceCheck } from './realtimeVideoConformanceTypes.js';
2
+ /** VF01-VF02, in order. */
3
+ export declare const REALTIME_VIDEO_FRAME_CHECKS: readonly RealtimeVideoConformanceCheck[];
4
+ //# sourceMappingURL=realtimeVideoConformanceFrameChecks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtimeVideoConformanceFrameChecks.d.ts","sourceRoot":"","sources":["../../src/testing/realtimeVideoConformanceFrameChecks.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAsCrF,2BAA2B;AAC3B,eAAO,MAAM,2BAA2B,EAAE,SAAS,6BAA6B,EAAiB,CAAC"}
@@ -0,0 +1,63 @@
1
+ import { AssertCount, AssertSameBytes, AssertTrue, AssertValue, Fail } from './conformanceAssertions.js';
2
+ import { ConformancePcm } from './conformanceFixtures.js';
3
+ import { AllOf, NeedsGrant, NeedsPlayout, NeedsTimedVoice } from './conformanceGates.js';
4
+ import { WithConformanceSession } from './realtimeVideoConformanceSession.js';
5
+ /** A granted avatar whose voice comes separately, as PCM: the case a clock is for. */
6
+ const SEPARATE_VOICE = { Grant: { Avatar: true, VideoCarriesVoice: false } };
7
+ const VF01 = {
8
+ Id: 'VF01',
9
+ Title: 'Frames reach the player typed, as the model sent them',
10
+ Gate: AllOf(NeedsPlayout, NeedsGrant),
11
+ Run: (harness) => WithConformanceSession(harness, { Grant: { Avatar: true } }, async (s) => {
12
+ const mark = s.Timeline.Mark();
13
+ const sent = [await s.StartVideo(), ...(await s.SendFrames(3))];
14
+ const appended = s.AppendedFrames(0, mark);
15
+ AssertSameBytes(appended.map((frame) => frame.Data), sent.map((frame) => frame.Data), "the frames' bytes, in the order the model sent them");
16
+ sent.forEach((frame, index) => assertSameFrame(appended[index], frame, index + 1));
17
+ }),
18
+ };
19
+ const VF02 = {
20
+ Id: 'VF02',
21
+ Title: "A timed voice drives the video's clock",
22
+ Gate: AllOf(NeedsPlayout, NeedsGrant, NeedsTimedVoice),
23
+ Run: (harness) => WithConformanceSession(harness, SEPARATE_VOICE, async (s) => {
24
+ const mark = s.Timeline.Mark();
25
+ const times = [await s.SendVoice(ConformancePcm(1))];
26
+ const frames = [await s.StartVideo()];
27
+ times.push(await s.SendVoice(ConformancePcm(2)));
28
+ frames.push(...(await s.SendFrames(2)));
29
+ AssertCount(s.Players.length, 1, 'video players created for one avatar');
30
+ AssertTrue(s.Players[0].Options.Clock === s.Voice, "the video player's clock is the voice's playback", 'the player was created with another clock, or none');
31
+ const queued = s.Timeline.Of('voice-enqueue', mark).map((event) => event.MediaTimeMs);
32
+ AssertValue(JSON.stringify(queued), JSON.stringify(times), "the media times the voice was queued at (the model's)");
33
+ assertFramesOnTheVoicesTimeline(s, mark, frames);
34
+ }),
35
+ };
36
+ /** VF01-VF02, in order. */
37
+ export const REALTIME_VIDEO_FRAME_CHECKS = [VF01, VF02];
38
+ /** A frame the player got is the frame the model sent: its kind and type, and the fields its kind has. */
39
+ function assertSameFrame(actual, expected, position) {
40
+ if (!actual) {
41
+ Fail(`frame ${position}`, 'the player never got it');
42
+ }
43
+ AssertValue(actual.Kind, expected.Kind, `frame ${position}'s kind`);
44
+ AssertValue(actual.MimeType, expected.MimeType, `frame ${position}'s MIME type`);
45
+ if (actual.Kind === 'fmp4' && expected.Kind === 'fmp4') {
46
+ AssertValue(actual.Piece, expected.Piece, `fMP4 frame ${position}'s piece (init or fragment, by its first box)`);
47
+ }
48
+ if (expected.Kind !== 'fmp4') {
49
+ AssertValue(String(actual.PresentationTimeMs), String(expected.PresentationTimeMs), `frame ${position}'s presentation time (ms)`);
50
+ AssertValue(actual.KeyFrame ?? null, expected.KeyFrame ?? null, `frame ${position}'s key-frame flag`);
51
+ }
52
+ }
53
+ /** The frames the player got keep the model's presentation times: the timeline the voice was queued on. */
54
+ function assertFramesOnTheVoicesTimeline(s, mark, sent) {
55
+ const appended = s.AppendedFrames(0, mark);
56
+ AssertCount(appended.length, sent.length, 'frames given to the player');
57
+ sent.forEach((frame, index) => {
58
+ if (frame.Kind !== 'fmp4') {
59
+ AssertValue(String(appended[index].PresentationTimeMs), String(frame.PresentationTimeMs), `frame ${index + 1}'s presentation time on the voice's timeline (ms)`);
60
+ }
61
+ });
62
+ }
63
+ //# sourceMappingURL=realtimeVideoConformanceFrameChecks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtimeVideoConformanceFrameChecks.js","sourceRoot":"","sources":["../../src/testing/realtimeVideoConformanceFrameChecks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @fileoverview One conformance session: the harness's client connected with the kit's recorders, the host's track
3
+ * request, every event the client emits, and the warnings and info lines logged meanwhile, all on one timeline. A check
4
+ * drives the model's side through it and reads the timeline back.
5
+ *
6
+ * @module @memberjunction/ai-realtime-client/testing
7
+ */
8
+ import { type ClientRealtimeSessionConfig, type RealtimeTrack, type RealtimeVideoFrame } from '@memberjunction/ai';
9
+ import { BaseRealtimeClient, type RealtimeClientState } from '../generic/baseRealtimeClient.js';
10
+ import type { MediaVideoSource } from '../media/model.js';
11
+ import { RealtimeVideoConformanceTimeline, type RealtimeVideoConformanceEventKind, type RealtimeVideoConformanceEventOf } from './conformanceTimeline.js';
12
+ import { ConformanceVideoStream } from './conformanceVideoStream.js';
13
+ import { RecordingPcmPlayback, RecordingVideoPlayout } from './recordingPlayout.js';
14
+ import type { IRealtimeVideoConformanceHarness, RealtimeVideoConformanceGrant } from './realtimeVideoConformanceTypes.js';
15
+ /** What a session starts with. */
16
+ export interface ConformanceSessionSetup {
17
+ /** What the provider's server grants. */
18
+ Grant: RealtimeVideoConformanceGrant;
19
+ /** Whether the host shows the agent's video: its Avatar channel asks for the outbound video track. Default `true`. */
20
+ ShowAgentVideo?: boolean;
21
+ }
22
+ /** One connected session of a check, recorded on one timeline. */
23
+ export declare class ConformanceSession {
24
+ readonly Harness: IRealtimeVideoConformanceHarness;
25
+ readonly Setup: ConformanceSessionSetup;
26
+ readonly Timeline: RealtimeVideoConformanceTimeline;
27
+ readonly Microphone: MediaStream;
28
+ readonly Voice: RecordingPcmPlayback;
29
+ /** The video the model sends, in the provider's form. */
30
+ readonly Video: ConformanceVideoStream;
31
+ private readonly players;
32
+ private client;
33
+ private disconnected;
34
+ constructor(Harness: IRealtimeVideoConformanceHarness, Setup: ConformanceSessionSetup);
35
+ /** The video players the driver created, in order. */
36
+ get Players(): readonly RecordingVideoPlayout[];
37
+ /** The connected client. */
38
+ get Client(): BaseRealtimeClient;
39
+ /** Whether the avatar's video carries the voice: as the grant says, else whenever the provider's video can. */
40
+ get VideoCarriesVoice(): boolean;
41
+ /** Mints, adds the host's track request, creates the client with the recorders, observes it, and connects. */
42
+ Start(): Promise<void>;
43
+ /** Disconnects the client, as the host does when the call ends. */
44
+ Disconnect(): Promise<void>;
45
+ /** Ends the session after the check: disconnects the client if the check didn't. Never throws. */
46
+ Close(): Promise<void>;
47
+ /**
48
+ * The model starts its video: an fMP4 init segment (with the voice's audio track when the video carries it), or the
49
+ * first chunk (a key frame) or image. Returns the frame sent.
50
+ */
51
+ StartVideo(): Promise<RealtimeVideoFrame>;
52
+ /** The model sends the stream's next `count` video frames. Returns them. */
53
+ SendFrames(count: number): Promise<RealtimeVideoFrame[]>;
54
+ /**
55
+ * The model sends a chunk of its voice: timed at the video's next frame when the provider keeps one timeline
56
+ * (`TimedVoice`), else untimed. Returns the media time sent, or `undefined`.
57
+ */
58
+ SendVoice(pcm16: ArrayBuffer): Promise<number | undefined>;
59
+ /** The model ends its turn: generation complete when the harness has it, then turn complete. */
60
+ EndTurn(): Promise<void>;
61
+ /** Models the agent's media playing out: every video player and the voice reach the end of what they were given. */
62
+ FinishPlaying(): void;
63
+ /** The states the client reported, from a mark on. */
64
+ States(since?: number): RealtimeClientState[];
65
+ /** How many events of a kind happened from a mark on. */
66
+ Count(kind: RealtimeVideoConformanceEventKind, since?: number): number;
67
+ /** The events of a kind that one player recorded, from a mark on. */
68
+ PlayerEvents<K extends 'player-append' | 'player-end-of-turn' | 'player-flush' | 'player-dispose'>(kind: K, player: number, since?: number): RealtimeVideoConformanceEventOf<K>[];
69
+ /** The frames one player was given, from a mark on. */
70
+ AppendedFrames(player: number, since?: number): RealtimeVideoFrame[];
71
+ /** The agent's video the client handed over, from a mark on. */
72
+ RemoteVideos(since?: number): MediaVideoSource[];
73
+ /** The PCM the driver queued, from a mark on. */
74
+ VoiceEnqueued(since?: number): ArrayBuffer[];
75
+ /** The last state the client reported, or `null`. */
76
+ LastState(): RealtimeClientState | null;
77
+ /** The agent's video track (outbound video), as the client reports it now; `undefined` when it has none. */
78
+ OutboundVideoTrack(): RealtimeTrack | undefined;
79
+ /** The seconds of generated video the client reported (`OutputTokenDetails.VideoSeconds`), from a mark on. */
80
+ VideoSeconds(since?: number): number;
81
+ /** How many usage updates carried video seconds, from a mark on. */
82
+ VideoSecondsReports(since?: number): number;
83
+ /** How many warnings mention `text`, from a mark on. */
84
+ Warnings(text: string, since?: number): number;
85
+ /** The warning and info lines logged so far, for a failure's message. */
86
+ LoggedLines(): string[];
87
+ /** What the harness wires into the driver: the microphone, the voice recorder, and a recorder per player. */
88
+ private media;
89
+ /** Registers the kit's handlers: every emission goes on the timeline. */
90
+ private observe;
91
+ }
92
+ /**
93
+ * Runs `body` on a started session with the console captured onto its timeline, then disconnects the client (if `body`
94
+ * didn't) and restores the console, failed or not. A failure's message gains the lines logged during the session.
95
+ */
96
+ export declare function WithConformanceSession(harness: IRealtimeVideoConformanceHarness, setup: ConformanceSessionSetup, body: (session: ConformanceSession) => Promise<void>): Promise<void>;
97
+ /**
98
+ * The config with the host's track request added, as the realtime runtime builds it when a channel shows the agent's
99
+ * video: the audio floor, what the mint requested, and the agent's outbound video, one each. Unchanged when the host
100
+ * shows no agent video.
101
+ */
102
+ export declare function WithHostTrackRequest(config: ClientRealtimeSessionConfig, showAgentVideo: boolean): ClientRealtimeSessionConfig;
103
+ /**
104
+ * Sends `console.warn` and `console.info` to the timeline instead of the output, for "reported once" and quiet test
105
+ * output. Returns the function that restores them.
106
+ */
107
+ export declare function CaptureConsole(timeline: RealtimeVideoConformanceTimeline): () => void;
108
+ //# sourceMappingURL=realtimeVideoConformanceSession.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtimeVideoConformanceSession.d.ts","sourceRoot":"","sources":["../../src/testing/realtimeVideoConformanceSession.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAEH,KAAK,2BAA2B,EAGhC,KAAK,aAAa,EAClB,KAAK,kBAAkB,EAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAgC,KAAK,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAC3H,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAIvD,OAAO,EACH,gCAAgC,EAEhC,KAAK,iCAAiC,EACtC,KAAK,+BAA+B,EACvC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,KAAK,EAAE,gCAAgC,EAAE,6BAA6B,EAAiC,MAAM,iCAAiC,CAAC;AAKtJ,kCAAkC;AAClC,MAAM,WAAW,uBAAuB;IACpC,yCAAyC;IACzC,KAAK,EAAE,6BAA6B,CAAC;IACrC,sHAAsH;IACtH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,kEAAkE;AAClE,qBAAa,kBAAkB;aAUC,OAAO,EAAE,gCAAgC;aAAkB,KAAK,EAAE,uBAAuB;IATrH,SAAgB,QAAQ,mCAA0C;IAClE,SAAgB,UAAU,EAAE,WAAW,CAAiC;IACxE,SAAgB,KAAK,EAAE,oBAAoB,CAAC;IAC5C,yDAAyD;IACzD,SAAgB,KAAK,EAAE,sBAAsB,CAAC;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,YAAY,CAAS;gBAED,OAAO,EAAE,gCAAgC,EAAkB,KAAK,EAAE,uBAAuB;IAKrH,sDAAsD;IACtD,IAAW,OAAO,IAAI,SAAS,qBAAqB,EAAE,CAErD;IAED,4BAA4B;IAC5B,IAAW,MAAM,IAAI,kBAAkB,CAKtC;IAED,+GAA+G;IAC/G,IAAW,iBAAiB,IAAI,OAAO,CAEtC;IAED,8GAA8G;IACjG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYnC,mEAAmE;IACtD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAKxC,kGAAkG;IACrF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAanC;;;OAGG;IACU,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAMtD,4EAA4E;IAC/D,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAQrE;;;OAGG;IACU,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAMvE,gGAAgG;IACnF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAKrC,oHAAoH;IAC7G,aAAa,IAAI,IAAI;IAS5B,sDAAsD;IAC/C,MAAM,CAAC,KAAK,GAAE,MAAU,GAAG,mBAAmB,EAAE;IAIvD,yDAAyD;IAClD,KAAK,CAAC,IAAI,EAAE,iCAAiC,EAAE,KAAK,GAAE,MAAU,GAAG,MAAM;IAIhF,qEAAqE;IAC9D,YAAY,CAAC,CAAC,SAAS,eAAe,GAAG,oBAAoB,GAAG,cAAc,GAAG,gBAAgB,EACpG,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAAU,GAClB,+BAA+B,CAAC,CAAC,CAAC,EAAE;IAIvC,uDAAuD;IAChD,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,kBAAkB,EAAE;IAI9E,gEAAgE;IACzD,YAAY,CAAC,KAAK,GAAE,MAAU,GAAG,gBAAgB,EAAE;IAI1D,iDAAiD;IAC1C,aAAa,CAAC,KAAK,GAAE,MAAU,GAAG,WAAW,EAAE;IAItD,qDAAqD;IAC9C,SAAS,IAAI,mBAAmB,GAAG,IAAI;IAI9C,4GAA4G;IACrG,kBAAkB,IAAI,aAAa,GAAG,SAAS;IAItD,8GAA8G;IACvG,YAAY,CAAC,KAAK,GAAE,MAAU,GAAG,MAAM;IAI9C,oEAAoE;IAC7D,mBAAmB,CAAC,KAAK,GAAE,MAAU,GAAG,MAAM;IAIrD,wDAAwD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,MAAM;IAIxD,yEAAyE;IAClE,WAAW,IAAI,MAAM,EAAE;IAM9B,6GAA6G;IAC7G,OAAO,CAAC,KAAK;IAYb,yEAAyE;IACzE,OAAO,CAAC,OAAO;CAQlB;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CACxC,OAAO,EAAE,gCAAgC,EACzC,KAAK,EAAE,uBAAuB,EAC9B,IAAI,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,GACrD,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,2BAA2B,EAAE,cAAc,EAAE,OAAO,GAAG,2BAA2B,CAc9H;AAkBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,gCAAgC,GAAG,MAAM,IAAI,CAUrF"}