@memberjunction/ai-realtime-client 6.2.0-edge.3 → 6.2.0-edge.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) 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 +99 -0
  33. package/dist/drivers/geminiEnterpriseRealtimeClient.js.map +1 -0
  34. package/dist/drivers/geminiRealtimeClient.d.ts +325 -50
  35. package/dist/drivers/geminiRealtimeClient.d.ts.map +1 -1
  36. package/dist/drivers/geminiRealtimeClient.js +782 -184
  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 +13 -26
  43. package/dist/drivers/openAIRealtimeClient.d.ts.map +1 -1
  44. package/dist/drivers/openAIRealtimeClient.js +28 -55
  45. package/dist/drivers/openAIRealtimeClient.js.map +1 -1
  46. package/dist/drivers/xaiRealtimeClient.d.ts.map +1 -1
  47. package/dist/drivers/xaiRealtimeClient.js +19 -14
  48. package/dist/drivers/xaiRealtimeClient.js.map +1 -1
  49. package/dist/generic/baseRealtimeClient.d.ts +183 -29
  50. package/dist/generic/baseRealtimeClient.d.ts.map +1 -1
  51. package/dist/generic/baseRealtimeClient.js +246 -14
  52. package/dist/generic/baseRealtimeClient.js.map +1 -1
  53. package/dist/generic/openAIProtocolClient.d.ts +2 -0
  54. package/dist/generic/openAIProtocolClient.d.ts.map +1 -1
  55. package/dist/generic/openAIProtocolClient.js +17 -0
  56. package/dist/generic/openAIProtocolClient.js.map +1 -1
  57. package/dist/index.d.ts +2 -3
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +3 -3
  60. package/dist/index.js.map +1 -1
  61. package/dist/media/attachVideoSource.d.ts +23 -0
  62. package/dist/media/attachVideoSource.d.ts.map +1 -0
  63. package/dist/media/attachVideoSource.js +49 -0
  64. package/dist/media/attachVideoSource.js.map +1 -0
  65. package/dist/media/channelVideoSource.d.ts +110 -14
  66. package/dist/media/channelVideoSource.d.ts.map +1 -1
  67. package/dist/media/channelVideoSource.js +183 -18
  68. package/dist/media/channelVideoSource.js.map +1 -1
  69. package/dist/media/decoders/frameScheduler.d.ts +119 -0
  70. package/dist/media/decoders/frameScheduler.d.ts.map +1 -0
  71. package/dist/media/decoders/frameScheduler.js +238 -0
  72. package/dist/media/decoders/frameScheduler.js.map +1 -0
  73. package/dist/media/decoders/imageFrameDecoder.d.ts +58 -0
  74. package/dist/media/decoders/imageFrameDecoder.d.ts.map +1 -0
  75. package/dist/media/decoders/imageFrameDecoder.js +110 -0
  76. package/dist/media/decoders/imageFrameDecoder.js.map +1 -0
  77. package/dist/media/decoders/mseFmp4Decoder.d.ts +130 -0
  78. package/dist/media/decoders/mseFmp4Decoder.d.ts.map +1 -0
  79. package/dist/media/decoders/mseFmp4Decoder.js +402 -0
  80. package/dist/media/decoders/mseFmp4Decoder.js.map +1 -0
  81. package/dist/media/decoders/streamCanvas.d.ts +46 -0
  82. package/dist/media/decoders/streamCanvas.d.ts.map +1 -0
  83. package/dist/media/decoders/streamCanvas.js +163 -0
  84. package/dist/media/decoders/streamCanvas.js.map +1 -0
  85. package/dist/media/decoders/videoMimeTypes.d.ts +29 -0
  86. package/dist/media/decoders/videoMimeTypes.d.ts.map +1 -0
  87. package/dist/media/decoders/videoMimeTypes.js +50 -0
  88. package/dist/media/decoders/videoMimeTypes.js.map +1 -0
  89. package/dist/media/decoders/webCodecsChunkDecoder.d.ts +99 -0
  90. package/dist/media/decoders/webCodecsChunkDecoder.d.ts.map +1 -0
  91. package/dist/media/decoders/webCodecsChunkDecoder.js +265 -0
  92. package/dist/media/decoders/webCodecsChunkDecoder.js.map +1 -0
  93. package/dist/media/displayCapture.d.ts +128 -0
  94. package/dist/media/displayCapture.d.ts.map +1 -0
  95. package/dist/media/displayCapture.js +245 -0
  96. package/dist/media/displayCapture.js.map +1 -0
  97. package/dist/media/frameCapture.d.ts +25 -8
  98. package/dist/media/frameCapture.d.ts.map +1 -1
  99. package/dist/media/frameCapture.js +42 -72
  100. package/dist/media/frameCapture.js.map +1 -1
  101. package/dist/media/frameSampler.d.ts +94 -0
  102. package/dist/media/frameSampler.d.ts.map +1 -0
  103. package/dist/media/frameSampler.js +134 -0
  104. package/dist/media/frameSampler.js.map +1 -0
  105. package/dist/media/index.d.ts +32 -0
  106. package/dist/media/index.d.ts.map +1 -0
  107. package/dist/media/index.js +32 -0
  108. package/dist/media/index.js.map +1 -0
  109. package/dist/media/localMediaController.d.ts +116 -0
  110. package/dist/media/localMediaController.d.ts.map +1 -0
  111. package/dist/media/localMediaController.js +281 -0
  112. package/dist/media/localMediaController.js.map +1 -0
  113. package/dist/media/mediaLayout.d.ts +93 -0
  114. package/dist/media/mediaLayout.d.ts.map +1 -0
  115. package/dist/media/mediaLayout.js +187 -0
  116. package/dist/media/mediaLayout.js.map +1 -0
  117. package/dist/media/mediaPreview.d.ts +94 -0
  118. package/dist/media/mediaPreview.d.ts.map +1 -0
  119. package/dist/media/mediaPreview.js +154 -0
  120. package/dist/media/mediaPreview.js.map +1 -0
  121. package/dist/media/mediaStage.d.ts +99 -0
  122. package/dist/media/mediaStage.d.ts.map +1 -0
  123. package/dist/media/mediaStage.js +171 -0
  124. package/dist/media/mediaStage.js.map +1 -0
  125. package/dist/media/model.d.ts +154 -0
  126. package/dist/media/model.d.ts.map +1 -0
  127. package/dist/media/model.js +9 -0
  128. package/dist/media/model.js.map +1 -0
  129. package/dist/media/playbackClock.d.ts +20 -0
  130. package/dist/media/playbackClock.d.ts.map +1 -0
  131. package/dist/media/playbackClock.js +13 -0
  132. package/dist/media/playbackClock.js.map +1 -0
  133. package/dist/media/videoFrameDecoder.d.ts +86 -0
  134. package/dist/media/videoFrameDecoder.d.ts.map +1 -0
  135. package/dist/media/videoFrameDecoder.js +2 -0
  136. package/dist/media/videoFrameDecoder.js.map +1 -0
  137. package/dist/media/videoFrameDecoderRegistry.d.ts +40 -0
  138. package/dist/media/videoFrameDecoderRegistry.d.ts.map +1 -0
  139. package/dist/media/videoFrameDecoderRegistry.js +69 -0
  140. package/dist/media/videoFrameDecoderRegistry.js.map +1 -0
  141. package/dist/media/videoPacing.d.ts +32 -0
  142. package/dist/media/videoPacing.d.ts.map +1 -0
  143. package/dist/media/videoPacing.js +37 -0
  144. package/dist/media/videoPacing.js.map +1 -0
  145. package/dist/media/videoPlayout.d.ts +168 -0
  146. package/dist/media/videoPlayout.d.ts.map +1 -0
  147. package/dist/media/videoPlayout.js +217 -0
  148. package/dist/media/videoPlayout.js.map +1 -0
  149. package/dist/media/videoSourceArbiter.d.ts +250 -0
  150. package/dist/media/videoSourceArbiter.d.ts.map +1 -0
  151. package/dist/media/videoSourceArbiter.js +423 -0
  152. package/dist/media/videoSourceArbiter.js.map +1 -0
  153. package/dist/testing/conformanceAssertions.d.ts +25 -0
  154. package/dist/testing/conformanceAssertions.d.ts.map +1 -0
  155. package/dist/testing/conformanceAssertions.js +64 -0
  156. package/dist/testing/conformanceAssertions.js.map +1 -0
  157. package/dist/testing/conformanceFixtures.d.ts +76 -0
  158. package/dist/testing/conformanceFixtures.d.ts.map +1 -0
  159. package/dist/testing/conformanceFixtures.js +169 -0
  160. package/dist/testing/conformanceFixtures.js.map +1 -0
  161. package/dist/testing/conformanceGates.d.ts +32 -0
  162. package/dist/testing/conformanceGates.d.ts.map +1 -0
  163. package/dist/testing/conformanceGates.js +35 -0
  164. package/dist/testing/conformanceGates.js.map +1 -0
  165. package/dist/testing/conformanceMicrophone.d.ts +10 -0
  166. package/dist/testing/conformanceMicrophone.d.ts.map +1 -0
  167. package/dist/testing/conformanceMicrophone.js +71 -0
  168. package/dist/testing/conformanceMicrophone.js.map +1 -0
  169. package/dist/testing/conformanceTimeline.d.ts +128 -0
  170. package/dist/testing/conformanceTimeline.d.ts.map +1 -0
  171. package/dist/testing/conformanceTimeline.js +32 -0
  172. package/dist/testing/conformanceTimeline.js.map +1 -0
  173. package/dist/testing/conformanceVideoStream.d.ts +29 -0
  174. package/dist/testing/conformanceVideoStream.d.ts.map +1 -0
  175. package/dist/testing/conformanceVideoStream.js +39 -0
  176. package/dist/testing/conformanceVideoStream.js.map +1 -0
  177. package/dist/testing/index.d.ts +29 -0
  178. package/dist/testing/index.d.ts.map +1 -0
  179. package/dist/testing/index.js +28 -0
  180. package/dist/testing/index.js.map +1 -0
  181. package/dist/testing/realtimeVideoConformance.d.ts +23 -0
  182. package/dist/testing/realtimeVideoConformance.d.ts.map +1 -0
  183. package/dist/testing/realtimeVideoConformance.js +139 -0
  184. package/dist/testing/realtimeVideoConformance.js.map +1 -0
  185. package/dist/testing/realtimeVideoConformanceChecks.d.ts +4 -0
  186. package/dist/testing/realtimeVideoConformanceChecks.d.ts.map +1 -0
  187. package/dist/testing/realtimeVideoConformanceChecks.js +164 -0
  188. package/dist/testing/realtimeVideoConformanceChecks.js.map +1 -0
  189. package/dist/testing/realtimeVideoConformanceFrameChecks.d.ts +4 -0
  190. package/dist/testing/realtimeVideoConformanceFrameChecks.d.ts.map +1 -0
  191. package/dist/testing/realtimeVideoConformanceFrameChecks.js +63 -0
  192. package/dist/testing/realtimeVideoConformanceFrameChecks.js.map +1 -0
  193. package/dist/testing/realtimeVideoConformanceSession.d.ts +108 -0
  194. package/dist/testing/realtimeVideoConformanceSession.d.ts.map +1 -0
  195. package/dist/testing/realtimeVideoConformanceSession.js +270 -0
  196. package/dist/testing/realtimeVideoConformanceSession.js.map +1 -0
  197. package/dist/testing/realtimeVideoConformanceTurnChecks.d.ts +4 -0
  198. package/dist/testing/realtimeVideoConformanceTurnChecks.d.ts.map +1 -0
  199. package/dist/testing/realtimeVideoConformanceTurnChecks.js +248 -0
  200. package/dist/testing/realtimeVideoConformanceTurnChecks.js.map +1 -0
  201. package/dist/testing/realtimeVideoConformanceTypes.d.ts +155 -0
  202. package/dist/testing/realtimeVideoConformanceTypes.d.ts.map +1 -0
  203. package/dist/testing/realtimeVideoConformanceTypes.js +2 -0
  204. package/dist/testing/realtimeVideoConformanceTypes.js.map +1 -0
  205. package/dist/testing/recordingPlayout.d.ts +84 -0
  206. package/dist/testing/recordingPlayout.d.ts.map +1 -0
  207. package/dist/testing/recordingPlayout.js +120 -0
  208. package/dist/testing/recordingPlayout.js.map +1 -0
  209. package/package.json +29 -4
@@ -0,0 +1,169 @@
1
+ /**
2
+ * @fileoverview The media the video conformance kit sends as the model: tiny, synthetic, deterministic video in each
3
+ * form a model's video comes in (Core's `RealtimeVideoFrame` kinds), and PCM chunks. Nothing here decodes; the frames
4
+ * only need to be read (by `@memberjunction/ai`'s fMP4 reader) and routed.
5
+ *
6
+ * - **Fragmented MP4**, as a realtime avatar sends it: an init segment (`ftyp` + `moov`) with an H.264 `avc1.42c01f` video
7
+ * track at a 90 kHz timescale and an AAC-LC `mp4a.40.2` audio track at 24 kHz unless the video comes without the
8
+ * voice; video fragments (`moof` + `mdat`) of one sample per 24 fps frame, so each frame is
9
+ * {@link CONFORMANCE_FMP4_FRAME_SECONDS}; audio-only fragments of a muxed avatar, which carry no video seconds.
10
+ * - **Encoded chunks** ({@link ConformanceChunkFrames}): opaque bytes labelled H.264, a key frame every 24, presentation
11
+ * times 24 to the second.
12
+ * - **Images** ({@link ConformanceImageFrame}): JPEG start and end markers around a few bytes, 24 to the second.
13
+ * - **PCM** chunks of 4 bytes, too short to ever be read as an MP4 box.
14
+ *
15
+ * Every kind is spaced 1/24 s apart, so a frame is {@link CONFORMANCE_FMP4_FRAME_SECONDS} whatever its kind. The box
16
+ * builders are exported for this package's own tests; the `/testing` entry exports only the fixtures.
17
+ *
18
+ * @module @memberjunction/ai-realtime-client/testing
19
+ */
20
+ import { Fmp4PieceToVideoFrame, } from '@memberjunction/ai';
21
+ /** One 24 fps video frame at the video track's 90 kHz timescale. */
22
+ const VIDEO_FRAME_UNITS = 3750;
23
+ /** The video track's timescale: units per second. */
24
+ const VIDEO_TIMESCALE = 90000;
25
+ /** One AAC frame at the audio track's 24 kHz timescale. */
26
+ const AUDIO_FRAME_UNITS = 1024;
27
+ /** The audio track's timescale. */
28
+ const AUDIO_TIMESCALE = 24000;
29
+ /** The seconds of video one frame carries, of any kind: 1/24. A {@link ConformanceFmp4VideoFragment} frame lasts this long. */
30
+ export const CONFORMANCE_FMP4_FRAME_SECONDS = VIDEO_FRAME_UNITS / VIDEO_TIMESCALE;
31
+ /** The H.264 type the kit's encoded chunks are labelled with: Constrained Baseline 3.0, as WebCodecs names it. */
32
+ const CHUNK_MIME_TYPE = 'video/h264; codecs="avc1.42e01f"';
33
+ /** How many chunks apart the kit's key frames are. */
34
+ const CHUNK_KEY_FRAME_INTERVAL = 24;
35
+ /** The type of the kit's images. */
36
+ const IMAGE_MIME_TYPE = 'image/jpeg';
37
+ /** Joins byte arrays end to end. */
38
+ export function ConcatBytes(...parts) {
39
+ const out = new Uint8Array(parts.reduce((total, part) => total + part.length, 0));
40
+ let offset = 0;
41
+ for (const part of parts) {
42
+ out.set(part, offset);
43
+ offset += part.length;
44
+ }
45
+ return out;
46
+ }
47
+ /** A big-endian 32-bit unsigned integer. */
48
+ export function Uint32Bytes(value) {
49
+ const out = new Uint8Array(4);
50
+ new DataView(out.buffer).setUint32(0, value);
51
+ return out;
52
+ }
53
+ /** The bytes of an ASCII string, such as a box type. */
54
+ export function AsciiBytes(text) {
55
+ return Uint8Array.from(text, (c) => c.charCodeAt(0));
56
+ }
57
+ /** An MP4 box: its size, its four-character type, then its payload. */
58
+ export function Mp4Box(type, ...payload) {
59
+ const body = ConcatBytes(...payload);
60
+ return ConcatBytes(Uint32Bytes(8 + body.length), AsciiBytes(type), body);
61
+ }
62
+ /** A full box: version 0, no flags, then the payload. */
63
+ export function Mp4FullBox(type, ...payload) {
64
+ return Mp4Box(type, new Uint8Array(4), ...payload);
65
+ }
66
+ /** A track whose `mdhd` gives `timescale` units a second. */
67
+ function trak(id, handler, entry, timescale) {
68
+ const tkhd = Mp4FullBox('tkhd', new Uint8Array(8), Uint32Bytes(id), new Uint8Array(68));
69
+ const hdlr = Mp4FullBox('hdlr', Uint32Bytes(0), AsciiBytes(handler), new Uint8Array(13));
70
+ const stbl = Mp4Box('stbl', Mp4FullBox('stsd', Uint32Bytes(1), entry));
71
+ const mdhd = Mp4FullBox('mdhd', new Uint8Array(8), Uint32Bytes(timescale), new Uint8Array(8));
72
+ return Mp4Box('trak', tkhd, Mp4Box('mdia', mdhd, hdlr, Mp4Box('minf', stbl)));
73
+ }
74
+ /** A track fragment: `tfhd` (default-base-is-moof, a default sample duration) and a `trun` of `samples` samples. */
75
+ function traf(trackID, sampleUnits, samples) {
76
+ const tfhd = Mp4Box('tfhd', Uint8Array.of(0, 0x02, 0x00, 0x08), Uint32Bytes(trackID), Uint32Bytes(sampleUnits));
77
+ const trun = Mp4Box('trun', Uint8Array.of(0, 0, 0, 0x01), Uint32Bytes(samples), Uint32Bytes(0));
78
+ return Mp4Box('traf', tfhd, trun);
79
+ }
80
+ /** An H.264 sample entry whose `avcC` names Constrained Baseline 3.1 (`avc1.42c01f`). */
81
+ function avc1() {
82
+ return Mp4Box('avc1', new Uint8Array(6), Uint8Array.of(0, 1), new Uint8Array(70), Mp4Box('avcC', Uint8Array.of(1, 0x42, 0xc0, 0x1f, 0xff, 0xe0, 0)));
83
+ }
84
+ /** An AAC sample entry: ES descriptor → decoder config (AAC, 0x40) → AudioSpecificConfig 0x13 0x08 (AAC-LC) → SL config. */
85
+ function mp4a() {
86
+ const esds = Mp4FullBox('esds', Uint8Array.of(0x03, 25, 0, 1, 0, 0x04, 17, 0x40, 0x15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x05, 2, 0x13, 0x08, 0x06, 1, 2));
87
+ return Mp4Box('mp4a', new Uint8Array(6), Uint8Array.of(0, 1), new Uint8Array(8), Uint8Array.of(0, 1, 0, 16), new Uint8Array(4), Uint32Bytes(AUDIO_TIMESCALE * 65536), esds);
88
+ }
89
+ /** A copy of the bytes in an `ArrayBuffer` of their own. */
90
+ function toArrayBuffer(bytes) {
91
+ return bytes.slice().buffer;
92
+ }
93
+ /**
94
+ * An init segment (`ftyp` + `moov`): an H.264 video track at `videoTimescale` units a second, and an AAC-LC audio track
95
+ * (the avatar's voice) unless `withAudio` is false.
96
+ *
97
+ * @param withAudio Whether the video carries the voice: an audio track beside the video. Default `true`.
98
+ * @param videoTimescale The video track's units per second. Default 90 000, which times each frame at 1/24 s.
99
+ */
100
+ export function ConformanceFmp4InitSegment(withAudio = true, videoTimescale = VIDEO_TIMESCALE) {
101
+ const video = trak(1, 'vide', avc1(), videoTimescale);
102
+ const traks = withAudio ? [video, trak(2, 'soun', mp4a(), AUDIO_TIMESCALE)] : [video];
103
+ return toArrayBuffer(ConcatBytes(Mp4Box('ftyp', AsciiBytes('iso5'), Uint32Bytes(512)), Mp4Box('moov', Mp4FullBox('mvhd', new Uint8Array(96)), ...traks)));
104
+ }
105
+ /**
106
+ * A video fragment (`moof` + `mdat`) of `frames` 24 fps frames, {@link CONFORMANCE_FMP4_FRAME_SECONDS} each under the
107
+ * default init segment. `sequence` makes each fragment's bytes distinct.
108
+ */
109
+ export function ConformanceFmp4VideoFragment(frames = 1, sequence = 1) {
110
+ const moof = Mp4Box('moof', Mp4FullBox('mfhd', Uint32Bytes(sequence)), traf(1, VIDEO_FRAME_UNITS, frames));
111
+ return toArrayBuffer(ConcatBytes(moof, Mp4Box('mdat', Uint32Bytes(sequence))));
112
+ }
113
+ /** An audio-only fragment of a muxed avatar: one AAC frame and no video, so it adds no video seconds. */
114
+ export function ConformanceFmp4AudioFragment(sequence = 1) {
115
+ const moof = Mp4Box('moof', Mp4FullBox('mfhd', Uint32Bytes(sequence)), traf(2, AUDIO_FRAME_UNITS, 1));
116
+ return toArrayBuffer(ConcatBytes(moof, Mp4Box('mdat', Uint32Bytes(sequence))));
117
+ }
118
+ /**
119
+ * A 4-byte PCM16 chunk of the agent's voice. Too short to be read as an MP4 box, so a driver that sniffs bytes never
120
+ * takes it for video. `seed` makes each chunk's bytes distinct.
121
+ */
122
+ export function ConformancePcm(seed = 1) {
123
+ return Uint8Array.of(seed & 0xff, 0, seed & 0xff, 0).buffer;
124
+ }
125
+ /**
126
+ * `count` encoded chunks as a raw-frame provider sends them: each with distinct opaque bytes, its presentation time on a
127
+ * 24 fps timeline (chunk `n` at `n` × 1000/24 ms), and a key frame every 24 (chunk 0, 24, 48 …). Nothing decodes them.
128
+ */
129
+ export function ConformanceChunkFrames(count, options = {}) {
130
+ const first = options.FirstIndex ?? 0;
131
+ return Array.from({ length: count }, (_, i) => {
132
+ const index = first + i;
133
+ return {
134
+ Kind: 'chunk',
135
+ Data: Uint8Array.of(0, 0, 0, 1, 0x65, index & 0xff, (index >> 8) & 0xff).buffer,
136
+ MimeType: options.MimeType ?? CHUNK_MIME_TYPE,
137
+ PresentationTimeMs: FrameTimeMs(index),
138
+ KeyFrame: index % CHUNK_KEY_FRAME_INTERVAL === 0,
139
+ };
140
+ });
141
+ }
142
+ /** Image `index` of a 24 fps stream: JPEG start and end markers around distinct bytes, timed at `index` × 1000/24 ms. */
143
+ export function ConformanceImageFrame(index = 0) {
144
+ return {
145
+ Kind: 'image',
146
+ Data: Uint8Array.of(0xff, 0xd8, index & 0xff, (index >> 8) & 0xff, 0xff, 0xd9).buffer,
147
+ MimeType: IMAGE_MIME_TYPE,
148
+ PresentationTimeMs: FrameTimeMs(index),
149
+ KeyFrame: true,
150
+ };
151
+ }
152
+ /**
153
+ * A piece of fragmented MP4 as the frame a provider's driver builds from it (Core's `Fmp4PieceToVideoFrame`), labelled
154
+ * `video/mp4`. For this package's own use; a harness gets the frames the kit sends.
155
+ *
156
+ * @throws When the piece is not fragmented MP4.
157
+ */
158
+ export function Fmp4Frame(piece) {
159
+ const frame = Fmp4PieceToVideoFrame(piece, 'video/mp4', null);
160
+ if (!frame) {
161
+ throw new Error('The piece is not fragmented MP4.');
162
+ }
163
+ return frame;
164
+ }
165
+ /** Frame `index`'s presentation time on the kit's 24 fps timeline, in ms. */
166
+ export function FrameTimeMs(index) {
167
+ return index * CONFORMANCE_FMP4_FRAME_SECONDS * 1000;
168
+ }
169
+ //# sourceMappingURL=conformanceFixtures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformanceFixtures.js","sourceRoot":"","sources":["../../src/testing/conformanceFixtures.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @fileoverview When a check runs: what it needs from the provider (its traits) and from the harness (its optional
3
+ * methods). Each gate returns why the check can't run, or `null`.
4
+ *
5
+ * @module @memberjunction/ai-realtime-client/testing
6
+ */
7
+ import type { IRealtimeVideoConformanceHarness } from './realtimeVideoConformanceTypes.js';
8
+ /** A gate: why a check can't run against a harness, or `null`. */
9
+ export type ConformanceGate = (harness: IRealtimeVideoConformanceHarness) => string | null;
10
+ /** The harness's optional methods a check can need. */
11
+ export type ConformanceHarnessMethod = 'SendPart' | 'GenerationComplete' | 'Resume' | 'RefusePlayback';
12
+ /** Runs for every provider. */
13
+ export declare const NoGate: ConformanceGate;
14
+ /** Needs a provider that hands over the agent's video. */
15
+ export declare const NeedsAgentVideo: ConformanceGate;
16
+ /** Needs a provider whose server can grant an avatar. */
17
+ export declare const NeedsGrant: ConformanceGate;
18
+ /** Needs a provider whose video plays through a player the kit records. */
19
+ export declare const NeedsPlayout: ConformanceGate;
20
+ /** Needs a driver that plays the voice as PCM through the kit's recorder. */
21
+ export declare const NeedsPcmVoice: ConformanceGate;
22
+ /** Needs a provider whose video can carry the voice. */
23
+ export declare const NeedsVideoThatCanCarryVoice: ConformanceGate;
24
+ /** Needs a driver that reports generated video seconds. */
25
+ export declare const NeedsVideoUsage: ConformanceGate;
26
+ /** Needs a driver that keeps its voice and its video on one media timeline. */
27
+ export declare const NeedsTimedVoice: ConformanceGate;
28
+ /** Needs one of the harness's optional methods. */
29
+ export declare function NeedsHarnessMethod(method: ConformanceHarnessMethod): ConformanceGate;
30
+ /** All of the gates: the first reason any of them gives, or `null`. */
31
+ export declare function AllOf(...gates: ConformanceGate[]): ConformanceGate;
32
+ //# sourceMappingURL=conformanceGates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformanceGates.d.ts","sourceRoot":"","sources":["../../src/testing/conformanceGates.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,iCAAiC,CAAC;AAExF,kEAAkE;AAClE,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,gCAAgC,KAAK,MAAM,GAAG,IAAI,CAAC;AAE3F,uDAAuD;AACvD,MAAM,MAAM,wBAAwB,GAAG,UAAU,GAAG,oBAAoB,GAAG,QAAQ,GAAG,gBAAgB,CAAC;AAEvG,+BAA+B;AAC/B,eAAO,MAAM,MAAM,EAAE,eAA4B,CAAC;AAElD,0DAA0D;AAC1D,eAAO,MAAM,eAAe,EAAE,eAC6F,CAAC;AAE5H,yDAAyD;AACzD,eAAO,MAAM,UAAU,EAAE,eAC0F,CAAC;AAEpH,2EAA2E;AAC3E,eAAO,MAAM,YAAY,EAAE,eAGoF,CAAC;AAEhH,6EAA6E;AAC7E,eAAO,MAAM,aAAa,EAAE,eACuH,CAAC;AAEpJ,wDAAwD;AACxD,eAAO,MAAM,2BAA2B,EAAE,eAC2F,CAAC;AAEtI,2DAA2D;AAC3D,eAAO,MAAM,eAAe,EAAE,eAC0F,CAAC;AAEzH,+EAA+E;AAC/E,eAAO,MAAM,eAAe,EAAE,eACuF,CAAC;AAEtH,mDAAmD;AACnD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,wBAAwB,GAAG,eAAe,CAEpF;AAED,uEAAuE;AACvE,wBAAgB,KAAK,CAAC,GAAG,KAAK,EAAE,eAAe,EAAE,GAAG,eAAe,CAUlE"}
@@ -0,0 +1,35 @@
1
+ /** Runs for every provider. */
2
+ export const NoGate = () => null;
3
+ /** Needs a provider that hands over the agent's video. */
4
+ export const NeedsAgentVideo = (harness) => harness.Traits.AgentVideo === 'none' ? `${harness.Name} hands over no agent video (Traits.AgentVideo is 'none')` : null;
5
+ /** Needs a provider whose server can grant an avatar. */
6
+ export const NeedsGrant = (harness) => harness.Traits.GrantsAvatar ? null : `${harness.Name}'s server grants no avatar (Traits.GrantsAvatar is false)`;
7
+ /** Needs a provider whose video plays through a player the kit records. */
8
+ export const NeedsPlayout = (harness) => harness.Traits.AgentVideo === 'playout'
9
+ ? null
10
+ : `${harness.Name} has no video player to record (Traits.AgentVideo is '${harness.Traits.AgentVideo}')`;
11
+ /** Needs a driver that plays the voice as PCM through the kit's recorder. */
12
+ export const NeedsPcmVoice = (harness) => harness.Traits.Voice === 'pcm' ? null : `${harness.Name}'s voice plays through its transport, not a PCM playback (Traits.Voice is 'transport')`;
13
+ /** Needs a provider whose video can carry the voice. */
14
+ export const NeedsVideoThatCanCarryVoice = (harness) => harness.Traits.VideoCanCarryVoice ? null : `${harness.Name}'s video never carries the voice (Traits.VideoCanCarryVoice is false)`;
15
+ /** Needs a driver that reports generated video seconds. */
16
+ export const NeedsVideoUsage = (harness) => harness.Traits.VideoUsage ? null : `${harness.Name} reports no generated video seconds (Traits.VideoUsage is false)`;
17
+ /** Needs a driver that keeps its voice and its video on one media timeline. */
18
+ export const NeedsTimedVoice = (harness) => harness.Traits.TimedVoice ? null : `${harness.Name}'s voice carries no media time (Traits.TimedVoice is not set)`;
19
+ /** Needs one of the harness's optional methods. */
20
+ export function NeedsHarnessMethod(method) {
21
+ return (harness) => (typeof harness[method] === 'function' ? null : `${harness.Name}'s harness has no ${method}`);
22
+ }
23
+ /** All of the gates: the first reason any of them gives, or `null`. */
24
+ export function AllOf(...gates) {
25
+ return (harness) => {
26
+ for (const gate of gates) {
27
+ const reason = gate(harness);
28
+ if (reason !== null) {
29
+ return reason;
30
+ }
31
+ }
32
+ return null;
33
+ };
34
+ }
35
+ //# sourceMappingURL=conformanceGates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformanceGates.js","sourceRoot":"","sources":["../../src/testing/conformanceGates.ts"],"names":[],"mappings":"AAcA,+BAA+B;AAC/B,MAAM,CAAC,MAAM,MAAM,GAAoB,GAAG,EAAE,CAAC,IAAI,CAAC;AAElD,0DAA0D;AAC1D,MAAM,CAAC,MAAM,eAAe,GAAoB,CAAC,OAAO,EAAE,EAAE,CACxD,OAAO,CAAC,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,0DAA0D,CAAC,CAAC,CAAC,IAAI,CAAC;AAE5H,yDAAyD;AACzD,MAAM,CAAC,MAAM,UAAU,GAAoB,CAAC,OAAO,EAAE,EAAE,CACnD,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,2DAA2D,CAAC;AAEpH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,YAAY,GAAoB,CAAC,OAAO,EAAE,EAAE,CACrD,OAAO,CAAC,MAAM,CAAC,UAAU,KAAK,SAAS;IACnC,CAAC,CAAC,IAAI;IACN,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,yDAAyD,OAAO,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC;AAEhH,6EAA6E;AAC7E,MAAM,CAAC,MAAM,aAAa,GAAoB,CAAC,OAAO,EAAE,EAAE,CACtD,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,wFAAwF,CAAC;AAEpJ,wDAAwD;AACxD,MAAM,CAAC,MAAM,2BAA2B,GAAoB,CAAC,OAAO,EAAE,EAAE,CACpE,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,uEAAuE,CAAC;AAEtI,2DAA2D;AAC3D,MAAM,CAAC,MAAM,eAAe,GAAoB,CAAC,OAAO,EAAE,EAAE,CACxD,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,kEAAkE,CAAC;AAEzH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,eAAe,GAAoB,CAAC,OAAO,EAAE,EAAE,CACxD,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,+DAA+D,CAAC;AAEtH,mDAAmD;AACnD,MAAM,UAAU,kBAAkB,CAAC,MAAgC;IAC/D,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,qBAAqB,MAAM,EAAE,CAAC,CAAC;AACtH,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,KAAK,CAAC,GAAG,KAAwB;IAC7C,OAAO,CAAC,OAAO,EAAE,EAAE;QACf,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;YAC7B,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBAClB,OAAO,MAAM,CAAC;YAClB,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @fileoverview A microphone for conformance sessions: a `MediaStream` with one audio track that captures nothing. It
3
+ * needs no devices and no DOM, only `EventTarget`, so the kit runs in plain Node. The track and the stream are plain
4
+ * objects with the platform's member names, so a driver uses them as it uses the browser's.
5
+ *
6
+ * @module @memberjunction/ai-realtime-client/testing
7
+ */
8
+ /** A microphone stream with one audio track that captures nothing, to connect a driver with. */
9
+ export declare function CreateConformanceMicrophone(): MediaStream;
10
+ //# sourceMappingURL=conformanceMicrophone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformanceMicrophone.d.ts","sourceRoot":"","sources":["../../src/testing/conformanceMicrophone.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgEH,gGAAgG;AAChG,wBAAgB,2BAA2B,IAAI,WAAW,CAEzD"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @fileoverview A microphone for conformance sessions: a `MediaStream` with one audio track that captures nothing. It
3
+ * needs no devices and no DOM, only `EventTarget`, so the kit runs in plain Node. The track and the stream are plain
4
+ * objects with the platform's member names, so a driver uses them as it uses the browser's.
5
+ *
6
+ * @module @memberjunction/ai-realtime-client/testing
7
+ */
8
+ /** The `EventTarget` half of a platform object, delegated to a real `EventTarget`. */
9
+ function eventTargetOf(events) {
10
+ return {
11
+ addEventListener: events.addEventListener.bind(events),
12
+ removeEventListener: events.removeEventListener.bind(events),
13
+ dispatchEvent: events.dispatchEvent.bind(events),
14
+ };
15
+ }
16
+ /** An audio track that captures nothing. `stop()` ends it, as a real track's does. */
17
+ function createSilentAudioTrack() {
18
+ let readyState = 'live';
19
+ return {
20
+ ...eventTargetOf(new EventTarget()),
21
+ contentHint: '',
22
+ enabled: true,
23
+ id: 'conformance-microphone-track',
24
+ kind: 'audio',
25
+ label: 'Conformance microphone',
26
+ muted: false,
27
+ onended: null,
28
+ onmute: null,
29
+ onunmute: null,
30
+ get readyState() {
31
+ return readyState;
32
+ },
33
+ applyConstraints: async () => undefined,
34
+ clone: () => createSilentAudioTrack(),
35
+ getCapabilities: () => ({}),
36
+ getConstraints: () => ({}),
37
+ getSettings: () => ({}),
38
+ stop: () => {
39
+ readyState = 'ended';
40
+ },
41
+ };
42
+ }
43
+ /** A stream of the tracks it was made with. */
44
+ function createStream(tracks) {
45
+ return {
46
+ ...eventTargetOf(new EventTarget()),
47
+ active: true,
48
+ id: 'conformance-microphone',
49
+ onaddtrack: null,
50
+ onremovetrack: null,
51
+ addTrack: (track) => {
52
+ tracks.push(track);
53
+ },
54
+ clone: () => createStream([...tracks]),
55
+ getAudioTracks: () => tracks.filter((track) => track.kind === 'audio'),
56
+ getTrackById: (trackId) => tracks.find((track) => track.id === trackId) ?? null,
57
+ getTracks: () => [...tracks],
58
+ getVideoTracks: () => tracks.filter((track) => track.kind === 'video'),
59
+ removeTrack: (track) => {
60
+ const index = tracks.indexOf(track);
61
+ if (index >= 0) {
62
+ tracks.splice(index, 1);
63
+ }
64
+ },
65
+ };
66
+ }
67
+ /** A microphone stream with one audio track that captures nothing, to connect a driver with. */
68
+ export function CreateConformanceMicrophone() {
69
+ return createStream([createSilentAudioTrack()]);
70
+ }
71
+ //# sourceMappingURL=conformanceMicrophone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformanceMicrophone.js","sourceRoot":"","sources":["../../src/testing/conformanceMicrophone.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,sFAAsF;AACtF,SAAS,aAAa,CAAC,MAAmB;IACtC,OAAO;QACH,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC;QACtD,mBAAmB,EAAE,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC;QAC5D,aAAa,EAAE,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC;KACnD,CAAC;AACN,CAAC;AAED,sFAAsF;AACtF,SAAS,sBAAsB;IAC3B,IAAI,UAAU,GAA0B,MAAM,CAAC;IAC/C,OAAO;QACH,GAAG,aAAa,CAAC,IAAI,WAAW,EAAE,CAAC;QACnC,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,IAAI;QACb,EAAE,EAAE,8BAA8B;QAClC,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,wBAAwB;QAC/B,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,IAAI;QACd,IAAI,UAAU;YACV,OAAO,UAAU,CAAC;QACtB,CAAC;QACD,gBAAgB,EAAE,KAAK,IAAmB,EAAE,CAAC,SAAS;QACtD,KAAK,EAAE,GAAqB,EAAE,CAAC,sBAAsB,EAAE;QACvD,eAAe,EAAE,GAA2B,EAAE,CAAC,CAAC,EAAE,CAAC;QACnD,cAAc,EAAE,GAA0B,EAAE,CAAC,CAAC,EAAE,CAAC;QACjD,WAAW,EAAE,GAAuB,EAAE,CAAC,CAAC,EAAE,CAAC;QAC3C,IAAI,EAAE,GAAS,EAAE;YACb,UAAU,GAAG,OAAO,CAAC;QACzB,CAAC;KACJ,CAAC;AACN,CAAC;AAED,+CAA+C;AAC/C,SAAS,YAAY,CAAC,MAA0B;IAC5C,OAAO;QACH,GAAG,aAAa,CAAC,IAAI,WAAW,EAAE,CAAC;QACnC,MAAM,EAAE,IAAI;QACZ,EAAE,EAAE,wBAAwB;QAC5B,UAAU,EAAE,IAAI;QAChB,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,CAAC,KAAuB,EAAQ,EAAE;YACxC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;QACD,KAAK,EAAE,GAAgB,EAAE,CAAC,YAAY,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;QACnD,cAAc,EAAE,GAAuB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;QAC1F,YAAY,EAAE,CAAC,OAAe,EAA2B,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,IAAI;QAChH,SAAS,EAAE,GAAuB,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC;QAChD,cAAc,EAAE,GAAuB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;QAC1F,WAAW,EAAE,CAAC,KAAuB,EAAQ,EAAE;YAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACpC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;gBACb,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAC5B,CAAC;QACL,CAAC;KACJ,CAAC;AACN,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,2BAA2B;IACvC,OAAO,YAAY,CAAC,CAAC,sBAAsB,EAAE,CAAC,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @fileoverview The ordered record of one conformance session: what the driver did with the kit's recorders (the
3
+ * avatar's video players and the PCM playback), what the client emitted, and what it logged. Checks read it by kind and
4
+ * from a mark, so "since the barge-in" and "in this turn" are one slice.
5
+ *
6
+ * @module @memberjunction/ai-realtime-client/testing
7
+ */
8
+ import type { RealtimeTrack, RealtimeVideoFrame } from '@memberjunction/ai';
9
+ import type { RealtimeClientError, RealtimeClientState, RealtimeClientUsage } from '../generic/baseRealtimeClient.js';
10
+ import type { MediaVideoSource } from '../media/model.js';
11
+ import type { VideoPlayoutOptions } from '../media/videoPlayout.js';
12
+ /**
13
+ * One thing that happened in a conformance session, in the order it happened. `Player` numbers the video players the
14
+ * driver created in the session, from 0.
15
+ */
16
+ export type RealtimeVideoConformanceEvent =
17
+ /** The driver created a video player. */
18
+ {
19
+ Kind: 'player-created';
20
+ Player: number;
21
+ Options: VideoPlayoutOptions;
22
+ }
23
+ /** The driver handed a frame of video to a player. */
24
+ | {
25
+ Kind: 'player-append';
26
+ Player: number;
27
+ Frame: RealtimeVideoFrame;
28
+ }
29
+ /** The driver told a player the turn's video is all in. */
30
+ | {
31
+ Kind: 'player-end-of-turn';
32
+ Player: number;
33
+ }
34
+ /** The driver dropped what a player had not played (barge-in). */
35
+ | {
36
+ Kind: 'player-flush';
37
+ Player: number;
38
+ }
39
+ /** The driver released a player. */
40
+ | {
41
+ Kind: 'player-dispose';
42
+ Player: number;
43
+ }
44
+ /** The driver changed whether a player plays the video's audio. */
45
+ | {
46
+ Kind: 'player-carries-voice';
47
+ Player: number;
48
+ CarriesVoice: boolean;
49
+ }
50
+ /** The driver queued PCM on the voice playback, with its media time when the driver gave one. */
51
+ | {
52
+ Kind: 'voice-enqueue';
53
+ Data: ArrayBuffer;
54
+ MediaTimeMs?: number;
55
+ }
56
+ /** The driver dropped the PCM the voice playback had not played. */
57
+ | {
58
+ Kind: 'voice-flush';
59
+ }
60
+ /** The driver closed the voice playback. */
61
+ | {
62
+ Kind: 'voice-close';
63
+ }
64
+ /** The client reported a state. */
65
+ | {
66
+ Kind: 'state';
67
+ State: RealtimeClientState;
68
+ }
69
+ /** The client handed over the agent's video (`OnRemoteVideo`). */
70
+ | {
71
+ Kind: 'remote-video';
72
+ Video: MediaVideoSource;
73
+ }
74
+ /** The client reported a barge-in (`OnInterruption`). */
75
+ | {
76
+ Kind: 'interruption';
77
+ }
78
+ /** The client reported usage (`OnUsage`). */
79
+ | {
80
+ Kind: 'usage';
81
+ Usage: RealtimeClientUsage;
82
+ }
83
+ /** The client reported a track's state (`OnTrackStateChange`). */
84
+ | {
85
+ Kind: 'track';
86
+ Track: RealtimeTrack;
87
+ }
88
+ /** The client reported an error (`OnError`). */
89
+ | {
90
+ Kind: 'error';
91
+ Error: RealtimeClientError;
92
+ }
93
+ /** Something logged a warning while the session ran. */
94
+ | {
95
+ Kind: 'warn';
96
+ Message: string;
97
+ }
98
+ /** Something logged an info line while the session ran. */
99
+ | {
100
+ Kind: 'info';
101
+ Message: string;
102
+ };
103
+ /** The kinds of {@link RealtimeVideoConformanceEvent}. */
104
+ export type RealtimeVideoConformanceEventKind = RealtimeVideoConformanceEvent['Kind'];
105
+ /** The event of one kind. */
106
+ export type RealtimeVideoConformanceEventOf<K extends RealtimeVideoConformanceEventKind> = Extract<RealtimeVideoConformanceEvent, {
107
+ Kind: K;
108
+ }>;
109
+ /** An ordered, append-only record of a conformance session, shared by its recorders and its observers. */
110
+ export declare class RealtimeVideoConformanceTimeline {
111
+ private readonly entries;
112
+ /** Every event, in order. */
113
+ get Entries(): readonly RealtimeVideoConformanceEvent[];
114
+ /** Appends one event. */
115
+ Record(event: RealtimeVideoConformanceEvent): void;
116
+ /** The position the next event will take. Pass it to {@link Of} or {@link Since} to read only what came after. */
117
+ Mark(): number;
118
+ /** The events from a mark on. */
119
+ Since(mark: number): readonly RealtimeVideoConformanceEvent[];
120
+ /**
121
+ * The events of one kind, in order, from a mark on.
122
+ *
123
+ * @param kind The kind to keep.
124
+ * @param since A {@link Mark}; default the start of the session.
125
+ */
126
+ Of<K extends RealtimeVideoConformanceEventKind>(kind: K, since?: number): RealtimeVideoConformanceEventOf<K>[];
127
+ }
128
+ //# sourceMappingURL=conformanceTimeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformanceTimeline.d.ts","sourceRoot":"","sources":["../../src/testing/conformanceTimeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /** An ordered, append-only record of a conformance session, shared by its recorders and its observers. */
2
+ export class RealtimeVideoConformanceTimeline {
3
+ constructor() {
4
+ this.entries = [];
5
+ }
6
+ /** Every event, in order. */
7
+ get Entries() {
8
+ return this.entries;
9
+ }
10
+ /** Appends one event. */
11
+ Record(event) {
12
+ this.entries.push(event);
13
+ }
14
+ /** The position the next event will take. Pass it to {@link Of} or {@link Since} to read only what came after. */
15
+ Mark() {
16
+ return this.entries.length;
17
+ }
18
+ /** The events from a mark on. */
19
+ Since(mark) {
20
+ return this.entries.slice(mark);
21
+ }
22
+ /**
23
+ * The events of one kind, in order, from a mark on.
24
+ *
25
+ * @param kind The kind to keep.
26
+ * @param since A {@link Mark}; default the start of the session.
27
+ */
28
+ Of(kind, since = 0) {
29
+ return this.entries.slice(since).filter((event) => event.Kind === kind);
30
+ }
31
+ }
32
+ //# sourceMappingURL=conformanceTimeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformanceTimeline.js","sourceRoot":"","sources":["../../src/testing/conformanceTimeline.ts"],"names":[],"mappings":"AA0DA,0GAA0G;AAC1G,MAAM,OAAO,gCAAgC;IAA7C;QACqB,YAAO,GAAoC,EAAE,CAAC;IA+BnE,CAAC;IA7BG,6BAA6B;IAC7B,IAAW,OAAO;QACd,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;IAED,yBAAyB;IAClB,MAAM,CAAC,KAAoC;QAC9C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,kHAAkH;IAC3G,IAAI;QACP,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED,iCAAiC;IAC1B,KAAK,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAED;;;;;OAKG;IACI,EAAE,CAA8C,IAAO,EAAE,QAAgB,CAAC;QAC7E,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAA+C,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACzH,CAAC;CACJ"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @fileoverview The video a conformance session's model sends, in the provider's form: an fMP4 init segment then
3
+ * one-frame fragments, or encoded chunks from a key frame, or images. Each call continues the same 24 fps stream, so every
4
+ * frame's bytes are distinct and its time follows the last.
5
+ *
6
+ * @module @memberjunction/ai-realtime-client/testing
7
+ */
8
+ import type { RealtimeVideoFrame, RealtimeVideoFrameKind } from '@memberjunction/ai';
9
+ /** One session's video stream, of one frame kind. */
10
+ export declare class ConformanceVideoStream {
11
+ readonly Kind: RealtimeVideoFrameKind;
12
+ readonly CarriesVoice: boolean;
13
+ /** The number of the next video frame (an fMP4 fragment, a chunk or an image), from 0. */
14
+ private next;
15
+ /**
16
+ * @param Kind The form the provider's model sends its video in.
17
+ * @param CarriesVoice Whether an fMP4 stream's init segment has the voice's audio track.
18
+ */
19
+ constructor(Kind: RealtimeVideoFrameKind, CarriesVoice: boolean);
20
+ /** Where the next frame sits on the stream's media timeline, in ms: the time a voice chunk sent now goes with. */
21
+ get NextTimeMs(): number;
22
+ /** The frame a stream starts with: an fMP4 init segment, or the first chunk (a key frame) or image. */
23
+ Start(): RealtimeVideoFrame;
24
+ /** The stream's next `count` video frames: one-frame fMP4 fragments, chunks or images. */
25
+ Frames(count: number): RealtimeVideoFrame[];
26
+ }
27
+ /** The seconds of video some frames carry: 1/24 s each, an fMP4 init segment none. */
28
+ export declare function SecondsOfVideo(frames: readonly RealtimeVideoFrame[]): number;
29
+ //# sourceMappingURL=conformanceVideoStream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformanceVideoStream.d.ts","sourceRoot":"","sources":["../../src/testing/conformanceVideoStream.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAWrF,qDAAqD;AACrD,qBAAa,sBAAsB;aAQH,IAAI,EAAE,sBAAsB;aAAkB,YAAY,EAAE,OAAO;IAP/F,0FAA0F;IAC1F,OAAO,CAAC,IAAI,CAAK;IAEjB;;;OAGG;gBACyB,IAAI,EAAE,sBAAsB,EAAkB,YAAY,EAAE,OAAO;IAE/F,kHAAkH;IAClH,IAAW,UAAU,IAAI,MAAM,CAE9B;IAED,uGAAuG;IAChG,KAAK,IAAI,kBAAkB;IAOlC,0FAA0F;IACnF,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,EAAE;CAUrD;AAED,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,CAE5E"}
@@ -0,0 +1,39 @@
1
+ import { CONFORMANCE_FMP4_FRAME_SECONDS, ConformanceChunkFrames, ConformanceFmp4InitSegment, ConformanceFmp4VideoFragment, ConformanceImageFrame, Fmp4Frame, FrameTimeMs, } from './conformanceFixtures.js';
2
+ /** One session's video stream, of one frame kind. */
3
+ export class ConformanceVideoStream {
4
+ /**
5
+ * @param Kind The form the provider's model sends its video in.
6
+ * @param CarriesVoice Whether an fMP4 stream's init segment has the voice's audio track.
7
+ */
8
+ constructor(Kind, CarriesVoice) {
9
+ this.Kind = Kind;
10
+ this.CarriesVoice = CarriesVoice;
11
+ /** The number of the next video frame (an fMP4 fragment, a chunk or an image), from 0. */
12
+ this.next = 0;
13
+ }
14
+ /** Where the next frame sits on the stream's media timeline, in ms: the time a voice chunk sent now goes with. */
15
+ get NextTimeMs() {
16
+ return FrameTimeMs(this.next);
17
+ }
18
+ /** The frame a stream starts with: an fMP4 init segment, or the first chunk (a key frame) or image. */
19
+ Start() {
20
+ if (this.Kind === 'fmp4') {
21
+ return Fmp4Frame(ConformanceFmp4InitSegment(this.CarriesVoice));
22
+ }
23
+ return this.Frames(1)[0];
24
+ }
25
+ /** The stream's next `count` video frames: one-frame fMP4 fragments, chunks or images. */
26
+ Frames(count) {
27
+ const first = this.next;
28
+ this.next += count;
29
+ if (this.Kind === 'chunk') {
30
+ return ConformanceChunkFrames(count, { FirstIndex: first });
31
+ }
32
+ return Array.from({ length: count }, (_, i) => this.Kind === 'image' ? ConformanceImageFrame(first + i) : Fmp4Frame(ConformanceFmp4VideoFragment(1, first + i + 1)));
33
+ }
34
+ }
35
+ /** The seconds of video some frames carry: 1/24 s each, an fMP4 init segment none. */
36
+ export function SecondsOfVideo(frames) {
37
+ return frames.filter((frame) => !(frame.Kind === 'fmp4' && frame.Piece === 'init')).length * CONFORMANCE_FMP4_FRAME_SECONDS;
38
+ }
39
+ //# sourceMappingURL=conformanceVideoStream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformanceVideoStream.js","sourceRoot":"","sources":["../../src/testing/conformanceVideoStream.ts"],"names":[],"mappings":"AAQA,OAAO,EACH,8BAA8B,EAC9B,sBAAsB,EACtB,0BAA0B,EAC1B,4BAA4B,EAC5B,qBAAqB,EACrB,SAAS,EACT,WAAW,GACd,MAAM,uBAAuB,CAAC;AAE/B,qDAAqD;AACrD,MAAM,OAAO,sBAAsB;IAI/B;;;OAGG;IACH,YAA4B,IAA4B,EAAkB,YAAqB;QAAnE,SAAI,GAAJ,IAAI,CAAwB;QAAkB,iBAAY,GAAZ,YAAY,CAAS;QAP/F,0FAA0F;QAClF,SAAI,GAAG,CAAC,CAAC;IAMiF,CAAC;IAEnG,kHAAkH;IAClH,IAAW,UAAU;QACjB,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,uGAAuG;IAChG,KAAK;QACR,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACvB,OAAO,SAAS,CAAC,0BAA0B,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7B,CAAC;IAED,0FAA0F;IACnF,MAAM,CAAC,KAAa;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC;QACnB,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACxB,OAAO,sBAAsB,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAsB,EAAE,CAC9D,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CACvH,CAAC;IACN,CAAC;CACJ;AAED,sFAAsF;AACtF,MAAM,UAAU,cAAc,CAAC,MAAqC;IAChE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,8BAA8B,CAAC;AAChI,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @fileoverview The `@memberjunction/ai-realtime-client/testing` entry point: the video provider conformance kit. A
3
+ * provider's test runs it against the provider's client driver to prove the driver meets the realtime video contract:
4
+ * what it hands the host, where the model's video and voice go, what barge-in, turn ends, resumes and Disconnect do to
5
+ * them, and the generated video seconds it reports.
6
+ *
7
+ * The checks (VC01-VC15, VF01-VF02) take the agent's video as Core's `RealtimeVideoFrame`s, in whichever form the
8
+ * provider's model sends it: fragmented MP4, encoded chunks or images.
9
+ *
10
+ * The kit needs no test framework: {@link RunRealtimeVideoConformance} resolves to results, and
11
+ * {@link ListRealtimeVideoConformanceChecks} gives a runner one test per check. A provider writes a harness
12
+ * ({@link IRealtimeVideoConformanceHarness}): what its server mints, its client driver with a fake transport and its
13
+ * creation seams wired to the kit's recorders, and the model's side of the wire.
14
+ *
15
+ * Everything reachable from here may import only other `/testing` modules, `/media`, `src/audio/`,
16
+ * `generic/baseRealtimeClient`, `@memberjunction/ai`, `@memberjunction/global` and `rxjs`: no driver, no
17
+ * `@google/genai`, no test framework. `testing-entry-boundary.test.ts` fails the build otherwise. The main entry does
18
+ * not export the kit, so apps never bundle it.
19
+ *
20
+ * @module @memberjunction/ai-realtime-client/testing
21
+ */
22
+ export { RealtimeVideoConformanceError } from './conformanceAssertions.js';
23
+ export { CONFORMANCE_FMP4_FRAME_SECONDS, ConformanceChunkFrames, ConformanceFmp4AudioFragment, ConformanceFmp4InitSegment, ConformanceFmp4VideoFragment, ConformanceImageFrame, ConformancePcm, type ConformanceChunkOptions, } from './conformanceFixtures.js';
24
+ export { CreateConformanceMicrophone } from './conformanceMicrophone.js';
25
+ export { RealtimeVideoConformanceTimeline, type RealtimeVideoConformanceEvent, type RealtimeVideoConformanceEventKind, type RealtimeVideoConformanceEventOf, } from './conformanceTimeline.js';
26
+ export { RecordingPcmPlayback, RecordingVideoPlayout } from './recordingPlayout.js';
27
+ export { ListRealtimeVideoConformanceChecks, REALTIME_VIDEO_CONFORMANCE_CHECKS, RunRealtimeVideoConformance } from './realtimeVideoConformance.js';
28
+ export type { IRealtimeVideoConformanceHarness, RealtimeVideoConformanceCheck, RealtimeVideoConformanceCheckRun, RealtimeVideoConformanceDriverFactory, RealtimeVideoConformanceGrant, RealtimeVideoConformanceMedia, RealtimeVideoConformanceResult, RealtimeVideoConformanceTraits, } from './realtimeVideoConformanceTypes.js';
29
+ //# sourceMappingURL=index.d.ts.map