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-recorder
Then, to stop the recording:
docker stop quick-demo
You 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-recorder
To 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.internal
and 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: true
Create 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 me
Start your server using node-ip
from above:
./bin/livekit-server --keys "{api_key}: {api_secret}" --node-ip 192.168.65.2 --dev
Open 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-recorder
To 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-recorder
End the recording:
docker stop s3-demo
After 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-recorder
End the recording:
docker stop gcp-demo
Create 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-recorder
Note: 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-demo
Below is a full config, with all optional parameters.
api_key
,api_secret
, andws_url
are required for recording LiveKit roomslog_level: error
is recommended for production setups. GStreamer logs can be noisyredis
is required for service mode- Only one of
file_output.s3
orfile_output.azblob
should be set. defaults
can 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
url
ortemplate
url
: any url that chrome can connect to for recordingtemplate
:layout
androom_name
required.base_url
is 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
filepath
orrtmp
. 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.mp4
rtmp
: a list of rtmp urls to stream to
options
: will override anything inconfig.defaults
. Usingpreset
will 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.conf
and comment out the line that saysbind 127.0.0.1
- change
protected-mode yes
toprotected-mode no
in the same file - add
--network host
to yourdocker run
command - find your IP as seen by docker
ws_url
needs 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.internal
and you should see something likeName: host.docker.internal Address: 192.168.65.2
- update your
redis
andws_url
to use this IP instead oflocalhost
, and setinsecure
to true in yourconfig.yaml
- your livekit-server must be run using
--node-ip
set 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-recorder
You 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
EndRecordingRequest
isn'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 stop
or anEndRecordingRequest
.
- Start with a
url
request recording from, for example, YouTube. - If the
url
request works, try atemplate
request next. - Join the room yourself by connecting on https://example.livekit.io - recording an empty room will not work.
- If the
template
request doesn't work, the recorder probably isn't connecting to the room. Usinglog_level: debug
, the recorder should print a message that sayslaunching chrome
along with a url. Try navigating to this url in your browser to see if it connects to the room.
- Start with a
url
request recording from, for example, YouTube. - If the
url
request works, try atemplate
request 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.