@pipecat-ai/client-react 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,531 @@
1
+ import {jsx as $h9lXz$jsx, Fragment as $h9lXz$Fragment} from "react/jsx-runtime";
2
+ import {RTVIEvent as $h9lXz$RTVIEvent} from "@pipecat-ai/client-js";
3
+ import $h9lXz$react, {useRef as $h9lXz$useRef, useEffect as $h9lXz$useEffect, useCallback as $h9lXz$useCallback, useContext as $h9lXz$useContext, createContext as $h9lXz$createContext, forwardRef as $h9lXz$forwardRef} from "react";
4
+ import {createStore as $h9lXz$createStore, atom as $h9lXz$atom, useAtomValue as $h9lXz$useAtomValue, useAtom as $h9lXz$useAtom} from "jotai";
5
+ import {Provider as $h9lXz$Provider} from "jotai/react";
6
+ import {atomFamily as $h9lXz$atomFamily, useAtomCallback as $h9lXz$useAtomCallback} from "jotai/utils";
7
+
8
+ /**
9
+ * Copyright (c) 2024, Daily.
10
+ *
11
+ * SPDX-License-Identifier: BSD-2-Clause
12
+ */
13
+
14
+
15
+ /**
16
+ * Copyright (c) 2024, Daily.
17
+ *
18
+ * SPDX-License-Identifier: BSD-2-Clause
19
+ */
20
+ /**
21
+ * Copyright (c) 2024, Daily.
22
+ *
23
+ * SPDX-License-Identifier: BSD-2-Clause
24
+ */
25
+
26
+
27
+
28
+
29
+ const $f3f7d4263dc13c6a$var$defaultStore = (0, $h9lXz$createStore)();
30
+ const $f3f7d4263dc13c6a$export$8d2b07cbee622e7c = /*#__PURE__*/ (0, $h9lXz$createContext)({});
31
+ const $f3f7d4263dc13c6a$export$4a4ae2d5dc96782 = ({ children: children, client: client, jotaiStore: jotaiStore = $f3f7d4263dc13c6a$var$defaultStore })=>{
32
+ return (0, $h9lXz$jsx)((0, $h9lXz$Provider), {
33
+ store: jotaiStore,
34
+ children: (0, $h9lXz$jsx)($f3f7d4263dc13c6a$export$8d2b07cbee622e7c.Provider, {
35
+ value: {
36
+ client: client
37
+ },
38
+ children: children
39
+ })
40
+ });
41
+ };
42
+ $f3f7d4263dc13c6a$export$4a4ae2d5dc96782.displayName = "RTVIClientProvider";
43
+
44
+
45
+ const $54a3c9f5bdbf0854$export$31a5f6a22c9b8fba = ()=>{
46
+ const { client: client } = (0, $h9lXz$useContext)((0, $f3f7d4263dc13c6a$export$8d2b07cbee622e7c));
47
+ return client;
48
+ };
49
+
50
+
51
+ const $824ea64b5f757259$export$33a6ac53b8f02625 = (event, handler)=>{
52
+ const client = (0, $54a3c9f5bdbf0854$export$31a5f6a22c9b8fba)();
53
+ (0, $h9lXz$useEffect)(()=>{
54
+ if (!client) return;
55
+ client.on(event, handler);
56
+ return ()=>{
57
+ client.off(event, handler);
58
+ };
59
+ }, [
60
+ event,
61
+ handler,
62
+ client
63
+ ]);
64
+ };
65
+
66
+
67
+ /**
68
+ * Copyright (c) 2024, Daily.
69
+ *
70
+ * SPDX-License-Identifier: BSD-2-Clause
71
+ */
72
+
73
+
74
+
75
+
76
+
77
+ const $194c75143b7a1fa0$var$localAudioTrackAtom = (0, $h9lXz$atom)(null);
78
+ const $194c75143b7a1fa0$var$localVideoTrackAtom = (0, $h9lXz$atom)(null);
79
+ const $194c75143b7a1fa0$var$botAudioTrackAtom = (0, $h9lXz$atom)(null);
80
+ const $194c75143b7a1fa0$var$botVideoTrackAtom = (0, $h9lXz$atom)(null);
81
+ const $194c75143b7a1fa0$var$trackAtom = (0, $h9lXz$atomFamily)(({ local: local, trackType: trackType })=>{
82
+ if (local) return trackType === "audio" ? $194c75143b7a1fa0$var$localAudioTrackAtom : $194c75143b7a1fa0$var$localVideoTrackAtom;
83
+ return trackType === "audio" ? $194c75143b7a1fa0$var$botAudioTrackAtom : $194c75143b7a1fa0$var$botVideoTrackAtom;
84
+ });
85
+ const $194c75143b7a1fa0$export$7c03381e0d26a6c3 = (trackType, participantType)=>{
86
+ const client = (0, $54a3c9f5bdbf0854$export$31a5f6a22c9b8fba)();
87
+ const track = (0, $h9lXz$useAtomValue)($194c75143b7a1fa0$var$trackAtom({
88
+ local: participantType === "local",
89
+ trackType: trackType
90
+ }));
91
+ const updateTrack = (0, $h9lXz$useAtomCallback)((0, $h9lXz$useCallback)((get, set, track, trackType, local)=>{
92
+ const atom = $194c75143b7a1fa0$var$trackAtom({
93
+ local: local,
94
+ trackType: trackType
95
+ });
96
+ const oldTrack = get(atom);
97
+ if (oldTrack?.id === track.id) return;
98
+ set(atom, track);
99
+ }, [
100
+ participantType,
101
+ track,
102
+ trackType
103
+ ]));
104
+ (0, $824ea64b5f757259$export$33a6ac53b8f02625)((0, $h9lXz$RTVIEvent).TrackStarted, (0, $h9lXz$useCallback)((track, participant)=>{
105
+ updateTrack(track, track.kind, Boolean(participant?.local));
106
+ }, []));
107
+ (0, $h9lXz$useEffect)(()=>{
108
+ if (!client) return;
109
+ const tracks = client.tracks();
110
+ const track = tracks?.[participantType]?.[trackType];
111
+ if (!track) return;
112
+ updateTrack(track, trackType, participantType === "local");
113
+ }, [
114
+ participantType,
115
+ trackType,
116
+ updateTrack,
117
+ client
118
+ ]);
119
+ return track;
120
+ };
121
+
122
+
123
+ const $f8b885726fc652c0$export$ba1245f7cbf3ae02 = ()=>{
124
+ const botAudioRef = (0, $h9lXz$useRef)(null);
125
+ const botAudioTrack = (0, $194c75143b7a1fa0$export$7c03381e0d26a6c3)("audio", "bot");
126
+ (0, $h9lXz$useEffect)(()=>{
127
+ if (!botAudioRef.current || !botAudioTrack) return;
128
+ if (botAudioRef.current.srcObject) {
129
+ const oldTrack = botAudioRef.current.srcObject.getAudioTracks()[0];
130
+ if (oldTrack.id === botAudioTrack.id) return;
131
+ }
132
+ botAudioRef.current.srcObject = new MediaStream([
133
+ botAudioTrack
134
+ ]);
135
+ }, [
136
+ botAudioTrack
137
+ ]);
138
+ (0, $824ea64b5f757259$export$33a6ac53b8f02625)((0, $h9lXz$RTVIEvent).SpeakerUpdated, (0, $h9lXz$useCallback)((speaker)=>{
139
+ if (!botAudioRef.current) return;
140
+ if (typeof botAudioRef.current.setSinkId !== "function") return;
141
+ botAudioRef.current.setSinkId(speaker.deviceId);
142
+ }, []));
143
+ return (0, $h9lXz$jsx)((0, $h9lXz$Fragment), {
144
+ children: (0, $h9lXz$jsx)("audio", {
145
+ ref: botAudioRef,
146
+ autoPlay: true
147
+ })
148
+ });
149
+ };
150
+ $f8b885726fc652c0$export$ba1245f7cbf3ae02.displayName = "RTVIClientAudio";
151
+
152
+
153
+
154
+
155
+
156
+
157
+ /**
158
+ * Copyright (c) 2024, Daily.
159
+ *
160
+ * SPDX-License-Identifier: BSD-2-Clause
161
+ *
162
+ * This file contains code derived from:
163
+ * https://github.com/jaredLunde/react-hook/blob/master/packages/merged-ref/src/index.tsx
164
+ * Original author: Jared Lunde (https://github.com/jaredLunde)
165
+ * Original license: MIT (https://github.com/jaredLunde/react-hook/blob/master/LICENSE)
166
+ */
167
+ function $9098519210cf34e2$var$useMergedRef(...refs) {
168
+ return (0, $h9lXz$useCallback)((element)=>{
169
+ for(let i = 0; i < refs.length; i++){
170
+ const ref = refs[i];
171
+ if (typeof ref === "function") ref(element);
172
+ else if (ref && typeof ref === "object") ref.current = element;
173
+ }
174
+ }, // eslint-disable-next-line react-hooks/exhaustive-deps
175
+ refs);
176
+ }
177
+ var $9098519210cf34e2$export$2e2bcd8739ae039 = $9098519210cf34e2$var$useMergedRef;
178
+
179
+
180
+ const $b76d887910983811$export$d090a384943608eb = /*#__PURE__*/ (0, $h9lXz$forwardRef)(function VoiceClientVideo({ participant: participant = "local", fit: fit = "contain", mirror: mirror, onResize: onResize, style: style = {}, ...props }, ref) {
181
+ const videoTrack = (0, $194c75143b7a1fa0$export$7c03381e0d26a6c3)("video", participant);
182
+ const videoEl = (0, $h9lXz$useRef)(null);
183
+ const videoRef = (0, $9098519210cf34e2$export$2e2bcd8739ae039)(videoEl, ref);
184
+ /**
185
+ * Handle canplay & picture-in-picture events.
186
+ */ (0, $h9lXz$useEffect)(function setupVideoEvents() {
187
+ const video = videoEl.current;
188
+ if (!video) return;
189
+ const playVideo = ()=>{
190
+ const promise = video.play();
191
+ if (promise !== undefined) promise.then(()=>{
192
+ // All good, playback started.
193
+ video.controls = false;
194
+ }).catch((error)=>{
195
+ // Auto-play was prevented. Show video controls, so user can play video manually.
196
+ video.controls = true;
197
+ console.warn("Failed to play video", error);
198
+ });
199
+ };
200
+ const handleCanPlay = ()=>{
201
+ if (!video.paused) return;
202
+ playVideo();
203
+ };
204
+ const handleEnterPIP = ()=>{
205
+ video.style.transform = "scale(1)";
206
+ };
207
+ const handleLeavePIP = ()=>{
208
+ video.style.transform = "";
209
+ setTimeout(()=>{
210
+ if (video.paused) playVideo();
211
+ }, 100);
212
+ };
213
+ const handleVisibilityChange = ()=>{
214
+ if (document.visibilityState === "hidden") return;
215
+ if (!video.paused) return;
216
+ playVideo();
217
+ };
218
+ video.addEventListener("canplay", handleCanPlay);
219
+ video.addEventListener("enterpictureinpicture", handleEnterPIP);
220
+ video.addEventListener("leavepictureinpicture", handleLeavePIP);
221
+ // Videos can be paused if media was played in another app on iOS.
222
+ document.addEventListener("visibilitychange", handleVisibilityChange);
223
+ return ()=>{
224
+ video.removeEventListener("canplay", handleCanPlay);
225
+ video.removeEventListener("enterpictureinpicture", handleEnterPIP);
226
+ video.removeEventListener("leavepictureinpicture", handleLeavePIP);
227
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
228
+ };
229
+ }, []);
230
+ /**
231
+ * Update srcObject.
232
+ */ (0, $h9lXz$useEffect)(function updateSrcObject() {
233
+ const video = videoEl.current;
234
+ if (!video || !videoTrack) return;
235
+ video.srcObject = new MediaStream([
236
+ videoTrack
237
+ ]);
238
+ video.load();
239
+ return ()=>{
240
+ // clean up when unmounted
241
+ video.srcObject = null;
242
+ video.load();
243
+ };
244
+ }, [
245
+ videoTrack,
246
+ videoTrack?.id
247
+ ]);
248
+ /**
249
+ * Add optional event listener for resize event so the parent component
250
+ * can know the video's native aspect ratio.
251
+ */ (0, $h9lXz$useEffect)(function reportVideoDimensions() {
252
+ const video = videoEl.current;
253
+ if (!onResize || !video) return;
254
+ let frame;
255
+ function handleResize() {
256
+ if (frame) cancelAnimationFrame(frame);
257
+ frame = requestAnimationFrame(()=>{
258
+ const video = videoEl.current;
259
+ if (!video || document.hidden) return;
260
+ const videoWidth = video.videoWidth;
261
+ const videoHeight = video.videoHeight;
262
+ if (videoWidth && videoHeight) onResize?.({
263
+ aspectRatio: videoWidth / videoHeight,
264
+ height: videoHeight,
265
+ width: videoWidth
266
+ });
267
+ });
268
+ }
269
+ handleResize();
270
+ video.addEventListener("loadedmetadata", handleResize);
271
+ video.addEventListener("resize", handleResize);
272
+ return ()=>{
273
+ if (frame) cancelAnimationFrame(frame);
274
+ video.removeEventListener("loadedmetadata", handleResize);
275
+ video.removeEventListener("resize", handleResize);
276
+ };
277
+ }, [
278
+ onResize
279
+ ]);
280
+ return (0, $h9lXz$jsx)("video", {
281
+ autoPlay: true,
282
+ muted: true,
283
+ playsInline: true,
284
+ ref: videoRef,
285
+ style: {
286
+ objectFit: fit,
287
+ transform: mirror ? "scale(-1, 1)" : "",
288
+ ...style
289
+ },
290
+ ...props
291
+ });
292
+ });
293
+ $b76d887910983811$export$d090a384943608eb.displayName = "RTVIClientVideo";
294
+
295
+
296
+
297
+
298
+
299
+
300
+
301
+
302
+
303
+
304
+ const $c7d06534b21735c2$var$availableMicsAtom = (0, $h9lXz$atom)([]);
305
+ const $c7d06534b21735c2$var$availableCamsAtom = (0, $h9lXz$atom)([]);
306
+ const $c7d06534b21735c2$var$availableSpeakersAtom = (0, $h9lXz$atom)([]);
307
+ const $c7d06534b21735c2$var$selectedMicAtom = (0, $h9lXz$atom)({});
308
+ const $c7d06534b21735c2$var$selectedCamAtom = (0, $h9lXz$atom)({});
309
+ const $c7d06534b21735c2$var$selectedSpeakerAtom = (0, $h9lXz$atom)({});
310
+ const $c7d06534b21735c2$export$652c54907b83a48d = ()=>{
311
+ const client = (0, $54a3c9f5bdbf0854$export$31a5f6a22c9b8fba)();
312
+ const availableCams = (0, $h9lXz$useAtomValue)($c7d06534b21735c2$var$availableCamsAtom);
313
+ const availableMics = (0, $h9lXz$useAtomValue)($c7d06534b21735c2$var$availableMicsAtom);
314
+ const availableSpeakers = (0, $h9lXz$useAtomValue)($c7d06534b21735c2$var$availableSpeakersAtom);
315
+ const selectedCam = (0, $h9lXz$useAtomValue)($c7d06534b21735c2$var$selectedCamAtom);
316
+ const selectedMic = (0, $h9lXz$useAtomValue)($c7d06534b21735c2$var$selectedMicAtom);
317
+ const selectedSpeaker = (0, $h9lXz$useAtomValue)($c7d06534b21735c2$var$selectedSpeakerAtom);
318
+ (0, $824ea64b5f757259$export$33a6ac53b8f02625)((0, $h9lXz$RTVIEvent).AvailableCamsUpdated, (0, $h9lXz$useAtomCallback)((0, $h9lXz$useCallback)((_get, set, cams)=>{
319
+ set($c7d06534b21735c2$var$availableCamsAtom, cams);
320
+ }, [])));
321
+ (0, $824ea64b5f757259$export$33a6ac53b8f02625)((0, $h9lXz$RTVIEvent).AvailableMicsUpdated, (0, $h9lXz$useAtomCallback)((0, $h9lXz$useCallback)((_get, set, mics)=>{
322
+ set($c7d06534b21735c2$var$availableMicsAtom, mics);
323
+ }, [])));
324
+ (0, $824ea64b5f757259$export$33a6ac53b8f02625)((0, $h9lXz$RTVIEvent).AvailableSpeakersUpdated, (0, $h9lXz$useAtomCallback)((0, $h9lXz$useCallback)((_get, set, speakers)=>{
325
+ set($c7d06534b21735c2$var$availableSpeakersAtom, speakers);
326
+ }, [])));
327
+ (0, $824ea64b5f757259$export$33a6ac53b8f02625)((0, $h9lXz$RTVIEvent).CamUpdated, (0, $h9lXz$useAtomCallback)((0, $h9lXz$useCallback)((_get, set, cam)=>{
328
+ set($c7d06534b21735c2$var$selectedCamAtom, cam);
329
+ }, [])));
330
+ (0, $824ea64b5f757259$export$33a6ac53b8f02625)((0, $h9lXz$RTVIEvent).MicUpdated, (0, $h9lXz$useAtomCallback)((0, $h9lXz$useCallback)((_get, set, mic)=>{
331
+ set($c7d06534b21735c2$var$selectedMicAtom, mic);
332
+ }, [])));
333
+ (0, $824ea64b5f757259$export$33a6ac53b8f02625)((0, $h9lXz$RTVIEvent).SpeakerUpdated, (0, $h9lXz$useAtomCallback)((0, $h9lXz$useCallback)((_get, set, speaker)=>{
334
+ set($c7d06534b21735c2$var$selectedSpeakerAtom, speaker);
335
+ }, [])));
336
+ const updateCam = (0, $h9lXz$useCallback)((id)=>{
337
+ client?.updateCam(id);
338
+ }, [
339
+ client
340
+ ]);
341
+ const updateMic = (0, $h9lXz$useCallback)((id)=>{
342
+ client?.updateMic(id);
343
+ }, [
344
+ client
345
+ ]);
346
+ const updateSpeaker = (0, $h9lXz$useCallback)((id)=>{
347
+ client?.updateSpeaker(id);
348
+ }, [
349
+ client
350
+ ]);
351
+ return {
352
+ availableCams: availableCams,
353
+ availableMics: availableMics,
354
+ availableSpeakers: availableSpeakers,
355
+ selectedCam: selectedCam,
356
+ selectedMic: selectedMic,
357
+ selectedSpeaker: selectedSpeaker,
358
+ updateCam: updateCam,
359
+ updateMic: updateMic,
360
+ updateSpeaker: updateSpeaker
361
+ };
362
+ };
363
+
364
+
365
+
366
+ /**
367
+ * Copyright (c) 2024, Daily.
368
+ *
369
+ * SPDX-License-Identifier: BSD-2-Clause
370
+ */
371
+
372
+
373
+ const $8376ffbc1b1f3c97$var$transportStateAtom = (0, $h9lXz$atom)("disconnected");
374
+ const $8376ffbc1b1f3c97$export$599fa01283bd4ece = ()=>{
375
+ const [transportState, setTransportState] = (0, $h9lXz$useAtom)($8376ffbc1b1f3c97$var$transportStateAtom);
376
+ (0, $824ea64b5f757259$export$33a6ac53b8f02625)((0, $h9lXz$RTVIEvent).TransportStateChanged, setTransportState);
377
+ return transportState;
378
+ };
379
+
380
+
381
+
382
+
383
+
384
+ const $993a744193844a95$export$59bf27bd43679db6 = /*#__PURE__*/ (0, $h9lXz$react).memo(({ backgroundColor: backgroundColor = "transparent", barColor: barColor = "black", barWidth: barWidth = 30, barGap: barGap = 12, barMaxHeight: barMaxHeight = 120, participantType: participantType })=>{
385
+ const canvasRef = (0, $h9lXz$useRef)(null);
386
+ const track = (0, $194c75143b7a1fa0$export$7c03381e0d26a6c3)("audio", participantType);
387
+ (0, $h9lXz$useEffect)(()=>{
388
+ if (!canvasRef.current) return;
389
+ const canvasWidth = 5 * barWidth + 4 * barGap;
390
+ const canvasHeight = barMaxHeight;
391
+ const canvas = canvasRef.current;
392
+ const scaleFactor = 2;
393
+ // Make canvas fill the width and height of its container
394
+ const resizeCanvas = ()=>{
395
+ canvas.width = canvasWidth * scaleFactor;
396
+ canvas.height = canvasHeight * scaleFactor;
397
+ canvas.style.width = `${canvasWidth}px`;
398
+ canvas.style.height = `${canvasHeight}px`;
399
+ canvasCtx.lineCap = "round";
400
+ canvasCtx.scale(scaleFactor, scaleFactor);
401
+ };
402
+ const canvasCtx = canvas.getContext("2d");
403
+ resizeCanvas();
404
+ if (!track) return;
405
+ const audioContext = new AudioContext();
406
+ const source = audioContext.createMediaStreamSource(new MediaStream([
407
+ track
408
+ ]));
409
+ const analyser = audioContext.createAnalyser();
410
+ analyser.fftSize = 1024;
411
+ source.connect(analyser);
412
+ const frequencyData = new Uint8Array(analyser.frequencyBinCount);
413
+ canvasCtx.lineCap = "round";
414
+ const bands = [
415
+ {
416
+ startFreq: 85,
417
+ endFreq: 255,
418
+ smoothValue: 0
419
+ },
420
+ {
421
+ startFreq: 255,
422
+ endFreq: 500,
423
+ smoothValue: 0
424
+ },
425
+ {
426
+ startFreq: 500,
427
+ endFreq: 2000,
428
+ smoothValue: 0
429
+ },
430
+ {
431
+ startFreq: 2000,
432
+ endFreq: 4000,
433
+ smoothValue: 0
434
+ },
435
+ {
436
+ startFreq: 4000,
437
+ endFreq: 8000,
438
+ smoothValue: 0
439
+ }
440
+ ];
441
+ const getFrequencyBinIndex = (frequency)=>{
442
+ const nyquist = audioContext.sampleRate / 2;
443
+ return Math.round(frequency / nyquist * (analyser.frequencyBinCount - 1));
444
+ };
445
+ function drawSpectrum() {
446
+ analyser.getByteFrequencyData(frequencyData);
447
+ canvasCtx.clearRect(0, 0, canvas.width / scaleFactor, canvas.height / scaleFactor);
448
+ canvasCtx.fillStyle = backgroundColor;
449
+ canvasCtx.fillRect(0, 0, canvas.width / scaleFactor, canvas.height / scaleFactor);
450
+ let isActive = false;
451
+ const totalBarsWidth = bands.length * barWidth + (bands.length - 1) * barGap;
452
+ const startX = (canvas.width / scaleFactor - totalBarsWidth) / 2; // Center bars
453
+ const adjustedCircleRadius = barWidth / 2; // Fixed radius for reset circles
454
+ bands.forEach((band, i)=>{
455
+ const startIndex = getFrequencyBinIndex(band.startFreq);
456
+ const endIndex = getFrequencyBinIndex(band.endFreq);
457
+ const bandData = frequencyData.slice(startIndex, endIndex);
458
+ const bandValue = bandData.reduce((acc, val)=>acc + val, 0) / bandData.length;
459
+ const smoothingFactor = 0.2;
460
+ if (bandValue < 1) band.smoothValue = Math.max(band.smoothValue - smoothingFactor * 5, 0);
461
+ else {
462
+ band.smoothValue = band.smoothValue + (bandValue - band.smoothValue) * smoothingFactor;
463
+ isActive = true;
464
+ }
465
+ const x = startX + i * (barWidth + barGap);
466
+ // Calculate bar height with a maximum cap
467
+ const barHeight = Math.min(band.smoothValue / 255 * barMaxHeight, barMaxHeight);
468
+ const yTop = Math.max(canvas.height / scaleFactor / 2 - barHeight / 2, adjustedCircleRadius);
469
+ const yBottom = Math.min(canvas.height / scaleFactor / 2 + barHeight / 2, canvas.height / scaleFactor - adjustedCircleRadius);
470
+ if (band.smoothValue > 0) {
471
+ canvasCtx.beginPath();
472
+ canvasCtx.moveTo(x + barWidth / 2, yTop);
473
+ canvasCtx.lineTo(x + barWidth / 2, yBottom);
474
+ canvasCtx.lineWidth = barWidth;
475
+ canvasCtx.strokeStyle = barColor;
476
+ canvasCtx.stroke();
477
+ } else {
478
+ canvasCtx.beginPath();
479
+ canvasCtx.arc(x + barWidth / 2, canvas.height / scaleFactor / 2, adjustedCircleRadius, 0, 2 * Math.PI);
480
+ canvasCtx.fillStyle = barColor;
481
+ canvasCtx.fill();
482
+ canvasCtx.closePath();
483
+ }
484
+ });
485
+ if (!isActive) drawInactiveCircles(adjustedCircleRadius, barColor);
486
+ requestAnimationFrame(drawSpectrum);
487
+ }
488
+ function drawInactiveCircles(circleRadius, color) {
489
+ const totalBarsWidth = bands.length * barWidth + (bands.length - 1) * barGap;
490
+ const startX = (canvas.width / scaleFactor - totalBarsWidth) / 2;
491
+ const y = canvas.height / scaleFactor / 2;
492
+ bands.forEach((_, i)=>{
493
+ const x = startX + i * (barWidth + barGap);
494
+ canvasCtx.beginPath();
495
+ canvasCtx.arc(x + barWidth / 2, y, circleRadius, 0, 2 * Math.PI);
496
+ canvasCtx.fillStyle = color;
497
+ canvasCtx.fill();
498
+ canvasCtx.closePath();
499
+ });
500
+ }
501
+ drawSpectrum();
502
+ // Handle resizing
503
+ window.addEventListener("resize", resizeCanvas);
504
+ return ()=>{
505
+ audioContext.close();
506
+ window.removeEventListener("resize", resizeCanvas);
507
+ };
508
+ }, [
509
+ backgroundColor,
510
+ barColor,
511
+ barGap,
512
+ barMaxHeight,
513
+ barWidth,
514
+ track
515
+ ]);
516
+ return (0, $h9lXz$jsx)("canvas", {
517
+ ref: canvasRef,
518
+ style: {
519
+ display: "block",
520
+ width: "100%",
521
+ height: "100%"
522
+ }
523
+ });
524
+ });
525
+ $993a744193844a95$export$59bf27bd43679db6.displayName = "VoiceVisualizer";
526
+
527
+
528
+
529
+
530
+ export {$f8b885726fc652c0$export$ba1245f7cbf3ae02 as RTVIClientAudio, $f3f7d4263dc13c6a$export$4a4ae2d5dc96782 as RTVIClientProvider, $b76d887910983811$export$d090a384943608eb as RTVIClientVideo, $54a3c9f5bdbf0854$export$31a5f6a22c9b8fba as useRTVIClient, $824ea64b5f757259$export$33a6ac53b8f02625 as useRTVIClientEvent, $c7d06534b21735c2$export$652c54907b83a48d as useRTVIClientMediaDevices, $194c75143b7a1fa0$export$7c03381e0d26a6c3 as useRTVIClientMediaTrack, $8376ffbc1b1f3c97$export$599fa01283bd4ece as useRTVIClientTransportState, $993a744193844a95$export$59bf27bd43679db6 as VoiceVisualizer};
531
+ //# sourceMappingURL=index.module.js.map
@@ -0,0 +1 @@
1
+ {"mappings":"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","sources":["client-react/src/index.ts","client-react/src/RTVIClientAudio.tsx","client-react/src/useRTVIClientEvent.ts","client-react/src/useRTVIClient.ts","client-react/src/RTVIClientProvider.tsx","client-react/src/useRTVIClientMediaTrack.ts","client-react/src/RTVIClientVideo.tsx","client-react/src/useMergedRef.ts","client-react/src/useRTVIClientMediaDevices.ts","client-react/src/useRTVIClientTransportState.ts","client-react/src/VoiceVisualizer.tsx"],"sourcesContent":["/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport { RTVIClientAudio } from \"./RTVIClientAudio\";\nimport { RTVIClientProvider } from \"./RTVIClientProvider\";\nimport { RTVIClientVideo } from \"./RTVIClientVideo\";\nimport { useRTVIClient } from \"./useRTVIClient\";\nimport { useRTVIClientEvent } from \"./useRTVIClientEvent\";\nimport { useRTVIClientMediaDevices } from \"./useRTVIClientMediaDevices\";\nimport { useRTVIClientMediaTrack } from \"./useRTVIClientMediaTrack\";\nimport { useRTVIClientTransportState } from \"./useRTVIClientTransportState\";\nimport { VoiceVisualizer } from \"./VoiceVisualizer\";\n\nexport {\n RTVIClientAudio,\n RTVIClientProvider,\n RTVIClientVideo,\n useRTVIClient,\n useRTVIClientEvent,\n useRTVIClientMediaDevices,\n useRTVIClientMediaTrack,\n useRTVIClientTransportState,\n VoiceVisualizer,\n};\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport { RTVIEvent } from \"@pipecat-ai/client-js\";\nimport { useCallback, useEffect, useRef } from \"react\";\nimport { useRTVIClientEvent } from \"./useRTVIClientEvent\";\nimport { useRTVIClientMediaTrack } from \"./useRTVIClientMediaTrack\";\n\nexport const RTVIClientAudio = () => {\n const botAudioRef = useRef<HTMLAudioElement>(null);\n const botAudioTrack = useRTVIClientMediaTrack(\"audio\", \"bot\");\n\n useEffect(() => {\n if (!botAudioRef.current || !botAudioTrack) return;\n if (botAudioRef.current.srcObject) {\n const oldTrack = (\n botAudioRef.current.srcObject as MediaStream\n ).getAudioTracks()[0];\n if (oldTrack.id === botAudioTrack.id) return;\n }\n botAudioRef.current.srcObject = new MediaStream([botAudioTrack]);\n }, [botAudioTrack]);\n\n useRTVIClientEvent(\n RTVIEvent.SpeakerUpdated,\n useCallback((speaker: MediaDeviceInfo) => {\n if (!botAudioRef.current) return;\n if (typeof botAudioRef.current.setSinkId !== \"function\") return;\n botAudioRef.current.setSinkId(speaker.deviceId);\n }, [])\n );\n\n return (\n <>\n <audio ref={botAudioRef} autoPlay />\n </>\n );\n};\nRTVIClientAudio.displayName = \"RTVIClientAudio\";\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport { RTVIEvent, RTVIEventHandler } from \"@pipecat-ai/client-js\";\nimport { useEffect } from \"react\";\nimport { useRTVIClient } from \"./useRTVIClient\";\n\nexport const useRTVIClientEvent = <E extends RTVIEvent>(\n event: E,\n handler: RTVIEventHandler<E>\n) => {\n const client = useRTVIClient();\n\n useEffect(() => {\n if (!client) return;\n client.on(event, handler);\n return () => {\n client.off(event, handler);\n };\n }, [event, handler, client]);\n};\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport { useContext } from \"react\";\nimport { RTVIClientContext } from \"./RTVIClientProvider\";\n\nexport const useRTVIClient = () => {\n const { client } = useContext(RTVIClientContext);\n return client;\n};\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport { createContext } from \"react\";\n\nimport { RTVIClient } from \"@pipecat-ai/client-js\";\nimport { createStore } from \"jotai\";\nimport { Provider as JotaiProvider } from \"jotai/react\";\n\nexport interface Props {\n client: RTVIClient;\n jotaiStore?: React.ComponentProps<typeof JotaiProvider>[\"store\"];\n}\n\nconst defaultStore = createStore();\n\nexport const RTVIClientContext = createContext<{ client?: RTVIClient }>({});\n\nexport const RTVIClientProvider: React.FC<React.PropsWithChildren<Props>> = ({\n children,\n client,\n jotaiStore = defaultStore,\n}) => {\n return (\n <JotaiProvider store={jotaiStore}>\n <RTVIClientContext.Provider value={{ client }}>\n {children}\n </RTVIClientContext.Provider>\n </JotaiProvider>\n );\n};\nRTVIClientProvider.displayName = \"RTVIClientProvider\";\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport { Participant, RTVIEvent, Tracks } from \"@pipecat-ai/client-js\";\nimport { atom, useAtomValue } from \"jotai\";\nimport { atomFamily, useAtomCallback } from \"jotai/utils\";\nimport { PrimitiveAtom } from \"jotai/vanilla\";\nimport { useCallback, useEffect } from \"react\";\nimport { useRTVIClient } from \"./useRTVIClient\";\nimport { useRTVIClientEvent } from \"./useRTVIClientEvent\";\n\ntype ParticipantType = keyof Tracks;\ntype TrackType = keyof Tracks[\"local\"];\n\nconst localAudioTrackAtom = atom<MediaStreamTrack | null>(null);\nconst localVideoTrackAtom = atom<MediaStreamTrack | null>(null);\nconst botAudioTrackAtom = atom<MediaStreamTrack | null>(null);\nconst botVideoTrackAtom = atom<MediaStreamTrack | null>(null);\n\nconst trackAtom = atomFamily<\n { local: boolean; trackType: TrackType },\n PrimitiveAtom<MediaStreamTrack | null>\n>(({ local, trackType }) => {\n if (local)\n return trackType === \"audio\" ? localAudioTrackAtom : localVideoTrackAtom;\n return trackType === \"audio\" ? botAudioTrackAtom : botVideoTrackAtom;\n});\n\nexport const useRTVIClientMediaTrack = (\n trackType: TrackType,\n participantType: ParticipantType\n) => {\n const client = useRTVIClient();\n const track = useAtomValue(\n trackAtom({ local: participantType === \"local\", trackType })\n );\n\n const updateTrack = useAtomCallback(\n useCallback(\n (\n get,\n set,\n track: MediaStreamTrack,\n trackType: TrackType,\n local: boolean\n ) => {\n const atom = trackAtom({\n local,\n trackType,\n });\n const oldTrack = get(atom);\n if (oldTrack?.id === track.id) return;\n set(atom, track);\n },\n [participantType, track, trackType]\n )\n );\n\n useRTVIClientEvent(\n RTVIEvent.TrackStarted,\n useCallback((track: MediaStreamTrack, participant?: Participant) => {\n updateTrack(track, track.kind as TrackType, Boolean(participant?.local));\n }, [])\n );\n\n useEffect(() => {\n if (!client) return;\n const tracks = client.tracks();\n const track = tracks?.[participantType]?.[trackType];\n if (!track) return;\n updateTrack(track, trackType, participantType === \"local\");\n }, [participantType, trackType, updateTrack, client]);\n\n return track;\n};\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport React, { forwardRef, useEffect, useRef } from \"react\";\nimport { useRTVIClientMediaTrack } from \"./useRTVIClientMediaTrack\";\nimport useMergedRef from \"./useMergedRef\";\n\ninterface RTVIClientVideoInterface {\n aspectRatio: number;\n height: number;\n width: number;\n}\n\nexport interface Props\n extends Omit<React.VideoHTMLAttributes<HTMLVideoElement>, \"onResize\"> {\n participant: \"local\" | \"bot\";\n\n /**\n * Defines whether the video should be fully contained or cover the box. Default: 'contain'.\n */\n fit?: \"contain\" | \"cover\";\n /**\n * Forces the video to be mirrored, if set.\n */\n mirror?: boolean;\n\n /**\n * Optional callback, which is triggered whenever the video's rendered width or height changes.\n * Returns the video's native width, height and aspectRatio.\n */\n onResize?(dimensions: RTVIClientVideoInterface): void;\n}\n\nexport const RTVIClientVideo = forwardRef<HTMLVideoElement, Props>(\n function VoiceClientVideo(\n {\n participant = \"local\",\n fit = \"contain\",\n mirror,\n onResize,\n style = {},\n ...props\n },\n ref\n ) {\n const videoTrack: MediaStreamTrack | null = useRTVIClientMediaTrack(\n \"video\",\n participant\n );\n\n const videoEl = useRef<HTMLVideoElement>(null);\n const videoRef = useMergedRef<HTMLVideoElement>(videoEl, ref);\n\n /**\n * Handle canplay & picture-in-picture events.\n */\n useEffect(function setupVideoEvents() {\n const video = videoEl.current;\n if (!video) return;\n\n const playVideo = () => {\n const promise = video.play();\n if (promise !== undefined) {\n promise\n .then(() => {\n // All good, playback started.\n video.controls = false;\n })\n .catch((error) => {\n // Auto-play was prevented. Show video controls, so user can play video manually.\n video.controls = true;\n console.warn(\"Failed to play video\", error);\n });\n }\n };\n\n const handleCanPlay = () => {\n if (!video.paused) return;\n playVideo();\n };\n const handleEnterPIP = () => {\n video.style.transform = \"scale(1)\";\n };\n const handleLeavePIP = () => {\n video.style.transform = \"\";\n setTimeout(() => {\n if (video.paused) playVideo();\n }, 100);\n };\n const handleVisibilityChange = () => {\n if (document.visibilityState === \"hidden\") return;\n if (!video.paused) return;\n playVideo();\n };\n video.addEventListener(\"canplay\", handleCanPlay);\n video.addEventListener(\"enterpictureinpicture\", handleEnterPIP);\n video.addEventListener(\"leavepictureinpicture\", handleLeavePIP);\n\n // Videos can be paused if media was played in another app on iOS.\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n return () => {\n video.removeEventListener(\"canplay\", handleCanPlay);\n video.removeEventListener(\"enterpictureinpicture\", handleEnterPIP);\n video.removeEventListener(\"leavepictureinpicture\", handleLeavePIP);\n document.removeEventListener(\n \"visibilitychange\",\n handleVisibilityChange\n );\n };\n }, []);\n\n /**\n * Update srcObject.\n */\n useEffect(\n function updateSrcObject() {\n const video = videoEl.current;\n if (!video || !videoTrack) return;\n video.srcObject = new MediaStream([videoTrack]);\n video.load();\n return () => {\n // clean up when unmounted\n video.srcObject = null;\n video.load();\n };\n },\n [videoTrack, videoTrack?.id]\n );\n\n /**\n * Add optional event listener for resize event so the parent component\n * can know the video's native aspect ratio.\n */\n useEffect(\n function reportVideoDimensions() {\n const video = videoEl.current;\n if (!onResize || !video) return;\n\n let frame: ReturnType<typeof requestAnimationFrame>;\n function handleResize() {\n if (frame) cancelAnimationFrame(frame);\n frame = requestAnimationFrame(() => {\n const video = videoEl.current;\n if (!video || document.hidden) return;\n const videoWidth = video.videoWidth;\n const videoHeight = video.videoHeight;\n if (videoWidth && videoHeight) {\n onResize?.({\n aspectRatio: videoWidth / videoHeight,\n height: videoHeight,\n width: videoWidth,\n });\n }\n });\n }\n\n handleResize();\n video.addEventListener(\"loadedmetadata\", handleResize);\n video.addEventListener(\"resize\", handleResize);\n\n return () => {\n if (frame) cancelAnimationFrame(frame);\n video.removeEventListener(\"loadedmetadata\", handleResize);\n video.removeEventListener(\"resize\", handleResize);\n };\n },\n [onResize]\n );\n\n return (\n <video\n autoPlay\n muted\n playsInline\n ref={videoRef}\n style={{\n objectFit: fit,\n transform: mirror ? \"scale(-1, 1)\" : \"\",\n ...style,\n }}\n {...props}\n />\n );\n }\n);\nRTVIClientVideo.displayName = \"RTVIClientVideo\";\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n *\n * This file contains code derived from:\n * https://github.com/jaredLunde/react-hook/blob/master/packages/merged-ref/src/index.tsx\n * Original author: Jared Lunde (https://github.com/jaredLunde)\n * Original license: MIT (https://github.com/jaredLunde/react-hook/blob/master/LICENSE)\n */\n\nimport React, { useCallback } from \"react\";\n\nfunction useMergedRef<T>(...refs: React.Ref<T>[]): React.RefCallback<T> {\n return useCallback(\n (element: T) => {\n for (let i = 0; i < refs.length; i++) {\n const ref = refs[i];\n if (typeof ref === \"function\") ref(element);\n else if (ref && typeof ref === \"object\")\n (ref as React.MutableRefObject<T>).current = element;\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n refs\n );\n}\n\nexport default useMergedRef;\n","import { RTVIEvent } from \"@pipecat-ai/client-js\";\nimport { atom, useAtomValue } from \"jotai\";\nimport { useAtomCallback } from \"jotai/utils\";\nimport { useCallback } from \"react\";\nimport { useRTVIClient } from \"./useRTVIClient\";\nimport { useRTVIClientEvent } from \"./useRTVIClientEvent\";\n\ntype OptionalMediaDeviceInfo = MediaDeviceInfo | Record<string, never>;\n\nconst availableMicsAtom = atom<MediaDeviceInfo[]>([]);\nconst availableCamsAtom = atom<MediaDeviceInfo[]>([]);\nconst availableSpeakersAtom = atom<MediaDeviceInfo[]>([]);\nconst selectedMicAtom = atom<OptionalMediaDeviceInfo>({});\nconst selectedCamAtom = atom<OptionalMediaDeviceInfo>({});\nconst selectedSpeakerAtom = atom<OptionalMediaDeviceInfo>({});\n\nexport const useRTVIClientMediaDevices = () => {\n const client = useRTVIClient();\n\n const availableCams = useAtomValue(availableCamsAtom);\n const availableMics = useAtomValue(availableMicsAtom);\n const availableSpeakers = useAtomValue(availableSpeakersAtom);\n const selectedCam = useAtomValue(selectedCamAtom);\n const selectedMic = useAtomValue(selectedMicAtom);\n const selectedSpeaker = useAtomValue(selectedSpeakerAtom);\n\n useRTVIClientEvent(\n RTVIEvent.AvailableCamsUpdated,\n useAtomCallback(\n useCallback((_get, set, cams) => {\n set(availableCamsAtom, cams);\n }, [])\n )\n );\n useRTVIClientEvent(\n RTVIEvent.AvailableMicsUpdated,\n useAtomCallback(\n useCallback((_get, set, mics) => {\n set(availableMicsAtom, mics);\n }, [])\n )\n );\n useRTVIClientEvent(\n RTVIEvent.AvailableSpeakersUpdated,\n useAtomCallback(\n useCallback((_get, set, speakers) => {\n set(availableSpeakersAtom, speakers);\n }, [])\n )\n );\n useRTVIClientEvent(\n RTVIEvent.CamUpdated,\n useAtomCallback(\n useCallback((_get, set, cam) => {\n set(selectedCamAtom, cam);\n }, [])\n )\n );\n useRTVIClientEvent(\n RTVIEvent.MicUpdated,\n useAtomCallback(\n useCallback((_get, set, mic) => {\n set(selectedMicAtom, mic);\n }, [])\n )\n );\n useRTVIClientEvent(\n RTVIEvent.SpeakerUpdated,\n useAtomCallback(\n useCallback((_get, set, speaker) => {\n set(selectedSpeakerAtom, speaker);\n }, [])\n )\n );\n\n const updateCam = useCallback(\n (id: string) => {\n client?.updateCam(id);\n },\n [client]\n );\n const updateMic = useCallback(\n (id: string) => {\n client?.updateMic(id);\n },\n [client]\n );\n const updateSpeaker = useCallback(\n (id: string) => {\n client?.updateSpeaker(id);\n },\n [client]\n );\n\n return {\n availableCams,\n availableMics,\n availableSpeakers,\n selectedCam,\n selectedMic,\n selectedSpeaker,\n updateCam,\n updateMic,\n updateSpeaker,\n };\n};\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport { RTVIEvent, TransportState } from \"@pipecat-ai/client-js\";\nimport { atom, useAtom } from \"jotai\";\nimport { useRTVIClientEvent } from \"./useRTVIClientEvent\";\n\nconst transportStateAtom = atom<TransportState>(\"disconnected\");\n\nexport const useRTVIClientTransportState = () => {\n const [transportState, setTransportState] = useAtom(transportStateAtom);\n\n useRTVIClientEvent(RTVIEvent.TransportStateChanged, setTransportState);\n\n return transportState;\n};\n","/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport React, { useEffect, useRef } from \"react\";\nimport { useRTVIClientMediaTrack } from \"./useRTVIClientMediaTrack\";\n\ntype ParticipantType = Parameters<typeof useRTVIClientMediaTrack>[1];\n\ninterface Props {\n backgroundColor?: string;\n barColor?: string;\n barGap?: number;\n barWidth?: number;\n barMaxHeight?: number;\n participantType: ParticipantType;\n}\n\nexport const VoiceVisualizer: React.FC<Props> = React.memo(\n ({\n backgroundColor = \"transparent\",\n barColor = \"black\",\n barWidth = 30,\n barGap = 12,\n barMaxHeight = 120,\n participantType,\n }) => {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n\n const track: MediaStreamTrack | null = useRTVIClientMediaTrack(\n \"audio\",\n participantType\n );\n\n useEffect(() => {\n if (!canvasRef.current) return;\n\n const canvasWidth = 5 * barWidth + 4 * barGap;\n const canvasHeight = barMaxHeight;\n\n const canvas = canvasRef.current;\n\n const scaleFactor = 2;\n\n // Make canvas fill the width and height of its container\n const resizeCanvas = () => {\n canvas.width = canvasWidth * scaleFactor;\n canvas.height = canvasHeight * scaleFactor;\n\n canvas.style.width = `${canvasWidth}px`;\n canvas.style.height = `${canvasHeight}px`;\n\n canvasCtx.lineCap = \"round\";\n canvasCtx.scale(scaleFactor, scaleFactor);\n };\n\n const canvasCtx = canvas.getContext(\"2d\")!;\n resizeCanvas();\n\n if (!track) return;\n\n const audioContext = new AudioContext();\n const source = audioContext.createMediaStreamSource(\n new MediaStream([track])\n );\n const analyser = audioContext.createAnalyser();\n\n analyser.fftSize = 1024;\n\n source.connect(analyser);\n\n const frequencyData = new Uint8Array(analyser.frequencyBinCount);\n\n canvasCtx.lineCap = \"round\";\n\n const bands = [\n { startFreq: 85, endFreq: 255, smoothValue: 0 }, // Covers fundamental frequencies for male and female voices\n { startFreq: 255, endFreq: 500, smoothValue: 0 }, // Lower formants and some harmonics\n { startFreq: 500, endFreq: 2000, smoothValue: 0 }, // Vowel formants and key consonant frequencies\n { startFreq: 2000, endFreq: 4000, smoothValue: 0 }, // Higher formants, \"clarity\" of speech\n { startFreq: 4000, endFreq: 8000, smoothValue: 0 }, // Sibilance and high-frequency consonants\n ];\n\n const getFrequencyBinIndex = (frequency: number) => {\n const nyquist = audioContext.sampleRate / 2;\n return Math.round(\n (frequency / nyquist) * (analyser.frequencyBinCount - 1)\n );\n };\n\n function drawSpectrum() {\n analyser.getByteFrequencyData(frequencyData);\n canvasCtx.clearRect(\n 0,\n 0,\n canvas.width / scaleFactor,\n canvas.height / scaleFactor\n );\n canvasCtx.fillStyle = backgroundColor;\n canvasCtx.fillRect(\n 0,\n 0,\n canvas.width / scaleFactor,\n canvas.height / scaleFactor\n );\n\n let isActive = false;\n\n const totalBarsWidth =\n bands.length * barWidth + (bands.length - 1) * barGap;\n const startX = (canvas.width / scaleFactor - totalBarsWidth) / 2; // Center bars\n\n const adjustedCircleRadius = barWidth / 2; // Fixed radius for reset circles\n\n bands.forEach((band, i) => {\n const startIndex = getFrequencyBinIndex(band.startFreq);\n const endIndex = getFrequencyBinIndex(band.endFreq);\n const bandData = frequencyData.slice(startIndex, endIndex);\n const bandValue =\n bandData.reduce((acc, val) => acc + val, 0) / bandData.length;\n\n const smoothingFactor = 0.2;\n\n if (bandValue < 1) {\n band.smoothValue = Math.max(\n band.smoothValue - smoothingFactor * 5,\n 0\n );\n } else {\n band.smoothValue =\n band.smoothValue +\n (bandValue - band.smoothValue) * smoothingFactor;\n isActive = true;\n }\n\n const x = startX + i * (barWidth + barGap);\n // Calculate bar height with a maximum cap\n const barHeight = Math.min(\n (band.smoothValue / 255) * barMaxHeight,\n barMaxHeight\n );\n\n const yTop = Math.max(\n canvas.height / scaleFactor / 2 - barHeight / 2,\n adjustedCircleRadius\n );\n const yBottom = Math.min(\n canvas.height / scaleFactor / 2 + barHeight / 2,\n canvas.height / scaleFactor - adjustedCircleRadius\n );\n\n if (band.smoothValue > 0) {\n canvasCtx.beginPath();\n canvasCtx.moveTo(x + barWidth / 2, yTop);\n canvasCtx.lineTo(x + barWidth / 2, yBottom);\n canvasCtx.lineWidth = barWidth;\n canvasCtx.strokeStyle = barColor;\n canvasCtx.stroke();\n } else {\n canvasCtx.beginPath();\n canvasCtx.arc(\n x + barWidth / 2,\n canvas.height / scaleFactor / 2,\n adjustedCircleRadius,\n 0,\n 2 * Math.PI\n );\n canvasCtx.fillStyle = barColor;\n canvasCtx.fill();\n canvasCtx.closePath();\n }\n });\n\n if (!isActive) {\n drawInactiveCircles(adjustedCircleRadius, barColor);\n }\n\n requestAnimationFrame(drawSpectrum);\n }\n\n function drawInactiveCircles(circleRadius: number, color: string) {\n const totalBarsWidth =\n bands.length * barWidth + (bands.length - 1) * barGap;\n const startX = (canvas.width / scaleFactor - totalBarsWidth) / 2;\n const y = canvas.height / scaleFactor / 2;\n\n bands.forEach((_, i) => {\n const x = startX + i * (barWidth + barGap);\n\n canvasCtx.beginPath();\n canvasCtx.arc(x + barWidth / 2, y, circleRadius, 0, 2 * Math.PI);\n canvasCtx.fillStyle = color;\n canvasCtx.fill();\n canvasCtx.closePath();\n });\n }\n\n drawSpectrum();\n\n // Handle resizing\n window.addEventListener(\"resize\", resizeCanvas);\n\n return () => {\n audioContext.close();\n window.removeEventListener(\"resize\", resizeCanvas);\n };\n }, [backgroundColor, barColor, barGap, barMaxHeight, barWidth, track]);\n\n return (\n <canvas\n ref={canvasRef}\n style={{\n display: \"block\",\n width: \"100%\",\n height: \"100%\",\n }}\n />\n );\n }\n);\n\nVoiceVisualizer.displayName = \"VoiceVisualizer\";\n"],"names":[],"version":3,"file":"index.module.js.map"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@pipecat-ai/client-react",
3
+ "version": "0.3.0",
4
+ "license": "BSD-2-Clause",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.module.js",
7
+ "types": "dist/index.d.ts",
8
+ "source": "src/index.ts",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/pipecat-ai/pipecat-client-web.git"
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "package.json",
16
+ "README.md"
17
+ ],
18
+ "scripts": {
19
+ "build": "parcel build --no-cache",
20
+ "dev": "parcel watch",
21
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
22
+ },
23
+ "devDependencies": {
24
+ "@pipecat-ai/client-js": "*",
25
+ "@types/react": "^18.3.3",
26
+ "@types/react-dom": "^18.3.0",
27
+ "eslint": "^9.11.1",
28
+ "eslint-config-prettier": "^9.1.0",
29
+ "eslint-plugin-simple-import-sort": "^12.1.1",
30
+ "parcel": "^2.12.0",
31
+ "react": "^18.3.1",
32
+ "react-dom": "^18.3.1",
33
+ "typescript": "^5.2.2"
34
+ },
35
+ "peerDependencies": {
36
+ "react": ">=18",
37
+ "react-dom": ">=18",
38
+ "@pipecat-ai/client-js": "*"
39
+ },
40
+ "dependencies": {
41
+ "jotai": "^2.9.0"
42
+ }
43
+ }