RoomComposite egress
One common requirement when recording a room is to capture all of the participants and interactions that take place. This can be challenging in a multi-user application, where different users may be joining, leaving, turning their cameras on and off. It may also be desirable for the recording to look as close to the actual application experience as possible, capturing the richness and interactivity of your application.
A RoomComposite
egress uses a web app to create the composited view, rendering the output with an instance of headless Chromium. In most cases, your existing LiveKit application can be used as a compositing template with few modifications.
Default layouts
We provide a few default compositing layouts that works out of the box. They'll be used by default if a custom template URL is not passed in. These templates are deployed alongside and served by the egress service (source).
While it's a great starting point, you can easily create your own layout using standard web technologies that you are already familiar with.
Layout | Preview |
---|---|
grid | |
speaker | |
single-speaker |
Additionally, you can use a -light
suffix to change background color to white. i.e. grid-light
.
Starting a RoomComposite
The following example starts a recording for archival to S3. It uses an EncodedFileOutput
for the egress.
const egressClient = new EgressClient('https://my-livekit-host','livekit-api-key','livekit-api-secret',);const fileOutput = new EncodedFileOutput({filepath: 'livekit-demo/room-composite-test.mp4',output: {case: 's3',value: new S3Upload({accessKey: 'aws-access-key',secret: 'aws-access-secret',region: 'aws-region',bucket: 'my-bucket',}),},});const info = await egressClient.startRoomCompositeEgress('my-room',{file: fileOutput,},{layout: 'speaker',// uncomment to use your own templates// customBaseUrl: 'https://my-template-url.com',},);const egressID = info.egressId;
fileRequest.Output.File.Output
can be left empty if one ofs3
,azure
, orgcp
is supplied with your config.fileRequest.Output.File.Filepath
can be left empty, and a unique filename will be generated based on the date and room name.
Stream to RTMP
To stream to RTMP, you would use a StreamOutput
. When multiple RTMP URLs are specified, LiveKit would multi-cast to all of them at the same time. Stream URLs can be changed even after the egress has started with UpdateStream
const streamOutput = new StreamOutput({protocol: StreamProtocol.RTMP,urls: ['rtmp://youtube-url/stream', 'rtmps://twitch-url/path'],});const info = await egressClient.startRoomCompositeEgress('my-room',{ stream: streamOutput },{ layout: 'grid' },);
Stream to HLS
As an alternative to generating a single media file, it is possible to have the Egress service generate segments by using the SegmentedFileOutput
output. The Egress service will split the output in media segments of equal duration (6s by default), and generate a manifest listing all the generated segments.
Currently, only HTTP Live Streaming compatible segments (using the MPEG TS file format) and manifests are supported.
If one of s3
, azure
, or gcp
is supplied with the config or request, each segment will be uploaded with an updated manifest as soon as it is generated. This allows playback of the exported media while the export is still ongoing.
const segmentedOutput = new SegmentedFileOutput({filenamePrefix: 'livekit-demo/room-composite-test-',playlistName: 'room-composite-test.m3u8',segmentDuration: 6,protocol: SegmentedFileProtocol.HLS_PROTOCOL,output: {case: 's3',value: new S3Upload({accessKey: 'aws-access-key',secret: 'aws-access-secret',region: 'aws-region',bucket: 'my-bucket',}),},});const info = await egressClient.startRoomCompositeEgress('my-room', { segments: segmentedOutput });
segmentsRequest.Output.Segments.FilenamePrefix
andsegmentsRequest.Output.Segments.PlaylistName
can be left empty, and unique filenames will be generated based on the date and room name.- The playlist file will always be created in the same directory as the segments, as indicated in
segmentsRequest.Output.Segments.FilenamePrefix
, regardless of any potential directory prefix added tosegmentsRequest.Output.Segments.PlaylistName
.
Generate Image snapshots
It is possible to have the egress service generate image snaphots of the room composite at regular interval. This can be used for instance to generate thumbnails. A manifest is generated that lists the images with their filename and timestamps.
If one of s3
, azure
, or gcp
is supplied with the config or request, each image will be uploaded with an updated manifest as soon as it is generated.
const imageOutput = new ImageOutput({captureInterval: 10,filenamePrefix: 'livekit-demo/room-composite-test-',width: 640,height: 480,output: {case: 's3',value: new S3Upload({accessKey: 'aws-access-key',secret: 'aws-access-secret',region: 'aws-region',bucket: 'my-bucket',}),},});const info = await egressClient.startRoomCompositeEgress('my-room', { images: imageOutput });
Recording in portrait
Portrait orientation can be specified by either setting a preset or advanced options. Egress will resize the Chrome compositor to your specified resolution. However, keep in mind:
- Chrome has a minimum browser width limit of 500px.
- Your application should maintain a portrait layout, even when the browser reports a width larger than typical mobile phones. (e.g., 720px width or higher).
const segmentedOutput = new SegmentedFileOutput({filenamePrefix: 'livekit-demo/room-composite-test-',playlistName: 'room-composite-test.m3u8',segmentDuration: 6,protocol: SegmentedFileProtocol.HLS_PROTOCOL,preset: EncodingOptionsPreset.PORTRAIT_H264_720P_30,output: {...},});const info = await egressClient.startRoomCompositeEgress('my-room', {segments: segmentedOutput});
Audio-only composite
If your application is audio-only, you can export a mixed audio file containing audio from all participants in the room. To start an audio-only composite, pass audio_only=true
when starting an Egress.
const info = await egressClient.startRoomCompositeEgress('my-room', output, { audioOnly: true });