@chanl/widget-sdk 0.2.0-canary.0

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 (128) hide show
  1. package/README.md +257 -0
  2. package/dist/auth.d.ts +26 -0
  3. package/dist/auth.d.ts.map +1 -0
  4. package/dist/auth.js +36 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/chat/chat-client.d.ts +81 -0
  7. package/dist/chat/chat-client.d.ts.map +1 -0
  8. package/dist/chat/chat-client.js +192 -0
  9. package/dist/chat/chat-client.js.map +1 -0
  10. package/dist/chat/stream-parser.d.ts +20 -0
  11. package/dist/chat/stream-parser.d.ts.map +1 -0
  12. package/dist/chat/stream-parser.js +134 -0
  13. package/dist/chat/stream-parser.js.map +1 -0
  14. package/dist/chat/widget-config.d.ts +7 -0
  15. package/dist/chat/widget-config.d.ts.map +1 -0
  16. package/dist/chat/widget-config.js +26 -0
  17. package/dist/chat/widget-config.js.map +1 -0
  18. package/dist/client.d.ts +66 -0
  19. package/dist/client.d.ts.map +1 -0
  20. package/dist/client.js +49 -0
  21. package/dist/client.js.map +1 -0
  22. package/dist/defaults.d.ts +12 -0
  23. package/dist/defaults.d.ts.map +1 -0
  24. package/dist/defaults.js +27 -0
  25. package/dist/defaults.js.map +1 -0
  26. package/dist/embed/loader-types.d.ts +119 -0
  27. package/dist/embed/loader-types.d.ts.map +1 -0
  28. package/dist/embed/loader-types.js +20 -0
  29. package/dist/embed/loader-types.js.map +1 -0
  30. package/dist/embed/loader.d.ts +101 -0
  31. package/dist/embed/loader.d.ts.map +1 -0
  32. package/dist/embed/loader.js +439 -0
  33. package/dist/embed/loader.js.map +1 -0
  34. package/dist/embed/v1.global.js +5 -0
  35. package/dist/embed/v1.global.js.map +1 -0
  36. package/dist/events.d.ts +10 -0
  37. package/dist/events.d.ts.map +1 -0
  38. package/dist/events.js +25 -0
  39. package/dist/events.js.map +1 -0
  40. package/dist/index.d.ts +19 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +29 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/logger.d.ts +14 -0
  45. package/dist/logger.d.ts.map +1 -0
  46. package/dist/logger.js +3 -0
  47. package/dist/logger.js.map +1 -0
  48. package/dist/next/index.d.ts +58 -0
  49. package/dist/next/index.d.ts.map +1 -0
  50. package/dist/next/index.js +83 -0
  51. package/dist/next/index.js.map +1 -0
  52. package/dist/react/index.d.ts +16 -0
  53. package/dist/react/index.d.ts.map +1 -0
  54. package/dist/react/index.js +20 -0
  55. package/dist/react/index.js.map +1 -0
  56. package/dist/react/types.d.ts +27 -0
  57. package/dist/react/types.d.ts.map +1 -0
  58. package/dist/react/types.js +8 -0
  59. package/dist/react/types.js.map +1 -0
  60. package/dist/react/use-chanl.d.ts +27 -0
  61. package/dist/react/use-chanl.d.ts.map +1 -0
  62. package/dist/react/use-chanl.js +57 -0
  63. package/dist/react/use-chanl.js.map +1 -0
  64. package/dist/react/use-chat.d.ts +32 -0
  65. package/dist/react/use-chat.d.ts.map +1 -0
  66. package/dist/react/use-chat.js +224 -0
  67. package/dist/react/use-chat.js.map +1 -0
  68. package/dist/react/use-voice.d.ts +37 -0
  69. package/dist/react/use-voice.d.ts.map +1 -0
  70. package/dist/react/use-voice.js +268 -0
  71. package/dist/react/use-voice.js.map +1 -0
  72. package/dist/react/widget.d.ts +43 -0
  73. package/dist/react/widget.d.ts.map +1 -0
  74. package/dist/react/widget.js +188 -0
  75. package/dist/react/widget.js.map +1 -0
  76. package/dist/storage/session-storage.d.ts +48 -0
  77. package/dist/storage/session-storage.d.ts.map +1 -0
  78. package/dist/storage/session-storage.js +84 -0
  79. package/dist/storage/session-storage.js.map +1 -0
  80. package/dist/types.d.ts +140 -0
  81. package/dist/types.d.ts.map +1 -0
  82. package/dist/types.js +7 -0
  83. package/dist/types.js.map +1 -0
  84. package/dist/voice/audio-recorder.d.ts +43 -0
  85. package/dist/voice/audio-recorder.d.ts.map +1 -0
  86. package/dist/voice/audio-recorder.js +127 -0
  87. package/dist/voice/audio-recorder.js.map +1 -0
  88. package/dist/voice/index.d.ts +13 -0
  89. package/dist/voice/index.d.ts.map +1 -0
  90. package/dist/voice/index.js +16 -0
  91. package/dist/voice/index.js.map +1 -0
  92. package/dist/voice/mock-mode.d.ts +93 -0
  93. package/dist/voice/mock-mode.d.ts.map +1 -0
  94. package/dist/voice/mock-mode.js +375 -0
  95. package/dist/voice/mock-mode.js.map +1 -0
  96. package/dist/voice/transports/index.d.ts +5 -0
  97. package/dist/voice/transports/index.d.ts.map +1 -0
  98. package/dist/voice/transports/index.js +10 -0
  99. package/dist/voice/transports/index.js.map +1 -0
  100. package/dist/voice/transports/transport.d.ts +70 -0
  101. package/dist/voice/transports/transport.d.ts.map +1 -0
  102. package/dist/voice/transports/transport.js +12 -0
  103. package/dist/voice/transports/transport.js.map +1 -0
  104. package/dist/voice/transports/vapi.d.ts +147 -0
  105. package/dist/voice/transports/vapi.d.ts.map +1 -0
  106. package/dist/voice/transports/vapi.js +337 -0
  107. package/dist/voice/transports/vapi.js.map +1 -0
  108. package/dist/voice/transports/webrtc.d.ts +58 -0
  109. package/dist/voice/transports/webrtc.d.ts.map +1 -0
  110. package/dist/voice/transports/webrtc.js +318 -0
  111. package/dist/voice/transports/webrtc.js.map +1 -0
  112. package/dist/voice/transports/websocket.d.ts +39 -0
  113. package/dist/voice/transports/websocket.d.ts.map +1 -0
  114. package/dist/voice/transports/websocket.js +280 -0
  115. package/dist/voice/transports/websocket.js.map +1 -0
  116. package/dist/voice/types.d.ts +323 -0
  117. package/dist/voice/types.d.ts.map +1 -0
  118. package/dist/voice/types.js +41 -0
  119. package/dist/voice/types.js.map +1 -0
  120. package/dist/voice/utils.d.ts +22 -0
  121. package/dist/voice/utils.d.ts.map +1 -0
  122. package/dist/voice/utils.js +44 -0
  123. package/dist/voice/utils.js.map +1 -0
  124. package/dist/voice/voice-client.d.ts +231 -0
  125. package/dist/voice/voice-client.d.ts.map +1 -0
  126. package/dist/voice/voice-client.js +1187 -0
  127. package/dist/voice/voice-client.js.map +1 -0
  128. package/package.json +91 -0
@@ -0,0 +1,318 @@
1
+ "use strict";
2
+ /**
3
+ * WebRTCTransport — native browser WebRTC for voice calls.
4
+ *
5
+ * Audio path:
6
+ * Mic → getUserMedia → addTrack(pc) → RTP to server (no base64, no encoding)
7
+ * Server → remote audio track → <audio> element (native playback)
8
+ *
9
+ * Messages (transcripts, config, events) go through RTCDataChannel.
10
+ * Signaling uses HTTP POST /offer + /candidates to the voice-bot-sdk.
11
+ *
12
+ * Advantages over WebSocket:
13
+ * - No base64 encoding overhead (33% bandwidth savings)
14
+ * - Native echo cancellation + noise suppression
15
+ * - Lower latency (no JSON framing per audio chunk)
16
+ * - Browser-native audio playback (no PCMPlayer)
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.WebRTCTransport = void 0;
20
+ class WebRTCTransport {
21
+ /**
22
+ * @param callbacks — transport event callbacks
23
+ * @param signalingUrl — platform API base URL for signaling relay.
24
+ * The transport POSTs to `{signalingUrl}/offer/{interactionId}` and
25
+ * `{signalingUrl}/candidates`.
26
+ */
27
+ constructor(callbacks, signalingUrl) {
28
+ this.pc = null;
29
+ this.dc = null;
30
+ this.stream = null;
31
+ this.audioEl = null;
32
+ this.pingInterval = null;
33
+ this.micMuted = false;
34
+ this.audioDeafened = false;
35
+ this.debug = false;
36
+ this.callbacks = callbacks;
37
+ this.signalingUrl = signalingUrl;
38
+ }
39
+ // ── ITransport: connect ──────────────────────────────────────────────
40
+ async connect(config) {
41
+ this.debug = config.debug ?? false;
42
+ // The platform /offer relay resolves the room by interactionId, NOT the
43
+ // room's own id. Use interactionId; fall back to roomId only if absent.
44
+ // roomState is always present for WebRTCTransport (room-based flow only).
45
+ const interactionId = config.roomState.interactionId ?? config.roomState.roomId;
46
+ if (this.debug) {
47
+ console.debug('🌐 [WebRTCTransport] Connecting, interaction:', interactionId);
48
+ }
49
+ // 1. Get microphone
50
+ this.stream = await navigator.mediaDevices.getUserMedia({
51
+ audio: {
52
+ echoCancellation: true,
53
+ noiseSuppression: true,
54
+ autoGainControl: true,
55
+ },
56
+ });
57
+ if (this.debug)
58
+ console.debug('[WebRTCTransport] Mic acquired');
59
+ // 2. Create peer connection
60
+ this.pc = new RTCPeerConnection({
61
+ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
62
+ });
63
+ // Add mic track
64
+ this.stream.getTracks().forEach((t) => this.pc.addTrack(t, this.stream));
65
+ // Add receive-only audio transceiver for bot audio
66
+ this.pc.addTransceiver('audio', { direction: 'recvonly' });
67
+ // 3. Create data channel for JSON messages
68
+ this.dc = this.pc.createDataChannel('pipecat');
69
+ this.dc.onopen = () => {
70
+ if (this.debug)
71
+ console.debug('[WebRTCTransport] Data channel open — ready');
72
+ // Keepalive ping every second
73
+ this.pingInterval = setInterval(() => {
74
+ try {
75
+ this.dc?.send('ping');
76
+ }
77
+ catch { /* ignore */ }
78
+ }, 1000);
79
+ // Data channel open = connection ready for WebRTC
80
+ // (WebSocket gets a separate 'ready' message, but WebRTC is ready when DC opens)
81
+ this.callbacks.onReady();
82
+ };
83
+ this.dc.onmessage = (e) => this.handleDataChannelMessage(e);
84
+ // 4. Handle remote audio track — play via <audio> element
85
+ this.pc.ontrack = (e) => {
86
+ if (this.debug)
87
+ console.debug('[WebRTCTransport] Remote track:', e.track.kind);
88
+ if (e.track.kind === 'audio') {
89
+ if (!this.audioEl) {
90
+ this.audioEl = document.createElement('audio');
91
+ this.audioEl.autoplay = true;
92
+ this.audioEl.setAttribute('playsinline', 'true');
93
+ // Detached <audio> elements don't reliably autoplay in Chrome — must
94
+ // be in the DOM. Hide off-screen so it never affects layout.
95
+ this.audioEl.style.position = 'fixed';
96
+ this.audioEl.style.top = '-9999px';
97
+ document.body.appendChild(this.audioEl);
98
+ }
99
+ this.audioEl.srcObject = e.streams[0];
100
+ this.audioEl.muted = this.audioDeafened;
101
+ this.audioEl.play().catch((err) => {
102
+ if (this.debug)
103
+ console.debug('[WebRTCTransport] audio.play() rejected:', err);
104
+ });
105
+ }
106
+ };
107
+ // 5. Collect ICE candidates
108
+ const candidates = [];
109
+ this.pc.onicecandidate = (e) => {
110
+ if (e.candidate) {
111
+ candidates.push({
112
+ candidate: e.candidate.candidate,
113
+ sdp_mid: e.candidate.sdpMid,
114
+ sdp_mline_index: e.candidate.sdpMLineIndex,
115
+ });
116
+ }
117
+ };
118
+ this.pc.oniceconnectionstatechange = () => {
119
+ if (this.debug) {
120
+ console.debug('[WebRTCTransport] ICE:', this.pc?.iceConnectionState);
121
+ }
122
+ if (this.pc?.iceConnectionState === 'failed' ||
123
+ this.pc?.iceConnectionState === 'disconnected') {
124
+ this.callbacks.onError(new Error(`ICE ${this.pc.iceConnectionState}`));
125
+ }
126
+ };
127
+ // 6. Create SDP offer
128
+ const offer = await this.pc.createOffer();
129
+ await this.pc.setLocalDescription(offer);
130
+ // Wait for ICE gathering (up to 3s)
131
+ await new Promise((resolve) => {
132
+ if (this.pc.iceGatheringState === 'complete')
133
+ return resolve();
134
+ const onGather = () => {
135
+ if (this.pc?.iceGatheringState === 'complete') {
136
+ this.pc.removeEventListener('icegatheringstatechange', onGather);
137
+ resolve();
138
+ }
139
+ };
140
+ this.pc.addEventListener('icegatheringstatechange', onGather);
141
+ setTimeout(resolve, 3000);
142
+ });
143
+ if (this.debug) {
144
+ console.debug('[WebRTCTransport] ICE candidates:', candidates.length);
145
+ }
146
+ // 7. Send offer via platform signaling relay
147
+ // POST /api/v1/bot/call/providers/webrtc/offer/{interactionId}
148
+ const offerResp = await fetch(`${this.signalingUrl}/offer/${interactionId}`, {
149
+ method: 'POST',
150
+ headers: { 'Content-Type': 'application/json' },
151
+ body: JSON.stringify({
152
+ sdp: this.pc.localDescription.sdp,
153
+ type: this.pc.localDescription.type,
154
+ }),
155
+ });
156
+ if (!offerResp.ok) {
157
+ const text = await offerResp.text().catch(() => '');
158
+ throw new Error(`WebRTC /offer failed [${offerResp.status}]: ${text}`);
159
+ }
160
+ const answer = await offerResp.json();
161
+ if (this.debug) {
162
+ console.debug('[WebRTCTransport] SDP answer, pc_id:', answer.pc_id);
163
+ }
164
+ await this.pc.setRemoteDescription(new RTCSessionDescription({ sdp: answer.sdp, type: answer.type }));
165
+ // 8. Send ICE candidates via platform relay.
166
+ // interactionId is required so the platform can route to the same PCC
167
+ // machine that handled /offer (PCC routes by sessionId, NestJS stores
168
+ // that mapping on the WebsocketRoom).
169
+ if (candidates.length > 0) {
170
+ await fetch(`${this.signalingUrl}/candidates/${interactionId}`, {
171
+ method: 'POST',
172
+ headers: { 'Content-Type': 'application/json' },
173
+ body: JSON.stringify({ pc_id: answer.pc_id, candidates }),
174
+ });
175
+ if (this.debug) {
176
+ console.debug('[WebRTCTransport] ICE candidates sent');
177
+ }
178
+ }
179
+ }
180
+ // ── ITransport: disconnect ───────────────────────────────────────────
181
+ disconnect(_code, _reason) {
182
+ this.destroy();
183
+ this.callbacks.onClose(_code ?? 1000, _reason ?? 'client-stop');
184
+ }
185
+ // ── ITransport: sendMessage ──────────────────────────────────────────
186
+ sendMessage(message) {
187
+ if (!this.dc || this.dc.readyState !== 'open') {
188
+ if (this.debug) {
189
+ console.warn('[WebRTCTransport] Cannot send: data channel not open');
190
+ }
191
+ return;
192
+ }
193
+ // Audio messages are N/A for WebRTC (audio goes via RTP track)
194
+ if (message.type === 'audio')
195
+ return;
196
+ this.dc.send(JSON.stringify(message));
197
+ }
198
+ // ── ITransport: isConnected ──────────────────────────────────────────
199
+ isConnected() {
200
+ return this.dc?.readyState === 'open';
201
+ }
202
+ // ── ITransport: audio controls ───────────────────────────────────────
203
+ muteMic() {
204
+ if (this.micMuted)
205
+ return;
206
+ this.micMuted = true;
207
+ this.stream?.getAudioTracks().forEach((t) => { t.enabled = false; });
208
+ }
209
+ async unmuteMic() {
210
+ if (!this.micMuted)
211
+ return;
212
+ this.micMuted = false;
213
+ this.stream?.getAudioTracks().forEach((t) => { t.enabled = true; });
214
+ }
215
+ deafen() {
216
+ if (this.audioDeafened)
217
+ return;
218
+ this.audioDeafened = true;
219
+ if (this.audioEl)
220
+ this.audioEl.muted = true;
221
+ }
222
+ undeafen() {
223
+ if (!this.audioDeafened)
224
+ return;
225
+ this.audioDeafened = false;
226
+ if (this.audioEl)
227
+ this.audioEl.muted = false;
228
+ }
229
+ setVolume(volume) {
230
+ if (this.audioEl)
231
+ this.audioEl.volume = Math.max(0, Math.min(1, volume));
232
+ }
233
+ clearAudioBuffer() {
234
+ // No-op for WebRTC — audio is real-time, no buffering to clear
235
+ }
236
+ // ── ITransport: destroy ──────────────────────────────────────────────
237
+ destroy() {
238
+ if (this.pingInterval) {
239
+ clearInterval(this.pingInterval);
240
+ this.pingInterval = null;
241
+ }
242
+ if (this.dc) {
243
+ try {
244
+ this.dc.close();
245
+ }
246
+ catch { /* ignore */ }
247
+ this.dc = null;
248
+ }
249
+ if (this.pc) {
250
+ this.pc.close();
251
+ this.pc = null;
252
+ }
253
+ if (this.stream) {
254
+ this.stream.getTracks().forEach((t) => t.stop());
255
+ this.stream = null;
256
+ }
257
+ if (this.audioEl) {
258
+ this.audioEl.srcObject = null;
259
+ this.audioEl.remove();
260
+ this.audioEl = null;
261
+ }
262
+ }
263
+ // ── Private: data channel message handling ───────────────────────────
264
+ handleDataChannelMessage(event) {
265
+ const raw = event.data;
266
+ // Ignore pong keepalive
267
+ if (raw === 'pong')
268
+ return;
269
+ try {
270
+ const msg = JSON.parse(raw);
271
+ // Handle RTVI format from pipecat data channel:
272
+ // {label:"rtvi-ai", type:"user-transcription", data:{text:"...", timestamp:"..."}}
273
+ if (msg.label === 'rtvi-ai') {
274
+ const converted = this.convertRTVIMessage(msg);
275
+ if (converted) {
276
+ this.callbacks.onMessage(converted);
277
+ return;
278
+ }
279
+ }
280
+ // Pass through to Audial for event routing
281
+ // (ready was already fired on DC open — skip duplicate)
282
+ this.callbacks.onMessage(msg);
283
+ }
284
+ catch {
285
+ if (this.debug) {
286
+ console.debug('[WebRTCTransport] Non-JSON DC message:', String(raw).slice(0, 80));
287
+ }
288
+ }
289
+ }
290
+ /**
291
+ * Convert pipecat RTVI-format data channel messages to Audial's message format.
292
+ *
293
+ * RTVI sends: {label:"rtvi-ai", type:"user-transcription"|"bot-transcription",
294
+ * data:{text:"...", user_id:"", timestamp:"..."}}
295
+ * Audial expects: {type:"transcript", text:"...", sender:"user"|"assistant", timestamp:123}
296
+ */
297
+ convertRTVIMessage(msg) {
298
+ const type = msg.type;
299
+ const data = msg.data;
300
+ if (type === 'user-transcription' || type === 'bot-transcription') {
301
+ const sender = type === 'user-transcription' ? 'user' : 'assistant';
302
+ const text = data?.text || '';
303
+ if (!text)
304
+ return null;
305
+ return {
306
+ type: 'transcript',
307
+ text,
308
+ sender,
309
+ timestamp: Date.now(),
310
+ };
311
+ }
312
+ // config_loaded, error, and other RTVI types — pass through as-is
313
+ // Audial's generic 'message' event handler picks these up
314
+ return null;
315
+ }
316
+ }
317
+ exports.WebRTCTransport = WebRTCTransport;
318
+ //# sourceMappingURL=webrtc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webrtc.js","sourceRoot":"","sources":["../../../src/voice/transports/webrtc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * WebSocketTransport — legacy transport that sends base64-encoded PCM audio
3
+ * over a JSON WebSocket. Extracted from Audial.ts for the ITransport refactor.
4
+ *
5
+ * Audio path:
6
+ * Mic → AudioRecorder (WAV → base64) → ws.send({type:'audio', data:...})
7
+ * Server → {type:'audio', data: base64} → base64 decode → PCMPlayer
8
+ *
9
+ * Messages (transcripts, config, events) share the same WebSocket.
10
+ */
11
+ import type { ITransport, TransportCallbacks, TransportConnectConfig } from './transport';
12
+ import type { OutboundClientMessage } from '../types';
13
+ export declare class WebSocketTransport implements ITransport {
14
+ private ws;
15
+ private recorder;
16
+ private player;
17
+ private audioDeafened;
18
+ private micMuted;
19
+ private debug;
20
+ private callbacks;
21
+ constructor(callbacks: TransportCallbacks);
22
+ connect(config: TransportConnectConfig): Promise<void>;
23
+ disconnect(code?: number, reason?: string): void;
24
+ sendMessage(message: OutboundClientMessage): void;
25
+ isConnected(): boolean;
26
+ muteMic(): void;
27
+ unmuteMic(): Promise<void>;
28
+ deafen(): void;
29
+ undeafen(): void;
30
+ setVolume(volume: number): void;
31
+ clearAudioBuffer(): void;
32
+ destroy(): void;
33
+ private handleMessage;
34
+ private sendRaw;
35
+ private initRecorder;
36
+ private initPlayer;
37
+ private sendTwilioSimulationMessages;
38
+ }
39
+ //# sourceMappingURL=websocket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../../src/voice/transports/websocket.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,kBAAkB,EAClB,sBAAsB,EACvB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAEV,qBAAqB,EAItB,MAAM,UAAU,CAAC;AAKlB,qBAAa,kBAAmB,YAAW,UAAU;IACnD,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,SAAS,CAAqB;gBAE1B,SAAS,EAAE,kBAAkB;IAMnC,OAAO,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAyD5D,UAAU,CAAC,IAAI,SAAO,EAAE,MAAM,SAAgB,GAAG,IAAI;IAQrD,WAAW,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAMjD,WAAW,IAAI,OAAO;IAMtB,OAAO,IAAI,IAAI;IAMT,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAMhC,MAAM,IAAI,IAAI;IAMd,QAAQ,IAAI,IAAI;IAMhB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,gBAAgB,IAAI,IAAI;IAUxB,OAAO,IAAI,IAAI;IAuBf,OAAO,CAAC,aAAa;IAmCrB,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,4BAA4B;CA4CrC"}
@@ -0,0 +1,280 @@
1
+ "use strict";
2
+ /**
3
+ * WebSocketTransport — legacy transport that sends base64-encoded PCM audio
4
+ * over a JSON WebSocket. Extracted from Audial.ts for the ITransport refactor.
5
+ *
6
+ * Audio path:
7
+ * Mic → AudioRecorder (WAV → base64) → ws.send({type:'audio', data:...})
8
+ * Server → {type:'audio', data: base64} → base64 decode → PCMPlayer
9
+ *
10
+ * Messages (transcripts, config, events) share the same WebSocket.
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ var __importDefault = (this && this.__importDefault) || function (mod) {
46
+ return (mod && mod.__esModule) ? mod : { "default": mod };
47
+ };
48
+ Object.defineProperty(exports, "__esModule", { value: true });
49
+ exports.WebSocketTransport = void 0;
50
+ const audio_recorder_1 = require("../audio-recorder");
51
+ const pcm_player_1 = __importDefault(require("pcm-player"));
52
+ const base64js = __importStar(require("base64-js"));
53
+ class WebSocketTransport {
54
+ constructor(callbacks) {
55
+ this.ws = null;
56
+ this.recorder = null;
57
+ this.player = null;
58
+ this.audioDeafened = false;
59
+ this.micMuted = false;
60
+ this.debug = false;
61
+ this.callbacks = callbacks;
62
+ }
63
+ // ── ITransport: connect ──────────────────────────────────────────────
64
+ async connect(config) {
65
+ this.debug = config.debug ?? false;
66
+ // roomState is always present for WebSocketTransport (room-based flow only).
67
+ const wsUrl = config.roomState.websocketUrl;
68
+ if (!wsUrl) {
69
+ throw new Error('WebSocketTransport: no websocketUrl in roomState');
70
+ }
71
+ if (this.debug) {
72
+ console.debug('🔌 [WSTransport] Connecting:', wsUrl);
73
+ }
74
+ // Init audio components
75
+ this.initPlayer();
76
+ this.initRecorder();
77
+ // Start recording (mic capture)
78
+ await this.recorder?.start();
79
+ // Open WebSocket
80
+ this.ws = new WebSocket(wsUrl);
81
+ this.ws.binaryType = 'arraybuffer';
82
+ this.ws.onopen = () => {
83
+ if (this.debug)
84
+ console.debug('[WSTransport] WS open');
85
+ // Send PCC-compatibility simulation messages
86
+ this.sendTwilioSimulationMessages(config.roomState);
87
+ // Send audio config start message
88
+ const start = {
89
+ type: 'start',
90
+ input_audio_config: { sampling_rate: 48000, audio_encoding: 'linear16' },
91
+ output_audio_config: { sampling_rate: 24000, audio_encoding: 'linear16' },
92
+ };
93
+ this.sendRaw(start);
94
+ };
95
+ this.ws.onmessage = (event) => {
96
+ this.handleMessage(event);
97
+ };
98
+ this.ws.onerror = () => {
99
+ this.callbacks.onError(new Error('WebSocket error'));
100
+ };
101
+ this.ws.onclose = (event) => {
102
+ if (this.debug) {
103
+ console.debug('🔌 [WSTransport] WS closed:', { code: event.code, reason: event.reason });
104
+ }
105
+ this.callbacks.onClose(event.code, event.reason);
106
+ };
107
+ }
108
+ // ── ITransport: disconnect ───────────────────────────────────────────
109
+ disconnect(code = 1000, reason = 'client-stop') {
110
+ if (this.ws) {
111
+ this.ws.close(code, reason);
112
+ }
113
+ }
114
+ // ── ITransport: sendMessage ──────────────────────────────────────────
115
+ sendMessage(message) {
116
+ this.sendRaw(message);
117
+ }
118
+ // ── ITransport: isConnected ──────────────────────────────────────────
119
+ isConnected() {
120
+ return this.ws?.readyState === WebSocket.OPEN;
121
+ }
122
+ // ── ITransport: audio controls ───────────────────────────────────────
123
+ muteMic() {
124
+ if (this.micMuted)
125
+ return;
126
+ this.micMuted = true;
127
+ this.recorder?.stop();
128
+ }
129
+ async unmuteMic() {
130
+ if (!this.micMuted)
131
+ return;
132
+ this.micMuted = false;
133
+ await this.recorder?.start();
134
+ }
135
+ deafen() {
136
+ if (this.audioDeafened)
137
+ return;
138
+ this.audioDeafened = true;
139
+ this.player?.volume(0);
140
+ }
141
+ undeafen() {
142
+ if (!this.audioDeafened)
143
+ return;
144
+ this.audioDeafened = false;
145
+ this.player?.volume(1);
146
+ }
147
+ setVolume(volume) {
148
+ this.player?.volume(volume);
149
+ }
150
+ clearAudioBuffer() {
151
+ if (this.player) {
152
+ this.player.destroy();
153
+ this.player = null;
154
+ }
155
+ this.initPlayer();
156
+ }
157
+ // ── ITransport: destroy ──────────────────────────────────────────────
158
+ destroy() {
159
+ // Stop recorder and release mic
160
+ this.recorder?.stop();
161
+ this.recorder = null;
162
+ // Destroy player
163
+ if (this.player) {
164
+ this.player.destroy();
165
+ this.player = null;
166
+ }
167
+ // Cleanup WebSocket
168
+ if (this.ws) {
169
+ this.ws.onopen = null;
170
+ this.ws.onmessage = null;
171
+ this.ws.onerror = null;
172
+ this.ws.onclose = null;
173
+ this.ws = null;
174
+ }
175
+ }
176
+ // ── Private: message handling ────────────────────────────────────────
177
+ handleMessage(event) {
178
+ try {
179
+ const msg = JSON.parse(event.data);
180
+ // Handle audio internally — decode base64 and feed to PCMPlayer
181
+ if (msg.type === 'audio') {
182
+ if (this.player && !this.audioDeafened) {
183
+ try {
184
+ const dataBase64 = msg.data;
185
+ const byteArray = base64js.toByteArray(dataBase64);
186
+ const int16Array = new Int16Array(byteArray.buffer);
187
+ this.player.volume(1);
188
+ this.player.feed(int16Array);
189
+ }
190
+ catch (e) {
191
+ if (this.debug) {
192
+ console.error('[WSTransport] Error processing audio:', e);
193
+ }
194
+ }
195
+ }
196
+ }
197
+ // Pass ALL messages (including audio) to Audial for event routing
198
+ this.callbacks.onMessage(msg);
199
+ }
200
+ catch (error) {
201
+ if (this.debug) {
202
+ console.error('[WSTransport] Error parsing message:', error);
203
+ }
204
+ this.callbacks.onError(error instanceof Error ? error : new Error(String(error)));
205
+ }
206
+ }
207
+ // ── Private: send raw JSON ───────────────────────────────────────────
208
+ sendRaw(message) {
209
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
210
+ if (this.debug) {
211
+ console.warn('[WSTransport] Cannot send: WS not open');
212
+ }
213
+ return;
214
+ }
215
+ this.ws.send(JSON.stringify(message));
216
+ }
217
+ // ── Private: audio init ──────────────────────────────────────────────
218
+ initRecorder() {
219
+ this.recorder = new audio_recorder_1.AudioRecorder({
220
+ onData: (base64) => {
221
+ if (this.audioDeafened)
222
+ return;
223
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
224
+ return;
225
+ this.sendRaw({ type: 'audio', data: base64 });
226
+ },
227
+ onError: (error) => this.callbacks.onError(error),
228
+ });
229
+ }
230
+ initPlayer() {
231
+ this.player = new pcm_player_1.default({
232
+ inputCodec: 'Int16',
233
+ channels: 1,
234
+ sampleRate: 24000,
235
+ flushTime: 175,
236
+ fftSize: 1024,
237
+ });
238
+ this.player.volume(this.audioDeafened ? 0 : 1);
239
+ }
240
+ // ── Private: PCC compatibility ───────────────────────────────────────
241
+ sendTwilioSimulationMessages(roomState) {
242
+ const customParameters = roomState.connectionParameters;
243
+ if (!customParameters) {
244
+ if (this.debug) {
245
+ console.error('[WSTransport] No connectionParameters — cannot init');
246
+ }
247
+ return;
248
+ }
249
+ const roomId = roomState.roomId || Date.now().toString();
250
+ const connectedMessage = {
251
+ event: 'connected',
252
+ protocol: 'Call',
253
+ version: '1.0.0',
254
+ };
255
+ const startMessage = {
256
+ event: 'start',
257
+ sequenceNumber: '1',
258
+ start: {
259
+ accountSid: 'AC' + 'x'.repeat(32),
260
+ streamSid: `MZ${roomId}`,
261
+ callSid: `CA${roomId}`,
262
+ tracks: ['inbound', 'outbound'],
263
+ mediaFormat: {
264
+ encoding: 'audio/x-mulaw',
265
+ sampleRate: 8000,
266
+ channels: 1,
267
+ },
268
+ customParameters,
269
+ },
270
+ streamSid: `MZ${roomId}`,
271
+ };
272
+ this.sendRaw(connectedMessage);
273
+ this.sendRaw(startMessage);
274
+ if (this.debug) {
275
+ console.debug('[WSTransport] Sent Twilio simulation messages');
276
+ }
277
+ }
278
+ }
279
+ exports.WebSocketTransport = WebSocketTransport;
280
+ //# sourceMappingURL=websocket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../../src/voice/transports/websocket.ts"],"names":[],"mappings":"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"}