@rannah-labs/react-voice-orb 1.1.3

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 (60) hide show
  1. package/README.md +240 -0
  2. package/assets/orb-ss.png +0 -0
  3. package/assets/thing.png +0 -0
  4. package/dist/bun-server/src/types/index.d.ts +37 -0
  5. package/dist/bun-server/src/types/index.js +2 -0
  6. package/dist/src/app/Types/TranscriberStuff.d.ts +0 -0
  7. package/dist/src/app/Types/TranscriberStuff.js +1 -0
  8. package/dist/src/app/Types/apiModels.d.ts +31 -0
  9. package/dist/src/app/Types/apiModels.js +2 -0
  10. package/dist/src/app/Types/api_types.d.ts +34 -0
  11. package/dist/src/app/Types/api_types.js +2 -0
  12. package/dist/src/app/Types/better-trpc.d.ts +5 -0
  13. package/dist/src/app/Types/better-trpc.js +23 -0
  14. package/dist/src/app/Types/browser-only.d.ts +1 -0
  15. package/dist/src/app/Types/browser-only.js +12 -0
  16. package/dist/src/app/Types/builltInNodesTemplates.d.ts +1070 -0
  17. package/dist/src/app/Types/builltInNodesTemplates.js +1341 -0
  18. package/dist/src/app/Types/defaults.d.ts +7 -0
  19. package/dist/src/app/Types/defaults.js +210 -0
  20. package/dist/src/app/Types/demo_extension.d.ts +11 -0
  21. package/dist/src/app/Types/demo_extension.js +190 -0
  22. package/dist/src/app/Types/envObject.d.ts +97 -0
  23. package/dist/src/app/Types/envObject.js +5 -0
  24. package/dist/src/app/Types/firebase.d.ts +30413 -0
  25. package/dist/src/app/Types/firebase.js +6696 -0
  26. package/dist/src/app/Types/gen_openapi.d.ts +130 -0
  27. package/dist/src/app/Types/gen_openapi.js +2 -0
  28. package/dist/src/app/Types/global_types.d.ts +254 -0
  29. package/dist/src/app/Types/global_types.js +6 -0
  30. package/dist/src/app/Types/messages_types.d.ts +76 -0
  31. package/dist/src/app/Types/messages_types.js +1 -0
  32. package/dist/src/app/Types/vapi_types.d.ts +358 -0
  33. package/dist/src/app/Types/vapi_types.js +2 -0
  34. package/dist/src/app/Types/vf_types.d.ts +33 -0
  35. package/dist/src/app/Types/vf_types.js +2 -0
  36. package/dist/src/public_packages/react-voice-orb/src/animation-orb.d.ts +11 -0
  37. package/dist/src/public_packages/react-voice-orb/src/animation-orb.js +397 -0
  38. package/dist/src/public_packages/react-voice-orb/src/index.d.ts +5 -0
  39. package/dist/src/public_packages/react-voice-orb/src/index.js +16 -0
  40. package/dist/src/public_packages/react-voice-orb/src/providers/AIAudioProvider.d.ts +21 -0
  41. package/dist/src/public_packages/react-voice-orb/src/providers/AIAudioProvider.js +81 -0
  42. package/dist/src/public_packages/react-voice-orb/src/providers/ThemeProvider.d.ts +23 -0
  43. package/dist/src/public_packages/react-voice-orb/src/providers/ThemeProvider.js +202 -0
  44. package/dist/src/public_packages/react-voice-orb/src/scripts/same-script.d.ts +1 -0
  45. package/dist/src/public_packages/react-voice-orb/src/scripts/same-script.js +79 -0
  46. package/dist/src/public_packages/react-voice-orb/src/spinner.d.ts +3 -0
  47. package/dist/src/public_packages/react-voice-orb/src/spinner.js +17 -0
  48. package/dist/src/public_packages/react-voice-orb/tsconfig.tsbuildinfo +1 -0
  49. package/dist/vg-docker/src/+global_consts/client.d.ts +84 -0
  50. package/dist/vg-docker/src/+global_consts/client.js +105 -0
  51. package/package.json +46 -0
  52. package/scripts/post-tsc.ts +74 -0
  53. package/src/animation-orb.tsx +441 -0
  54. package/src/index.ts +5 -0
  55. package/src/providers/AIAudioProvider.tsx +100 -0
  56. package/src/providers/ThemeProvider.tsx +211 -0
  57. package/src/scripts/same-script.ts +73 -0
  58. package/src/spinner.tsx +19 -0
  59. package/tsconfig.json +34 -0
  60. package/webpack.config.js +141 -0
@@ -0,0 +1,441 @@
1
+ "use client";
2
+ import React, { useEffect, useRef } from "react";
3
+ import * as THREE from "three";
4
+ import { useOrbTheme } from "./providers/ThemeProvider"
5
+ import { useAIVoice } from "./providers/AIAudioProvider";
6
+
7
+ const AudioAnimationOrb = (props: {
8
+ width: number;
9
+ height: number;
10
+ colorPallet?: string[];
11
+ animationSensitivity?: number;
12
+ orbPlaceholder?: React.ReactNode;
13
+ children: React.ReactNode;
14
+ showOrb: boolean;
15
+ }) => {
16
+
17
+ const { webCall, callState, isMuted } = useAIVoice();
18
+ const { getColor, customStyles } = useOrbTheme();
19
+ const mountRef = useRef<HTMLDivElement>(null);
20
+
21
+ // if (!webCall) {
22
+ // throw new Error("webCall is not found");
23
+ // }
24
+ // ======== Sensitivity factor ========
25
+ const SENSITIVITY = props.animationSensitivity ?? 1.5; // Adjust this to increase or decrease overall responsiveness
26
+
27
+ useEffect(() => {
28
+ const scene = new THREE.Scene();
29
+ // Calculate aspect ratio
30
+ const aspect = props.width / props.height;
31
+
32
+ // Define the size of the visible area
33
+ const innerRadius = 2; // Circle radius
34
+ const frustumHeight = innerRadius * 2; // Diameter of the circle
35
+ const frustumWidth = frustumHeight * aspect;
36
+
37
+ // Create an OrthographicCamera
38
+ const camera = new THREE.OrthographicCamera(
39
+ -frustumWidth / 2,
40
+ frustumWidth / 2,
41
+ frustumHeight / 2,
42
+ -frustumHeight / 2,
43
+ -1000,
44
+ 1000
45
+ );
46
+ camera.position.z = 0;
47
+
48
+ const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
49
+ renderer.setSize(props.width, props.height);
50
+ renderer.setPixelRatio(window.devicePixelRatio);
51
+ mountRef.current?.appendChild(renderer.domElement);
52
+
53
+ // Audio context and analyser
54
+ const audioContext = new (window.AudioContext ||
55
+ (window as any).webkitAudioContext)();
56
+ const analyser = audioContext.createAnalyser();
57
+ analyser.fftSize = 256;
58
+ const dataArray = new Uint8Array(analyser.frequencyBinCount);
59
+
60
+ const outerSegments = 1024;
61
+
62
+ // Circle geometry
63
+ const innerGeometry = new THREE.CircleGeometry(innerRadius, outerSegments);
64
+
65
+ const innerMaterial = new THREE.ShaderMaterial({
66
+ vertexShader: `
67
+ uniform float time;
68
+ varying vec2 vUv;
69
+ varying vec3 vPosition;
70
+ // Now we'll receive an array of 4 colors
71
+ uniform vec3 uColor[4];
72
+ varying vec3 vColor;
73
+
74
+ uniform float uFreqData;
75
+ uniform float freqInfluencedTime;
76
+
77
+ // Simplex noise utility functions
78
+ vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);}
79
+ vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;}
80
+
81
+ float snoise(vec3 v){
82
+ const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
83
+ const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
84
+
85
+ vec3 i = floor(v + dot(v, C.yyy) );
86
+ vec3 x0 = v - i + dot(i, C.xxx);
87
+
88
+ vec3 g = step(x0.yzx, x0.xyz);
89
+ vec3 l = 1.0 - g;
90
+ vec3 i1 = min( g.xyz, l.zxy );
91
+ vec3 i2 = max( g.xyz, l.zxy );
92
+
93
+ vec3 x1 = x0 - i1 + 1.0 * C.xxx;
94
+ vec3 x2 = x0 - i2 + 2.0 * C.xxx;
95
+ vec3 x3 = x0 - 1.0 + 3.0 * C.xxx;
96
+
97
+ i = mod(i, 289.0 );
98
+ vec4 p = permute( permute( permute(
99
+ i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
100
+ + i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
101
+ + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
102
+
103
+ float n_ = 1.0/7.0;
104
+ vec3 ns = n_ * D.wyz - D.xzx;
105
+
106
+ vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
107
+
108
+ vec4 x_ = floor(j * ns.z);
109
+ vec4 y_ = floor(j - 7.0 * x_ );
110
+ vec4 x = x_ *ns.x + ns.yyyy;
111
+ vec4 y = y_ *ns.x + ns.yyyy;
112
+ vec4 h = 1.0 - abs(x) - abs(y);
113
+
114
+ vec4 b0 = vec4( x.xy, y.xy );
115
+ vec4 b1 = vec4( x.zw, y.zw );
116
+
117
+ vec4 s0 = floor(b0)*2.0 + 1.0;
118
+ vec4 s1 = floor(b1)*2.0 + 1.0;
119
+ vec4 sh = -step(h, vec4(0.0));
120
+
121
+ vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
122
+ vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
123
+
124
+ vec3 p0 = vec3(a0.xy,h.x);
125
+ vec3 p1 = vec3(a0.zw,h.y);
126
+ vec3 p2 = vec3(a1.xy,h.z);
127
+ vec3 p3 = vec3(a1.zw,h.w);
128
+
129
+ vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2,p2), dot(p3,p3)));
130
+ p0 *= norm.x;
131
+ p1 *= norm.y;
132
+ p2 *= norm.z;
133
+ p3 *= norm.w;
134
+
135
+ vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
136
+ m = m * m;
137
+ return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
138
+ dot(p2,x2), dot(p3,x3) ) );
139
+ }
140
+
141
+ void main() {
142
+ float frequencyInfluence = uFreqData * 0.005;
143
+ float modified_time = freqInfluencedTime;
144
+
145
+ vUv = uv;
146
+
147
+ vec2 noiseCoord = uv * vec2(3.0, 4.0);
148
+ float noise = snoise(vec3(noiseCoord, modified_time * 0.3));
149
+
150
+ float distToCenter = length(uv - 0.5) * 2.0;
151
+ float influence = smoothstep(0.9, 0.8, distToCenter);
152
+
153
+ float displacement = influence * sin(vUv.x * 5.0 + freqInfluencedTime * 1.0) * 0.05 * uFreqData / 30.0;
154
+ displacement += influence * cos(vUv.y * 5.0 + freqInfluencedTime * 1.5) * 0.05 * uFreqData / 30.0;
155
+
156
+ vec3 pos = vec3(position.x, position.y + displacement, position.z - abs(displacement));
157
+
158
+ // Start from a neutral color instead of one of the array colors
159
+ vColor = vec3(0.0);
160
+
161
+ // Incorporate all 4 colors
162
+ for (int i = 0; i < 4; i++) {
163
+ float noiseFlow = 5.0 + float(i) * 0.3;
164
+ float noiseSpeed = 10.0 + float(i) * 0.3;
165
+ float noiseSeed = 1.0 + float(i) * 10.0;
166
+ vec2 noiseFreq = vec2(0.3, 0.4);
167
+ float noiseFloor = 0.1;
168
+ float noiseCeil = 0.6 + float(i) * 0.07;
169
+
170
+ float localNoise = smoothstep(
171
+ noiseFloor,
172
+ noiseCeil,
173
+ snoise(vec3(
174
+ noiseCoord * noiseFreq + vec2(modified_time * noiseFlow, modified_time * noiseSpeed),
175
+ noiseSeed
176
+ ))
177
+ );
178
+
179
+ // Mix each color in
180
+ vColor = mix(vColor, uColor[i], localNoise);
181
+ }
182
+
183
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
184
+ }
185
+ `,
186
+ fragmentShader: `
187
+ uniform float time;
188
+ varying vec2 vUv;
189
+ varying vec3 vPosition;
190
+ varying vec3 vColor;
191
+ uniform float freqInfluencedTime;
192
+
193
+ void main() {
194
+ gl_FragColor = vec4(vColor, 1.0);
195
+ }
196
+ `,
197
+ side: THREE.DoubleSide,
198
+ uniforms: {
199
+ time: { value: 0.0 },
200
+ uFreqData: { value: 0.0 },
201
+ // Change to 4 colors in the shader
202
+ uColor: {
203
+ value: [
204
+ new THREE.Color().set(getColor("primary-500")),
205
+ new THREE.Color().set(getColor("primary-800")),
206
+ new THREE.Color().set(getColor("primary-200")),
207
+ new THREE.Color().set(getColor("primary-600")),
208
+ ],
209
+ },
210
+ resolution: { value: new THREE.Vector4() },
211
+ freqInfluencedTime: { value: 0.0 },
212
+ },
213
+ transparent: true,
214
+ });
215
+
216
+ const innerCircle = new THREE.Mesh(innerGeometry, innerMaterial);
217
+ scene.add(innerCircle);
218
+
219
+ // Green spot
220
+ const smallerInnerGeometry = new THREE.CircleGeometry(
221
+ innerRadius,
222
+ outerSegments
223
+ );
224
+
225
+ const greenMaterial = new THREE.ShaderMaterial({
226
+ vertexShader: `
227
+ varying vec2 vUv;
228
+ uniform float uTime;
229
+ uniform float uFreqData;
230
+ void main() {
231
+ vUv = uv;
232
+ vec3 pos = position;
233
+
234
+ float distToCenter = length(vUv - 0.5);
235
+ float influence = smoothstep(0.5, 0.45, distToCenter);
236
+
237
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
238
+ }
239
+ `,
240
+ fragmentShader: `
241
+ varying vec2 vUv;
242
+ uniform float uTime;
243
+ uniform float uFreqData;
244
+ uniform float uMargin;
245
+ uniform float uOpacity;
246
+ uniform vec3 uSpotColor;
247
+
248
+ vec4 permute(vec4 x) {
249
+ return mod(((x*34.0)+1.0)*x, 289.0);
250
+ }
251
+
252
+ float perlinNoise(vec2 p) {
253
+ vec2 i = floor(p);
254
+ vec2 f = fract(p);
255
+
256
+ vec4 v = vec4(
257
+ dot(i, vec2(127.1, 311.7)),
258
+ dot(i + vec2(1.0, 0.0), vec2(127.1, 311.7)),
259
+ dot(i + vec2(0.0, 1.0), vec2(127.1, 311.7)),
260
+ dot(i + vec2(1.0, 1.0), vec2(127.1, 311.7))
261
+ );
262
+
263
+ v = fract(sin(v) * 43758.5453123);
264
+ vec2 u = f * f * (3.0 - 2.0 * f);
265
+
266
+ return mix(
267
+ mix(v.x, v.y, u.x),
268
+ mix(v.z, v.w, u.x),
269
+ u.y
270
+ );
271
+ }
272
+
273
+ void main() {
274
+ vec2 centeredUv = vUv - 0.5;
275
+ float distToCenter = length(centeredUv);
276
+
277
+ float maxRadius = 0.5 - uMargin;
278
+ float dynamicRadius = maxRadius;
279
+ float normalizedFreq = (uFreqData / 256.0);
280
+
281
+ float noiseScale = 3.0;
282
+ float adjustedTime = uTime * 0.1;
283
+ float edgeNoise = perlinNoise(centeredUv * noiseScale + adjustedTime);
284
+ edgeNoise = smoothstep(normalizedFreq, 1.0, edgeNoise);
285
+
286
+ float noisyRadius = dynamicRadius - edgeNoise * 0.2;
287
+ float edge = smoothstep(noisyRadius - 0.03, noisyRadius + 0.03, distToCenter);
288
+
289
+ vec3 spotColor = uSpotColor;
290
+ float alpha = (1.0 - edge) * uOpacity;
291
+
292
+ if (uMargin == 0.0) {
293
+ alpha = uOpacity * (1.0 - smoothstep(0.5 - 0.001, 0.5, distToCenter));
294
+ }
295
+
296
+ gl_FragColor = vec4(spotColor, alpha);
297
+ }
298
+ `,
299
+ uniforms: {
300
+ uTime: { value: 0.0 },
301
+ uFreqData: { value: 0.0 },
302
+ uMargin: { value: 0.0001 },
303
+ uOpacity: { value: 0.3 },
304
+ uSpotColor: { value: new THREE.Color().set(getColor("primary-100")) },
305
+ },
306
+ transparent: true,
307
+ });
308
+
309
+ const InnerCircle = new THREE.Mesh(smallerInnerGeometry, greenMaterial);
310
+ scene.add(InnerCircle);
311
+ InnerCircle.position.z = 0.01;
312
+
313
+ let animationFrameId: number;
314
+ const animate = () => {
315
+ animationFrameId = requestAnimationFrame(animate);
316
+
317
+ analyser.getByteFrequencyData(dataArray);
318
+ // Calculate average frequency and scale by SENSITIVITY
319
+ let freqData =
320
+ dataArray.reduce((acc, value) => acc + value, 0) / dataArray.length;
321
+ freqData *= SENSITIVITY; // Apply sensitivity here
322
+
323
+ // Update uniforms
324
+ innerMaterial.uniforms.time.value += 0.0005;
325
+ innerMaterial.uniforms.freqInfluencedTime.value +=
326
+ 0.0001 + freqData * 0.00001;
327
+ innerMaterial.uniforms.uFreqData.value = freqData;
328
+
329
+ greenMaterial.uniforms.uTime.value += 0.05;
330
+ greenMaterial.uniforms.uFreqData.value = freqData;
331
+
332
+ renderer.render(scene, camera);
333
+ };
334
+
335
+ let source: MediaStreamAudioSourceNode;
336
+ let stream: MediaStream;
337
+
338
+ navigator.mediaDevices
339
+ .getUserMedia({ audio: true })
340
+ .then((s) => {
341
+ stream = s;
342
+ source = audioContext.createMediaStreamSource(stream);
343
+ source.connect(analyser);
344
+ animate();
345
+ })
346
+ .catch((err) => {
347
+ console.error("Failed microphone access: ", err);
348
+ });
349
+
350
+ // Handle window resize
351
+ const handleResize = () => {
352
+ if (!mountRef.current) return;
353
+
354
+ const aspect = props.width / props.height;
355
+ const frustumHeight = innerRadius * 2;
356
+ const frustumWidth = frustumHeight * aspect;
357
+
358
+ camera.left = -frustumWidth / 2;
359
+ camera.right = frustumWidth / 2;
360
+ camera.top = frustumHeight / 2;
361
+ camera.bottom = -frustumHeight / 2;
362
+ camera.updateProjectionMatrix();
363
+
364
+ renderer.setSize(props.width, props.height);
365
+ };
366
+
367
+ window.addEventListener("resize", handleResize);
368
+
369
+ return () => {
370
+ // Cancel animation loop
371
+ if (animationFrameId) {
372
+ cancelAnimationFrame(animationFrameId);
373
+ }
374
+
375
+ // Remove event listener
376
+ window.removeEventListener("resize", handleResize);
377
+
378
+ // Clean up WebGL
379
+ if (mountRef.current) {
380
+ try {
381
+ mountRef.current.removeChild(renderer.domElement);
382
+ } catch (error) {
383
+ console.error(`error removing dom element`, error);
384
+ }
385
+ }
386
+ renderer.dispose();
387
+
388
+ // Stop audio streams/tracks immediately
389
+ if (stream) {
390
+ console.log(`stopping stream`);
391
+ stream.getTracks().forEach((track) => track.stop());
392
+ } else {
393
+ console.log(`stream not found`);
394
+ }
395
+
396
+ // Disconnect audio source if exists
397
+ if (source) {
398
+ console.log(`disconnecting source`);
399
+ source.disconnect();
400
+ } else {
401
+ console.log(`source not found`);
402
+ }
403
+
404
+ // Close the audio context
405
+ audioContext
406
+ .close()
407
+ .catch((err) => console.error("Error closing audioContext: ", err));
408
+ };
409
+ }, [customStyles, props.width, props.height, props.showOrb]);
410
+
411
+ return (
412
+ <div
413
+ className="ta-orb-wrapper"
414
+ style={{ position: "relative", width: props.width, height: props.height }}
415
+ >
416
+ <div
417
+ className="ta-orb-container"
418
+ style={{
419
+ position: "absolute",
420
+ top: 0,
421
+ left: 0,
422
+ width: "100%",
423
+ height: "100%",
424
+ }}
425
+ >
426
+ {props.children}
427
+ </div>
428
+ {props.showOrb ? (
429
+ <div
430
+ className="ta-orb-placeholder"
431
+ ref={mountRef}
432
+ style={{ width: props.width, height: props.height }}
433
+ />
434
+ ) : (
435
+ props.orbPlaceholder
436
+ )}
437
+ </div>
438
+ );
439
+ };
440
+
441
+ export default AudioAnimationOrb;
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { default as VoiceProvider } from "./providers/AIAudioProvider";
2
+ export { default as OrbThemeProvider } from "./providers/ThemeProvider";
3
+ export { useAIVoice } from "./providers/AIAudioProvider";
4
+ export { default as AudioAnimationOrb } from "./animation-orb";
5
+ export { default as Spinner } from "./spinner";
@@ -0,0 +1,100 @@
1
+ "use client";
2
+ import React, { createContext, ReactNode, useContext, useState } from "react";
3
+ declare module "react" {
4
+ interface CSSProperties {
5
+ [key: `--${string}`]: string | number;
6
+ }
7
+ }
8
+ import { WebCall } from "@rannah-labs/web-sdk";
9
+ import {
10
+ InitCallOptionsType,
11
+ InitWebRtcCall,
12
+ } from "../../../../app/Types/firebase";
13
+
14
+ const VoiceContext = createContext<VoiceProviderProps | null>(null);
15
+
16
+ export type VoiceProviderProps = {
17
+ webCall: WebCall;
18
+ callState: "idle" | "connecting" | "connected";
19
+ isMuted: boolean;
20
+ };
21
+
22
+ export function useAIVoice() {
23
+ const context = useContext<VoiceProviderProps | null>(VoiceContext);
24
+ if (!context) {
25
+ throw new Error(
26
+ "use tixae voice must be used within a tixae voice provider"
27
+ );
28
+ }
29
+ return context;
30
+ }
31
+
32
+ const VoiceProvider = (props: {
33
+ children: ReactNode;
34
+ agentId: string;
35
+ region: "eu" | "na";
36
+ initCallOptions?: InitCallOptionsType;
37
+ }) => {
38
+
39
+ const [tixaeVoice, setTixaeVoice] = React.useState<WebCall>(
40
+ new WebCall()
41
+ );
42
+ const [callState, setCallState] = React.useState<
43
+ "idle" | "connecting" | "connected"
44
+ >("idle");
45
+ const [isMuted, setIsMuted] = React.useState(false);
46
+
47
+ async function initVoice() {
48
+ await tixaeVoice.init({
49
+ agentId: props.agentId,
50
+ region: props.region,
51
+ options: props.initCallOptions,
52
+ });
53
+
54
+ setTixaeVoice(tixaeVoice);
55
+
56
+ tixaeVoice.on("call-start", () => {
57
+ console.log(`call has started..`);
58
+ });
59
+ tixaeVoice.on("call-end", () => {
60
+ console.log(`call has ended..`);
61
+ });
62
+
63
+ // must handle errors
64
+ tixaeVoice.on("error", (error) => {
65
+ console.error(`error`, error);
66
+ });
67
+
68
+ tixaeVoice.on("conversation-update", (payload) => {
69
+ console.log(`conversation-update`, payload);
70
+ });
71
+
72
+ tixaeVoice.on("state-change", (state) => {
73
+ console.log(`state-change`, state);
74
+ setCallState(state);
75
+ });
76
+
77
+ tixaeVoice.on("mute-change", (isMuted) => {
78
+ console.log(`mute-change`, isMuted);
79
+ setIsMuted(isMuted);
80
+ });
81
+ }
82
+
83
+ React.useEffect(() => {
84
+ initVoice();
85
+ }, []);
86
+
87
+ const value: VoiceProviderProps = {
88
+ webCall: tixaeVoice,
89
+ callState: callState,
90
+ isMuted: isMuted,
91
+ };
92
+
93
+ return (
94
+ <VoiceContext.Provider value={value}>
95
+ {props.children}
96
+ </VoiceContext.Provider>
97
+ );
98
+ };
99
+
100
+ export default VoiceProvider;