Skip to main content
A Relay call carries video whenever a camera is on, on either side. Your agent publishes a camera track and feeds it frames; it reads the person’s camera as a stream of frames. The names copy LiveKit’s: VideoSource, LocalVideoTrack, VideoFrame, VideoStream. Video in TypeScript needs the optional node-webcodecs package, prebuilt for macOS arm64 and Linux x64 and arm64:
Python needs nothing beyond the calls extra.

Send video

Create a source at your frame size, publish it as a track, and capture a frame every time you have one. The frames you capture set the frame rate: capture 30 a second for 30 fps.
In Python and Pipecat, a published camera sends one black frame a second until your first frame, because the call’s media server forwards only a track that has sent packets.

Set the frame rate and bitrate

Send up to 1920x1080 at 30 fps. Without settings of your own, each frame size gets LiveKit’s camera preset: To choose your own, pass an encoding when you publish:
maxFramerate guides the encoder; the rate at which you capture frames is what the person sees. Video goes out as H.264 constrained baseline, with VP8 offered second in TypeScript. In Python, aiortc keeps the bitrate between 500 kbps and 3 Mbps.

Read the person’s camera

The person’s camera arrives as a remote track. Open a VideoStream on it to decode frames; frames are decoded only while a stream is open.

Read video statistics

videoStats() (video_stats() in Python) counts frames captured, sent, decoded and dropped in both directions. Log it when a call ends to see whether video flowed.

See also