Recording room composite as HLS
This example records a room composite layout as HLS segments to an S3-compatible bucket.
When live_playlist_name is provided, a playlist is generated containing only the last few segments. This can be useful to livestream the recording via HLS.
{"room_name": "my-room","layout": "grid","preset": "H264_720P_30","custom_base_url": "https://my-custom-template.com","audio_only": false,"segment_outputs": [{"filename_prefix": "path/to/my-output","playlist_name": "my-output.m3u8","live_playlist_name": "my-output-live.m3u8","segment_duration": 2,"s3": {"access_key": "","secret": "","region": "","bucket": "my-bucket","force_path_style": true}}]}
lk egress start --type room-composite egress.json
import { LiveKitAPI, SegmentedFileOutput, EncodingOptionsPreset } from 'livekit-server-sdk';const api = new LiveKitAPI();const outputs = {segments: new SegmentedFileOutput({filenamePrefix: 'my-output',playlistName: 'my-output.m3u8',livePlaylistName: 'my-output-live.m3u8',segmentDuration: 2,output: {case: 's3',value: {accessKey: '',secret: '',bucket: '',region: '',forcePathStyle: true,},},}),};await api.egress.startRoomCompositeEgress('my-room', outputs, {layout: 'grid',customBaseUrl: 'https://my-custom-template.com',encodingOptions: EncodingOptionsPreset.H264_1080P_30,audioOnly: false,});
from livekit import apireq = api.RoomCompositeEgressRequest(room_name="my-room",layout="speaker",custom_base_url="http://my-custom-template.com",preset=api.EncodingOptionsPreset.H264_720P_30,audio_only=False,segment_outputs=[api.SegmentedFileOutput(filename_prefix="my-output",playlist_name="my-playlist.m3u8",live_playlist_name="my-live-playlist.m3u8",segment_duration=2,s3=api.S3Upload(bucket="my-bucket",region="",access_key="",secret="",force_path_style=True,),)],)async with api.LiveKitAPI() as lkapi:res = await lkapi.egress.start_room_composite_egress(req)
require 'livekit'lkapi = LiveKit::LiveKitAPI.newoutputs = [LiveKit::Proto::SegmentedFileOutput.new(filename_prefix: "my-output",playlist_name: "my-output.m3u8",live_playlist_name: "my-output-live.m3u8",segment_duration: 2,s3: LiveKit::Proto::S3Upload.new(access_key: "",secret: "",endpoint: "",region: "",bucket: "my-bucket",force_path_style: true,))]lkapi.egress.start_room_composite_egress('my-room',outputs,layout: 'speaker',custom_base_url: 'https://my-custom-template.com',preset: LiveKit::Proto::EncodingOptionsPreset::H264_1080P_30,audio_only: false)
import lksdk "github.com/livekit/server-sdk-go/v2"req := &livekit.RoomCompositeEgressRequest{RoomName: "my-room-to-record",Layout: "speaker",AudioOnly: false,CustomBaseUrl: "https://my-custom-template.com",Options: &livekit.RoomCompositeEgressRequest_Preset{Preset: livekit.EncodingOptionsPreset_PORTRAIT_H264_1080P_30,},}req.SegmentOutputs = []*livekit.SegmentedFileOutput{{FilenamePrefix: "my-output",PlaylistName: "my-output.m3u8",LivePlaylistName: "my-output-live.m3u8",SegmentDuration: 2,Output: &livekit.SegmentedFileOutput_S3{S3: &livekit.S3Upload{AccessKey: "",Secret: "",Endpoint: "",Bucket: "",ForcePathStyle: true,},},},}api, err := lksdk.NewLiveKitAPI()res, err := api.Egress().StartRoomCompositeEgress(context.Background(), req)
import io.livekit.server.LiveKitAPIimport livekit.LivekitEgressval api = LiveKitAPI.createClient(host, apiKey, secret)val segmentOutput = LivekitEgress.SegmentedFileOutput.newBuilder().setFilenamePrefix("my-segmented-file").setPlaylistName("my-playlist.m3u8").setLivePlaylistName("my-live-playlist.m3u8").setSegmentDuration(2).setS3(LivekitEgress.S3Upload.newBuilder().setBucket("").setAccessKey("").setSecret("").setForcePathStyle(true)).build()val info = api.egress.startRoomCompositeEgress("my-room",segmentOutput,layout = "speaker",optionsPreset = LivekitEgress.EncodingOptionsPreset.H264_720P_30,customBaseUrl = "https://my-templates.com",).execute().body()
use livekit_api::services::egress::{EgressOutput, RoomCompositeOptions};use livekit_api::services::LiveKitApi;use livekit_protocol as proto;use livekit_protocol::segmented_file_output::Output;let api = LiveKitApi::with_api_key(host, api_key, api_secret);let segments = proto::SegmentedFileOutput {filename_prefix: "my-output".to_string(),playlist_name: "my-output.m3u8".to_string(),live_playlist_name: "my-output-live.m3u8".to_string(),segment_duration: 2,output: Some(Output::S3(proto::S3Upload {access_key: "".to_string(),secret: "".to_string(),bucket: "my-bucket".to_string(),force_path_style: true,..Default::default()})),..Default::default()};let res = api.egress().start_room_composite_egress("my-room",vec![EgressOutput::Segments(segments)],RoomCompositeOptions {layout: "speaker".to_string(),custom_base_url: "https://my-custom-template.com".to_string(),..Default::default()},).await?;
Recording web in portrait
This example records a web page in portrait mode to Google Cloud Storage, streaming to RTMP.
Portrait orientation can be specified by either using a preset option or setting advanced options. Egress automatically resizes the Chrome compositor to your specified resolution. However, keep in mind the following requirements:
- Chrome has a minimum browser width of 500px.
- Your application must maintain a portrait layout, even when the browser reports a width larger than typical mobile phones. (for example, 720px width or larger).
{"url": "https://my-page.com","preset": "PORTRAIT_H264_720P_30","audio_only": false,"file_outputs": [{"filepath": "my-test-file.mp4","gcp": {"credentials": "{\"type\": \"service_account\", ...}","bucket": "my-bucket"}}],"stream_outputs": [{"protocol": "RTMP","urls": ["rtmps://my-rtmp-server.com/live/stream-key"]}]}
lk egress start --type web egress.json
import * as fs from 'fs';import { LiveKitAPI, EncodedFileOutput, GCPUpload, StreamOutput, StreamProtocol, EncodingOptionsPreset } from 'livekit-server-sdk';const api = new LiveKitAPI();const content = fs.readFileSync('/path/to/credentials.json');const outputs = {file: new EncodedFileOutput({filepath: 'my-recording.mp4',output: {case: 'gcp',value: new GCPUpload({// credentials need to be a JSON encoded string containing credentialscredentials: content.toString(),bucket: 'my-bucket',}),},}),stream: new StreamOutput({protocol: StreamProtocol.RTMP,urls: ['rtmp://example.com/live/stream-key'],}),};await api.egress.startWebEgress('https://my-site.com', outputs, {encodingOptions: EncodingOptionsPreset.PORTRAIT_H264_1080P_30,audioOnly: false,});
from livekit import apicontent = ""with open("/path/to/credentials.json", "r") as f:content = f.read()file_output = api.EncodedFileOutput(filepath="myfile.mp4",gcp=api.GCPUpload(credentials=content,bucket="my-bucket",),)req = api.WebEgressRequest(url="https://my-site.com",preset=api.EncodingOptionsPreset.PORTRAIT_H264_1080P_30,audio_only=False,file_outputs=[file_output],stream_outputs=[api.StreamOutput(protocol=api.StreamProtocol.RTMP,urls=["rtmp://myserver.com/live/stream-key"],)],)async with api.LiveKitAPI() as lkapi:res = await lkapi.egress.start_web_egress(req)
require 'livekit'lkapi = LiveKit::LiveKitAPI.newcontent = File.read("/path/to/credentials.json")outputs = [LiveKit::Proto::EncodedFileOutput.new(filepath: "myfile.mp4",gcp: LiveKit::Proto::GCPUpload.new(credentials: content,bucket: "my-bucket")),LiveKit::Proto::StreamOutput.new(protocol: LiveKit::Proto::StreamProtocol::RTMP,urls: ["rtmp://myserver.com/live/stream-key"])]lkapi.egress.start_web_egress('https://my-website.com',outputs,preset: LiveKit::Proto::EncodingOptionsPreset::PORTRAIT_H264_1080P_30,audio_only: false)
import lksdk "github.com/livekit/server-sdk-go/v2"credentialsJson, err := os.ReadFile("/path/to/credentials.json")if err != nil {panic(err.Error())}req := &livekit.WebEgressRequest{Url: "https://my-website.com",AudioOnly: false,Options: &livekit.WebEgressRequest_Preset{Preset: livekit.EncodingOptionsPreset_PORTRAIT_H264_1080P_30,},}req.FileOutputs = []*livekit.EncodedFileOutput{{Filepath: "myfile.mp4",Output: &livekit.EncodedFileOutput_Gcp{Gcp: &livekit.GCPUpload{Credentials: string(credentialsJson),Bucket: "my-bucket",},},},}req.StreamOutputs = []*livekit.StreamOutput{{Protocol: livekit.StreamProtocol_RTMP,Urls: []string{"rtmp://myserver.com/live/stream-key"},},}api, err := lksdk.NewLiveKitAPI()res, err := api.Egress().StartWebEgress(context.Background(), req)
import io.livekit.server.EncodedOutputsimport io.livekit.server.LiveKitAPIimport livekit.LivekitEgressval api = LiveKitAPI.createClient(host, apiKey, secret)// We recommend using Google's auth library (google-auth-library-oauth2-http) to load the credentials file.val credentials = GoogleCredentials.fromStream(FileInputStream("/path/to/credentials.json"))val fileOutput = LivekitEgress.EncodedFileOutput.newBuilder().setFilepath("myfile.mp4").setGcp(LivekitEgress.GCPUpload.newBuilder().setBucket("my-bucket").setCredentials(credentials.toString())).build()val streamOutput = LivekitEgress.StreamOutput.newBuilder().setProtocol(LivekitEgress.StreamProtocol.RTMP).addUrls("rtmps://myserver.com/live/stream-key").build()val outputs = EncodedOutputs(fileOutput, streamOutput, null, null)val info = api.egress.startWebEgress("https://my-site.com",outputs,optionsPreset = LivekitEgress.EncodingOptionsPreset.PORTRAIT_H264_720P_30,audioOnly = false,videoOnly = false,awaitStartSignal = true,).execute().body()
use livekit_api::services::egress::{EgressOutput, WebOptions};use livekit_api::services::LiveKitApi;use livekit_protocol as proto;use livekit_protocol::{encoded_file_output, stream_output};let api = LiveKitApi::with_api_key(host, api_key, api_secret);let credentials = std::fs::read_to_string("/path/to/credentials.json")?;let file = proto::EncodedFileOutput {filepath: "myfile.mp4".to_string(),output: Some(encoded_file_output::Output::Gcp(proto::GcpUpload {credentials,bucket: "my-bucket".to_string(),..Default::default()})),..Default::default()};let stream = proto::StreamOutput {protocol: proto::StreamProtocol::Rtmp as i32,urls: vec!["rtmp://myserver.com/live/stream-key".to_string()],};let res = api.egress().start_web_egress("https://my-site.com",vec![EgressOutput::File(file), EgressOutput::Stream(stream)],WebOptions::default(),).await?;
SRT streaming with thumbnails
This example streams an individual participant to an SRT server, generating thumbnails every 5 seconds. Thumbnails are stored in Azure Blob Storage.
{"room_name": "my-room","identity": "participant-to-record","screen_share": false,"advanced": {"width": 1280,"height": 720,"framerate": 30,"audioCodec": "AAC","audioBitrate": 128,"videoCodec": "H264_HIGH","videoBitrate": 5000,"keyFrameInterval": 2},"stream_outputs": [{"protocol": "SRT","urls": ["srt://my-srt-server.com:9999"]}],"image_outputs": [{"capture_interval": 5,"width": 1280,"height": 720,"filename_prefix": "{room_name}/{publisher_identity}","filename_suffix": "IMAGE_SUFFIX_TIMESTAMP","disable_manifest": true,"azure": {"account_name": "my-account","account_key": "my-key","container_name": "my-container"}}]}
lk egress start --type participant egress.json
import { LiveKitAPI, StreamOutput, StreamProtocol, ImageOutput, ImageFileSuffix, AudioCodec, VideoCodec, EncodingOptions } from 'livekit-server-sdk';const api = new LiveKitAPI();const outputs = {stream: new StreamOutput({protocol: StreamProtocol.SRT,urls: ['srt://my-srt-server.com:9999'],}),images: new ImageOutput({captureInterval: 5,width: 1280,height: 720,filenamePrefix: '{room_name}/{publisher_identity}',filenameSuffix: ImageFileSuffix.IMAGE_SUFFIX_TIMESTAMP,output: {case: 'azure',value: {accountName: 'azure-account-name',accountKey: 'azure-account-key',containerName: 'azure-container',},},}),};const info = await api.egress.startParticipantEgress('my-room', 'participant-to-record', outputs, {screenShare: false,encodingOptions: new EncodingOptions({width: 1280,height: 720,framerate: 30,audioCodec: AudioCodec.AAC,audioBitrate: 128,videoCodec: VideoCodec.H264_HIGH,videoBitrate: 5000,keyFrameInterval: 2,}),});
from livekit import apirequest = api.ParticipantEgressRequest(room_name="my-room",identity="publisher-to-record",screen_share=False,advanced=api.EncodingOptions(width=1280,height=720,framerate=30,audio_codec=api.AudioCodec.AAC,audio_bitrate=128,video_codec=api.VideoCodec.H264_HIGH,video_bitrate=5000,key_frame_interval=2,),stream_outputs=[api.StreamOutput(protocol=api.StreamProtocol.SRT,urls=["srt://my-srt-server:9999"],)],image_outputs=[api.ImageOutput(capture_interval=5,width=1280,height=720,filename_prefix="{room_name}/{publisher_identity}",filename_suffix=api.ImageFileSuffix.IMAGE_SUFFIX_TIMESTAMP,azure=api.AzureBlobUpload(account_name="my-azure-account",account_key="my-azure-key",container_name="my-azure-container",),)],)async with api.LiveKitAPI() as lkapi:info = await lkapi.egress.start_participant_egress(request)
require 'livekit'lkapi = LiveKit::LiveKitAPI.newoutputs = [LiveKit::Proto::StreamOutput.new(protocol: LiveKit::Proto::StreamProtocol::SRT,urls: ["srt://my-srt-server:9999"],),LiveKit::Proto::ImageOutput.new(capture_interval: 5,width: 1280,height: 720,filename_prefix: "{room_name}/{publisher_identity}",filename_suffix: LiveKit::Proto::ImageFileSuffix::IMAGE_SUFFIX_TIMESTAMP,azure: LiveKit::Proto::AzureBlobUpload.new(account_name: "account-name",account_key: "account-key",container_name: "container-name",))]info = lkapi.egress.start_participant_egress('room-name','publisher-identity',outputs,screen_share: false,advanced: LiveKit::Proto::EncodingOptions.new(width: 1280,height: 720,framerate: 30,audio_codec: LiveKit::Proto::AudioCodec::AAC,audio_bitrate: 128,video_codec: LiveKit::Proto::VideoCodec::H264_HIGH,video_bitrate: 5000,key_frame_interval: 2,))
import lksdk "github.com/livekit/server-sdk-go/v2"req := &livekit.ParticipantEgressRequest{RoomName: "my-room",Identity: "participant-to-record",ScreenShare: false,Options: &livekit.ParticipantEgressRequest_Advanced{Advanced: &livekit.EncodingOptions{Width: 1280,Height: 720,Framerate: 30,AudioCodec: livekit.AudioCodec_AAC,AudioBitrate: 128,VideoCodec: livekit.VideoCodec_H264_HIGH,VideoBitrate: 5000,KeyFrameInterval: 2,},},StreamOutputs: []*livekit.StreamOutput{{Protocol: livekit.StreamProtocol_SRT,Urls: []string{"srt://my-srt-host:9999"},}},ImageOutputs: []*livekit.ImageOutput{{CaptureInterval: 5,Width: 1280,Height: 720,FilenamePrefix: "{room_name}/{publisher_identity}",FilenameSuffix: livekit.ImageFileSuffix_IMAGE_SUFFIX_TIMESTAMP,DisableManifest: true,Output: &livekit.ImageOutput_Azure{Azure: &livekit.AzureBlobUpload{AccountName: "my-account-name",AccountKey: "my-account-key",ContainerName: "my-container",},},}},}api, err := lksdk.NewLiveKitAPI()info, err := api.Egress().StartParticipantEgress(context.Background(), req)
import io.livekit.server.EncodedOutputsimport io.livekit.server.LiveKitAPIimport livekit.LivekitEgressimport livekit.LivekitModelsval api = LiveKitAPI.createClient(host, apiKey, secret)val streamOutput = LivekitEgress.StreamOutput.newBuilder().setProtocol(LivekitEgress.StreamProtocol.SRT).addUrls("srt://my-srt-server:9999").build()val imageOutput = LivekitEgress.ImageOutput.newBuilder().setCaptureInterval(5).setWidth(1280).setHeight(720).setFilenamePrefix("{room_name}/{publisher_identity}").setFilenameSuffix(LivekitEgress.ImageFileSuffix.IMAGE_SUFFIX_TIMESTAMP).setAzure(LivekitEgress.AzureBlobUpload.newBuilder().setAccountName("").setAccountKey("").setContainerName("")).build()val outputs = EncodedOutputs(null, streamOutput, null, imageOutput)val encodingOptions = LivekitEgress.EncodingOptions.newBuilder().setWidth(1280).setHeight(720).setFramerate(30).setAudioCodec(LivekitModels.AudioCodec.AAC).setAudioBitrate(128).setVideoCodec(LivekitModels.VideoCodec.H264_HIGH).setVideoBitrate(5000).setKeyFrameInterval(2.0).build()val info = api.egress.startParticipantEgress("my-room","publisher-to-record",outputs,screenShare = false,optionsAdvanced = encodingOptions,).execute().body()
use livekit_api::services::egress::encoding::EncodingOptions;use livekit_api::services::egress::{EgressOutput, ParticipantEgressOptions};use livekit_api::services::LiveKitApi;use livekit_protocol as proto;use livekit_protocol::image_output;let api = LiveKitApi::with_api_key(host, api_key, api_secret);let stream = proto::StreamOutput {protocol: proto::StreamProtocol::Srt as i32,urls: vec!["srt://my-srt-server:9999".to_string()],};let images = proto::ImageOutput {capture_interval: 5,width: 1280,height: 720,filename_prefix: "{room_name}/{publisher_identity}".to_string(),filename_suffix: proto::ImageFileSuffix::ImageSuffixTimestamp as i32,disable_manifest: true,output: Some(image_output::Output::Azure(proto::AzureBlobUpload {account_name: "my-account-name".to_string(),account_key: "my-account-key".to_string(),container_name: "my-container".to_string(),})),..Default::default()};let info = api.egress().start_participant_egress("my-room","participant-to-record",vec![EgressOutput::Stream(stream), EgressOutput::Image(images)],ParticipantEgressOptions {screenshare: false,encoding: EncodingOptions {width: 1280,height: 720,framerate: 30,audio_codec: proto::AudioCodec::Aac,audio_bitrate: 128,video_codec: proto::VideoCodec::H264High,video_bitrate: 5000,keyframe_interval: 2.0,..EncodingOptions::default()},},).await?;
Adding RTMP to track composite egress
Create a TrackComposite Egress recorded as HLS segments, with RTMP output added later.
{"room_name": "my-room","audio_track_id": "TR_AUDIO_ID","video_track_id": "TR_VIDEO_ID","stream_outputs": [{"protocol": "RTMP","urls": []}],"segment_outputs": [{"filename_prefix": "path/to/my-output","playlist_name": "my-output.m3u8","segment_duration": 2,"s3": {"access_key": "","secret": "","region": "","bucket": "my-bucket"}}]}
lk egress start --type track-composite egress.json# later, to add a RTMP outputlk egress update-stream --id <egress-id> --add-urls rtmp://new-server.com/live/stream-key# to remove RTMP outputlk egress update-stream --id <egress-id> --remove-urls rtmp://new-server.com/live/stream-key
import { LiveKitAPI, StreamOutput, StreamProtocol, SegmentedFileOutput, EncodingOptionsPreset } from 'livekit-server-sdk';const api = new LiveKitAPI();const outputs = {// a placeholder RTMP output is needed to ensure stream urls can be added to it laterstream: new StreamOutput({protocol: StreamProtocol.RTMP,urls: [],}),segments: new SegmentedFileOutput({filenamePrefix: 'my-output',playlistName: 'my-output.m3u8',segmentDuration: 2,output: {case: 's3',value: {accessKey: '',secret: '',bucket: '',region: '',forcePathStyle: true,},},}),};const info = await api.egress.startTrackCompositeEgress('my-room', outputs, {videoTrackId: 'TR_VIDEO_TRACK_ID',audioTrackId: 'TR_AUDIO_TRACK_ID',encodingOptions: EncodingOptionsPreset.H264_720P_30,});// later, to add RTMP outputawait api.egress.updateStream(info.egressId, ['rtmp://new-server.com/live/stream-key']);// to remove RTMP outputawait api.egress.updateStream(info.egressId, [], ['rtmp://new-server.com/live/stream-key']);
from livekit import apirequest = api.TrackCompositeEgressRequest(room_name="my-room",audio_track_id="TR_AUDIO_TRACK_ID",video_track_id="TR_VIDEO_TRACK_ID",preset=api.EncodingOptionsPreset.H264_720P_30,# a placeholder RTMP output is needed to ensure stream urls can be added to it laterstream_outputs=[api.StreamOutput(protocol=api.StreamProtocol.RTMP,urls=[],)],segment_outputs=[api.SegmentedFileOutput(filename_prefix="my-output",playlist_name="my-playlist.m3u8",live_playlist_name="my-live-playlist.m3u8",segment_duration=2,s3=api.S3Upload(bucket="my-bucket",region="",access_key="",secret="",force_path_style=True,),)],)async with api.LiveKitAPI() as lkapi:info = await lkapi.egress.start_track_composite_egress(request)# add new output URL to the streamawait lkapi.egress.update_stream(api.UpdateStreamRequest(egress_id=info.egress_id,add_output_urls=["rtmp://new-server.com/live/stream-key"],))# remove an output URL from the streamawait lkapi.egress.update_stream(api.UpdateStreamRequest(egress_id=info.egress_id,remove_output_urls=["rtmp://new-server.com/live/stream-key"],))
require 'livekit'lkapi = LiveKit::LiveKitAPI.newoutputs = [# a placeholder RTMP output is needed to ensure stream urls can be added to it laterLiveKit::Proto::StreamOutput.new(protocol: LiveKit::Proto::StreamProtocol::RTMP,urls: [],),LiveKit::Proto::SegmentedFileOutput.new(filename_prefix: "my-output",playlist_name: "my-output.m3u8",segment_duration: 2,s3: LiveKit::Proto::S3Upload.new(access_key: "",secret: "",endpoint: "",region: "",bucket: "my-bucket",force_path_style: true,))]info = lkapi.egress.start_track_composite_egress('room-name',outputs,audio_track_id: 'TR_AUDIO_TRACK_ID',video_track_id: 'TR_VIDEO_TRACK_ID',preset: LiveKit::Proto::EncodingOptionsPreset::H264_1080P_30,)# add new output URL to the streamlkapi.egress.update_stream(info.egress_id, add_output_urls: ["rtmp://new-server.com/live/stream-key"])# remove an output URL from the streamlkapi.egress.update_stream(info.egress_id, remove_output_urls: ["rtmp://new-server.com/live/stream-key"])
import lksdk "github.com/livekit/server-sdk-go/v2"req := &livekit.TrackCompositeEgressRequest{RoomName: "my-room",VideoTrackId: "TR_VIDEO_TRACK_ID",AudioTrackId: "TR_AUDIO_TRACK_ID",Options: &livekit.TrackCompositeEgressRequest_Preset{Preset: livekit.EncodingOptionsPreset_H264_720P_30,},SegmentOutputs: []*livekit.SegmentedFileOutput{{FilenamePrefix: "my-output",PlaylistName: "my-output.m3u8",SegmentDuration: 2,Output: &livekit.SegmentedFileOutput_S3{S3: &livekit.S3Upload{AccessKey: "",Secret: "",Endpoint: "",Bucket: "",ForcePathStyle: true,},},}},// a placeholder RTMP output is needed to ensure stream urls can be added to it laterStreamOutputs: []*livekit.StreamOutput{{Protocol: livekit.StreamProtocol_RTMP,Urls: []string{},}},}api, err := lksdk.NewLiveKitAPI()info, err := api.Egress().StartTrackCompositeEgress(context.Background(), req)// add new output URL to the streamapi.Egress().UpdateStream(context.Background(), &livekit.UpdateStreamRequest{EgressId: info.EgressId,AddOutputUrls: []string{"rtmp://new-server.com/live/stream-key"},})// remove an output URL from the streamapi.Egress().UpdateStream(context.Background(), &livekit.UpdateStreamRequest{EgressId: info.EgressId,RemoveOutputUrls: []string{"rtmp://new-server.com/live/stream-key"},})
import io.livekit.server.EncodedOutputsimport io.livekit.server.LiveKitAPIimport livekit.LivekitEgressval api = LiveKitAPI.createClient(host, apiKey, secret)// a placeholder RTMP output is needed to ensure stream urls can be added to it laterval streamOutput = LivekitEgress.StreamOutput.newBuilder().setProtocol(LivekitEgress.StreamProtocol.RTMP).build()val segmentOutput = LivekitEgress.SegmentedFileOutput.newBuilder().setFilenamePrefix("my-hls-file").setPlaylistName("my-playlist.m3u8").setLivePlaylistName("my-live-playlist.m3u8").setSegmentDuration(2).setS3(LivekitEgress.S3Upload.newBuilder().setBucket("").setAccessKey("").setSecret("").setForcePathStyle(true)).build()val outputs = EncodedOutputs(null, streamOutput, segmentOutput, null)var info = api.egress.startTrackCompositeEgress("my-room",outputs,"TR_AUDIO_TRACK_ID","TR_VIDEO_TRACK_ID",optionsPreset = LivekitEgress.EncodingOptionsPreset.H264_1080P_30,).execute().body()// add new output URL to the streaminfo = api.egress.updateStream(info!!.egressId,listOf("rtmp://new-server.com/live/stream-key"),).execute().body()// remove an output URL from the streaminfo = api.egress.updateStream(info!!.egressId,emptyList(),listOf("rtmp://new-server.com/live/stream-key"),).execute().body()
use livekit_api::services::egress::{EgressOutput, TrackCompositeOptions};use livekit_api::services::egress::encoding::H264_720P_30;use livekit_api::services::LiveKitApi;use livekit_protocol as proto;use livekit_protocol::segmented_file_output::Output;let api = LiveKitApi::with_api_key(host, api_key, api_secret);// a placeholder RTMP output is needed to ensure stream urls can be added to it laterlet stream = proto::StreamOutput {protocol: proto::StreamProtocol::Rtmp as i32,urls: vec![],};let segments = proto::SegmentedFileOutput {filename_prefix: "my-output".to_string(),playlist_name: "my-output.m3u8".to_string(),segment_duration: 2,output: Some(Output::S3(proto::S3Upload {access_key: "".to_string(),secret: "".to_string(),bucket: "my-bucket".to_string(),force_path_style: true,..Default::default()})),..Default::default()};let info = api.egress().start_track_composite_egress("my-room",vec![EgressOutput::Stream(stream), EgressOutput::Segments(segments)],TrackCompositeOptions {audio_track_id: "TR_AUDIO_TRACK_ID".to_string(),video_track_id: "TR_VIDEO_TRACK_ID".to_string(),encoding: H264_720P_30,},).await?;// add new output URL to the streamapi.egress().update_stream(&info.egress_id, vec!["rtmp://new-server.com/live/stream-key".to_string()], vec![]).await?;// remove an output URL from the streamapi.egress().update_stream(&info.egress_id, vec![], vec!["rtmp://new-server.com/live/stream-key".to_string()]).await?;
Exporting individual tracks without transcoding
Export video tracks to Azure Blob Storage without transcoding.
Video and audio tracks must be exported separately using Track Egress.
{"room_name": "my-room","track_id": "TR_TRACK_ID","filepath": "{room_name}/{track_id}","azure": {"account_name": "my-account","account_key": "my-key","container_name": "my-container"}}
lk egress start --type track egress.json
import { LiveKitAPI, DirectFileOutput } from 'livekit-server-sdk';const api = new LiveKitAPI();const output = new DirectFileOutput({filepath: '{room_name}/{track_id}',output: {case: 'azure',value: {accountName: 'account-name',accountKey: 'account-key',containerName: 'container-name',},},});const info = await api.egress.startTrackEgress('my-room', output, 'TR_TRACK_ID');
from livekit import apirequest = api.TrackEgressRequest(room_name="my-room",track_id="TR_TRACK_ID",file=api.DirectFileOutput(filepath="{room_name}/{track_id}",azure=api.AzureBlobUpload(account_name="ACCOUNT_NAME",account_key="ACCOUNT_KEY",container_name="CONTAINER_NAME",),),)async with api.LiveKitAPI() as lkapi:egress_info = await lkapi.egress.start_track_egress(request)
require 'livekit'lkapi = LiveKit::LiveKitAPI.newoutput = LiveKit::Proto::DirectFileOutput.new(filepath: "{room_name}/{track_id}",azure: LiveKit::Proto::AzureBlobUpload.new(account_name: "account",account_key: "account-key",container_name: "container"))lkapi.egress.start_track_egress("my-room", output, "TR_TRACK_ID")
import lksdk "github.com/livekit/server-sdk-go/v2"req := &livekit.TrackEgressRequest{RoomName: "my-room",TrackId: "TR_TRACK_ID",Output: &livekit.TrackEgressRequest_File{File: &livekit.DirectFileOutput{Filepath: "{room_name}/{track_id}",Output: &livekit.DirectFileOutput_Azure{Azure: &livekit.AzureBlobUpload{AccountName: "",AccountKey: "",ContainerName: "",},},},},}api, err := lksdk.NewLiveKitAPI()info, err := api.Egress().StartTrackEgress(context.Background(), req)
import io.livekit.server.LiveKitAPIimport livekit.LivekitEgressval api = LiveKitAPI.createClient(host, apiKey, secret)val fileOutput = LivekitEgress.DirectFileOutput.newBuilder().setFilepath("{room_name}/{track_id}").setAzure(LivekitEgress.AzureBlobUpload.newBuilder().setAccountName("").setAccountKey("").setContainerName("")).build()val info = api.egress.startTrackEgress("my-room", fileOutput, "TR_TRACK_ID").execute().body()
use livekit_api::services::egress::TrackEgressOutput;use livekit_api::services::LiveKitApi;use livekit_protocol as proto;use livekit_protocol::direct_file_output::Output;let api = LiveKitApi::with_api_key(host, api_key, api_secret);let output = proto::DirectFileOutput {filepath: "{room_name}/{track_id}".to_string(),output: Some(Output::Azure(proto::AzureBlobUpload {account_name: "account".to_string(),account_key: "account-key".to_string(),container_name: "container".to_string(),})),..Default::default()};let info = api.egress().start_track_egress("my-room", TrackEgressOutput::File(Box::new(output)), "TR_TRACK_ID").await?;
Recording a room with StartEgress
This example uses StartEgress with a TemplateSource to record a room layout to an MP4 file. Storage is set once on the request, so every output uses it.
{"room_name": "my-room","template": { "layout": "grid" },"outputs": [{ "file": { "file_type": "MP4", "filepath": "my-room.mp4" } }],"storage": {"s3": {"access_key": "","secret": "","region": "","bucket": "my-bucket"}}}
lk egress start egress.json
import {EncodedFileType,FileOutput,LiveKitAPI,Output,StartEgressRequest,StorageConfig,TemplateSource,} from 'livekit-server-sdk';const api = new LiveKitAPI();const info = await api.egress.startEgress(new StartEgressRequest({roomName: 'my-room',source: { case: 'template', value: new TemplateSource({ layout: 'grid' }) },outputs: [new Output({config: {case: 'file',value: new FileOutput({ fileType: EncodedFileType.MP4, filepath: 'my-room.mp4' }),},}),],storage: {provider: {case: 's3',value: { accessKey: '', secret: '', bucket: 'my-bucket', region: '' },},},}),);
from livekit import apireq = api.StartEgressRequest(room_name="my-room",template=api.TemplateSource(layout="grid"),outputs=[api.Output(file=api.FileOutput(file_type=api.EncodedFileType.MP4,filepath="my-room.mp4",))],storage=api.StorageConfig(s3=api.S3Upload(bucket="my-bucket", region="", access_key="", secret="")),)async with api.LiveKitAPI() as lkapi:info = await lkapi.egress.start_egress(req)
require 'livekit'lkapi = LiveKit::LiveKitAPI.newlkapi.egress.start_egress(room_name: 'my-room',template: LiveKit::Proto::TemplateSource.new(layout: 'grid'),outputs: LiveKit::Proto::Output.new(file: LiveKit::Proto::FileOutput.new(file_type: LiveKit::Proto::EncodedFileType::MP4,filepath: 'my-room.mp4')),storage: LiveKit::Proto::StorageConfig.new(s3: LiveKit::Proto::S3Upload.new(bucket: 'my-bucket',region: '',access_key: '',secret: '')))
import lksdk "github.com/livekit/server-sdk-go/v2"api, err := lksdk.NewLiveKitAPI()info, err := api.Egress().StartEgress(ctx, &livekit.StartEgressRequest{RoomName: "my-room",Source: &livekit.StartEgressRequest_Template{Template: &livekit.TemplateSource{Layout: "grid"},},Outputs: []*livekit.Output{{Config: &livekit.Output_File{File: &livekit.FileOutput{FileType: livekit.EncodedFileType_MP4,Filepath: "my-room.mp4",},},}},Storage: &livekit.StorageConfig{Provider: &livekit.StorageConfig_S3{S3: &livekit.S3Upload{Bucket: "my-bucket"},},},})
import io.livekit.server.LiveKitAPIimport livekit.LivekitEgressval api = LiveKitAPI.createClient(host, apiKey, secret)val output = LivekitEgress.Output.newBuilder().setFile(LivekitEgress.FileOutput.newBuilder().setFileType(LivekitEgress.EncodedFileType.MP4).setFilepath("my-room.mp4")).build()val info = api.egress.startEgress(roomName = "my-room",template = LivekitEgress.TemplateSource.newBuilder().setLayout("grid").build(),outputs = listOf(output),storage = LivekitEgress.StorageConfig.newBuilder().setS3(LivekitEgress.S3Upload.newBuilder().setBucket("my-bucket")).build(),).execute().body()
use livekit_api::services::LiveKitApi;use livekit_protocol as proto;let api = LiveKitApi::with_api_key(host, api_key, api_secret);let info = api.egress().start_egress(proto::StartEgressRequest {room_name: "my-room".to_string(),source: Some(proto::start_egress_request::Source::Template(proto::TemplateSource {layout: "grid".to_string(),..Default::default()})),outputs: vec![proto::Output {config: Some(proto::output::Config::File(proto::FileOutput {file_type: proto::EncodedFileType::Mp4 as i32,filepath: "my-room.mp4".to_string(),..Default::default()})),..Default::default()}],storage: Some(proto::StorageConfig {provider: Some(proto::storage_config::Provider::S3(proto::S3Upload {bucket: "my-bucket".to_string(),..Default::default()})),}),..Default::default()}).await?;
Streaming a web page to RTMP
This example uses a WebSource to record an arbitrary URL and stream it to an RTMP destination. A stream output needs no storage, so the request sets none.
{"web": {"url": "https://my-page.com/scene","await_start_signal": true},"outputs": [{"stream": {"protocol": "RTMP","urls": ["rtmps://live.example.com/live/stream-key"]}}]}
lk egress start egress.json
import {LiveKitAPI,Output,StartEgressRequest,StreamOutput,StreamProtocol,WebSource,} from 'livekit-server-sdk';const api = new LiveKitAPI();const info = await api.egress.startEgress(new StartEgressRequest({source: {case: 'web',value: new WebSource({ url: 'https://my-page.com/scene', awaitStartSignal: true }),},outputs: [new Output({config: {case: 'stream',value: new StreamOutput({protocol: StreamProtocol.RTMP,urls: ['rtmps://live.example.com/live/stream-key'],}),},}),],}),);
from livekit import apireq = api.StartEgressRequest(web=api.WebSource(url="https://my-page.com/scene", await_start_signal=True),outputs=[api.Output(stream=api.StreamOutput(protocol=api.StreamProtocol.RTMP,urls=["rtmps://live.example.com/live/stream-key"],))],)async with api.LiveKitAPI() as lkapi:info = await lkapi.egress.start_egress(req)
require 'livekit'lkapi = LiveKit::LiveKitAPI.newlkapi.egress.start_egress(web: LiveKit::Proto::WebSource.new(url: 'https://my-page.com/scene',await_start_signal: true),outputs: LiveKit::Proto::Output.new(stream: LiveKit::Proto::StreamOutput.new(protocol: LiveKit::Proto::StreamProtocol::RTMP,urls: ['rtmps://live.example.com/live/stream-key'])))
import lksdk "github.com/livekit/server-sdk-go/v2"api, err := lksdk.NewLiveKitAPI()info, err := api.Egress().StartEgress(ctx, &livekit.StartEgressRequest{Source: &livekit.StartEgressRequest_Web{Web: &livekit.WebSource{Url: "https://my-page.com/scene",AwaitStartSignal: true,},},Outputs: []*livekit.Output{{Config: &livekit.Output_Stream{Stream: &livekit.StreamOutput{Protocol: livekit.StreamProtocol_RTMP,Urls: []string{"rtmps://live.example.com/live/stream-key"},},},}},})
import io.livekit.server.LiveKitAPIimport livekit.LivekitEgressval api = LiveKitAPI.createClient(host, apiKey, secret)val output = LivekitEgress.Output.newBuilder().setStream(LivekitEgress.StreamOutput.newBuilder().setProtocol(LivekitEgress.StreamProtocol.RTMP).addUrls("rtmps://live.example.com/live/stream-key")).build()val info = api.egress.startEgress(roomName = "",web = LivekitEgress.WebSource.newBuilder().setUrl("https://my-page.com/scene").setAwaitStartSignal(true).build(),outputs = listOf(output),).execute().body()
use livekit_api::services::LiveKitApi;use livekit_protocol as proto;let api = LiveKitApi::with_api_key(host, api_key, api_secret);let info = api.egress().start_egress(proto::StartEgressRequest {source: Some(proto::start_egress_request::Source::Web(proto::WebSource {url: "https://my-page.com/scene".to_string(),await_start_signal: true,..Default::default()})),outputs: vec![proto::Output {config: Some(proto::output::Config::Stream(proto::StreamOutput {protocol: proto::StreamProtocol::Rtmp as i32,urls: vec!["rtmps://live.example.com/live/stream-key".to_string()],})),..Default::default()}],..Default::default()}).await?;
Recording an agent and a caller on separate channels
This example uses a MediaSource with AudioConfig routes to record an audio-only conversation, putting the agent in the left channel and everyone else in the right. Because the request selects no video, the recording is audio only.
This replaces the DUAL_CHANNEL_AGENT mode of the deprecated audio_mixing field. Routes are matched in order and the first match wins, so a track from an agent lands left and every other participant's audio lands right.
{"room_name": "my-room","media": {"audio": {"routes": [{ "participant_kind": "AGENT", "channel": "AUDIO_CHANNEL_LEFT" },{ "participant_kind": "STANDARD", "channel": "AUDIO_CHANNEL_RIGHT" }]}},"outputs": [{ "file": { "file_type": "OGG", "filepath": "conversation.ogg" } }],"storage": { "s3": { "bucket": "my-bucket" } }}
lk egress start egress.json
import {AudioChannel,AudioConfig,AudioRoute,EncodedFileType,FileOutput,LiveKitAPI,MediaSource,Output,ParticipantInfo_Kind,StartEgressRequest,} from 'livekit-server-sdk';const api = new LiveKitAPI();const info = await api.egress.startEgress(new StartEgressRequest({roomName: 'my-room',source: {case: 'media',value: new MediaSource({audio: new AudioConfig({routes: [new AudioRoute({match: { case: 'participantKind', value: ParticipantInfo_Kind.AGENT },channel: AudioChannel.LEFT,}),new AudioRoute({match: { case: 'participantKind', value: ParticipantInfo_Kind.STANDARD },channel: AudioChannel.RIGHT,}),],}),}),},outputs: [new Output({config: {case: 'file',value: new FileOutput({ fileType: EncodedFileType.OGG, filepath: 'conversation.ogg' }),},}),],storage: {provider: {case: 's3',value: { accessKey: '', secret: '', bucket: 'my-bucket', region: '' },},},}),);
from livekit import apireq = api.StartEgressRequest(room_name="my-room",media=api.MediaSource(audio=api.AudioConfig(routes=[api.AudioRoute(participant_kind=api.ParticipantInfo.Kind.AGENT,channel=api.AudioChannel.AUDIO_CHANNEL_LEFT,),api.AudioRoute(participant_kind=api.ParticipantInfo.Kind.STANDARD,channel=api.AudioChannel.AUDIO_CHANNEL_RIGHT,),])),outputs=[api.Output(file=api.FileOutput(file_type=api.EncodedFileType.OGG,filepath="conversation.ogg",))],storage=api.StorageConfig(s3=api.S3Upload(bucket="my-bucket")),)async with api.LiveKitAPI() as lkapi:info = await lkapi.egress.start_egress(req)
require 'livekit'lkapi = LiveKit::LiveKitAPI.newlkapi.egress.start_egress(room_name: 'my-room',media: LiveKit::Proto::MediaSource.new(audio: LiveKit::Proto::AudioConfig.new(routes: [LiveKit::Proto::AudioRoute.new(participant_kind: LiveKit::Proto::ParticipantInfo::Kind::AGENT,channel: LiveKit::Proto::AudioChannel::AUDIO_CHANNEL_LEFT),LiveKit::Proto::AudioRoute.new(participant_kind: LiveKit::Proto::ParticipantInfo::Kind::STANDARD,channel: LiveKit::Proto::AudioChannel::AUDIO_CHANNEL_RIGHT)])),outputs: LiveKit::Proto::Output.new(file: LiveKit::Proto::FileOutput.new(file_type: LiveKit::Proto::EncodedFileType::OGG,filepath: 'conversation.ogg')),storage: LiveKit::Proto::StorageConfig.new(s3: LiveKit::Proto::S3Upload.new(bucket: 'my-bucket')))
import lksdk "github.com/livekit/server-sdk-go/v2"api, err := lksdk.NewLiveKitAPI()info, err := api.Egress().StartEgress(ctx, &livekit.StartEgressRequest{RoomName: "my-room",Source: &livekit.StartEgressRequest_Media{Media: &livekit.MediaSource{Audio: &livekit.AudioConfig{Routes: []*livekit.AudioRoute{{Match: &livekit.AudioRoute_ParticipantKind{ParticipantKind: livekit.ParticipantInfo_AGENT},Channel: livekit.AudioChannel_AUDIO_CHANNEL_LEFT,},{Match: &livekit.AudioRoute_ParticipantKind{ParticipantKind: livekit.ParticipantInfo_STANDARD},Channel: livekit.AudioChannel_AUDIO_CHANNEL_RIGHT,},},},},},Outputs: []*livekit.Output{{Config: &livekit.Output_File{File: &livekit.FileOutput{FileType: livekit.EncodedFileType_OGG,Filepath: "conversation.ogg",},},}},Storage: &livekit.StorageConfig{Provider: &livekit.StorageConfig_S3{S3: &livekit.S3Upload{Bucket: "my-bucket"},},},})
import io.livekit.server.LiveKitAPIimport livekit.LivekitEgressimport livekit.LivekitModelsval api = LiveKitAPI.createClient(host, apiKey, secret)val audio = LivekitEgress.AudioConfig.newBuilder().addRoutes(LivekitEgress.AudioRoute.newBuilder().setParticipantKind(LivekitModels.ParticipantInfo.Kind.AGENT).setChannel(LivekitEgress.AudioChannel.AUDIO_CHANNEL_LEFT)).addRoutes(LivekitEgress.AudioRoute.newBuilder().setParticipantKind(LivekitModels.ParticipantInfo.Kind.STANDARD).setChannel(LivekitEgress.AudioChannel.AUDIO_CHANNEL_RIGHT)).build()val output = LivekitEgress.Output.newBuilder().setFile(LivekitEgress.FileOutput.newBuilder().setFileType(LivekitEgress.EncodedFileType.OGG).setFilepath("conversation.ogg")).build()val info = api.egress.startEgress(roomName = "my-room",media = LivekitEgress.MediaSource.newBuilder().setAudio(audio).build(),outputs = listOf(output),storage = LivekitEgress.StorageConfig.newBuilder().setS3(LivekitEgress.S3Upload.newBuilder().setBucket("my-bucket")).build(),).execute().body()
use livekit_api::services::LiveKitApi;use livekit_protocol as proto;let api = LiveKitApi::with_api_key(host, api_key, api_secret);let audio = proto::AudioConfig {routes: vec![proto::AudioRoute {r#match: Some(proto::audio_route::Match::ParticipantKind(proto::participant_info::Kind::Agent as i32,)),channel: proto::AudioChannel::Left as i32,},proto::AudioRoute {r#match: Some(proto::audio_route::Match::ParticipantKind(proto::participant_info::Kind::Standard as i32,)),channel: proto::AudioChannel::Right as i32,},],..Default::default()};let info = api.egress().start_egress(proto::StartEgressRequest {room_name: "my-room".to_string(),source: Some(proto::start_egress_request::Source::Media(proto::MediaSource {audio: Some(audio),..Default::default()})),outputs: vec![proto::Output {config: Some(proto::output::Config::File(proto::FileOutput {file_type: proto::EncodedFileType::Ogg as i32,filepath: "conversation.ogg".to_string(),..Default::default()})),..Default::default()}],storage: Some(proto::StorageConfig {provider: Some(proto::storage_config::Provider::S3(proto::S3Upload {bucket: "my-bucket".to_string(),..Default::default()})),}),..Default::default()}).await?;
Exporting a single track without transcoding
This example exports one track in its native container, using the PASSTHROUGH preset (the StartEgress replacement for the deprecated Track egress). Passthrough captures exactly one track to exactly one file, so leave file_type unset and don't add other outputs. For the full list of constraints, see StartEgress.
{"room_name": "my-room","media": { "video_track_id": "TR_VIDEO_TRACK_ID" },"preset": "PASSTHROUGH","outputs": [{ "file": { "filepath": "my-track" } }],"storage": {"s3": {"access_key": "","secret": "","region": "","bucket": "my-bucket"}}}
lk egress start egress.json
import {EncodingOptionsPreset,FileOutput,LiveKitAPI,MediaSource,Output,StartEgressRequest,} from 'livekit-server-sdk';const api = new LiveKitAPI();const info = await api.egress.startEgress(new StartEgressRequest({roomName: 'my-room',source: { case: 'media', value: new MediaSource({ video: { case: 'videoTrackId', value: 'TR_VIDEO_TRACK_ID' } }) },encoding: { case: 'preset', value: EncodingOptionsPreset.PASSTHROUGH },outputs: [new Output({config: { case: 'file', value: new FileOutput({ filepath: 'my-track' }) },}),],storage: {provider: {case: 's3',value: { accessKey: '', secret: '', bucket: 'my-bucket', region: '' },},},}),);
from livekit import apireq = api.StartEgressRequest(room_name="my-room",media=api.MediaSource(video_track_id="TR_VIDEO_TRACK_ID"),preset=api.EncodingOptionsPreset.PASSTHROUGH,outputs=[api.Output(file=api.FileOutput(filepath="my-track"))],storage=api.StorageConfig(s3=api.S3Upload(bucket="my-bucket")),)async with api.LiveKitAPI() as lkapi:info = await lkapi.egress.start_egress(req)
require 'livekit'lkapi = LiveKit::LiveKitAPI.newlkapi.egress.start_egress(room_name: 'my-room',media: LiveKit::Proto::MediaSource.new(video_track_id: 'TR_VIDEO_TRACK_ID'),preset: LiveKit::Proto::EncodingOptionsPreset::PASSTHROUGH,outputs: LiveKit::Proto::Output.new(file: LiveKit::Proto::FileOutput.new(filepath: 'my-track')),storage: LiveKit::Proto::StorageConfig.new(s3: LiveKit::Proto::S3Upload.new(bucket: 'my-bucket')))
import lksdk "github.com/livekit/server-sdk-go/v2"api, err := lksdk.NewLiveKitAPI()info, err := api.Egress().StartEgress(ctx, &livekit.StartEgressRequest{RoomName: "my-room",Source: &livekit.StartEgressRequest_Media{Media: &livekit.MediaSource{Video: &livekit.MediaSource_VideoTrackId{VideoTrackId: "TR_VIDEO_TRACK_ID"},},},Encoding: &livekit.StartEgressRequest_Preset{Preset: livekit.EncodingOptionsPreset_PASSTHROUGH,},Outputs: []*livekit.Output{{Config: &livekit.Output_File{File: &livekit.FileOutput{Filepath: "my-track"},},}},Storage: &livekit.StorageConfig{Provider: &livekit.StorageConfig_S3{S3: &livekit.S3Upload{Bucket: "my-bucket"},},},})
import io.livekit.server.LiveKitAPIimport livekit.LivekitEgressval api = LiveKitAPI.createClient(host, apiKey, secret)val output = LivekitEgress.Output.newBuilder().setFile(LivekitEgress.FileOutput.newBuilder().setFilepath("my-track")).build()val info = api.egress.startEgress(roomName = "my-room",media = LivekitEgress.MediaSource.newBuilder().setVideoTrackId("TR_VIDEO_TRACK_ID").build(),outputs = listOf(output),optionsPreset = LivekitEgress.EncodingOptionsPreset.PASSTHROUGH,storage = LivekitEgress.StorageConfig.newBuilder().setS3(LivekitEgress.S3Upload.newBuilder().setBucket("my-bucket")).build(),).execute().body()
use livekit_api::services::LiveKitApi;use livekit_protocol as proto;let api = LiveKitApi::with_api_key(host, api_key, api_secret);let info = api.egress().start_egress(proto::StartEgressRequest {room_name: "my-room".to_string(),source: Some(proto::start_egress_request::Source::Media(proto::MediaSource {video: Some(proto::media_source::Video::VideoTrackId("TR_VIDEO_TRACK_ID".to_string())),..Default::default()})),encoding: Some(proto::start_egress_request::Encoding::Preset(proto::EncodingOptionsPreset::Passthrough as i32,)),outputs: vec![proto::Output {config: Some(proto::output::Config::File(proto::FileOutput {filepath: "my-track".to_string(),..Default::default()})),..Default::default()}],storage: Some(proto::StorageConfig {provider: Some(proto::storage_config::Provider::S3(proto::S3Upload {bucket: "my-bucket".to_string(),..Default::default()})),}),..Default::default()}).await?;
Stop an active egress
To stop an active egress, see the API reference for StopEgress for examples.