@convai/web-sdk 1.7.0 → 1.8.0-beta.1

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 (44) hide show
  1. package/dist/core/ConvaiClient.d.ts +40 -1
  2. package/dist/core/ConvaiClient.d.ts.map +1 -1
  3. package/dist/core/ConvaiClient.js +276 -167
  4. package/dist/core/ConvaiClient.js.map +1 -1
  5. package/dist/core/connectRequest.d.ts +1 -1
  6. package/dist/core/connectRequest.d.ts.map +1 -1
  7. package/dist/core/connectRequest.js.map +1 -1
  8. package/dist/core/types.d.ts +50 -2
  9. package/dist/core/types.d.ts.map +1 -1
  10. package/dist/core/types.js.map +1 -1
  11. package/dist/react/components/rtc-widget/components/AudioVisualizer.d.ts.map +1 -1
  12. package/dist/react/components/rtc-widget/components/AudioVisualizer.js +28 -1
  13. package/dist/react/components/rtc-widget/components/AudioVisualizer.js.map +1 -1
  14. package/dist/react/components/rtc-widget/components/conviComponents/VoiceModeOverlay.d.ts.map +1 -1
  15. package/dist/react/components/rtc-widget/components/conviComponents/VoiceModeOverlay.js +93 -49
  16. package/dist/react/components/rtc-widget/components/conviComponents/VoiceModeOverlay.js.map +1 -1
  17. package/dist/react/hooks/useConvaiClient.d.ts.map +1 -1
  18. package/dist/react/hooks/useConvaiClient.js +1 -0
  19. package/dist/react/hooks/useConvaiClient.js.map +1 -1
  20. package/dist/vanilla/AudioRenderer.d.ts +3 -1
  21. package/dist/vanilla/AudioRenderer.d.ts.map +1 -1
  22. package/dist/vanilla/AudioRenderer.js +2 -2
  23. package/dist/vanilla/AudioRenderer.js.map +1 -1
  24. package/dist/vanilla/ConvaiWidget.d.ts.map +1 -1
  25. package/dist/vanilla/ConvaiWidget.js +602 -114
  26. package/dist/vanilla/ConvaiWidget.js.map +1 -1
  27. package/dist/vanilla/icons.d.ts.map +1 -1
  28. package/dist/vanilla/icons.js +62 -15
  29. package/dist/vanilla/icons.js.map +1 -1
  30. package/dist/vanilla/index.d.ts +1 -1
  31. package/dist/vanilla/index.d.ts.map +1 -1
  32. package/dist/vanilla/index.js.map +1 -1
  33. package/dist/vanilla/styles.d.ts +18 -1
  34. package/dist/vanilla/styles.d.ts.map +1 -1
  35. package/dist/vanilla/styles.js +105 -29
  36. package/dist/vanilla/styles.js.map +1 -1
  37. package/dist/vanilla/types.d.ts +74 -0
  38. package/dist/vanilla/types.d.ts.map +1 -1
  39. package/dist/vanilla/types.js.map +1 -1
  40. package/dist/version.d.ts +1 -1
  41. package/dist/version.d.ts.map +1 -1
  42. package/dist/version.js +1 -1
  43. package/dist/version.js.map +1 -1
  44. package/package.json +14 -7
@@ -6,10 +6,91 @@ import { iosTransitions } from "../../styles/framerConfig";
6
6
  import { AudioVisualizer } from "../AudioVisualizer";
7
7
  export const VoiceModeOverlay = ({ isActive, isTalking, isListening = false, convaiClient, characterImage, characterName = "Character", room, }) => {
8
8
  const barsCount = 40; // Number of bars for user microphone waveform
9
- const [audioLevels, setAudioLevels] = useState(Array(barsCount).fill(0));
9
+ // PERF: the waveform is driven OUTSIDE React. A setState per animation
10
+ // frame re-rendered the whole overlay (reconcile + style recalc +
11
+ // framer-motion filter retarget) ~60x/s — ~30ms main-thread tasks that
12
+ // visibly juddered the host page's 3D scene whenever voice mode was
13
+ // open. Levels live in a ref and the SVG paths are updated directly.
14
+ const audioLevelsRef = useRef(Array(barsCount).fill(0));
15
+ const waveCanvasRef = useRef(null);
10
16
  const analyzerRef = useRef(null);
11
17
  const animationFrameRef = useRef(undefined);
12
18
  const audioContextRef = useRef(null);
19
+ // Paint the three waves onto a small canvas — no React, no SVG filters.
20
+ // (The previous SVG version re-rasterized a 35px drop-shadow blur every
21
+ // frame; that GPU paint alone pushed the host page to ~30fps.) Glow is
22
+ // approximated with a wide low-alpha understroke, which is ~free.
23
+ // Painting is THROTTLED to 30fps and skipped entirely while silent:
24
+ // every canvas update forces the compositor to re-blend the whole
25
+ // panel stack over the host WebGL canvas, so idle repaints are pure
26
+ // waste that judders the 3D scene.
27
+ const waveFrameParityRef = useRef(0);
28
+ const waveWasSilentRef = useRef(false);
29
+ const drawWaves = () => {
30
+ waveFrameParityRef.current ^= 1;
31
+ if (waveFrameParityRef.current)
32
+ return; // 30fps is plenty for a waveform
33
+ const canvas = waveCanvasRef.current;
34
+ if (!canvas)
35
+ return;
36
+ {
37
+ const lv = audioLevelsRef.current;
38
+ let sum = 0;
39
+ for (let i = 0; i < lv.length; i++)
40
+ sum += lv[i];
41
+ const silent = sum / lv.length < 0.012;
42
+ if (silent && waveWasSilentRef.current)
43
+ return; // static line already drawn
44
+ waveWasSilentRef.current = silent;
45
+ }
46
+ const dpr = Math.min(window.devicePixelRatio || 1, 2);
47
+ if (canvas.width !== 250 * dpr) {
48
+ canvas.width = 250 * dpr;
49
+ canvas.height = 80 * dpr;
50
+ }
51
+ const ctx = canvas.getContext("2d");
52
+ if (!ctx)
53
+ return;
54
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
55
+ ctx.clearRect(0, 0, 250, 80);
56
+ const audioLevels = audioLevelsRef.current;
57
+ const centerY = 40;
58
+ const waveWidth = 250;
59
+ const segments = barsCount;
60
+ const avgLevel = audioLevels.reduce((sum, level) => sum + level, 0) / audioLevels.length;
61
+ const waveColors = [
62
+ aeroTheme.colors.convai.light,
63
+ aeroTheme.colors.convai.light,
64
+ "#34d399",
65
+ ];
66
+ ctx.lineCap = "round";
67
+ ctx.lineJoin = "round";
68
+ for (let waveIndex = 2; waveIndex >= 0; waveIndex--) {
69
+ ctx.beginPath();
70
+ for (let i = 0; i <= segments; i++) {
71
+ const x = (i / segments) * waveWidth;
72
+ const levelIndex = Math.floor((i / segments) * (audioLevels.length - 1));
73
+ const level = audioLevels[levelIndex] || 0;
74
+ const phase = (Date.now() / 500 + i * 0.2 + waveIndex * 1.5) % (Math.PI * 2);
75
+ const baseAmplitude = avgLevel > 0.05 ? 2 + waveIndex * 1.5 : 0;
76
+ const amplitude = baseAmplitude + level * (25 - baseAmplitude);
77
+ const y = centerY + Math.sin(phase) * amplitude;
78
+ if (i === 0)
79
+ ctx.moveTo(x, y);
80
+ else
81
+ ctx.lineTo(x, y);
82
+ }
83
+ // glow understroke scaled by level, then the crisp line on top
84
+ ctx.strokeStyle = waveColors[waveIndex];
85
+ ctx.globalAlpha = 0.18 * (0.3 + avgLevel);
86
+ ctx.lineWidth = (2.5 - waveIndex * 0.4) + 8 * avgLevel + 3;
87
+ ctx.stroke();
88
+ ctx.globalAlpha = 0.95 - waveIndex * 0.15;
89
+ ctx.lineWidth = 2.5 - waveIndex * 0.4;
90
+ ctx.stroke();
91
+ }
92
+ ctx.globalAlpha = 1;
93
+ };
13
94
  // Setup audio analysis for USER microphone input ONLY
14
95
  useEffect(() => {
15
96
  if (!isActive) {
@@ -17,7 +98,8 @@ export const VoiceModeOverlay = ({ isActive, isTalking, isListening = false, con
17
98
  if (animationFrameRef.current) {
18
99
  cancelAnimationFrame(animationFrameRef.current);
19
100
  }
20
- setAudioLevels(Array(barsCount).fill(0));
101
+ audioLevelsRef.current = Array(barsCount).fill(0);
102
+ drawWaves();
21
103
  return;
22
104
  }
23
105
  let stream = null;
@@ -50,17 +132,17 @@ export const VoiceModeOverlay = ({ isActive, isTalking, isListening = false, con
50
132
  const rms = Math.sqrt(sum / dataArray.length);
51
133
  // Apply some scaling and clamping
52
134
  const volume = Math.min(1, rms * 3); // Boost sensitivity
53
- // Create left-to-right wave effect
54
- const levels = Array(barsCount)
55
- .fill(0)
56
- .map((_, i) => {
57
- // Progressive wave from left to right
135
+ // Create left-to-right wave effect — write into the ref and paint
136
+ // the SVG directly (no setState: a per-frame React render here
137
+ // visibly juddered the host page).
138
+ const levels = audioLevelsRef.current;
139
+ for (let i = 0; i < barsCount; i++) {
58
140
  const position = i / barsCount; // 0 to 1 from left to right
59
141
  const wavePhase = Date.now() / 300 + position * Math.PI * 2;
60
142
  const waveVariation = Math.sin(wavePhase) * 0.15 + 0.85; // 0.7 to 1.0
61
- return volume * waveVariation;
62
- });
63
- setAudioLevels(levels);
143
+ levels[i] = volume * waveVariation;
144
+ }
145
+ drawWaves();
64
146
  animationFrameRef.current = requestAnimationFrame(updateLevels);
65
147
  };
66
148
  updateLevels();
@@ -200,45 +282,7 @@ export const VoiceModeOverlay = ({ isActive, isTalking, isListening = false, con
200
282
  width: "250px",
201
283
  height: "80px",
202
284
  position: "relative",
203
- }, children: _jsx("svg", { width: "250", height: "80", style: {
204
- overflow: "visible",
205
- }, children: [0, 1, 2].map((waveIndex) => {
206
- // Calculate wave path based on audio levels
207
- const points = [];
208
- const centerY = 40;
209
- const waveWidth = 250;
210
- const segments = barsCount;
211
- // Calculate average audio level for glow intensity
212
- const avgLevel = audioLevels.reduce((sum, level) => sum + level, 0) / audioLevels.length;
213
- const glowIntensity = avgLevel * 35; // 0-35px glow (increased from 20)
214
- // Green color variants for each wave
215
- const waveColors = [
216
- aeroTheme.colors.convai.light, // Bright green - front wave
217
- aeroTheme.colors.convai.light, // Medium green - mid wave
218
- "#34d399", // Medium-light green - back wave (lighter than dark)
219
- ];
220
- for (let i = 0; i <= segments; i++) {
221
- const x = (i / segments) * waveWidth;
222
- const levelIndex = Math.floor((i / segments) * (audioLevels.length - 1));
223
- const level = audioLevels[levelIndex] || 0;
224
- // When idle (low audio), show straight line
225
- // When active, create waves with increased amplitude
226
- const phase = (Date.now() / 500 + i * 0.2 + waveIndex * 1.5) % (Math.PI * 2);
227
- // Only add wave motion when there's audio
228
- // Idle: amplitude ~0 (straight line)
229
- // Active: amplitude up to 25px (increased from 15)
230
- const baseAmplitude = avgLevel > 0.05 ? (2 + waveIndex * 1.5) : 0;
231
- const amplitude = baseAmplitude + level * (25 - baseAmplitude);
232
- const y = centerY + Math.sin(phase) * amplitude;
233
- points.push(`${x},${y}`);
234
- }
235
- return (_jsx(motion.path, { d: `M ${points.join(" L ")}`, fill: "none", stroke: waveColors[waveIndex], strokeWidth: 2.5 - waveIndex * 0.4, strokeLinecap: "round", strokeLinejoin: "round", opacity: 0.95 - waveIndex * 0.15, animate: {
236
- filter: `drop-shadow(0 0 ${glowIntensity}px ${waveColors[waveIndex]}) blur(${waveIndex * 0.3}px)`,
237
- }, transition: {
238
- duration: 0.1,
239
- ease: "easeOut",
240
- } }, waveIndex));
241
- }) }) })) }), _jsxs(motion.div, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { delay: 0.2, ...iosTransitions.fadePop }, children: [_jsx("div", { style: {
285
+ }, children: _jsx("canvas", { ref: waveCanvasRef, style: { width: "250px", height: "80px" } }) })) }), _jsxs(motion.div, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { delay: 0.2, ...iosTransitions.fadePop }, children: [_jsx("div", { style: {
242
286
  fontSize: "16px",
243
287
  fontWeight: 600,
244
288
  color: aeroTheme.colors.text.primary,
@@ -1 +1 @@
1
- {"version":3,"file":"VoiceModeOverlay.js","sourceRoot":"","sources":["../../../../../../src/react/components/rtc-widget/components/conviComponents/VoiceModeOverlay.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAcrD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,EAC/B,QAAQ,EACR,SAAS,EACT,WAAW,GAAG,KAAK,EACnB,YAAY,EACZ,cAAc,EACd,aAAa,GAAG,WAAW,EAC3B,IAAI,GACkB,EAAE,EAAE;IAC1B,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC,8CAA8C;IACpE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAC5C,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAa,CACrC,CAAC;IACF,MAAM,WAAW,GAAG,MAAM,CAAsB,IAAI,CAAC,CAAC;IACtD,MAAM,iBAAiB,GAAG,MAAM,CAAqB,SAAS,CAAC,CAAC;IAChE,MAAM,eAAe,GAAG,MAAM,CAAsB,IAAI,CAAC,CAAC;IAE1D,sDAAsD;IACtD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,qCAAqC;YACrC,IAAI,iBAAiB,CAAC,OAAO,EAAE,CAAC;gBAC9B,oBAAoB,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAClD,CAAC;YACD,cAAc,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACzC,OAAO;QACT,CAAC;QAED,IAAI,MAAM,GAAuB,IAAI,CAAC;QAEtC,MAAM,kBAAkB,GAAG,KAAK,IAAI,EAAE;YACpC,IAAI,CAAC;gBACH,wBAAwB;gBACxB,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBAEpE,oCAAoC;gBACpC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY;oBAC1C,MAAc,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBACxC,eAAe,CAAC,OAAO,GAAG,YAAY,CAAC;gBAEvC,MAAM,QAAQ,GAAG,YAAY,CAAC,cAAc,EAAE,CAAC;gBAC/C,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,oCAAoC;gBAC5D,QAAQ,CAAC,qBAAqB,GAAG,GAAG,CAAC;gBACrC,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAC;gBAE/B,MAAM,MAAM,GAAG,YAAY,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;gBAC5D,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAEzB,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAEnD,MAAM,YAAY,GAAG,GAAG,EAAE;oBACxB,IAAI,CAAC,WAAW,CAAC,OAAO;wBAAE,OAAO;oBAEjC,uDAAuD;oBACvD,QAAQ,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;oBAE1C,8CAA8C;oBAC9C,IAAI,GAAG,GAAG,CAAC,CAAC;oBACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;wBAC1C,MAAM,UAAU,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,kBAAkB;wBACjE,GAAG,IAAI,UAAU,GAAG,UAAU,CAAC;oBACjC,CAAC;oBACD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;oBAE9C,kCAAkC;oBAClC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAoB;oBAEzD,mCAAmC;oBACnC,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;yBAC5B,IAAI,CAAC,CAAC,CAAC;yBACP,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;wBACZ,sCAAsC;wBACtC,MAAM,QAAQ,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,4BAA4B;wBAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,QAAQ,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;wBAC5D,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,aAAa;wBACtE,OAAO,MAAM,GAAG,aAAa,CAAC;oBAChC,CAAC,CAAC,CAAC;oBAEL,cAAc,CAAC,MAAM,CAAC,CAAC;oBACvB,iBAAiB,CAAC,OAAO,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;gBAClE,CAAC,CAAC;gBAEF,YAAY,EAAE,CAAC;YACjB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,KAAK,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC,CAAC;QAEF,kBAAkB,EAAE,CAAC;QAErB,OAAO,GAAG,EAAE;YACV,IAAI,iBAAiB,CAAC,OAAO,EAAE,CAAC;gBAC9B,oBAAoB,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAClD,CAAC;YACD,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YACtD,CAAC;YACD,IAAI,eAAe,CAAC,OAAO,EAAE,CAAC;gBAC5B,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAClC,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;IAE1B,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE1D,OAAO,CACL,eACE,KAAK,EAAE;YACL,QAAQ,EAAE,UAAU;YACpB,GAAG,EAAE,KAAK;YACV,IAAI,EAAE,KAAK;YACX,SAAS,EAAE,uBAAuB;YAClC,SAAS,EAAE,QAAQ;YACnB,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,EAAE;YACV,aAAa,EAAE,MAAM;YACrB,OAAO,EAAE,MAAM;YACf,aAAa,EAAE,QAAQ;YACvB,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,MAAM;SACZ,aAGD,eACE,KAAK,EAAE;oBACL,QAAQ,EAAE,UAAU;oBACpB,OAAO,EAAE,MAAM;oBACf,UAAU,EAAE,QAAQ;oBACpB,cAAc,EAAE,QAAQ;oBACxB,SAAS,EAAE,SAAS,EAAE,0BAA0B;iBACjD,aAGA,IAAI,IAAI,CACP,KAAC,MAAM,CAAC,GAAG,IACT,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,EACnC,OAAO,EAAE;4BACP,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;4BAC9B,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;yBAC/B,EACD,UAAU,EAAE,cAAc,CAAC,OAAO,EAClC,KAAK,EAAE;4BACL,QAAQ,EAAE,UAAU;4BACpB,KAAK,EAAE,OAAO;4BACd,MAAM,EAAE,OAAO;4BACf,MAAM,EAAE,CAAC,CAAC,EAAE,yCAAyC;4BACrD,aAAa,EAAE,MAAM;yBACtB,YAED,KAAC,eAAe,IACd,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,GAAG,EACT,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EACpC,OAAO,EAAE,GAAG,EACZ,YAAY,EAAE,GAAG,EACjB,QAAQ,EAAE,EAAE,EACZ,gBAAgB,EAAE,gBAAgB,GAClC,GACS,CACd,EAGD,MAAC,MAAM,CAAC,GAAG,IAET,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,EACnC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EACjC,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,EAChC,UAAU,EAAE,cAAc,CAAC,OAAO,EAClC,KAAK,EAAE;4BACL,QAAQ,EAAE,UAAU;4BACpB,MAAM,EAAE,EAAE,EAAE,sCAAsC;4BAClD,YAAY,EAAE,KAAK;4BACnB,QAAQ,EAAE,SAAS,EAAE,kCAAkC;4BACvD,SAAS,EAAE,+BAA+B;4BAC1C,UAAU,EAAE,OAAO;yBACpB,aAGD,KAAC,MAAM,CAAC,GAAG,IACT,OAAO,EAAE;oCACP,MAAM,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC;oCAChB,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iCACpD,EACD,UAAU,EAAE;oCACV,MAAM,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;oCAC1D,KAAK,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE;iCAC5D,EACD,KAAK,EAAE;oCACL,QAAQ,EAAE,UAAU;oCACpB,KAAK,EAAE,OAAO;oCACd,MAAM,EAAE,OAAO;oCACf,YAAY,EAAE,KAAK;oCACnB,UAAU,EAAE;;;oBAGN,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK;oBAC7B,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK;oBAC7B,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI;oBAC5B,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK;oBAC7B,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK;;eAElC;oCACD,OAAO,EAAE,GAAG;oCACZ,MAAM,EAAE,WAAW;oCACnB,MAAM,EAAE,CAAC,CAAC;iCACX,GACD,EAGF,KAAC,MAAM,CAAC,GAAG,IACT,OAAO,EAAE;oCACP,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;oCAChB,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iCACpD,EACD,UAAU,EAAE;oCACV,MAAM,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;oCAC1D,KAAK,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE;iCAC9D,EACD,KAAK,EAAE;oCACL,QAAQ,EAAE,UAAU;oCACpB,KAAK,EAAE,OAAO;oCACd,MAAM,EAAE,OAAO;oCACf,YAAY,EAAE,KAAK;oCACnB,UAAU,EAAE;;;oBAGN,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK;oBAC7B,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK;;;;;oBAK7B,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI;oBAC5B,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI;;;eAGjC;oCACD,OAAO,EAAE,GAAG;oCACZ,MAAM,EAAE,WAAW;oCACnB,MAAM,EAAE,CAAC,CAAC;iCACX,GACD,EAGD,cACE,KAAK,EAAE;oCACL,QAAQ,EAAE,UAAU;oCACpB,YAAY,EAAE,KAAK;oCACnB,QAAQ,EAAE,QAAQ;oCAClB,MAAM,EAAE,oCAAoC;iCAC7C,YAED,cAAc,CAAC,CAAC,CAAC,CAChB,KAAC,MAAM,CAAC,GAAG,IACT,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE;wCACP,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;qCAChC,EACD,UAAU,EAAE;wCACV,QAAQ,EAAE,GAAG;wCACb,IAAI,EAAE,WAAW;qCAClB,EACD,KAAK,EAAE;wCACL,KAAK,EAAE,OAAO;wCACd,MAAM,EAAE,OAAO;wCACf,SAAS,EAAE,OAAO;wCAClB,OAAO,EAAE,OAAO;qCACjB,GACD,CACH,CAAC,CAAC,CAAC,CACF,cACE,KAAK,EAAE;wCACL,KAAK,EAAE,OAAO;wCACd,MAAM,EAAE,OAAO;wCACf,eAAe,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI;wCACrD,OAAO,EAAE,MAAM;wCACf,UAAU,EAAE,QAAQ;wCACpB,cAAc,EAAE,QAAQ;wCACxB,QAAQ,EAAE,MAAM;wCAChB,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK;wCACpC,UAAU,EAAE,GAAG;qCAChB,YAEA,aAAa,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,GAAG,GACnC,CACP,GACG,KA5HF,eAAe,CAAC,wDAAwD;qBA6HjE,IACT,EAGN,KAAC,eAAe,cACb,QAAQ,IAAI,CACX,KAAC,MAAM,CAAC,GAAG,IACT,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAC9B,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAC7B,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAC5B,UAAU,EAAE,cAAc,CAAC,OAAO,EAClC,KAAK,EAAE;wBACL,KAAK,EAAE,OAAO;wBACd,MAAM,EAAE,MAAM;wBACd,QAAQ,EAAE,UAAU;qBACrB,YAED,cACE,KAAK,EAAC,KAAK,EACX,MAAM,EAAC,IAAI,EACX,KAAK,EAAE;4BACL,QAAQ,EAAE,SAAS;yBACpB,YAGA,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE;4BAC3B,4CAA4C;4BAC5C,MAAM,MAAM,GAAa,EAAE,CAAC;4BAC5B,MAAM,OAAO,GAAG,EAAE,CAAC;4BACnB,MAAM,SAAS,GAAG,GAAG,CAAC;4BACtB,MAAM,QAAQ,GAAG,SAAS,CAAC;4BAE3B,mDAAmD;4BACnD,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC;4BACzF,MAAM,aAAa,GAAG,QAAQ,GAAG,EAAE,CAAC,CAAC,kCAAkC;4BAEvE,qCAAqC;4BACrC,MAAM,UAAU,GAAG;gCACjB,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAI,4BAA4B;gCAC7D,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAI,0BAA0B;gCAC3D,SAAS,EAAwB,qDAAqD;6BACvF,CAAC;4BAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;gCACnC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,SAAS,CAAC;gCACrC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;gCACzE,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gCAE3C,4CAA4C;gCAC5C,qDAAqD;gCACrD,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,SAAS,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;gCAE7E,0CAA0C;gCAC1C,qCAAqC;gCACrC,mDAAmD;gCACnD,MAAM,aAAa,GAAG,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gCAClE,MAAM,SAAS,GAAG,aAAa,GAAG,KAAK,GAAG,CAAC,EAAE,GAAG,aAAa,CAAC,CAAC;gCAC/D,MAAM,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;gCAEhD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;4BAC3B,CAAC;4BAED,OAAO,CACL,KAAC,MAAM,CAAC,IAAI,IAEV,CAAC,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,EAC5B,IAAI,EAAC,MAAM,EACX,MAAM,EAAE,UAAU,CAAC,SAAS,CAAC,EAC7B,WAAW,EAAE,GAAG,GAAG,SAAS,GAAG,GAAG,EAClC,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EACtB,OAAO,EAAE,IAAI,GAAG,SAAS,GAAG,IAAI,EAChC,OAAO,EAAE;oCACP,MAAM,EAAE,mBAAmB,aAAa,MAAM,UAAU,CAAC,SAAS,CAAC,UAAU,SAAS,GAAG,GAAG,KAAK;iCAClG,EACD,UAAU,EAAE;oCACV,QAAQ,EAAE,GAAG;oCACb,IAAI,EAAE,SAAS;iCAChB,IAdI,SAAS,CAed,CACH,CAAC;wBACJ,CAAC,CAAC,GACE,GACK,CACd,GACe,EAGlB,MAAC,MAAM,CAAC,GAAG,IACT,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAC9B,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAC7B,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,cAAc,CAAC,OAAO,EAAE,aAErD,cACE,KAAK,EAAE;4BACL,QAAQ,EAAE,MAAM;4BAChB,UAAU,EAAE,GAAG;4BACf,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO;4BACpC,YAAY,EAAE,QAAQ;yBACvB,YAEA,SAAS;4BACR,CAAC,CAAC,GAAG,aAAa,cAAc;4BAChC,CAAC,CAAC,WAAW,IAAI,QAAQ;gCACvB,CAAC,CAAC,cAAc;gCAChB,CAAC,CAAC,YAAY,GACd,EACN,cACE,KAAK,EAAE;4BACL,QAAQ,EAAE,MAAM;4BAChB,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS;yBACvC,YAEA,WAAW,IAAI,QAAQ,IAAI,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,wBAAwB,GAC7E,IACK,IACT,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { aeroTheme } from \"../../styles/theme\";\nimport { iosTransitions } from \"../../styles/framerConfig\";\nimport { AudioVisualizer } from \"../AudioVisualizer\";\nimport { Room } from \"livekit-client\";\n\ninterface VoiceModeOverlayProps {\n isActive: boolean;\n isTalking: boolean;\n /** When true (user is speaking, from server), show \"Listening...\" label */\n isListening?: boolean;\n convaiClient?: any; // Reference to convai client for audio analysis\n characterImage?: string;\n characterName?: string;\n room?: Room | null;\n}\n\nexport const VoiceModeOverlay = ({\n isActive,\n isTalking,\n isListening = false,\n convaiClient,\n characterImage,\n characterName = \"Character\",\n room,\n}: VoiceModeOverlayProps) => {\n const barsCount = 40; // Number of bars for user microphone waveform\n const [audioLevels, setAudioLevels] = useState<number[]>(\n Array(barsCount).fill(0) as number[],\n );\n const analyzerRef = useRef<AnalyserNode | null>(null);\n const animationFrameRef = useRef<number | undefined>(undefined);\n const audioContextRef = useRef<AudioContext | null>(null);\n\n // Setup audio analysis for USER microphone input ONLY\n useEffect(() => {\n if (!isActive) {\n // Clean up when user is not speaking\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n setAudioLevels(Array(barsCount).fill(0));\n return;\n }\n\n let stream: MediaStream | null = null;\n\n const setupAudioAnalysis = async () => {\n try {\n // Get microphone stream\n stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n\n // Create audio context and analyzer\n const audioContext = new (window.AudioContext ||\n (window as any).webkitAudioContext)();\n audioContextRef.current = audioContext;\n\n const analyzer = audioContext.createAnalyser();\n analyzer.fftSize = 256; // Better resolution for time domain\n analyzer.smoothingTimeConstant = 0.7;\n analyzerRef.current = analyzer;\n\n const source = audioContext.createMediaStreamSource(stream);\n source.connect(analyzer);\n\n const dataArray = new Uint8Array(analyzer.fftSize);\n\n const updateLevels = () => {\n if (!analyzerRef.current) return;\n\n // Use time domain data (waveform) instead of frequency\n analyzer.getByteTimeDomainData(dataArray);\n\n // Calculate RMS (Root Mean Square) for volume\n let sum = 0;\n for (let i = 0; i < dataArray.length; i++) {\n const normalized = (dataArray[i] - 128) / 128; // Center around 0\n sum += normalized * normalized;\n }\n const rms = Math.sqrt(sum / dataArray.length);\n\n // Apply some scaling and clamping\n const volume = Math.min(1, rms * 3); // Boost sensitivity\n\n // Create left-to-right wave effect\n const levels = Array(barsCount)\n .fill(0)\n .map((_, i) => {\n // Progressive wave from left to right\n const position = i / barsCount; // 0 to 1 from left to right\n const wavePhase = Date.now() / 300 + position * Math.PI * 2;\n const waveVariation = Math.sin(wavePhase) * 0.15 + 0.85; // 0.7 to 1.0\n return volume * waveVariation;\n });\n\n setAudioLevels(levels);\n animationFrameRef.current = requestAnimationFrame(updateLevels);\n };\n\n updateLevels();\n } catch (error) {\n console.error(\"Error setting up audio analysis:\", error);\n }\n };\n\n setupAudioAnalysis();\n\n return () => {\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n }\n if (audioContextRef.current) {\n audioContextRef.current.close();\n }\n };\n }, [isActive, barsCount]);\n\n const [isBotSpeaking, setIsBotSpeaking] = useState(false);\n\n return (\n <div\n style={{\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n textAlign: \"center\",\n padding: \"1rem\",\n zIndex: 10,\n pointerEvents: \"none\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"2rem\",\n }}\n >\n {/* Character Avatar with Audio Visualizer */}\n <div\n style={{\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n isolation: \"isolate\", // Create stacking context\n }}\n >\n {/* Audio Visualizer - positioned absolutely behind the character */}\n {room && (\n <motion.div\n initial={{ opacity: 0, scale: 0.8 }}\n animate={{\n opacity: isBotSpeaking ? 1 : 0,\n scale: isBotSpeaking ? 1 : 0.8,\n }}\n transition={iosTransitions.fadePop}\n style={{\n position: \"absolute\",\n width: \"220px\",\n height: \"220px\",\n zIndex: -1, // Negative z-index to ensure it's behind\n pointerEvents: \"none\",\n }}\n >\n <AudioVisualizer\n room={room}\n size={220}\n color={aeroTheme.colors.convai.light}\n opacity={0.6}\n avatarRadius={110}\n barCount={48}\n onSpeakingChange={setIsBotSpeaking}\n />\n </motion.div>\n )}\n\n {/* Character Image - pops from header to center */}\n <motion.div\n key=\"center-avatar\" // Use key instead of layoutId for independent animation\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={iosTransitions.fadePop}\n style={{\n position: \"relative\",\n zIndex: 10, // Higher z-index to be clearly on top\n borderRadius: \"50%\",\n overflow: \"visible\", // Changed to visible to show glow\n boxShadow: \"0 8px 32px rgba(0, 0, 0, 0.3)\",\n background: \"white\",\n }}\n >\n {/* Animated liquid gradient - Layer 1 */}\n <motion.div\n animate={{\n rotate: [0, 360],\n scale: isBotSpeaking ? [1, 1.05, 1.02, 1.05, 1] : 1,\n }}\n transition={{\n rotate: { duration: 20, repeat: Infinity, ease: \"linear\" },\n scale: { duration: 3, repeat: Infinity, ease: \"easeInOut\" },\n }}\n style={{\n position: \"absolute\",\n width: \"126px\",\n height: \"126px\",\n borderRadius: \"50%\",\n background: `\n conic-gradient(\n from 0deg,\n ${aeroTheme.colors.convai.light}00 0%,\n ${aeroTheme.colors.convai.light}40 25%,\n ${aeroTheme.colors.convai.dark}60 50%,\n ${aeroTheme.colors.convai.light}40 75%,\n ${aeroTheme.colors.convai.light}00 100%\n )\n `,\n opacity: 0.8,\n filter: \"blur(8px)\",\n zIndex: -2,\n }}\n />\n\n {/* Animated liquid gradient - Layer 2 (counter-rotating) */}\n <motion.div\n animate={{\n rotate: [360, 0],\n scale: isBotSpeaking ? [1, 1.03, 1.06, 1.03, 1] : 1,\n }}\n transition={{\n rotate: { duration: 15, repeat: Infinity, ease: \"linear\" },\n scale: { duration: 2.5, repeat: Infinity, ease: \"easeInOut\" },\n }}\n style={{\n position: \"absolute\",\n width: \"126px\",\n height: \"126px\",\n borderRadius: \"50%\",\n background: `\n radial-gradient(\n ellipse 80% 100% at 30% 40%,\n ${aeroTheme.colors.convai.light}50,\n ${aeroTheme.colors.convai.light}30 40%,\n transparent 70%\n ),\n radial-gradient(\n ellipse 80% 100% at 70% 60%,\n ${aeroTheme.colors.convai.dark}50,\n ${aeroTheme.colors.convai.dark}30 40%,\n transparent 70%\n )\n `,\n opacity: 0.9,\n filter: \"blur(6px)\",\n zIndex: -1,\n }}\n />\n\n {/* Character container with border */}\n <div\n style={{\n position: \"relative\",\n borderRadius: \"50%\",\n overflow: \"hidden\",\n border: `3px solid rgba(255, 255, 255, 0.2)`,\n }}\n >\n {characterImage ? (\n <motion.img\n src={characterImage}\n alt={characterName}\n animate={{\n scale: isBotSpeaking ? 1.05 : 1,\n }}\n transition={{\n duration: 0.3,\n ease: \"easeInOut\",\n }}\n style={{\n width: \"120px\",\n height: \"120px\",\n objectFit: \"cover\",\n display: \"block\",\n }}\n />\n ) : (\n <div\n style={{\n width: \"120px\",\n height: \"120px\",\n backgroundColor: aeroTheme.colors.convai.light + \"20\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"48px\",\n color: aeroTheme.colors.convai.light,\n fontWeight: 600,\n }}\n >\n {characterName[0]?.toUpperCase() || \"C\"}\n </div>\n )}\n </div>\n </motion.div>\n </div>\n\n {/* Sound Wave Lines - USER microphone ONLY */}\n <AnimatePresence>\n {isActive && (\n <motion.div\n initial={{ opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -20 }}\n transition={iosTransitions.fadePop}\n style={{\n width: \"250px\",\n height: \"80px\",\n position: \"relative\",\n }}\n >\n <svg\n width=\"250\"\n height=\"80\"\n style={{\n overflow: \"visible\",\n }}\n >\n {/* Generate 3 wave lines with green shades */}\n {[0, 1, 2].map((waveIndex) => {\n // Calculate wave path based on audio levels\n const points: string[] = [];\n const centerY = 40;\n const waveWidth = 250;\n const segments = barsCount;\n \n // Calculate average audio level for glow intensity\n const avgLevel = audioLevels.reduce((sum, level) => sum + level, 0) / audioLevels.length;\n const glowIntensity = avgLevel * 35; // 0-35px glow (increased from 20)\n \n // Green color variants for each wave\n const waveColors = [\n aeroTheme.colors.convai.light, // Bright green - front wave\n aeroTheme.colors.convai.light, // Medium green - mid wave\n \"#34d399\", // Medium-light green - back wave (lighter than dark)\n ];\n \n for (let i = 0; i <= segments; i++) {\n const x = (i / segments) * waveWidth;\n const levelIndex = Math.floor((i / segments) * (audioLevels.length - 1));\n const level = audioLevels[levelIndex] || 0;\n \n // When idle (low audio), show straight line\n // When active, create waves with increased amplitude\n const phase = (Date.now() / 500 + i * 0.2 + waveIndex * 1.5) % (Math.PI * 2);\n \n // Only add wave motion when there's audio\n // Idle: amplitude ~0 (straight line)\n // Active: amplitude up to 25px (increased from 15)\n const baseAmplitude = avgLevel > 0.05 ? (2 + waveIndex * 1.5) : 0;\n const amplitude = baseAmplitude + level * (25 - baseAmplitude);\n const y = centerY + Math.sin(phase) * amplitude;\n \n points.push(`${x},${y}`);\n }\n \n return (\n <motion.path\n key={waveIndex}\n d={`M ${points.join(\" L \")}`}\n fill=\"none\"\n stroke={waveColors[waveIndex]}\n strokeWidth={2.5 - waveIndex * 0.4}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n opacity={0.95 - waveIndex * 0.15}\n animate={{\n filter: `drop-shadow(0 0 ${glowIntensity}px ${waveColors[waveIndex]}) blur(${waveIndex * 0.3}px)`,\n }}\n transition={{\n duration: 0.1,\n ease: \"easeOut\",\n }}\n />\n );\n })}\n </svg>\n </motion.div>\n )}\n </AnimatePresence>\n\n {/* Status Text */}\n <motion.div\n initial={{ opacity: 0, y: 10 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ delay: 0.2, ...iosTransitions.fadePop }}\n >\n <div\n style={{\n fontSize: \"16px\",\n fontWeight: 600,\n color: aeroTheme.colors.text.primary,\n marginBottom: \"0.5rem\",\n }}\n >\n {isTalking\n ? `${characterName} Speaking...`\n : isListening || isActive\n ? \"Listening...\"\n : \"Voice Mode\"}\n </div>\n <div\n style={{\n fontSize: \"13px\",\n color: aeroTheme.colors.text.secondary,\n }}\n >\n {isListening || isActive || isTalking ? \"Audio active\" : \"Tap microphone to talk\"}\n </div>\n </motion.div>\n </div>\n );\n};\n"]}
1
+ {"version":3,"file":"VoiceModeOverlay.js","sourceRoot":"","sources":["../../../../../../src/react/components/rtc-widget/components/conviComponents/VoiceModeOverlay.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { aeroTheme } from \"../../styles/theme\";\nimport { iosTransitions } from \"../../styles/framerConfig\";\nimport { AudioVisualizer } from \"../AudioVisualizer\";\nimport { Room } from \"livekit-client\";\n\ninterface VoiceModeOverlayProps {\n isActive: boolean;\n isTalking: boolean;\n /** When true (user is speaking, from server), show \"Listening...\" label */\n isListening?: boolean;\n convaiClient?: any; // Reference to convai client for audio analysis\n characterImage?: string;\n characterName?: string;\n room?: Room | null;\n}\n\nexport const VoiceModeOverlay = ({\n isActive,\n isTalking,\n isListening = false,\n convaiClient,\n characterImage,\n characterName = \"Character\",\n room,\n}: VoiceModeOverlayProps) => {\n const barsCount = 40; // Number of bars for user microphone waveform\n // PERF: the waveform is driven OUTSIDE React. A setState per animation\n // frame re-rendered the whole overlay (reconcile + style recalc +\n // framer-motion filter retarget) ~60x/s — ~30ms main-thread tasks that\n // visibly juddered the host page's 3D scene whenever voice mode was\n // open. Levels live in a ref and the SVG paths are updated directly.\n const audioLevelsRef = useRef<number[]>(Array(barsCount).fill(0));\n const waveCanvasRef = useRef<HTMLCanvasElement | null>(null);\n const analyzerRef = useRef<AnalyserNode | null>(null);\n const animationFrameRef = useRef<number | undefined>(undefined);\n const audioContextRef = useRef<AudioContext | null>(null);\n\n // Paint the three waves onto a small canvas — no React, no SVG filters.\n // (The previous SVG version re-rasterized a 35px drop-shadow blur every\n // frame; that GPU paint alone pushed the host page to ~30fps.) Glow is\n // approximated with a wide low-alpha understroke, which is ~free.\n // Painting is THROTTLED to 30fps and skipped entirely while silent:\n // every canvas update forces the compositor to re-blend the whole\n // panel stack over the host WebGL canvas, so idle repaints are pure\n // waste that judders the 3D scene.\n const waveFrameParityRef = useRef(0);\n const waveWasSilentRef = useRef(false);\n const drawWaves = () => {\n waveFrameParityRef.current ^= 1;\n if (waveFrameParityRef.current) return; // 30fps is plenty for a waveform\n const canvas = waveCanvasRef.current;\n if (!canvas) return;\n {\n const lv = audioLevelsRef.current;\n let sum = 0;\n for (let i = 0; i < lv.length; i++) sum += lv[i];\n const silent = sum / lv.length < 0.012;\n if (silent && waveWasSilentRef.current) return; // static line already drawn\n waveWasSilentRef.current = silent;\n }\n const dpr = Math.min(window.devicePixelRatio || 1, 2);\n if (canvas.width !== 250 * dpr) {\n canvas.width = 250 * dpr;\n canvas.height = 80 * dpr;\n }\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, 250, 80);\n const audioLevels = audioLevelsRef.current;\n const centerY = 40;\n const waveWidth = 250;\n const segments = barsCount;\n const avgLevel =\n audioLevels.reduce((sum, level) => sum + level, 0) / audioLevels.length;\n const waveColors = [\n aeroTheme.colors.convai.light,\n aeroTheme.colors.convai.light,\n \"#34d399\",\n ];\n ctx.lineCap = \"round\";\n ctx.lineJoin = \"round\";\n for (let waveIndex = 2; waveIndex >= 0; waveIndex--) {\n ctx.beginPath();\n for (let i = 0; i <= segments; i++) {\n const x = (i / segments) * waveWidth;\n const levelIndex = Math.floor((i / segments) * (audioLevels.length - 1));\n const level = audioLevels[levelIndex] || 0;\n const phase = (Date.now() / 500 + i * 0.2 + waveIndex * 1.5) % (Math.PI * 2);\n const baseAmplitude = avgLevel > 0.05 ? 2 + waveIndex * 1.5 : 0;\n const amplitude = baseAmplitude + level * (25 - baseAmplitude);\n const y = centerY + Math.sin(phase) * amplitude;\n if (i === 0) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n }\n // glow understroke scaled by level, then the crisp line on top\n ctx.strokeStyle = waveColors[waveIndex];\n ctx.globalAlpha = 0.18 * (0.3 + avgLevel);\n ctx.lineWidth = (2.5 - waveIndex * 0.4) + 8 * avgLevel + 3;\n ctx.stroke();\n ctx.globalAlpha = 0.95 - waveIndex * 0.15;\n ctx.lineWidth = 2.5 - waveIndex * 0.4;\n ctx.stroke();\n }\n ctx.globalAlpha = 1;\n };\n\n // Setup audio analysis for USER microphone input ONLY\n useEffect(() => {\n if (!isActive) {\n // Clean up when user is not speaking\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n audioLevelsRef.current = Array(barsCount).fill(0);\n drawWaves();\n return;\n }\n\n let stream: MediaStream | null = null;\n\n const setupAudioAnalysis = async () => {\n try {\n // Get microphone stream\n stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n\n // Create audio context and analyzer\n const audioContext = new (window.AudioContext ||\n (window as any).webkitAudioContext)();\n audioContextRef.current = audioContext;\n\n const analyzer = audioContext.createAnalyser();\n analyzer.fftSize = 256; // Better resolution for time domain\n analyzer.smoothingTimeConstant = 0.7;\n analyzerRef.current = analyzer;\n\n const source = audioContext.createMediaStreamSource(stream);\n source.connect(analyzer);\n\n const dataArray = new Uint8Array(analyzer.fftSize);\n\n const updateLevels = () => {\n if (!analyzerRef.current) return;\n\n // Use time domain data (waveform) instead of frequency\n analyzer.getByteTimeDomainData(dataArray);\n\n // Calculate RMS (Root Mean Square) for volume\n let sum = 0;\n for (let i = 0; i < dataArray.length; i++) {\n const normalized = (dataArray[i] - 128) / 128; // Center around 0\n sum += normalized * normalized;\n }\n const rms = Math.sqrt(sum / dataArray.length);\n\n // Apply some scaling and clamping\n const volume = Math.min(1, rms * 3); // Boost sensitivity\n\n // Create left-to-right wave effect — write into the ref and paint\n // the SVG directly (no setState: a per-frame React render here\n // visibly juddered the host page).\n const levels = audioLevelsRef.current;\n for (let i = 0; i < barsCount; i++) {\n const position = i / barsCount; // 0 to 1 from left to right\n const wavePhase = Date.now() / 300 + position * Math.PI * 2;\n const waveVariation = Math.sin(wavePhase) * 0.15 + 0.85; // 0.7 to 1.0\n levels[i] = volume * waveVariation;\n }\n drawWaves();\n animationFrameRef.current = requestAnimationFrame(updateLevels);\n };\n\n updateLevels();\n } catch (error) {\n console.error(\"Error setting up audio analysis:\", error);\n }\n };\n\n setupAudioAnalysis();\n\n return () => {\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n }\n if (audioContextRef.current) {\n audioContextRef.current.close();\n }\n };\n }, [isActive, barsCount]);\n\n const [isBotSpeaking, setIsBotSpeaking] = useState(false);\n\n return (\n <div\n style={{\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n textAlign: \"center\",\n padding: \"1rem\",\n zIndex: 10,\n pointerEvents: \"none\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"2rem\",\n }}\n >\n {/* Character Avatar with Audio Visualizer */}\n <div\n style={{\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n isolation: \"isolate\", // Create stacking context\n }}\n >\n {/* Audio Visualizer - positioned absolutely behind the character */}\n {room && (\n <motion.div\n initial={{ opacity: 0, scale: 0.8 }}\n animate={{\n opacity: isBotSpeaking ? 1 : 0,\n scale: isBotSpeaking ? 1 : 0.8,\n }}\n transition={iosTransitions.fadePop}\n style={{\n position: \"absolute\",\n width: \"220px\",\n height: \"220px\",\n zIndex: -1, // Negative z-index to ensure it's behind\n pointerEvents: \"none\",\n }}\n >\n <AudioVisualizer\n room={room}\n size={220}\n color={aeroTheme.colors.convai.light}\n opacity={0.6}\n avatarRadius={110}\n barCount={48}\n onSpeakingChange={setIsBotSpeaking}\n />\n </motion.div>\n )}\n\n {/* Character Image - pops from header to center */}\n <motion.div\n key=\"center-avatar\" // Use key instead of layoutId for independent animation\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={iosTransitions.fadePop}\n style={{\n position: \"relative\",\n zIndex: 10, // Higher z-index to be clearly on top\n borderRadius: \"50%\",\n overflow: \"visible\", // Changed to visible to show glow\n boxShadow: \"0 8px 32px rgba(0, 0, 0, 0.3)\",\n background: \"white\",\n }}\n >\n {/* Animated liquid gradient - Layer 1 */}\n <motion.div\n animate={{\n rotate: [0, 360],\n scale: isBotSpeaking ? [1, 1.05, 1.02, 1.05, 1] : 1,\n }}\n transition={{\n rotate: { duration: 20, repeat: Infinity, ease: \"linear\" },\n scale: { duration: 3, repeat: Infinity, ease: \"easeInOut\" },\n }}\n style={{\n position: \"absolute\",\n width: \"126px\",\n height: \"126px\",\n borderRadius: \"50%\",\n background: `\n conic-gradient(\n from 0deg,\n ${aeroTheme.colors.convai.light}00 0%,\n ${aeroTheme.colors.convai.light}40 25%,\n ${aeroTheme.colors.convai.dark}60 50%,\n ${aeroTheme.colors.convai.light}40 75%,\n ${aeroTheme.colors.convai.light}00 100%\n )\n `,\n opacity: 0.8,\n filter: \"blur(8px)\",\n zIndex: -2,\n }}\n />\n\n {/* Animated liquid gradient - Layer 2 (counter-rotating) */}\n <motion.div\n animate={{\n rotate: [360, 0],\n scale: isBotSpeaking ? [1, 1.03, 1.06, 1.03, 1] : 1,\n }}\n transition={{\n rotate: { duration: 15, repeat: Infinity, ease: \"linear\" },\n scale: { duration: 2.5, repeat: Infinity, ease: \"easeInOut\" },\n }}\n style={{\n position: \"absolute\",\n width: \"126px\",\n height: \"126px\",\n borderRadius: \"50%\",\n background: `\n radial-gradient(\n ellipse 80% 100% at 30% 40%,\n ${aeroTheme.colors.convai.light}50,\n ${aeroTheme.colors.convai.light}30 40%,\n transparent 70%\n ),\n radial-gradient(\n ellipse 80% 100% at 70% 60%,\n ${aeroTheme.colors.convai.dark}50,\n ${aeroTheme.colors.convai.dark}30 40%,\n transparent 70%\n )\n `,\n opacity: 0.9,\n filter: \"blur(6px)\",\n zIndex: -1,\n }}\n />\n\n {/* Character container with border */}\n <div\n style={{\n position: \"relative\",\n borderRadius: \"50%\",\n overflow: \"hidden\",\n border: `3px solid rgba(255, 255, 255, 0.2)`,\n }}\n >\n {characterImage ? (\n <motion.img\n src={characterImage}\n alt={characterName}\n animate={{\n scale: isBotSpeaking ? 1.05 : 1,\n }}\n transition={{\n duration: 0.3,\n ease: \"easeInOut\",\n }}\n style={{\n width: \"120px\",\n height: \"120px\",\n objectFit: \"cover\",\n display: \"block\",\n }}\n />\n ) : (\n <div\n style={{\n width: \"120px\",\n height: \"120px\",\n backgroundColor: aeroTheme.colors.convai.light + \"20\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"48px\",\n color: aeroTheme.colors.convai.light,\n fontWeight: 600,\n }}\n >\n {characterName[0]?.toUpperCase() || \"C\"}\n </div>\n )}\n </div>\n </motion.div>\n </div>\n\n {/* Sound Wave Lines - USER microphone ONLY */}\n <AnimatePresence>\n {isActive && (\n <motion.div\n initial={{ opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -20 }}\n transition={iosTransitions.fadePop}\n style={{\n width: \"250px\",\n height: \"80px\",\n position: \"relative\",\n }}\n >\n {/* Wave lines painted by drawWaves() (rAF-driven canvas) — the\n previous SVG + animated drop-shadow filter re-rasterized a\n blurred layer every frame and juddered the host page. */}\n <canvas\n ref={waveCanvasRef}\n style={{ width: \"250px\", height: \"80px\" }}\n />\n </motion.div>\n )}\n </AnimatePresence>\n\n {/* Status Text */}\n <motion.div\n initial={{ opacity: 0, y: 10 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ delay: 0.2, ...iosTransitions.fadePop }}\n >\n <div\n style={{\n fontSize: \"16px\",\n fontWeight: 600,\n color: aeroTheme.colors.text.primary,\n marginBottom: \"0.5rem\",\n }}\n >\n {isTalking\n ? `${characterName} Speaking...`\n : isListening || isActive\n ? \"Listening...\"\n : \"Voice Mode\"}\n </div>\n <div\n style={{\n fontSize: \"13px\",\n color: aeroTheme.colors.text.secondary,\n }}\n >\n {isListening || isActive || isTalking ? \"Audio active\" : \"Tap microphone to talk\"}\n </div>\n </motion.div>\n </div>\n );\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"useConvaiClient.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useConvaiClient.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,eAAe,GAC1B,SAAS,YAAY,KACpB,aAAa,GAAG;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,mBAAmB,EAAE,OAAO,CAAC;CA0N9B,CAAC"}
1
+ {"version":3,"file":"useConvaiClient.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useConvaiClient.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,eAAe,GAC1B,SAAS,YAAY,KACpB,aAAa,GAAG;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,mBAAmB,EAAE,OAAO,CAAC;CA2N9B,CAAC"}
@@ -167,6 +167,7 @@ export const useConvaiClient = (config) => {
167
167
  ...(client.authToken && { authToken: client.authToken }),
168
168
  characterId: client.characterId,
169
169
  connect,
170
+ connectWithConnectionData: client.connectWithConnectionData.bind(client),
170
171
  disconnect: client.disconnect.bind(client),
171
172
  reconnect,
172
173
  resetSession: client.resetSession.bind(client),
@@ -1 +1 @@
1
- {"version":3,"file":"useConvaiClient.js","sourceRoot":"","sources":["../../../src/react/hooks/useConvaiClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport { ConvaiClient as CoreConvaiClient } from \"../../core\";\nimport type {\n ConvaiConfig,\n IConvaiClient,\n ChatMessage,\n} from \"../../core/types\";\n\n/**\n * React hook wrapper for ConvaiClient\n * Main hook for managing Convai client connection and functionality.\n *\n * Provides a complete interface for connecting to Convai's AI-powered voice assistants,\n * managing real-time audio/video conversations, and handling various message types.\n *\n * @param config - Optional configuration to store for later connection\n * @returns {ConvaiClient & { activity: string; chatMessages: ChatMessage[] }} Complete client interface with connection state, methods, and message history\n *\n * @example\n * ```tsx\n * function App() {\n * const convaiClient = useConvaiClient({\n * apiKey: 'your-api-key',\n * characterId: 'your-character-id',\n * endUserId: 'user-uuid', // Optional: enables memory & analytics\n * enableVideo: true,\n * });\n *\n * return (\n * <ConvaiWidget convaiClient={convaiClient} />\n * );\n * }\n * ```\n */\nexport const useConvaiClient = (\n config?: ConvaiConfig,\n): IConvaiClient & {\n activity: string;\n chatMessages: ChatMessage[];\n isAudioMuted: boolean;\n isVideoEnabled: boolean;\n isScreenShareActive: boolean;\n} => {\n // Create client instance once\n const [client] = useState(() => new CoreConvaiClient());\n\n // React state for UI updates\n const [state, setState] = useState(client.state);\n const [activity, setActivity] = useState<string>(\"Idle\");\n const [chatMessages, setChatMessages] = useState<ChatMessage[]>(\n client.chatMessages,\n );\n const [userTranscription, setUserTranscription] = useState<string>(\n client.userTranscription,\n );\n const [isSpeaking, setIsSpeaking] = useState<boolean>(false);\n const [isBotReady, setIsBotReady] = useState<boolean>(client.isBotReady);\n \n // Reactive states for control managers\n const [isAudioMuted, setIsAudioMuted] = useState<boolean>(\n client.audioControls.isAudioMuted\n );\n const [isVideoEnabled, setIsVideoEnabled] = useState<boolean>(\n client.videoControls.isVideoEnabled\n );\n const [isScreenShareActive, setIsScreenShareActive] = useState<boolean>(\n client.screenShareControls.isScreenShareActive\n );\n\n // Store config if provided\n const [storedConfig] = useState<ConvaiConfig | undefined>(config);\n\n // Setup event listeners\n useEffect(() => {\n // State change listener\n const unsubStateChange = client.on(\"stateChange\", (newState) => {\n setState(newState);\n\n // Update activity based on state (priority: speaking > listening > thinking > connected)\n if (!newState.isConnected) {\n setActivity(\"Disconnected\");\n } else if (newState.isConnecting) {\n setActivity(\"Connecting...\");\n } else if (newState.isSpeaking) {\n setActivity(\"Speaking\");\n } else if (newState.isListening) {\n setActivity(\"Listening\");\n } else if (newState.isThinking) {\n setActivity(\"Thinking\");\n } else {\n setActivity(\"Connected\");\n }\n });\n\n // Messages change listener\n const unsubMessagesChange = client.on(\"messagesChange\", (messages) => {\n setChatMessages([...messages]);\n });\n\n // User transcription change listener\n const unsubUserTranscription = client.on(\n \"userTranscriptionChange\",\n (transcription) => {\n setUserTranscription(transcription);\n },\n );\n\n // Speaking change listener\n const unsubSpeaking = client.on(\"speakingChange\", (speaking) => {\n setIsSpeaking(speaking);\n });\n\n // Bot ready listener\n const unsubBotReady = client.on(\"botReady\", () => {\n setIsBotReady(true);\n setActivity(\"Connected\");\n });\n\n // Connect listener\n const unsubConnect = client.on(\"connect\", () => {\n setState(client.state);\n });\n\n // Disconnect listener\n const unsubDisconnect = client.on(\"disconnect\", () => {\n setIsBotReady(false);\n setState(client.state);\n setActivity(\"Disconnected\");\n setChatMessages([]);\n // Reset control states on disconnect\n setIsAudioMuted(true);\n setIsVideoEnabled(false);\n setIsScreenShareActive(false);\n });\n\n // WebSocket transport: play bot audio track via a hidden <audio> element\n const wsAudioEl = document.createElement(\"audio\");\n wsAudioEl.autoplay = true;\n wsAudioEl.dataset.convaiWs = \"true\";\n document.body.appendChild(wsAudioEl);\n\n const unsubBotAudioTrack = client.on(\n \"botAudioTrack\",\n (track: MediaStreamTrack) => {\n wsAudioEl.srcObject = new MediaStream([track]);\n },\n );\n\n // Disconnect listener also clears WS audio\n const unsubDisconnectWsAudio = client.on(\"disconnect\", () => {\n wsAudioEl.srcObject = null;\n });\n\n // Audio controls state change listener\n const unsubAudioState = client.audioControls.on(\"audioStateChange\", (audioState: any) => {\n if (audioState.isAudioMuted !== undefined) {\n setIsAudioMuted(audioState.isAudioMuted);\n }\n });\n\n // Video controls state change listener\n const unsubVideoState = client.videoControls.on(\"videoStateChange\", (videoState: any) => {\n if (videoState.isVideoEnabled !== undefined) {\n setIsVideoEnabled(videoState.isVideoEnabled);\n }\n });\n\n // Screen share controls state change listener\n const unsubScreenShareState = client.screenShareControls.on(\"screenShareStateChange\", (screenShareState: any) => {\n if (screenShareState.isScreenShareActive !== undefined) {\n setIsScreenShareActive(screenShareState.isScreenShareActive);\n }\n });\n\n // Cleanup listeners on unmount\n return () => {\n unsubStateChange();\n unsubMessagesChange();\n unsubUserTranscription();\n unsubSpeaking();\n unsubBotReady();\n unsubConnect();\n unsubDisconnect();\n unsubBotAudioTrack();\n unsubDisconnectWsAudio();\n unsubAudioState();\n unsubVideoState();\n unsubScreenShareState();\n wsAudioEl.srcObject = null;\n wsAudioEl.remove();\n };\n }, [client]);\n\n // Create enhanced connect function that can use stored config\n const connect = useCallback(\n async (configOverride?: ConvaiConfig) => {\n const finalConfig = configOverride || storedConfig;\n\n if (!finalConfig) {\n throw new Error(\n \"No configuration provided. Pass config to useConvaiClient() or to connect()\",\n );\n }\n\n await client.connect(finalConfig);\n },\n [client, storedConfig],\n );\n\n // Create reconnect function wrapper\n const reconnect = useCallback(async () => {\n await client.reconnect();\n }, [client]);\n\n // Return client interface with React-friendly additions\n return {\n state,\n connectionType: client.connectionType,\n ...(client.apiKey && { apiKey: client.apiKey }),\n ...(client.authToken && { authToken: client.authToken }),\n characterId: client.characterId,\n connect,\n disconnect: client.disconnect.bind(client),\n reconnect,\n resetSession: client.resetSession.bind(client),\n room: client.room,\n sendUserTextMessage: client.sendUserTextMessage.bind(client),\n sendTriggerMessage: client.sendTriggerMessage.bind(client),\n sendInterruptMessage: client.sendInterruptMessage.bind(client),\n resetIdleTimer: client.resetIdleTimer.bind(client),\n updateTemplateKeys: client.updateTemplateKeys.bind(client),\n updateDynamicInfo: client.updateDynamicInfo.bind(client),\n updateContext: client.updateContext.bind(client),\n updateEmotion: client.updateEmotion.bind(client),\n visionStatus: client.visionStatus.bind(client),\n visionTrigger: client.visionTrigger.bind(client),\n respondModeUpdate: client.respondModeUpdate.bind(client),\n updateSceneMetadata: client.updateSceneMetadata.bind(client),\n activity,\n chatMessages,\n userTranscription,\n characterSessionId: client.characterSessionId,\n isBotReady,\n audioControls: client.audioControls,\n videoControls: client.videoControls,\n screenShareControls: client.screenShareControls,\n blendshapeQueue: client.blendshapeQueue,\n conversationSessionId: client.conversationSessionId,\n memoryManager: client.memoryManager,\n toggleTts: client.toggleTts.bind(client),\n toggleStt: client.toggleStt.bind(client),\n uploadFile: client.uploadFile.bind(client),\n on: client.on.bind(client),\n off: client.off.bind(client),\n // Reactive control states\n isAudioMuted,\n isVideoEnabled,\n isScreenShareActive,\n };\n};\n"]}
1
+ {"version":3,"file":"useConvaiClient.js","sourceRoot":"","sources":["../../../src/react/hooks/useConvaiClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport { ConvaiClient as CoreConvaiClient } from \"../../core\";\nimport type {\n ConvaiConfig,\n IConvaiClient,\n ChatMessage,\n} from \"../../core/types\";\n\n/**\n * React hook wrapper for ConvaiClient\n * Main hook for managing Convai client connection and functionality.\n *\n * Provides a complete interface for connecting to Convai's AI-powered voice assistants,\n * managing real-time audio/video conversations, and handling various message types.\n *\n * @param config - Optional configuration to store for later connection\n * @returns {ConvaiClient & { activity: string; chatMessages: ChatMessage[] }} Complete client interface with connection state, methods, and message history\n *\n * @example\n * ```tsx\n * function App() {\n * const convaiClient = useConvaiClient({\n * apiKey: 'your-api-key',\n * characterId: 'your-character-id',\n * endUserId: 'user-uuid', // Optional: enables memory & analytics\n * enableVideo: true,\n * });\n *\n * return (\n * <ConvaiWidget convaiClient={convaiClient} />\n * );\n * }\n * ```\n */\nexport const useConvaiClient = (\n config?: ConvaiConfig,\n): IConvaiClient & {\n activity: string;\n chatMessages: ChatMessage[];\n isAudioMuted: boolean;\n isVideoEnabled: boolean;\n isScreenShareActive: boolean;\n} => {\n // Create client instance once\n const [client] = useState(() => new CoreConvaiClient());\n\n // React state for UI updates\n const [state, setState] = useState(client.state);\n const [activity, setActivity] = useState<string>(\"Idle\");\n const [chatMessages, setChatMessages] = useState<ChatMessage[]>(\n client.chatMessages,\n );\n const [userTranscription, setUserTranscription] = useState<string>(\n client.userTranscription,\n );\n const [isSpeaking, setIsSpeaking] = useState<boolean>(false);\n const [isBotReady, setIsBotReady] = useState<boolean>(client.isBotReady);\n \n // Reactive states for control managers\n const [isAudioMuted, setIsAudioMuted] = useState<boolean>(\n client.audioControls.isAudioMuted\n );\n const [isVideoEnabled, setIsVideoEnabled] = useState<boolean>(\n client.videoControls.isVideoEnabled\n );\n const [isScreenShareActive, setIsScreenShareActive] = useState<boolean>(\n client.screenShareControls.isScreenShareActive\n );\n\n // Store config if provided\n const [storedConfig] = useState<ConvaiConfig | undefined>(config);\n\n // Setup event listeners\n useEffect(() => {\n // State change listener\n const unsubStateChange = client.on(\"stateChange\", (newState) => {\n setState(newState);\n\n // Update activity based on state (priority: speaking > listening > thinking > connected)\n if (!newState.isConnected) {\n setActivity(\"Disconnected\");\n } else if (newState.isConnecting) {\n setActivity(\"Connecting...\");\n } else if (newState.isSpeaking) {\n setActivity(\"Speaking\");\n } else if (newState.isListening) {\n setActivity(\"Listening\");\n } else if (newState.isThinking) {\n setActivity(\"Thinking\");\n } else {\n setActivity(\"Connected\");\n }\n });\n\n // Messages change listener\n const unsubMessagesChange = client.on(\"messagesChange\", (messages) => {\n setChatMessages([...messages]);\n });\n\n // User transcription change listener\n const unsubUserTranscription = client.on(\n \"userTranscriptionChange\",\n (transcription) => {\n setUserTranscription(transcription);\n },\n );\n\n // Speaking change listener\n const unsubSpeaking = client.on(\"speakingChange\", (speaking) => {\n setIsSpeaking(speaking);\n });\n\n // Bot ready listener\n const unsubBotReady = client.on(\"botReady\", () => {\n setIsBotReady(true);\n setActivity(\"Connected\");\n });\n\n // Connect listener\n const unsubConnect = client.on(\"connect\", () => {\n setState(client.state);\n });\n\n // Disconnect listener\n const unsubDisconnect = client.on(\"disconnect\", () => {\n setIsBotReady(false);\n setState(client.state);\n setActivity(\"Disconnected\");\n setChatMessages([]);\n // Reset control states on disconnect\n setIsAudioMuted(true);\n setIsVideoEnabled(false);\n setIsScreenShareActive(false);\n });\n\n // WebSocket transport: play bot audio track via a hidden <audio> element\n const wsAudioEl = document.createElement(\"audio\");\n wsAudioEl.autoplay = true;\n wsAudioEl.dataset.convaiWs = \"true\";\n document.body.appendChild(wsAudioEl);\n\n const unsubBotAudioTrack = client.on(\n \"botAudioTrack\",\n (track: MediaStreamTrack) => {\n wsAudioEl.srcObject = new MediaStream([track]);\n },\n );\n\n // Disconnect listener also clears WS audio\n const unsubDisconnectWsAudio = client.on(\"disconnect\", () => {\n wsAudioEl.srcObject = null;\n });\n\n // Audio controls state change listener\n const unsubAudioState = client.audioControls.on(\"audioStateChange\", (audioState: any) => {\n if (audioState.isAudioMuted !== undefined) {\n setIsAudioMuted(audioState.isAudioMuted);\n }\n });\n\n // Video controls state change listener\n const unsubVideoState = client.videoControls.on(\"videoStateChange\", (videoState: any) => {\n if (videoState.isVideoEnabled !== undefined) {\n setIsVideoEnabled(videoState.isVideoEnabled);\n }\n });\n\n // Screen share controls state change listener\n const unsubScreenShareState = client.screenShareControls.on(\"screenShareStateChange\", (screenShareState: any) => {\n if (screenShareState.isScreenShareActive !== undefined) {\n setIsScreenShareActive(screenShareState.isScreenShareActive);\n }\n });\n\n // Cleanup listeners on unmount\n return () => {\n unsubStateChange();\n unsubMessagesChange();\n unsubUserTranscription();\n unsubSpeaking();\n unsubBotReady();\n unsubConnect();\n unsubDisconnect();\n unsubBotAudioTrack();\n unsubDisconnectWsAudio();\n unsubAudioState();\n unsubVideoState();\n unsubScreenShareState();\n wsAudioEl.srcObject = null;\n wsAudioEl.remove();\n };\n }, [client]);\n\n // Create enhanced connect function that can use stored config\n const connect = useCallback(\n async (configOverride?: ConvaiConfig) => {\n const finalConfig = configOverride || storedConfig;\n\n if (!finalConfig) {\n throw new Error(\n \"No configuration provided. Pass config to useConvaiClient() or to connect()\",\n );\n }\n\n await client.connect(finalConfig);\n },\n [client, storedConfig],\n );\n\n // Create reconnect function wrapper\n const reconnect = useCallback(async () => {\n await client.reconnect();\n }, [client]);\n\n // Return client interface with React-friendly additions\n return {\n state,\n connectionType: client.connectionType,\n ...(client.apiKey && { apiKey: client.apiKey }),\n ...(client.authToken && { authToken: client.authToken }),\n characterId: client.characterId,\n connect,\n connectWithConnectionData: client.connectWithConnectionData.bind(client),\n disconnect: client.disconnect.bind(client),\n reconnect,\n resetSession: client.resetSession.bind(client),\n room: client.room,\n sendUserTextMessage: client.sendUserTextMessage.bind(client),\n sendTriggerMessage: client.sendTriggerMessage.bind(client),\n sendInterruptMessage: client.sendInterruptMessage.bind(client),\n resetIdleTimer: client.resetIdleTimer.bind(client),\n updateTemplateKeys: client.updateTemplateKeys.bind(client),\n updateDynamicInfo: client.updateDynamicInfo.bind(client),\n updateContext: client.updateContext.bind(client),\n updateEmotion: client.updateEmotion.bind(client),\n visionStatus: client.visionStatus.bind(client),\n visionTrigger: client.visionTrigger.bind(client),\n respondModeUpdate: client.respondModeUpdate.bind(client),\n updateSceneMetadata: client.updateSceneMetadata.bind(client),\n activity,\n chatMessages,\n userTranscription,\n characterSessionId: client.characterSessionId,\n isBotReady,\n audioControls: client.audioControls,\n videoControls: client.videoControls,\n screenShareControls: client.screenShareControls,\n blendshapeQueue: client.blendshapeQueue,\n conversationSessionId: client.conversationSessionId,\n memoryManager: client.memoryManager,\n toggleTts: client.toggleTts.bind(client),\n toggleStt: client.toggleStt.bind(client),\n uploadFile: client.uploadFile.bind(client),\n on: client.on.bind(client),\n off: client.off.bind(client),\n // Reactive control states\n isAudioMuted,\n isVideoEnabled,\n isScreenShareActive,\n };\n};\n"]}
@@ -13,7 +13,9 @@ export declare class AudioRenderer {
13
13
  private boundHandleTrackSubscribed;
14
14
  private boundHandleTrackUnsubscribed;
15
15
  private boundHandleParticipantDisconnected;
16
- constructor(room: Room);
16
+ constructor(room: Room, options?: {
17
+ container?: HTMLElement;
18
+ });
17
19
  /**
18
20
  * Setup event listeners for room events
19
21
  */
@@ -1 +1 @@
1
- {"version":3,"file":"AudioRenderer.d.ts","sourceRoot":"","sources":["../../src/vanilla/AudioRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAwD,MAAM,gBAAgB,CAAC;AAG5F;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,aAAa,CAA4C;IACjE,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAA+B;IAGpD,OAAO,CAAC,0BAA0B,CAAM;IACxC,OAAO,CAAC,4BAA4B,CAAM;IAC1C,OAAO,CAAC,kCAAkC,CAAM;gBAEpC,IAAI,EAAE,IAAI;IAmBtB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAM3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAU7B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAU/B;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAMrC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA+BxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,eAAe,CAAiC;IAExD;;OAEG;IACH,oBAAoB,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IASnD,oBAAoB,IAAI,IAAI;IAS5B;;OAEG;IACH,OAAO,IAAI,IAAI;CAmBhB"}
1
+ {"version":3,"file":"AudioRenderer.d.ts","sourceRoot":"","sources":["../../src/vanilla/AudioRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAwD,MAAM,gBAAgB,CAAC;AAG5F;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,aAAa,CAA4C;IACjE,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAA+B;IAGpD,OAAO,CAAC,0BAA0B,CAAM;IACxC,OAAO,CAAC,4BAA4B,CAAM;IAC1C,OAAO,CAAC,kCAAkC,CAAM;gBAEpC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,WAAW,CAAA;KAAE;IAmB7D;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAM3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAU7B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAU/B;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAMrC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA+BxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,eAAe,CAAiC;IAExD;;OAEG;IACH,oBAAoB,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IASnD,oBAAoB,IAAI,IAAI;IAS5B;;OAEG;IACH,OAAO,IAAI,IAAI;CAmBhB"}
@@ -6,7 +6,7 @@ import { logger } from '../utils/logger';
6
6
  * This replaces React's RoomAudioRenderer for vanilla implementations
7
7
  */
8
8
  export class AudioRenderer {
9
- constructor(room) {
9
+ constructor(room, options) {
10
10
  this.audioElements = new Map();
11
11
  this.livekitTracks = new Map(); // Store track references
12
12
  this._wsAudioElement = null;
@@ -20,7 +20,7 @@ export class AudioRenderer {
20
20
  this.container = document.createElement('div');
21
21
  this.container.id = `convai-audio-renderer-${this.rendererId}`;
22
22
  this.container.style.display = 'none';
23
- document.body.appendChild(this.container);
23
+ (options?.container ?? document.body).appendChild(this.container);
24
24
  this.setupEventListeners();
25
25
  this.attachExistingTracks();
26
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AudioRenderer.js","sourceRoot":"","sources":["../../src/vanilla/AudioRenderer.ts"],"names":[],"mappings":"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","sourcesContent":["import { Room, RoomEvent, RemoteTrackPublication, RemoteParticipant } from 'livekit-client';\nimport { logger } from '../utils/logger';\n\n/**\n * AudioRenderer - Manages audio playback for remote participants\n * Automatically creates and attaches audio elements for remote audio tracks\n * This replaces React's RoomAudioRenderer for vanilla implementations\n */\nexport class AudioRenderer {\n private room: Room;\n private audioElements: Map<string, HTMLAudioElement> = new Map();\n private container: HTMLElement;\n private rendererId: string; // Unique ID for debugging\n private livekitTracks: Map<string, any> = new Map(); // Store track references\n\n // Store bound event handlers so we can properly remove them\n private boundHandleTrackSubscribed: any;\n private boundHandleTrackUnsubscribed: any;\n private boundHandleParticipantDisconnected: any;\n\n constructor(room: Room) {\n this.room = room;\n this.rendererId = `renderer-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n \n // Bind event handlers once and store references\n this.boundHandleTrackSubscribed = this.handleTrackSubscribed.bind(this);\n this.boundHandleTrackUnsubscribed = this.handleTrackUnsubscribed.bind(this);\n this.boundHandleParticipantDisconnected = this.handleParticipantDisconnected.bind(this);\n \n // Create a hidden container for audio elements\n this.container = document.createElement('div');\n this.container.id = `convai-audio-renderer-${this.rendererId}`;\n this.container.style.display = 'none';\n document.body.appendChild(this.container);\n\n this.setupEventListeners();\n this.attachExistingTracks();\n }\n\n /**\n * Setup event listeners for room events\n */\n private setupEventListeners(): void {\n this.room.on(RoomEvent.TrackSubscribed, this.boundHandleTrackSubscribed);\n this.room.on(RoomEvent.TrackUnsubscribed, this.boundHandleTrackUnsubscribed);\n this.room.on(RoomEvent.ParticipantDisconnected, this.boundHandleParticipantDisconnected);\n }\n\n /**\n * Attach audio elements for existing tracks (if any)\n */\n private attachExistingTracks(): void {\n this.room.remoteParticipants.forEach((participant) => {\n participant.audioTrackPublications.forEach((publication) => {\n if (publication.track && publication.isSubscribed) {\n this.attachAudioTrack(publication, participant);\n }\n });\n });\n }\n\n /**\n * Handle track subscribed event\n */\n private handleTrackSubscribed(\n track: any,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant\n ): void {\n if (track.kind === 'audio') {\n this.attachAudioTrack(publication, participant);\n }\n }\n\n /**\n * Handle track unsubscribed event\n */\n private handleTrackUnsubscribed(\n track: any,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant\n ): void {\n if (track.kind === 'audio') {\n this.detachAudioTrack(publication.trackSid);\n }\n }\n\n /**\n * Handle participant disconnected event\n */\n private handleParticipantDisconnected(participant: RemoteParticipant): void {\n participant.audioTrackPublications.forEach((publication) => {\n this.detachAudioTrack(publication.trackSid);\n });\n }\n\n /**\n * Attach an audio track to an audio element\n */\n private attachAudioTrack(\n publication: RemoteTrackPublication,\n participant: RemoteParticipant\n ): void {\n const track = publication.track;\n if (!track || track.kind !== 'audio') return;\n\n const trackSid = publication.trackSid;\n\n // Skip if already attached\n if (this.audioElements.has(trackSid)) {\n return;\n }\n\n try {\n // Create audio element\n const audioElement = document.createElement('audio');\n audioElement.id = `audio-${trackSid}`;\n audioElement.autoplay = true;\n \n // Direct track attachment - play audio immediately\n track.attach(audioElement);\n \n this.container.appendChild(audioElement);\n this.audioElements.set(trackSid, audioElement);\n this.livekitTracks.set(trackSid, track);\n } catch (error) {\n logger.error('Failed to attach audio track:', error);\n }\n }\n\n /**\n * Detach an audio track and remove its element\n */\n private detachAudioTrack(trackSid: string): void {\n // Remove audio element\n const audioElement = this.audioElements.get(trackSid);\n if (audioElement) {\n // Detach from LiveKit track\n const livekitTrack = this.livekitTracks.get(trackSid);\n if (livekitTrack) {\n livekitTrack.detach(audioElement);\n this.livekitTracks.delete(trackSid);\n }\n\n audioElement.pause();\n audioElement.srcObject = null;\n audioElement.remove();\n }\n \n this.audioElements.delete(trackSid);\n }\n\n private _wsAudioElement: HTMLAudioElement | null = null;\n\n /**\n * Attach a MediaStreamTrack from WebSocket transport for bot audio playback.\n */\n attachWebSocketTrack(track: MediaStreamTrack): void {\n this.detachWebSocketTrack();\n const el = document.createElement('audio');\n el.autoplay = true;\n el.srcObject = new MediaStream([track]);\n this.container.appendChild(el);\n this._wsAudioElement = el;\n }\n\n detachWebSocketTrack(): void {\n if (this._wsAudioElement) {\n this._wsAudioElement.pause();\n this._wsAudioElement.srcObject = null;\n this._wsAudioElement.remove();\n this._wsAudioElement = null;\n }\n }\n\n /**\n * Cleanup and destroy the audio renderer\n */\n destroy(): void {\n this.detachWebSocketTrack();\n\n // Remove all audio elements\n this.audioElements.forEach((element, trackSid) => {\n this.detachAudioTrack(trackSid);\n });\n this.audioElements.clear();\n\n // Remove container\n if (this.container && this.container.parentElement) {\n this.container.remove();\n }\n\n // Remove event listeners using stored bound references\n this.room.off(RoomEvent.TrackSubscribed, this.boundHandleTrackSubscribed);\n this.room.off(RoomEvent.TrackUnsubscribed, this.boundHandleTrackUnsubscribed);\n this.room.off(RoomEvent.ParticipantDisconnected, this.boundHandleParticipantDisconnected);\n }\n}\n\n"]}
1
+ {"version":3,"file":"AudioRenderer.js","sourceRoot":"","sources":["../../src/vanilla/AudioRenderer.ts"],"names":[],"mappings":"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","sourcesContent":["import { Room, RoomEvent, RemoteTrackPublication, RemoteParticipant } from 'livekit-client';\nimport { logger } from '../utils/logger';\n\n/**\n * AudioRenderer - Manages audio playback for remote participants\n * Automatically creates and attaches audio elements for remote audio tracks\n * This replaces React's RoomAudioRenderer for vanilla implementations\n */\nexport class AudioRenderer {\n private room: Room;\n private audioElements: Map<string, HTMLAudioElement> = new Map();\n private container: HTMLElement;\n private rendererId: string; // Unique ID for debugging\n private livekitTracks: Map<string, any> = new Map(); // Store track references\n\n // Store bound event handlers so we can properly remove them\n private boundHandleTrackSubscribed: any;\n private boundHandleTrackUnsubscribed: any;\n private boundHandleParticipantDisconnected: any;\n\n constructor(room: Room, options?: { container?: HTMLElement }) {\n this.room = room;\n this.rendererId = `renderer-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n \n // Bind event handlers once and store references\n this.boundHandleTrackSubscribed = this.handleTrackSubscribed.bind(this);\n this.boundHandleTrackUnsubscribed = this.handleTrackUnsubscribed.bind(this);\n this.boundHandleParticipantDisconnected = this.handleParticipantDisconnected.bind(this);\n \n // Create a hidden container for audio elements\n this.container = document.createElement('div');\n this.container.id = `convai-audio-renderer-${this.rendererId}`;\n this.container.style.display = 'none';\n (options?.container ?? document.body).appendChild(this.container);\n\n this.setupEventListeners();\n this.attachExistingTracks();\n }\n\n /**\n * Setup event listeners for room events\n */\n private setupEventListeners(): void {\n this.room.on(RoomEvent.TrackSubscribed, this.boundHandleTrackSubscribed);\n this.room.on(RoomEvent.TrackUnsubscribed, this.boundHandleTrackUnsubscribed);\n this.room.on(RoomEvent.ParticipantDisconnected, this.boundHandleParticipantDisconnected);\n }\n\n /**\n * Attach audio elements for existing tracks (if any)\n */\n private attachExistingTracks(): void {\n this.room.remoteParticipants.forEach((participant) => {\n participant.audioTrackPublications.forEach((publication) => {\n if (publication.track && publication.isSubscribed) {\n this.attachAudioTrack(publication, participant);\n }\n });\n });\n }\n\n /**\n * Handle track subscribed event\n */\n private handleTrackSubscribed(\n track: any,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant\n ): void {\n if (track.kind === 'audio') {\n this.attachAudioTrack(publication, participant);\n }\n }\n\n /**\n * Handle track unsubscribed event\n */\n private handleTrackUnsubscribed(\n track: any,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant\n ): void {\n if (track.kind === 'audio') {\n this.detachAudioTrack(publication.trackSid);\n }\n }\n\n /**\n * Handle participant disconnected event\n */\n private handleParticipantDisconnected(participant: RemoteParticipant): void {\n participant.audioTrackPublications.forEach((publication) => {\n this.detachAudioTrack(publication.trackSid);\n });\n }\n\n /**\n * Attach an audio track to an audio element\n */\n private attachAudioTrack(\n publication: RemoteTrackPublication,\n participant: RemoteParticipant\n ): void {\n const track = publication.track;\n if (!track || track.kind !== 'audio') return;\n\n const trackSid = publication.trackSid;\n\n // Skip if already attached\n if (this.audioElements.has(trackSid)) {\n return;\n }\n\n try {\n // Create audio element\n const audioElement = document.createElement('audio');\n audioElement.id = `audio-${trackSid}`;\n audioElement.autoplay = true;\n \n // Direct track attachment - play audio immediately\n track.attach(audioElement);\n \n this.container.appendChild(audioElement);\n this.audioElements.set(trackSid, audioElement);\n this.livekitTracks.set(trackSid, track);\n } catch (error) {\n logger.error('Failed to attach audio track:', error);\n }\n }\n\n /**\n * Detach an audio track and remove its element\n */\n private detachAudioTrack(trackSid: string): void {\n // Remove audio element\n const audioElement = this.audioElements.get(trackSid);\n if (audioElement) {\n // Detach from LiveKit track\n const livekitTrack = this.livekitTracks.get(trackSid);\n if (livekitTrack) {\n livekitTrack.detach(audioElement);\n this.livekitTracks.delete(trackSid);\n }\n\n audioElement.pause();\n audioElement.srcObject = null;\n audioElement.remove();\n }\n \n this.audioElements.delete(trackSid);\n }\n\n private _wsAudioElement: HTMLAudioElement | null = null;\n\n /**\n * Attach a MediaStreamTrack from WebSocket transport for bot audio playback.\n */\n attachWebSocketTrack(track: MediaStreamTrack): void {\n this.detachWebSocketTrack();\n const el = document.createElement('audio');\n el.autoplay = true;\n el.srcObject = new MediaStream([track]);\n this.container.appendChild(el);\n this._wsAudioElement = el;\n }\n\n detachWebSocketTrack(): void {\n if (this._wsAudioElement) {\n this._wsAudioElement.pause();\n this._wsAudioElement.srcObject = null;\n this._wsAudioElement.remove();\n this._wsAudioElement = null;\n }\n }\n\n /**\n * Cleanup and destroy the audio renderer\n */\n destroy(): void {\n this.detachWebSocketTrack();\n\n // Remove all audio elements\n this.audioElements.forEach((element, trackSid) => {\n this.detachAudioTrack(trackSid);\n });\n this.audioElements.clear();\n\n // Remove container\n if (this.container && this.container.parentElement) {\n this.container.remove();\n }\n\n // Remove event listeners using stored bound references\n this.room.off(RoomEvent.TrackSubscribed, this.boundHandleTrackSubscribed);\n this.room.off(RoomEvent.TrackUnsubscribed, this.boundHandleTrackUnsubscribed);\n this.room.off(RoomEvent.ParticipantDisconnected, this.boundHandleParticipantDisconnected);\n }\n}\n\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ConvaiWidget.d.ts","sourceRoot":"","sources":["../../src/vanilla/ConvaiWidget.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAYnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,WAAW,EACtB,OAAO,EAAE,oBAAoB,GAC5B,aAAa,CAyjEf;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAE/D"}
1
+ {"version":3,"file":"ConvaiWidget.d.ts","sourceRoot":"","sources":["../../src/vanilla/ConvaiWidget.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,OAAO,KAAK,EACV,oBAAoB,EACpB,aAAa,EAEd,MAAM,SAAS,CAAC;AA2HjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,WAAW,EACtB,OAAO,EAAE,oBAAoB,GAC5B,aAAa,CAu9Ef;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAE/D"}