@pipecat-ai/client-react 0.3.5 → 0.4.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.
package/README.md CHANGED
@@ -93,17 +93,58 @@ Creates a new `<video>` element that renders either the bot or local participant
93
93
  />
94
94
  ```
95
95
 
96
+ ### RTVIClientCamToggle
97
+
98
+ This is a stateful headless component and exposes the user's camEnabled state and an `onClick` handler to toggle the state.
99
+
100
+ #### Props
101
+
102
+ - `onCamEnabledChanged(enabled: boolean)` (function, optional): Triggered when the user's camEnabled state changes
103
+ - `disabled` (boolean, optional): Disables the cam toggle
104
+
105
+ ```jsx
106
+ <RTVIClientCamToggle>
107
+ {({ disabled, isCamEnabled, onClick }) => (
108
+ <button disabled={disabled} onClick={onClick}>
109
+ {isCamEnabled ? "Turn off" : "Turn on"} camera
110
+ </button>
111
+ )}
112
+ </RTVIClientCamToggle>
113
+ ```
114
+
115
+ ### RTVIClientMicToggle
116
+
117
+ This is a stateful headless component and exposes the user's micEnabled state and an `onClick` handler to toggle the state.
118
+
119
+ #### Props
120
+
121
+ - `onMicEnabledChanged(enabled: boolean)` (function, optional): Triggered when the user's micEnabled state changes
122
+ - `disabled` (boolean, optional): Disables the mic toggle
123
+
124
+ ```jsx
125
+ <RTVIClientMicToggle>
126
+ {({ disabled, isMicEnabled, onClick }) => (
127
+ <button disabled={disabled} onClick={onClick}>
128
+ {isMicEnabled ? "Mute" : "Unmute"} microphone
129
+ </button>
130
+ )}
131
+ </RTVIClientMicToggle>
132
+ ```
133
+
96
134
  ### VoiceVisualizer
97
135
 
98
136
  Renders a visual representation of audio input levels on a `<canvas>` element.
99
- The visualization consists of five vertical bars.
137
+ The visualization consists of vertical bars.
100
138
 
101
139
  #### Props
102
140
 
103
141
  - `participantType` (string, required): The participant type to visualize audio for.
104
142
  - `backgroundColor` (string, optional): The background color of the canvas. Default: 'transparent'.
105
143
  - `barColor` (string, optional): The color of the audio level bars. Default: 'black'.
144
+ - `barCount` (number, optional): The amount of bars to render. Default: 5
106
145
  - `barGap` (number, optional): The gap between bars in pixels. Default: 12.
146
+ - `barLineCap` ('round' | 'square', optional): The line cap for each bar. Default: 'round'
147
+ - `barOrigin` ('bottom' | 'center' | 'top', optional): The origin from where the bars grow to full height. Default: 'center'
107
148
  - `barWidth` (number, optional): The width of each bar in pixels. Default: 30.
108
149
  - `barMaxHeight` (number, optional): The maximum height at full volume of each bar in pixels. Default: 120.
109
150
 
@@ -157,6 +198,30 @@ function EventListener() {
157
198
  }
158
199
  ```
159
200
 
201
+ ### useRTVIClientCamControl
202
+
203
+ Allows to control the user's camera state.
204
+
205
+ ```jsx
206
+ import { useRTVIClientCamControl } from "@pipecat-ai/client-react";
207
+
208
+ function CustomCamToggle() {
209
+ const { enableCam, isCamEnabled } = useRTVIClientCamControl();
210
+ }
211
+ ```
212
+
213
+ ### useRTVIClientMicControl
214
+
215
+ Allows to control the user's microphone state.
216
+
217
+ ```jsx
218
+ import { useRTVIClientMicControl } from "@pipecat-ai/client-react";
219
+
220
+ function CustomMicToggle() {
221
+ const { enableMic, isMicEnabled } = useRTVIClientMicControl();
222
+ }
223
+ ```
224
+
160
225
  ### useRTVIClientMediaDevices
161
226
 
162
227
  Manage and list available media devices.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { RTVIClient, RTVIEvent, RTVIEventHandler, Tracks, TransportState } from "@pipecat-ai/client-js";
2
2
  import { Provider } from "jotai/react";
3
- import { JSX } from "react/jsx-runtime";
4
3
  import React from "react";
4
+ import { JSX } from "react/jsx-runtime";
5
5
  interface Props {
6
6
  client: RTVIClient;
7
7
  jotaiStore?: React.ComponentProps<typeof Provider>["store"];
@@ -16,6 +16,69 @@ export const RTVIClientAudio: {
16
16
  (): JSX.Element;
17
17
  displayName: string;
18
18
  };
19
+ export const useRTVIClientTransportState: () => TransportState;
20
+ /**
21
+ * Hook to control camera state
22
+ */
23
+ export const useRTVIClientCamControl: () => {
24
+ enableCam: (enabled: boolean) => void;
25
+ isCamEnabled: boolean;
26
+ };
27
+ interface RTVIClientCamToggleProps {
28
+ /**
29
+ * Callback fired when camera state changes
30
+ */
31
+ onCamEnabledChanged?: (enabled: boolean) => void;
32
+ /**
33
+ * Optional prop to disable the cam toggle.
34
+ * When disabled, changes are not applied to the client.
35
+ * @default false
36
+ */
37
+ disabled?: boolean;
38
+ /**
39
+ * Render prop that provides state and handlers to the children
40
+ */
41
+ children: (props: {
42
+ disabled?: boolean;
43
+ isCamEnabled: boolean;
44
+ onClick: () => void;
45
+ }) => React.ReactNode;
46
+ }
47
+ /**
48
+ * Headless component for controlling camera state
49
+ */
50
+ export const RTVIClientCamToggle: React.FC<RTVIClientCamToggleProps>;
51
+ /**
52
+ * Hook to control microphone state
53
+ */
54
+ export const useRTVIClientMicControl: () => {
55
+ enableMic: (enabled: boolean) => void;
56
+ isMicEnabled: boolean;
57
+ };
58
+ interface RTVIClientMicToggleProps {
59
+ /**
60
+ * Callback fired when microphone state changes
61
+ */
62
+ onMicEnabledChanged?: (enabled: boolean) => void;
63
+ /**
64
+ * Optional prop to disable the mic toggle.
65
+ * When disabled, changes are not applied to the client.
66
+ * @default false
67
+ */
68
+ disabled?: boolean;
69
+ /**
70
+ * Render prop that provides state and handlers to the children
71
+ */
72
+ children: (props: {
73
+ disabled?: boolean;
74
+ isMicEnabled: boolean;
75
+ onClick: () => void;
76
+ }) => React.ReactNode;
77
+ }
78
+ /**
79
+ * Headless component for controlling microphone state
80
+ */
81
+ export const RTVIClientMicToggle: React.FC<RTVIClientMicToggleProps>;
19
82
  interface RTVIClientVideoInterface {
20
83
  aspectRatio: number;
21
84
  height: number;
@@ -54,14 +117,16 @@ export const useRTVIClientMediaDevices: () => {
54
117
  updateMic: (id: string) => void;
55
118
  updateSpeaker: (id: string) => void;
56
119
  };
57
- export const useRTVIClientTransportState: () => TransportState;
58
120
  type _ParticipantType1 = Parameters<typeof useRTVIClientMediaTrack>[1];
59
121
  interface _Props2 {
60
122
  backgroundColor?: string;
61
123
  barColor?: string;
124
+ barCount?: number;
62
125
  barGap?: number;
63
- barWidth?: number;
126
+ barLineCap?: "round" | "square";
64
127
  barMaxHeight?: number;
128
+ barOrigin?: "top" | "bottom" | "center";
129
+ barWidth?: number;
65
130
  participantType: _ParticipantType1;
66
131
  }
67
132
  export const VoiceVisualizer: React.FC<_Props2>;
@@ -1 +1 @@
1
- {"mappings":";;;;AAYA;IACE,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,cAAc,CAAC,eAAoB,CAAC,CAAC,OAAO,CAAC,CAAC;CAClE;AAMD,OAAO,MAAM,oBAAoB,MAAM,EAAE,CAAC,MAAM,iBAAiB,CAAC,KAAK,CAAC,CAYvE,CAAC;ACxBF,OAAO,MAAM,2CAGZ,CAAC;ACFF,OAAO,MAAM,qBAAsB,CAAC,SAAS,SAAS,SAC7C,CAAC,WACC,iBAAiB,CAAC,CAAC,SAW7B,CAAC;ACTF,uBAAuB,MAAM,MAAM,CAAC;AACpC,iBAAiB,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;AA4BvC,OAAO,MAAM,qCACA,SAAS,mBACH,eAAe,4BAoDjC,CAAC;ACtFF,OAAO,MAAM;;;CA6BZ,CAAC;AE9BF;IACE,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,iBACE,SAAQ,IAAI,CAAC,MAAM,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,UAAU,CAAC;IACrE,WAAW,EAAE,OAAO,GAAG,KAAK,CAAC;IAE7B;;OAEG;IACH,SAAS,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;IAEpC;;OAEG;IACH,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC1B;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,QAAQ,CAAC,CAAC,UAAU,EAAE,wBAAwB,GAAG,IAAI,CAAC;CACvD;AAED,OAAO,MAAM,iGAwJZ,CAAC;AC1LF,+BAA+B,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AASvE,OAAO,MAAM;;;;;;;oBA4DJ,MAAM;oBAMN,MAAM;wBAMN,MAAM;CAiBd,CAAC;AC7FF,OAAO,MAAM,iDAMZ,CAAC;ACTF,yBAAuB,UAAU,CAAC,8BAA8B,CAAC,CAAC,CAAC,CAAC,CAAC;AAErE;IACE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,iBAAe,CAAC;CAClC;AAED,OAAO,MAAM,iBAAiB,MAAM,EAAE,CAAC,OAAK,CAyM3C,CAAC","sources":["client-react/src/src/RTVIClientProvider.tsx","client-react/src/src/useRTVIClient.ts","client-react/src/src/useRTVIClientEvent.ts","client-react/src/src/useRTVIClientMediaTrack.ts","client-react/src/src/RTVIClientAudio.tsx","client-react/src/src/useMergedRef.ts","client-react/src/src/RTVIClientVideo.tsx","client-react/src/src/useRTVIClientMediaDevices.ts","client-react/src/src/useRTVIClientTransportState.ts","client-react/src/src/VoiceVisualizer.tsx","client-react/src/src/index.ts","client-react/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,"/**\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"],"names":[],"version":3,"file":"index.d.ts.map"}
1
+ {"mappings":"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","sources":["client-react/src/src/RTVIClientProvider.tsx","client-react/src/src/useRTVIClient.ts","client-react/src/src/useRTVIClientEvent.ts","client-react/src/src/useRTVIClientMediaTrack.ts","client-react/src/src/RTVIClientAudio.tsx","client-react/src/src/useRTVIClientTransportState.ts","client-react/src/src/useRTVIClientCamControl.ts","client-react/src/src/RTVIClientCamToggle.tsx","client-react/src/src/useRTVIClientMicControl.ts","client-react/src/src/RTVIClientMicToggle.tsx","client-react/src/src/useMergedRef.ts","client-react/src/src/RTVIClientVideo.tsx","client-react/src/src/useRTVIClientMediaDevices.ts","client-react/src/src/VoiceVisualizer.tsx","client-react/src/src/index.ts","client-react/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"/**\n * Copyright (c) 2024, Daily.\n *\n * SPDX-License-Identifier: BSD-2-Clause\n */\n\nimport { RTVIClientAudio } from \"./RTVIClientAudio\";\nimport { RTVIClientCamToggle } from \"./RTVIClientCamToggle\";\nimport { RTVIClientMicToggle } from \"./RTVIClientMicToggle\";\nimport { RTVIClientProvider } from \"./RTVIClientProvider\";\nimport { RTVIClientVideo } from \"./RTVIClientVideo\";\nimport { useRTVIClient } from \"./useRTVIClient\";\nimport { useRTVIClientCamControl } from \"./useRTVIClientCamControl\";\nimport { useRTVIClientEvent } from \"./useRTVIClientEvent\";\nimport { useRTVIClientMediaDevices } from \"./useRTVIClientMediaDevices\";\nimport { useRTVIClientMediaTrack } from \"./useRTVIClientMediaTrack\";\nimport { useRTVIClientMicControl } from \"./useRTVIClientMicControl\";\nimport { useRTVIClientTransportState } from \"./useRTVIClientTransportState\";\nimport { VoiceVisualizer } from \"./VoiceVisualizer\";\n\nexport {\n RTVIClientAudio,\n RTVIClientCamToggle,\n RTVIClientMicToggle,\n RTVIClientProvider,\n RTVIClientVideo,\n useRTVIClient,\n useRTVIClientCamControl,\n useRTVIClientEvent,\n useRTVIClientMediaDevices,\n useRTVIClientMediaTrack,\n useRTVIClientMicControl,\n useRTVIClientTransportState,\n VoiceVisualizer,\n};\n"],"names":[],"version":3,"file":"index.d.ts.map"}
package/dist/index.js CHANGED
@@ -15,12 +15,16 @@ function $parcel$interopDefault(a) {
15
15
  }
16
16
 
17
17
  $parcel$export(module.exports, "RTVIClientAudio", () => $e6a9aa6ceb34e585$export$ba1245f7cbf3ae02);
18
+ $parcel$export(module.exports, "RTVIClientCamToggle", () => $e7a27a30474b270e$export$156c26e16246ae3e);
19
+ $parcel$export(module.exports, "RTVIClientMicToggle", () => $8a175691955798a2$export$bf1c2c9ca877628d);
18
20
  $parcel$export(module.exports, "RTVIClientProvider", () => $0befa35d025c789a$export$4a4ae2d5dc96782);
19
21
  $parcel$export(module.exports, "RTVIClientVideo", () => $c1952f9ddec789e5$export$d090a384943608eb);
20
22
  $parcel$export(module.exports, "useRTVIClient", () => $8ee07494475a7fa7$export$31a5f6a22c9b8fba);
23
+ $parcel$export(module.exports, "useRTVIClientCamControl", () => $affd351738e2f16c$export$46099a7ec2fe8ac5);
21
24
  $parcel$export(module.exports, "useRTVIClientEvent", () => $8a6b68ebf0332682$export$33a6ac53b8f02625);
22
25
  $parcel$export(module.exports, "useRTVIClientMediaDevices", () => $01bcacdf0a25e20c$export$652c54907b83a48d);
23
26
  $parcel$export(module.exports, "useRTVIClientMediaTrack", () => $e5be552b22401c66$export$7c03381e0d26a6c3);
27
+ $parcel$export(module.exports, "useRTVIClientMicControl", () => $b5946020fafb75c5$export$805915964ad7bc25);
24
28
  $parcel$export(module.exports, "useRTVIClientTransportState", () => $6b6c1a9f794236bd$export$599fa01283bd4ece);
25
29
  $parcel$export(module.exports, "VoiceVisualizer", () => $a1dfa75b13e6bb9b$export$59bf27bd43679db6);
26
30
  /**
@@ -125,18 +129,18 @@ const $e5be552b22401c66$export$7c03381e0d26a6c3 = (trackType, participantType)=>
125
129
  const oldTrack = get(atom);
126
130
  if (oldTrack?.id === track.id) return;
127
131
  set(atom, track);
128
- }, [
129
- participantType,
130
- track,
131
- trackType
132
- ]));
132
+ }, []));
133
133
  (0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).TrackStarted, (0, $5Zyvw$react.useCallback)((track, participant)=>{
134
134
  updateTrack(track, track.kind, Boolean(participant?.local));
135
- }, []));
135
+ }, [
136
+ updateTrack
137
+ ]));
136
138
  (0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).ScreenTrackStarted, (0, $5Zyvw$react.useCallback)((track, participant)=>{
137
139
  const trackType = track.kind === "audio" ? "screenAudio" : "screenVideo";
138
140
  updateTrack(track, trackType, Boolean(participant?.local));
139
- }, []));
141
+ }, [
142
+ updateTrack
143
+ ]));
140
144
  (0, $5Zyvw$react.useEffect)(()=>{
141
145
  if (!client) return;
142
146
  const tracks = client.tracks();
@@ -186,6 +190,128 @@ $e6a9aa6ceb34e585$export$ba1245f7cbf3ae02.displayName = "RTVIClientAudio";
186
190
 
187
191
 
188
192
 
193
+
194
+ /**
195
+ * Copyright (c) 2024, Daily.
196
+ *
197
+ * SPDX-License-Identifier: BSD-2-Clause
198
+ */
199
+
200
+
201
+ const $6b6c1a9f794236bd$var$transportStateAtom = (0, $5Zyvw$jotai.atom)("disconnected");
202
+ const $6b6c1a9f794236bd$export$599fa01283bd4ece = ()=>{
203
+ const [transportState, setTransportState] = (0, $5Zyvw$jotai.useAtom)($6b6c1a9f794236bd$var$transportStateAtom);
204
+ (0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).TransportStateChanged, setTransportState);
205
+ return transportState;
206
+ };
207
+
208
+
209
+ const $affd351738e2f16c$export$46099a7ec2fe8ac5 = ()=>{
210
+ const client = (0, $8ee07494475a7fa7$export$31a5f6a22c9b8fba)();
211
+ const [isCamEnabled, setIsCamEnabled] = (0, $5Zyvw$react.useState)(client?.isCamEnabled ?? false);
212
+ const transportState = (0, $6b6c1a9f794236bd$export$599fa01283bd4ece)();
213
+ // Sync component state with client state initially
214
+ (0, $5Zyvw$react.useEffect)(()=>{
215
+ if (!client || transportState !== "initialized" || typeof client.isCamEnabled !== "boolean") return;
216
+ setIsCamEnabled(client.isCamEnabled);
217
+ }, [
218
+ client,
219
+ transportState
220
+ ]);
221
+ const enableCam = (0, $5Zyvw$react.useCallback)((enabled)=>{
222
+ setIsCamEnabled(enabled);
223
+ client?.enableCam?.(enabled);
224
+ }, [
225
+ client
226
+ ]);
227
+ return {
228
+ enableCam: enableCam,
229
+ isCamEnabled: isCamEnabled
230
+ };
231
+ };
232
+
233
+
234
+ const $e7a27a30474b270e$export$156c26e16246ae3e = ({ onCamEnabledChanged: onCamEnabledChanged, disabled: disabled = false, children: children })=>{
235
+ const { isCamEnabled: isCamEnabled, enableCam: enableCam } = (0, $affd351738e2f16c$export$46099a7ec2fe8ac5)();
236
+ const handleToggleCam = (0, $5Zyvw$react.useCallback)(()=>{
237
+ if (disabled) return;
238
+ const newEnabledState = !isCamEnabled;
239
+ enableCam(newEnabledState);
240
+ onCamEnabledChanged?.(newEnabledState);
241
+ }, [
242
+ disabled,
243
+ enableCam,
244
+ isCamEnabled,
245
+ onCamEnabledChanged
246
+ ]);
247
+ return (0, $5Zyvw$reactjsxruntime.jsx)((0, $5Zyvw$reactjsxruntime.Fragment), {
248
+ children: children({
249
+ isCamEnabled: isCamEnabled,
250
+ onClick: handleToggleCam,
251
+ disabled: disabled
252
+ })
253
+ });
254
+ };
255
+ var $e7a27a30474b270e$export$2e2bcd8739ae039 = $e7a27a30474b270e$export$156c26e16246ae3e;
256
+
257
+
258
+
259
+
260
+
261
+
262
+
263
+ const $b5946020fafb75c5$export$805915964ad7bc25 = ()=>{
264
+ const client = (0, $8ee07494475a7fa7$export$31a5f6a22c9b8fba)();
265
+ const [isMicEnabled, setIsMicEnabled] = (0, $5Zyvw$react.useState)(client?.isMicEnabled ?? false);
266
+ const transportState = (0, $6b6c1a9f794236bd$export$599fa01283bd4ece)();
267
+ // Sync component state with client state initially
268
+ (0, $5Zyvw$react.useEffect)(()=>{
269
+ if (!client || transportState !== "initialized" || typeof client.isMicEnabled !== "boolean") return;
270
+ setIsMicEnabled(client.isMicEnabled);
271
+ }, [
272
+ client,
273
+ transportState
274
+ ]);
275
+ const enableMic = (0, $5Zyvw$react.useCallback)((enabled)=>{
276
+ setIsMicEnabled(enabled);
277
+ client?.enableMic?.(enabled);
278
+ }, [
279
+ client
280
+ ]);
281
+ return {
282
+ enableMic: enableMic,
283
+ isMicEnabled: isMicEnabled
284
+ };
285
+ };
286
+
287
+
288
+ const $8a175691955798a2$export$bf1c2c9ca877628d = ({ onMicEnabledChanged: onMicEnabledChanged, disabled: disabled = false, children: children })=>{
289
+ const { enableMic: enableMic, isMicEnabled: isMicEnabled } = (0, $b5946020fafb75c5$export$805915964ad7bc25)();
290
+ const handleToggleMic = (0, $5Zyvw$react.useCallback)(()=>{
291
+ if (disabled) return;
292
+ const newEnabledState = !isMicEnabled;
293
+ enableMic(newEnabledState);
294
+ onMicEnabledChanged?.(newEnabledState);
295
+ }, [
296
+ disabled,
297
+ enableMic,
298
+ isMicEnabled,
299
+ onMicEnabledChanged
300
+ ]);
301
+ return (0, $5Zyvw$reactjsxruntime.jsx)((0, $5Zyvw$reactjsxruntime.Fragment), {
302
+ children: children({
303
+ isMicEnabled: isMicEnabled,
304
+ onClick: handleToggleMic,
305
+ disabled: disabled
306
+ })
307
+ });
308
+ };
309
+ var $8a175691955798a2$export$2e2bcd8739ae039 = $8a175691955798a2$export$bf1c2c9ca877628d;
310
+
311
+
312
+
313
+
314
+
189
315
  /**
190
316
  * Copyright (c) 2024, Daily.
191
317
  *
@@ -334,6 +460,7 @@ $c1952f9ddec789e5$export$d090a384943608eb.displayName = "RTVIClientVideo";
334
460
 
335
461
 
336
462
 
463
+
337
464
  const $01bcacdf0a25e20c$var$availableMicsAtom = (0, $5Zyvw$jotai.atom)([]);
338
465
  const $01bcacdf0a25e20c$var$availableCamsAtom = (0, $5Zyvw$jotai.atom)([]);
339
466
  const $01bcacdf0a25e20c$var$availableSpeakersAtom = (0, $5Zyvw$jotai.atom)([]);
@@ -348,6 +475,25 @@ const $01bcacdf0a25e20c$export$652c54907b83a48d = ()=>{
348
475
  const selectedCam = (0, $5Zyvw$jotai.useAtomValue)($01bcacdf0a25e20c$var$selectedCamAtom);
349
476
  const selectedMic = (0, $5Zyvw$jotai.useAtomValue)($01bcacdf0a25e20c$var$selectedMicAtom);
350
477
  const selectedSpeaker = (0, $5Zyvw$jotai.useAtomValue)($01bcacdf0a25e20c$var$selectedSpeakerAtom);
478
+ const initDevices = (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)(async (_get, set)=>{
479
+ if (!client) return;
480
+ const availableCams = await client.getAllCams();
481
+ const availableMics = await client.getAllMics();
482
+ const availableSpeakers = await client.getAllSpeakers();
483
+ set($01bcacdf0a25e20c$var$availableCamsAtom, availableCams);
484
+ set($01bcacdf0a25e20c$var$availableMicsAtom, availableMics);
485
+ set($01bcacdf0a25e20c$var$availableSpeakersAtom, availableSpeakers);
486
+ set($01bcacdf0a25e20c$var$selectedCamAtom, client.selectedCam);
487
+ set($01bcacdf0a25e20c$var$selectedMicAtom, client.selectedMic);
488
+ set($01bcacdf0a25e20c$var$selectedSpeakerAtom, client.selectedSpeaker);
489
+ }, [
490
+ client
491
+ ]));
492
+ (0, $5Zyvw$react.useEffect)(()=>{
493
+ initDevices();
494
+ }, [
495
+ initDevices
496
+ ]);
351
497
  (0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).AvailableCamsUpdated, (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((_get, set, cams)=>{
352
498
  set($01bcacdf0a25e20c$var$availableCamsAtom, cams);
353
499
  }, [])));
@@ -396,30 +542,17 @@ const $01bcacdf0a25e20c$export$652c54907b83a48d = ()=>{
396
542
 
397
543
 
398
544
 
399
- /**
400
- * Copyright (c) 2024, Daily.
401
- *
402
- * SPDX-License-Identifier: BSD-2-Clause
403
- */
404
-
405
-
406
- const $6b6c1a9f794236bd$var$transportStateAtom = (0, $5Zyvw$jotai.atom)("disconnected");
407
- const $6b6c1a9f794236bd$export$599fa01283bd4ece = ()=>{
408
- const [transportState, setTransportState] = (0, $5Zyvw$jotai.useAtom)($6b6c1a9f794236bd$var$transportStateAtom);
409
- (0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).TransportStateChanged, setTransportState);
410
- return transportState;
411
- };
412
545
 
413
546
 
414
547
 
415
548
 
416
549
 
417
- const $a1dfa75b13e6bb9b$export$59bf27bd43679db6 = /*#__PURE__*/ (0, ($parcel$interopDefault($5Zyvw$react))).memo(({ backgroundColor: backgroundColor = "transparent", barColor: barColor = "black", barWidth: barWidth = 30, barGap: barGap = 12, barMaxHeight: barMaxHeight = 120, participantType: participantType })=>{
550
+ const $a1dfa75b13e6bb9b$export$59bf27bd43679db6 = /*#__PURE__*/ (0, ($parcel$interopDefault($5Zyvw$react))).memo(({ backgroundColor: backgroundColor = "transparent", barColor: barColor = "black", barCount: barCount = 5, barGap: barGap = 12, barLineCap: barLineCap = "round", barMaxHeight: barMaxHeight = 120, barOrigin: barOrigin = "center", barWidth: barWidth = 30, participantType: participantType })=>{
418
551
  const canvasRef = (0, $5Zyvw$react.useRef)(null);
419
552
  const track = (0, $e5be552b22401c66$export$7c03381e0d26a6c3)("audio", participantType);
420
553
  (0, $5Zyvw$react.useEffect)(()=>{
421
554
  if (!canvasRef.current) return;
422
- const canvasWidth = 5 * barWidth + 4 * barGap;
555
+ const canvasWidth = barCount * barWidth + (barCount - 1) * barGap;
423
556
  const canvasHeight = barMaxHeight;
424
557
  const canvas = canvasRef.current;
425
558
  const scaleFactor = 2;
@@ -429,7 +562,7 @@ const $a1dfa75b13e6bb9b$export$59bf27bd43679db6 = /*#__PURE__*/ (0, ($parcel$int
429
562
  canvas.height = canvasHeight * scaleFactor;
430
563
  canvas.style.width = `${canvasWidth}px`;
431
564
  canvas.style.height = `${canvasHeight}px`;
432
- canvasCtx.lineCap = "round";
565
+ canvasCtx.lineCap = barLineCap;
433
566
  canvasCtx.scale(scaleFactor, scaleFactor);
434
567
  };
435
568
  const canvasCtx = canvas.getContext("2d");
@@ -443,34 +576,29 @@ const $a1dfa75b13e6bb9b$export$59bf27bd43679db6 = /*#__PURE__*/ (0, ($parcel$int
443
576
  analyser.fftSize = 1024;
444
577
  source.connect(analyser);
445
578
  const frequencyData = new Uint8Array(analyser.frequencyBinCount);
446
- canvasCtx.lineCap = "round";
447
- const bands = [
448
- {
449
- startFreq: 85,
450
- endFreq: 255,
579
+ canvasCtx.lineCap = barLineCap;
580
+ // Create frequency bands based on barCount
581
+ const bands = Array.from({
582
+ length: barCount
583
+ }, (_, i)=>{
584
+ // Use improved logarithmic scale for better frequency distribution
585
+ const minFreq = barCount > 20 ? 200 : 80; // Adjust min frequency based on bar count
586
+ const maxFreq = 10000; // Cover most important audio frequencies
587
+ // Use Mel scale inspired approach for more perceptually uniform distribution
588
+ // This helps with a large number of bars by placing fewer in the very low range
589
+ // https://en.wikipedia.org/wiki/Mel_scale
590
+ const melMin = 2595 * Math.log10(1 + minFreq / 700);
591
+ const melMax = 2595 * Math.log10(1 + maxFreq / 700);
592
+ const melStep = (melMax - melMin) / barCount;
593
+ const melValue = melMin + i * melStep;
594
+ const startFreq = 700 * (Math.pow(10, melValue / 2595) - 1);
595
+ const endFreq = 700 * (Math.pow(10, (melValue + melStep) / 2595) - 1);
596
+ return {
597
+ startFreq: startFreq,
598
+ endFreq: endFreq,
451
599
  smoothValue: 0
452
- },
453
- {
454
- startFreq: 255,
455
- endFreq: 500,
456
- smoothValue: 0
457
- },
458
- {
459
- startFreq: 500,
460
- endFreq: 2000,
461
- smoothValue: 0
462
- },
463
- {
464
- startFreq: 2000,
465
- endFreq: 4000,
466
- smoothValue: 0
467
- },
468
- {
469
- startFreq: 4000,
470
- endFreq: 8000,
471
- smoothValue: 0
472
- }
473
- ];
600
+ };
601
+ });
474
602
  const getFrequencyBinIndex = (frequency)=>{
475
603
  const nyquist = audioContext.sampleRate / 2;
476
604
  return Math.round(frequency / nyquist * (analyser.frequencyBinCount - 1));
@@ -497,9 +625,25 @@ const $a1dfa75b13e6bb9b$export$59bf27bd43679db6 = /*#__PURE__*/ (0, ($parcel$int
497
625
  }
498
626
  const x = startX + i * (barWidth + barGap);
499
627
  // Calculate bar height with a maximum cap
500
- const barHeight = Math.min(band.smoothValue / 255 * barMaxHeight, barMaxHeight);
501
- const yTop = Math.max(canvas.height / scaleFactor / 2 - barHeight / 2, adjustedCircleRadius);
502
- const yBottom = Math.min(canvas.height / scaleFactor / 2 + barHeight / 2, canvas.height / scaleFactor - adjustedCircleRadius);
628
+ const minHeight = 0;
629
+ const barHeight = Math.max(minHeight, Math.min(band.smoothValue / 255 * barMaxHeight, barMaxHeight));
630
+ let yTop, yBottom;
631
+ const canvasHeight = canvas.height / scaleFactor;
632
+ switch(barOrigin){
633
+ case "top":
634
+ yTop = adjustedCircleRadius;
635
+ yBottom = Math.min(adjustedCircleRadius + barHeight, canvasHeight - adjustedCircleRadius);
636
+ break;
637
+ case "bottom":
638
+ yBottom = canvasHeight - adjustedCircleRadius;
639
+ yTop = Math.max(yBottom - barHeight, adjustedCircleRadius);
640
+ break;
641
+ case "center":
642
+ default:
643
+ yTop = Math.max(canvasHeight / 2 - barHeight / 2, adjustedCircleRadius);
644
+ yBottom = Math.min(canvasHeight / 2 + barHeight / 2, canvasHeight - adjustedCircleRadius);
645
+ break;
646
+ }
503
647
  if (band.smoothValue > 0) {
504
648
  canvasCtx.beginPath();
505
649
  canvasCtx.moveTo(x + barWidth / 2, yTop);
@@ -507,28 +651,47 @@ const $a1dfa75b13e6bb9b$export$59bf27bd43679db6 = /*#__PURE__*/ (0, ($parcel$int
507
651
  canvasCtx.lineWidth = barWidth;
508
652
  canvasCtx.strokeStyle = barColor;
509
653
  canvasCtx.stroke();
510
- } else {
511
- canvasCtx.beginPath();
512
- canvasCtx.arc(x + barWidth / 2, canvas.height / scaleFactor / 2, adjustedCircleRadius, 0, 2 * Math.PI);
513
- canvasCtx.fillStyle = barColor;
514
- canvasCtx.fill();
515
- canvasCtx.closePath();
516
- }
654
+ } else drawInactiveCircle(adjustedCircleRadius, barColor, x, yTop);
517
655
  });
518
656
  if (!isActive) drawInactiveCircles(adjustedCircleRadius, barColor);
519
657
  requestAnimationFrame(drawSpectrum);
520
658
  }
659
+ function drawInactiveCircle(circleRadius, color, x, y) {
660
+ switch(barLineCap){
661
+ case "square":
662
+ canvasCtx.fillStyle = color;
663
+ canvasCtx.fillRect(x + barWidth / 2 - circleRadius, y - circleRadius, circleRadius * 2, circleRadius * 2);
664
+ break;
665
+ case "round":
666
+ default:
667
+ canvasCtx.beginPath();
668
+ canvasCtx.arc(x + barWidth / 2, y, circleRadius, 0, 2 * Math.PI);
669
+ canvasCtx.fillStyle = color;
670
+ canvasCtx.fill();
671
+ canvasCtx.closePath();
672
+ break;
673
+ }
674
+ }
521
675
  function drawInactiveCircles(circleRadius, color) {
522
676
  const totalBarsWidth = bands.length * barWidth + (bands.length - 1) * barGap;
523
677
  const startX = (canvas.width / scaleFactor - totalBarsWidth) / 2;
524
- const y = canvas.height / scaleFactor / 2;
678
+ const canvasHeight = canvas.height / scaleFactor;
679
+ let y;
680
+ switch(barOrigin){
681
+ case "top":
682
+ y = circleRadius;
683
+ break;
684
+ case "bottom":
685
+ y = canvasHeight - circleRadius;
686
+ break;
687
+ case "center":
688
+ default:
689
+ y = canvasHeight / 2;
690
+ break;
691
+ }
525
692
  bands.forEach((_, i)=>{
526
693
  const x = startX + i * (barWidth + barGap);
527
- canvasCtx.beginPath();
528
- canvasCtx.arc(x + barWidth / 2, y, circleRadius, 0, 2 * Math.PI);
529
- canvasCtx.fillStyle = color;
530
- canvasCtx.fill();
531
- canvasCtx.closePath();
694
+ drawInactiveCircle(circleRadius, color, x, y);
532
695
  });
533
696
  }
534
697
  drawSpectrum();
@@ -541,8 +704,11 @@ const $a1dfa75b13e6bb9b$export$59bf27bd43679db6 = /*#__PURE__*/ (0, ($parcel$int
541
704
  }, [
542
705
  backgroundColor,
543
706
  barColor,
707
+ barCount,
544
708
  barGap,
709
+ barLineCap,
545
710
  barMaxHeight,
711
+ barOrigin,
546
712
  barWidth,
547
713
  track
548
714
  ]);