Voice UI Kit
View source

User Video Control

Camera control component with device selection and video preview

The UserVideoControl component provides a comprehensive camera control interface that includes camera toggle functionality, device selection, and optional video preview. It integrates with the Pipecat Client SDK to automatically manage camera state and device selection.

import { UserVideoControl } from "@pipecat-ai/voice-ui-kit";

<UserVideoControl
  isCamEnabled={true}
/>

You must call initDevices on the client before using the component.

PropTypeDefault
variant?
"primary" | "secondary" | "outline" | "destructive" | "ghost" | "link" | "active" | "inactive"
"outline"
size?
"sm" | "md" | "lg" | "xl"
"md"
state?
"default" | "active" | "inactive"
undefined
buttonProps?
Partial<ButtonProps>
undefined
classNames?
{ container?: string; video?: string; buttongroup?: string; button?: string; dropdownMenuTrigger?: string; dropdownMenuContent?: string; dropdownMenuCheckboxItem?: string; videoOffContainer?: string; videoOffText?: string; activeText?: string; inactiveText?: string; }
undefined
dropdownButtonProps?
Partial<ButtonProps>
undefined
deviceDropDownProps?
Partial<DeviceDropDownComponentProps>
undefined
noDevicePicker?
boolean
false
noVideo?
boolean
false
videoProps?
Partial<PipecatClientVideoProps>
undefined
noVideoText?
string | null
"Video disabled"
noIcon?
boolean
false
activeText?
string
undefined
inactiveText?
string
undefined
children?
React.ReactNode
undefined

UserVideoComponent

The UserVideoComponent is the headless variant that accepts all camera state and callbacks as props. This allows you to use it with any framework or state management solution.

import { UserVideoComponent } from "@pipecat-ai/voice-ui-kit";

// Example with mock data
const mockCams = [
  { deviceId: "cam1", label: "Built-in Camera" },
  { deviceId: "cam2", label: "External USB Camera" },
];

function Demo() {
  const [isCamEnabled, setIsCamEnabled] = React.useState(false);
  const [selectedCam, setSelectedCam] = React.useState(mockCams[0]);

  return (
    <UserVideoComponent
      isCamEnabled={isCamEnabled}
      onClick={() => setIsCamEnabled(!isCamEnabled)}
      availableCams={mockCams}
      selectedCam={selectedCam}
      updateCam={(deviceId) => {
        const cam = mockCams.find(c => c.deviceId === deviceId);
        if (cam) setSelectedCam(cam);
      }}
      activeText="Camera is on"
      inactiveText="Click to start"
    />
  );
}

render(<Demo />);
PropTypeDefault
onClick?
() => void
undefined
isCamEnabled?
boolean
false
availableCams?
MediaDeviceInfo[]
undefined
selectedCam?
OptionalMediaDeviceInfo
undefined
updateCam?
(deviceId: string) => void
undefined
variant?
"primary" | "secondary" | "outline" | "destructive" | "ghost" | "link" | "active" | "inactive"
"outline"
size?
"sm" | "md" | "lg" | "xl"
"md"
state?
"default" | "active" | "inactive"
undefined
buttonProps?
Partial<ButtonProps>
undefined
classNames?
{ container?: string; video?: string; buttongroup?: string; button?: string; dropdownMenuTrigger?: string; dropdownMenuContent?: string; dropdownMenuCheckboxItem?: string; videoOffContainer?: string; videoOffText?: string; activeText?: string; inactiveText?: string; }
undefined
dropdownButtonProps?
Partial<ButtonProps>
undefined
deviceDropDownProps?
Partial<DeviceDropDownComponentProps>
undefined
noDevicePicker?
boolean
false
noVideo?
boolean
false
videoProps?
Partial<PipecatClientVideoProps>
undefined
noVideoText?
string | null
"Video disabled"
noIcon?
boolean
false
activeText?
string
undefined
inactiveText?
string
undefined
children?
React.ReactNode
undefined
unavailableText?
string
undefined

Integration

The connected UserVideoControl component uses several hooks from the Pipecat Client React SDK:

  • usePipecatClientMediaDevices for device management
  • useMediaState for loading and error states
  • PipecatClientCamToggle for camera control

This means it must be used within a PipecatClientProvider context to function properly.

The component will automatically:

  • Fetch available camera devices
  • Display the currently selected camera
  • Handle device selection changes
  • Manage camera enable/disable state
  • Show appropriate loading and error states based on device availability
  • Keep the device picker accessible across connect/disconnect cycles once camera permission is granted
  • Update the Pipecat Client's camera configuration

Visual States

The component displays different visual states based on the camera status:

  • Inactive: Shows camera off icon with inactive styling and placeholder text
  • Active: Shows camera on icon with active styling and video preview
  • Loading: Shows loading spinner during device initialization
  • Unavailable: Shows disabled state with specific error messages (e.g., "Camera blocked", "Camera in use", "No camera")
  • Disabled: Shows disabled state when video is deliberately disabled via noVideo

Device Management

The component includes a dropdown menu for device selection that:

  • Lists all available camera devices
  • Shows the currently selected device
  • Allows switching between devices
  • Can be hidden with the noDevicePicker prop
  • Integrates with the DeviceDropDown component

Video Preview

The component can display a live video preview when the camera is enabled:

  • Shows the local camera feed using PipecatClientVideo
  • Automatically adjusts container size based on camera state
  • Can be hidden with the noVideo prop
  • Supports custom styling through videoProps
  • Displays placeholder text when camera is off or disabled

Changelog

v0.11.0
  • Now uses useMediaState instead of usePipecatClientTransportState for loading and error states.
  • Added unavailableText prop to UserVideoComponent for displaying device error states.
  • Device picker remains accessible across connect/disconnect cycles once camera permission is granted.
v0.3.0
  • Now accepts deviceDropDownProps for configuring the underlying dropdown.