livekit-recorder has been deprecated in favor of Egress. Egress contains a superset of features as recorder.
All your live recording needs in one place.
Record any website using our recorder, or deploy our service to manage it for you.
The recorder launches Chrome and navigates to the supplied url, grabs audio from pulse and video from a virtual frame buffer, and feeds them into GStreamer. You can write the output as mp4 to a file or upload it to s3, or forward the output to one or multiple rtmp streams.
Start by creating a config.yaml:
file_output:
local: true
Next, create a request.json:
{
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"filepath": "/out/demo.mp4"
}Start the recording:
mkdir -p ~/livekit/recordings
docker run --rm --name quick-demo \
-e LIVEKIT_RECORDER_CONFIG="$(cat config.yaml)" \
-e RECORDING_REQUEST="$(cat request.json)" \
-v ~/livekit/recordings:/out \
livekit/livekit-recorderThen, to stop the recording:
docker stop quick-demoYou should find a ~/livekit/recordings/demo.mp4.
If you already have a LiveKit server deployed with SSL, recording a room is simple. If not, skip to the next example.
Update your config.yaml with the same key and secret as your deployed server, along with your server websocket address:
api_key: <livekit-server-api-key>
api_secret: <livekit-server-api-secret>
ws_url: <livekit-server-ws-url>Create a room.json:
{
"template": {
"layout": "speaker-dark",
"room_name": "my-room"
},
"filepath": "out/room.mp4"
}Join the room, either using https://example.livekit.io, or using your own client
Start the recording:
docker run --rm --name room-demo \
-e LIVEKIT_RECORDER_CONFIG="$(cat config.yaml)" \
-e RECORDING_REQUEST="$(cat room.json)" \
-v ~/livekit/recordings:/out \
livekit/livekit-recorderTo stop recording, either leave the room, or docker stop room-demo. You'll find the file at ~/livekit/recordings/room.mp4
First, find your IP as seen by docker:
- on linux, this should be
172.17.0.1 - on mac or windows, run
docker run -it --rm alpine nslookup host.docker.internaland you should see something likeName: host.docker.internal Address: 192.168.65.2
Update your config.yaml with ws_url using this IP, along with adding your api_key and api_secret, and insecure:
api_key: <livekit-server-api-key>
api_secret: <livekit-server-api-secret>
ws_url: ws://192.168.65.2:7880
insecure: trueCreate a room.json:
{
"template": {
"layout": "speaker-dark",
"room_name": "my-room"
},
"filepath": "out/room.mp4"
}Generate a token for yourself using livekit-server:
./bin/livekit-server --keys "{api_key}: {api_secret}" create-join-token --room my-room --identity meStart your server using node-ip from above:
./bin/livekit-server --keys "{api_key}: {api_secret}" --node-ip 192.168.65.2 --devOpen https://example.livekit.io, enter the token you generated, and connect (keep ws://localhost:7880 as the LiveKit URL).
Start the recording:
docker run --rm --network host --name local-demo \
-e LIVEKIT_RECORDER_CONFIG="$(cat config.yaml)" \
-e RECORDING_REQUEST="$(cat room.json)" \
-v ~/livekit/recordings:/out \
livekit/livekit-recorderTo stop recording, either leave the room, or docker stop local-demo. You'll find the file at ~/livekit/recordings/room.mp4
Update file_output in your config.yaml:
file_output:
s3:
access_key: <s3-access-key>
secret: <s3-secret>
region: <s3-region>
bucket: <s3-bucket>Create a s3.json:
{
"template": {
"layout": "speaker-dark",
"room_name": "my-room"
},
"filepath": "path/filename.mp4",
"options": {
"preset": "HD_60"
}
}This time, we've added the HD_60 preset. This will record at 1280x720, 60fps (the default is 1920x1080, 30fps).
You can find the other presets and options below.
Join the room, and start the recording:
docker run --rm --name s3-demo \
-e LIVEKIT_RECORDER_CONFIG="$(cat config.yaml)" \
-e RECORDING_REQUEST="$(cat s3.json)" \
livekit/livekit-recorderEnd the recording:
docker stop s3-demoAfter the recording is stopped, the file will be uploaded to your S3 bucket.
Update file_output in your config.yaml:
file_output:
local: false
gcp:
bucket: <storage-bucket-name>Ensure you have a room.json created.
Join the room, and start the recording. Be sure to include your GCP SA credentials:
docker run --rm --name gcp-demo \
-e GOOGLE_APPLICATION_CREDENTIALS=/tmp/keys/FILENAME.json -v /path/to/local/sa-key.json:/tmp/keys/FILENAME.json:ro \
-e LIVEKIT_RECORDER_CONFIG="$(cat config.yaml)" \
-e RECORDING_REQUEST="$(cat room.json)" \
livekit/livekit-recorderEnd the recording:
docker stop gcp-demoCreate a rtmp.json (if you have a Twitch account you can fill in your stream key, otherwise replace the rtmp url with your provider):
{
"template": {
"layout": "speaker-dark",
"room_name": "my-room"
},
"rtmp": {
"urls": ["rtmp://live.twitch.tv/app/<stream-key>"]
},
"options": {
"width": "1280",
"height": "720",
"video_bitrate": 2048
}
}This time, we've set custom options to output 720p with a lower bitrate (2048 kbps - the default is 3000 kpbs). If you have sufficient bandwidth, try using preset: FULL_HD_60 instead for a high quality stream.
Join the room, then start the stream:
docker run --rm --name rtmp-demo \
-e LIVEKIT_RECORDER_CONFIG="$(cat config.yaml)" \
-e RECORDING_REQUEST="$(cat rtmp.json)" \
livekit/livekit-recorderNote: with Twitch, it will take about 25 seconds for them to process before they begin showing the stream. May be different with other providers.
Stop the stream:
docker stop rtmp-demoBelow is a full config, with all optional parameters.
api_key,api_secret, andws_urlare required for recording LiveKit roomslog_level: erroris recommended for production setups. GStreamer logs can be noisyredisis required for service mode- Only one of
file_output.s3orfile_output.azblobshould be set. defaultscan be overridden by a request
All config parameters:
api_key: livekit server api key
api_secret: livekit server api secret
ws_url: livekit server ws url
health_port: http port to serve status (optional)
log_level: valid levels are debug, info, warn, error, fatal, or panic. Defaults to debug
template_address: template url base, can be used to host your own templates. Defaults to https://recorder.livekit.io/#
insecure: should only be used for local testing
redis: (service mode only)
address: redis address, including port
username: redis username (optional)
password: redis password (optional)
db: redis db (optional)
file_output:
local: true/false (will default to true if you don't supply s3 config)
s3: (required if using s3 output)
access_key: s3 access key
secret: s3 access secret
region: s3 region
bucket: s3 bucket
endpoint: s3 server endpoint (optional - for use with minio)
azblob: (required if using azure blob output)
account_name: azure blob account
account_key: azure blob access key
container_name: azure blob container name
gcp: (required if using gcp storage output)
bucket: bucket name
defaults:
preset: defaults to "NONE", see options below. If preset is used, all other options are ignored.
width: defaults to 1920
height: defaults to 1080
depth: defaults to 24
framerate: defaults to 30
audio_bitrate: defaults to 128 (kbps)
audio_frequency: defaults to 44100 (Hz)
video_bitrate: defaults to 4500 (kbps)
profile: x264 encoding profile (baseline, main, or high). defaults to main| Preset | width | height | framerate | video_bitrate |
|---|---|---|---|---|
| "HD_30" | 1280 | 720 | 30 | 3000 |
| "HD_60" | 1280 | 720 | 60 | 4500 |
| "FULL_HD_30" | 1920 | 1080 | 30 | 4500 |
| "FULL_HD_60" | 1920 | 1080 | 60 | 6000 |
If preset is used, all other options will be ignored.
All presets use depth: 24, audio_bitrate: 128, audio_frequency: 44100, and profile: main.
See StartRecordingRequest. When using standalone mode, the request can be input as a json file. In service mode, these requests will be made through the LiveKit server's recording api.
- Input: either
urlortemplateurl: any url that chrome can connect to for recordingtemplate:layoutandroom_namerequired.base_urlis optional, used for custom templates- We currently have 4 templates available;
speaker-light,speaker-dark,grid-light, andgrid-dark. Check out our web README to learn more or create your own.
- Output: either
filepathorrtmp. File output and stream output cannot be mixedfilepath: whether writing to a local file, s3, azure blob, or gcp storage, this path will be used. Must end with.mp4rtmp: a list of rtmp urls to stream to
options: will override anything inconfig.defaults. Usingpresetwill override all other options
All request options:
{
"url": "website-to-record.com",
"template": {
"layout": "<grid|speaker>-<light|dark>",
"room_name": "my-room",
"base_url": "my-template-host.com"
},
"filepath": "path/output.mp4",
"rtmp": {
"urls": ["rtmp://stream-url-1.com", "rtmp://stream-url-2.com"]
},
"options": {
"preset": "FULL_HD_30",
"width": 1920,
"height": 1080,
"depth": 24,
"framerate": 30,
"audio_bitrate": 128,
"audio_frequency": 44100,
"video_bitrate": 4500,
"profile": "main"
}
}Simply deploy the service, and submit requests through your LiveKit server.
The service listens to a redis subscription and waits for the LiveKit server to make a reservation. Once the reservation is made to ensure availability, the server sends a StartRecording request to the reserved instance.
A single service instance can record one room at a time.
See guides and deployment docs at https://docs.livekit.io/guides/deploy/recorder.
This is not recommended for a production setup - the following redis changes make your redis server completely
accessible to the internet, and using --network host with your docker run command is also not recommended in production.
To run against a local livekit server, you'll need to do the following:
- open
/usr/local/etc/redis.confand comment out the line that saysbind 127.0.0.1 - change
protected-mode yestoprotected-mode noin the same file - add
--network hostto yourdocker runcommand - find your IP as seen by docker
ws_urlneeds to be set using the IP as Docker sees it- on linux, this should be
172.17.0.1 - on mac or windows, run
docker run -it --rm alpine nslookup host.docker.internaland you should see something likeName: host.docker.internal Address: 192.168.65.2
- update your
redisandws_urlto use this IP instead oflocalhost, and setinsecureto true in yourconfig.yaml - your livekit-server must be run using
--node-ipset to the above IP
These changes allow the service to connect to your local redis instance from inside the docker container. Finally, to build and run:
docker build -t livekit-recorder .
docker run --network host \
-e SERVICE_MODE=1 \
-e LIVEKIT_RECORDER_CONFIG="$(cat config.yaml)" \
livekit-recorderYou can then use our cli to submit recording requests to your server.
- Your livekit server cannot reach your recorder through redis. Make sure they are both able to reach the same redis db.
- Make sure you're using the latest cli, server sdks, livekit-server and livekit-recorder. This is still in beta, and we still occasionally release breaking changes.
-
There is currently a bug where the recorder doesn't work if it isn't receiving video - if your
EndRecordingRequestisn't stopping the recording, it's usually either because there's no video, or because it never connected to the room. See #22 -
GStreamer needs to be properly shut down - if the process is killed, the file will be unusable.
Make sure you're stopping the recording with either adocker stopor anEndRecordingRequest.
- Start with a
urlrequest recording from, for example, YouTube. - If the
urlrequest works, try atemplaterequest next. - Join the room yourself by connecting on https://example.livekit.io - recording an empty room will not work.
- If the
templaterequest doesn't work, the recorder probably isn't connecting to the room. Usinglog_level: debug, the recorder should print a message that sayslaunching chromealong with a url. Try navigating to this url in your browser to see if it connects to the room.
- Start with a
urlrequest recording from, for example, YouTube. - If the
urlrequest works, try atemplaterequest next. - Join the room yourself by connecting on https://example.livekit.io - recording an empty room will not work.
- Try streaming to a different rtmp endpoint. For testing, we use Twitch and RTSP Simple Server.
WARN flvmux ... Got backwards dts! (0:01:10.379000000 < 0:01:10.457000000)- Occurs when streaming to rtmp - safe to ignore. These warnings occur due to live sources being used for the flvmux. The dts difference should be small (under 150ms).
- It's possible, but not recommended. To do so, you would need gstreamer and all the plugins installed, along with xvfb, and have a pulseaudio server running.
- Since it records from system audio, each recorder needs to be run on its own machine or VM.
- Currently, it's not possible to keep X recorders available at all times, although we plan to add that in the future.
- In the meantime, you can autoscale based on CPU - each instance consistently uses 2.5-3 CPU while recording.
- Autoscaling by listening to webhooks and launching a new instance is possible, but not recommended. Note that each instance requires its own VM, and they are CPU intensive - with 16 cores on the host you should only expect to be able to run 4 or 5 instances.