Recording 🔗



OpenVidu Server can be configured to record sessions. Two modes of recordings are available:

  • COMPOSED: every publisher stream is composed in the same video file in a grid layout. You can use the default layout, that will evenly distribute each stream in the available space, or you can use your own custom layout implemented with HTML/CSS/JS.

  • INDIVIDUAL: every publisher stream is recorded in its own file, generating a ZIP file containing all videos along with a text file with synchronization data. This recording mode cannot directly produce a single mixed video file of all the streams of the session, but is much more efficient than COMPOSED mode (which is quite demanding in terms of CPU).



How to record sessions 🔗

1. Enable OpenVidu recording module 🔗

For OpenVidu production deployments 🔗

Configure the following property in the .env file at OpenVidu installation path (default to /opt/openvidu)

OPENVIDU_RECORDING=true

There are other environment variables related to recordings configuration that may be set.
Visit OpenVidu configuration to see the full list.

For OpenVidu development docker container 🔗

If your are using the official openvidu/openvidu-server-kms docker container in your development environment and want to enable the recording module, then run it like this:

docker run -p 4443:4443 --rm \
    -e OPENVIDU_RECORDING=true \
    -e OPENVIDU_RECORDING_PATH=/PATH/TO/VIDEO/FILES \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /PATH/TO/VIDEO/FILES:/PATH/TO/VIDEO/FILES \
openvidu/openvidu-server-kms:2.16.0

The two configuration properties that must be set are:

  • OPENVIDU_RECORDING: enables OpenVidu recording module. Another Docker image (openvidu/openvidu-recording) will be downloaded only during the first run of the container.
  • OPENVIDU_RECORDING_PATH: where to store the recorded video files on the host machine. OpenVidu Server must have write access to this path.

It is also necessary to mount 2 volumes:

  • -v /var/run/docker.sock:/var/run/docker.sock: gives OpenVidu development container access to the Docker daemon.
  • -v /PATH/TO/VIDEO/FILES:/PATH/TO/VIDEO/FILES: gives access to the recorded video files through the container.

IMPORTANT! /PATH/TO/VIDEO/FILES must be the same in property OPENVIDU_RECORDING_PATH=/PATH/TO/VIDEO/FILES and in both sides of volume flag -v /PATH/TO/VIDEO/FILES:/PATH/TO/VIDEO/FILES

There are other environment variables related to recordings configuration that may be set.
Visit OpenVidu configuration to see the full list.



2. Configure your Sessions to be recorded 🔗


Recording can be configured in two ways:

  • ALWAYS: the session will be automatically recorded from the moment the first participant starts publishing.

  • MANUAL: you will have to tell OpenVidu when to start the recording of the session.

In both cases you can stop the recording manually, and every recording will always be automatically stopped if last user leaves the session and certain timeout elapses (see Automatic stop of recordings).


You can use REST API or any of the server SDKs (openvidu-java-client, openvidu-node-client) to manage your recorded sessions.

  1. Initialize your sessions with this POST method: POST /openvidu/api/sessions
    You may configure default values for recordings started for this session by sending params such as defaultOutputMode or defaultRecordingLayout. This way you can pre-configure recordings that will be automatically started (for sessions with {"recordingMode": "ALWAYS"}). For these sessions configured with ALWAYS recording mode, no more steps are needed.

  2. If you have configured your session with "recordingMode": "MANUAL"




Composed recording 🔗

Every publisher stream is composed in the same video file in a grid layout. This is the default recording mode, and it will generate as output an MP4 file.

You can use the default layout, that will evenly distribute each stream in the available space, or you can use your own custom layout.
To use the default layout:

When starting the recording of a session with method POST /openvidu/api/recordings/start pass parameters
{"outputMode: "COMPOSED", "recordingLayout": "BEST_FIT"}


For example, for a session with two publishers the video file will look like this when using output mode COMPOSED and recording layout BEST_FIT


Notes on COMPOSED recordings

  • If a COMPOSED recording is configured to record video (that is, not being an audio-only recording), this type of grid recording can be a pretty heavy consuming process. A maximum number of 4 publishers is recommended, and starting more than 2 recordings of this type at the same time can overload server CPUs. For these reasons, it is desirable to launch OpenVidu Server in a host with significant CPU power if COMPOSED video recordings are expected. In comparison, INDIVIDUAL stream recording (and COMPOSED audio-only recording) can be 4x up to 10x more efficient

  • You can configure the resolution of the MP4 file for COMPOSED recordings by using resolution property when starting the recording

  • A thumbnail got from the middle of the video will be generated for COMPOSED recordings that have video. They will be stored next to the MP4 file and named [RECORDING_ID].jpg



Composed quick start recording 🔗

There is an extra recording output mode which is a variation of Composed recording. The resulting recorded file will be exactly the same, but in this case the lifespan of the recording module will be attached to the lifecycle of the session, not to the lifecycle of the recording. This means that:

  • If you configure a Session with this composed quick start recording mode, a new recording module especially dedicated to this session will be instantiated even before you start to record it. All of the session streams will be rendered by the recording module all the time, even when not being recorded.
  • When starting the recording, the process will be as fast as physically possible for composed recordings: no need to launch the recording module and to establish the inner media connections, as this has already been done in the background.
  • When stopping the recording, the recording module of this session won't be terminated. This way the next recording of the same session will also start as quickly as possible. Only when closing the session this particular recording module will be terminated and its resources freed up.

When should you consider using this mode? When response time starting a composed recording is key in your use case. If you are going to start and stop multiple short composed recordings for the same session over time, then this mode can also be helpful. But take into account that each one of the sessions initialized with this recording mode will require considerable CPU power in your server (at least 1 dedicated CPU).

To initialize a Session with this recording output mode, just use defaultOutputMode = COMPOSED_QUICK_START when configuring your sessions to be recorded:

Initialize your sessions with this POST method POST /openvidu/api/sessions passing {"defaultOutputMode": "COMPOSED_QUICK_START"}


Then you can initialize your recording as usual:

  • If you have configured the session with recording mode ALWAYS, then the recording will be automatically started in COMPOSED_QUICK_START output mode when the first user publishes.
  • If you have configured the session with recording mode MANUAL, then you can start recordings with COMPOSED_QUICK_START or COMPOSED output modes (both will end up being set to COMPOSED_QUICK_START), but also with INDIVIDUAL output mode if you need so.

The default recording output mode of the session will determine the output mode of its recordings. If the session is configured with COMPOSED, starting a recording with COMPOSED or COMPOSED_QUICK_START will always end up with the recording set to COMPOSED. If the session is configured with COMPOSED_QUICK_START, starting a recording with COMPOSED or COMPOSED_QUICK_START will always end up with the recording set to COMPOSED_QUICK_START.



Individual stream recording 🔗

Every publisher stream is recorded in its own file. The final result is a ZIP file containing one WEBM file for each published stream during the recording (named after each stream identifier), along with a text file with synchronization information.

When starting the recording of a session with method POST /openvidu/api/recordings/start pass parameter {"outputMode:"INDIVIDUAL"}


For example, for a session with 2 publishers the final content of the ZIP file could be:

MyRecording.zip
+-- MyRecording.json
+-- str_CAM_WyJt_con_HZPIDsWXBx.webm
+-- str_CAM_CPQ7_con_PHBKMPOlLb.webm

And the content of the JSON synchronization file (MyRecording.json in the example above) might be:

{
  "createdAt": 1548947712287,
  "id": "ses_MEx72i7vFd",
  "name": "MyRecording",
  "sessionId": "ses_MEx72i7vFd",
  "files": [
    {
      "connectionId": "con_HZPIDsWXBx",
      "streamId": "str_CAM_WyJt_con_HZPIDsWXBx",
      "size": 4006190,
      "clientData": "",
      "serverData": "UserA",
      "hasAudio": true,
      "hasVideo": true,
      "typeOfVideo": "SCREEN",
      "startTimeOffset": 95,
      "endTimeOffset": 56445
    },
    {
      "connectionId": "con_PHBKMPOlLb",
      "streamId": "str_CAM_CPQ7_con_PHBKMPOlLb",
      "size": 2404760,
      "clientData": "",
      "serverData": "UserB",
      "hasAudio": false,
      "hasVideo": true,
      "typeOfVideo": "CAMERA",
      "startTimeOffset": 148,
      "endTimeOffset": 56398
    }
  ]
}


These are the properties in the JSON file

  • createdAt: time when the recording was started in UTC milliseconds
  • id: unique identifier of the recording. It is built from the session identifier
  • name: custom name of the recording. You can set this parameter when starting the recording, and the final ZIP file will be named after it
  • sessionId: unique identifier of the session that was recorded
  • files: array containing one JSON object for each one of the WEBM videos inside the ZIP file
    • connectionId: unique identifier of the connection that published the stream
    • streamId: unique identifier of the recorded stream
    • size: size in bytes of this particular recorded file
    • clientData: data associated to the connection that published the stream, in the client side. You can use this field to identify the user that published this particular recorded stream
    • serverData: data associated to the connection that published the stream, in the server side. You can use this field to identify the user that published this particular recorded stream
    • hasAudio: whether this recorded stream has an audio track or not
    • hasVideo: whether this recorded stream has a video track or not
    • typeOfVideo: type of video ("CAMERA" or "SCREEN"). Only defined if hasVideo is true
    • startTimeOffset: the offset in milliseconds for when this particular stream started being recorded, from the createdAt property of the root element
    • endTimeOffset: the offset in milliseconds for when this particular stream stopped being recorded, from the createdAt property of the root element



Selecting streams to be recorded 🔗

This feature is part of OpenViduPRO tier.

In OpenVidu CE all of the streams published to a session being recorded with INDIVIDUAL mode will always be stored to disk. In OpenVidu Pro you have greater control: you can configure in detail which streams are to be recorded, and even activate and deactivate the recording of a specific stream during the very same recording process.

This applies to INDIVIDUAL recording. You can specify the streams that should or shouldn't be recorded in a session when creating the Connection for a participant. The default option when creating a Connection is to record all of the streams published by it. Below there are examples of Connections being created that will make the their published streams NOT to be recorded when recording the session in INDIVIDUAL mode.

When creating a Connection with method POST /openvidu/api/sessions/<SESSION_ID>/connection pass parameter record to false.


You can also change on the fly whether the streams of a Connection must be recorded or not. By using the capability of dynamically updating the options of a Connection you can start or stop the individual recording of the Connection's stream at any moment, even while the recording is active:

Use method PATCH /openvidu/api/sessions/<SESSION_ID>/connection/<CONNECTION_ID> to modify the connection property record to true or false. This will start or stop the recording of the stream published by the Connection identified by CONNECTION_ID.


If the same stream of some user is recorded multiple times during one INDIVIDUAL session recording, then the resulting ZIP file described in Individual stream recording may have this content:

MyRecording.zip
+-- MyRecording.json
+-- str_CAM_WyJt_con_HZPIDsWXBx.webm
+-- str_CAM_CPQ7_con_PHBKMPOlLb.webm
+-- str_CAM_CPQ7_con_PHBKMPOlLb-1.webm
+-- str_CAM_CPQ7_con_PHBKMPOlLb-2.webm

In this case the recording process for stream str_CAM_CPQ7_con_PHBKMPOlLb has been started and stopped 3 times, generating 3 separate files for the same recording named MyRecording.



Audio-only and video-only recordings 🔗

By default recordings will be generated with both audio and video, but you can configure them to record audio-only or video-only files.

When starting the recording of a session with method POST /openvidu/api/recordings/start simply pass parameters hasAudio or hasVideo with the desired values.

Notes on audio/video only recordings

  • Recordings configured to not record neither audio nor video will fail to start, returning a status error of 422

  • COMPOSED video-only recordings will generate an MP4 file. COMPOSED audio-only recordings will generate a WEBM file. INDIVIDUAL recordings will always generate a ZIP file containing one WEBM file for each recorded stream

  • Streams published during a video-only recording that are audio-only won't be recorded: they won't be included in the grid layout for COMPOSED recordings and won't generate a WEBM file in INDIVIDUAL recordings. Same for audio-only recordings with video-only streams

  • Recordings started automatically (with recording mode ALWAYS) will record both audio and video



Automatic stop of recordings 🔗

Any started recording will automatically be stopped when any of the following situations occur and certain timeout elapses. This timeout is by default 120 seconds, but you can configure it with system property OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT. The automatic recording stop timout will start:

  • For any recorded session, if last user disconnects from the session.

  • For sessions with recording mode MANUAL, if the recording is started and no user is publishing a stream.

The only condition to abort the timeout is to have any user publishing a stream to the session within the timeout.

During the timeout sessions will always remain opened and the recording active. If the timeout elapses and no stream is being published to the session, the recording will be stopped. If in addition there's no user connected to the session, the session will also be immediately closed.

You can always manually stop any recording at any time, even during the automatic stop timeout:



Custom recording layouts 🔗

You can create your own layouts for the session recording process. They are implemented with HTML/CSS/JS files, just as your OpenVidu application client-side.

1. Create your layout with HTML/CSS/JS files 🔗

Put them in a path accessible to openvidu-server. There must be an index.html file as entrypoint for your custom layout:


  • WHAT SHOULD YOUR JS CODE DO: by making use of openvidu-browser.js library, you need to connect a recorder participant to the session. This means:

    1) Your layout must connect to the session using a token like this:

    'wss://' + location.host + '?sessionId=' + SESSION_ID + '&secret=' + SECRET + '&recorder=true';
    

    Being SESSION_ID and SECRET two parameters that will be url-encoded under ids sessionId and secret respectively. So, for example:

    var url = new URL(window.location.href);
    var SESSION_ID = url.searchParams.get("sessionId");
    var SECRET = url.searchParams.get("secret");
    var TOKEN = 'wss://' + location.host + '?sessionId=' + SESSION_ID + '&secret=' + SECRET + '&recorder=true';
    var session = OV.initSession();
    session.connect(TOKEN);
    

    2) You will need to subscribe to, at least, one event: streamCreated of Session object. That way you can subscribe your recorder to every stream when any user starts publishing (by default, the video element will be automatically removed on every streamDestroyed event). To sum up, this would be the simplest code you need to properly start your recorder participant:

    var OV = new OpenVidu();
    
    var url = new URL(window.location.href);
    var SESSION_ID = url.searchParams.get("sessionId");
    var SECRET = url.searchParams.get("secret");
    var TOKEN = 'wss://' + location.host + '?sessionId=' + SESSION_ID + '&secret=' + SECRET + '&recorder=true';
    var session = OV.initSession();
    
    session.on("streamCreated", (event) => {
        session.subscribe(event.stream, 'html-id-where-insert-video');
    });
    
    session.connect(TOKEN);
    


  • HOW TO IDENTIFY YOUR USERS: you can identify them by making use of property Stream.connection.data of the Stream object retrieved in Session event "streamCreated". That way you may know which particular user should be displayed in which particular HTML element of your layout. For example:
    session.on("streamCreated", (event) => {
        var stream = event.stream;
        if (stream.connection.data === 'userBigVideo') {
            session.subscribe(stream, 'big-video-div');
        } else if (stream.connection.data === 'userSmallVideo') {
            session.subscribe(stream, 'small-video-div');
        }
    });
    



2. Configure custom layouts in OpenVidu Server 🔗

You can configure where should OpenVidu Server look for your custom layout in the system.
Default path is /opt/openvidu/custom-layout, but you can configure it with system property OPENVIDU_RECORDING_CUSTOM_LAYOUT. OpenVidu Server must have read access to that path, where you must have stored the index.html file of your layout.


OpenVidu production deployments

Default path /opt/openvidu/custom-layout is the recommended one. But if for any reason you want to change it, then set the following property in the .env configuration file:

OPENVIDU_RECORDING_CUSTOM_LAYOUT=/PATH/TO/INDEX/CUSTOM/LAYOUT


OpenVidu development docker container (development environment)

docker run -p 4443:4443 --rm \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /PATH/TO/VIDEO/FILES:/PATH/TO/VIDEO/FILES \
    -v /PATH/TO/INDEX/CUSTOM/LAYOUT:/PATH/TO/INDEX/CUSTOM/LAYOUT \
    -e OPENVIDU_RECORDING=true \
    -e OPENVIDU_RECORDING_PATH=/PATH/TO/VIDEO/FILES \
    -e OPENVIDU_RECORDING_CUSTOM_LAYOUT=/PATH/TO/INDEX/CUSTOM/LAYOUT \
openvidu/openvidu-server-kms:2.16.0

WARNING: remember to add the -v option mounting the path defined with OPENVIDU_RECORDING_CUSTOM_LAYOUT



3. Configure your recordings to use your custom layout 🔗

When starting the recording of a session with method POST /openvidu/api/recordings/start pass parameters
{"outputMode": "COMPOSED", "recordingLayout": "CUSTOM"}



Configuring multiple custom layouts 🔗

You can implement as many custom recording layouts as you want. Simply store each one of them (each one with its own index.html entrypoint file) in a subfolder under path defined with system property OPENVIDU_RECORDING_CUSTOM_LAYOUT (default value /opt/openvidu/custom-layout). Then, when configuring your sessions as stated above in point 3, just add a new parameter:

When starting the recording of a session with method POST /openvidu/api/recordings/start pass parameters
{"outputMode": "COMPOSED", "recordingLayout": "CUSTOM", "customLayout": "RELATIVE/PATH/TO/INDEX"}


In the snippets above, string RELATIVE/PATH/TO/INDEX is the path from openvidu-server configuration property OPENVIDU_RECORDING_CUSTOM_LAYOUT to the specific index.html you want to use for a particular recording. So, if you have the following folder tree structure in your OpenVidu Server host:

/opt
+-- /openvidu
|   +-- /my_custom_layouts
|       +-- index.html
|       +-- /layout1
|           +-- index.html
|       +-- /layout2
|           +-- index.html
/etc
    ...

You should start openvidu-server with property OPENVIDU_RECORDING_CUSTOM_LAYOUT=/opt/openvidu/my_custom_layouts and you can use any of the 3 index.html files for recording any of your sessions. To use the outer layout in a recording, just configure in recording properties recordingLayout to CUSTOM. To use any of the inner layouts, also configure customLayout to layout1 or layout2.



Using an external custom layout 🔗

OpenVidu allows you to configure a recording to use a custom layout deployed outside OpenVidu host. This is useful if, for whatever reason, you have your layout being served in a different server. To achieve this, you just have to configure the complete URL where your layout is served in property customLayout:

When starting the recording of a session with method POST /openvidu/api/recordings/start pass parameters
{"outputMode": "COMPOSED", "recordingLayout": "CUSTOM", "customLayout": "https://USER:PASS@my.domain.com:8888/path?myParam=123"}


As you can see, this URL may have credentials and any query parameter or token you may need in your custom layout.
For example, in the snippets above the layout files would be protected by Basic Auth with "USER" ans "PASS" as username and password, and you could access value 123 in your layout JS code just by calling
new URL(window.location.href).searchParams.get("myParam");



Debugging your custom layouts 🔗

To debug your custom layout, you just need to store it in the path declared with property OPENVIDU_RECORDING_CUSTOM_LAYOUT, as explained in section Configure custom layouts in OpenVidu Server.

Then, by using your OpenVidu application, start a session and as many publishers as you expect to be recorded in your custom layout. Finally you just have to connect to your layout through Chrome by entering url:

https://OPENVIDUAPP:SECRET@OPENVIDU_IP:OPENVIDU_PORT/openvidu/layouts/index.html?sessionId=SESSION_ID&secret=SECRET

Being:

  • SECRET: parameter OPENVIDU_SECRET configured when launching openvidu-server
  • OPENVIDU_IP: the IP where openvidu-server is accessible in your development machine. You will be probably using openvidu-server-kms docker container in your development environment, so this parameter is localhost if you are in Mac or Linux, and the docker IP of the container if you are in Windows (see this FAQ)
  • OPENVIDU_PORT: port where openvidu-server is listening. In OpenVidu production deployments this is by default 443 and if using the development container it is by default 4443.
  • SESSION_ID: the session ID you have initialized for the debugging process. Here's a little tip: you can initialize the session in openvidu-server (REST API, openvidu-java-client, openvidu-node-client) configuring parameter customSessionId to fix this session ID and avoid having to change it every time you restart your session.

By connecting with Chrome to the above URL you will see the exact result obtained when recording a session with your custom layout. You can open the browsers console to debug any error, and you can also change the HTML/CSS/JS files of your layout until you are happy with the outcome. Refresh the browser's tab after any change in the HTML/JS/CSS files to see the changes.



Sample custom layout 🔗

This is literally the simplest HTML for a custom recording layout. Use it as a template for building more complex ones (you will need latest openvidu-browser-VERSION.min.js file to be in the same folder. Be sure to use the same version number as your openvidu-server!)

<html>

<head><script src="openvidu-browser-2.8.0.min.js"></script></head>

<body>
    <div id="videos"></div>
</body>

<script>
    var url = new URL(window.location.href);
    var SESSION_ID = url.searchParams.get("sessionId");
    var SECRET = url.searchParams.get("secret");
    var TOKEN = 'wss://' + location.host + '?sessionId=' + SESSION_ID + '&secret=' + SECRET + '&recorder=true';

    var OV = new OpenVidu();
    var session = OV.initSession();

    session.on("streamCreated", (event) => {
        session.subscribe(event.stream, 'videos');
    });
    session.connect(TOKEN)
        .then(() => { console.log('Recorder participant connected') })
        .catch(error => { console.error(error) });
</script>

</html>




Uploading recordings to AWS S3 🔗

This feature is part of OpenViduPRO tier.

OpenVidu Pro can be configured to upload recordings to an Amazon Web Services S3 bucket instead of storing them in local storage. You can enable S3 recording storage in any deployment environment. It is not limited to OpenVidu Pro AWS deployments.

AWS S3 provides persistance for recording data in OpenVidu Pro clusters. It brings multiple advantages:

  • You can terminate clusters without worrying losing your recordings, as long as they are properly uploaded to the bucket.
  • Launching an OpenVidu Pro cluster configured to use an already populated S3 bucket will make the existing recordings accessible and manageable from the new cluster.
  • You can upload to the same S3 bucket from different OpenVidu Pro clusters.

Bare in mind that the upload process is not performed in real time while the recording is active. Recordings must be first stopped before they are automatically uploaded to S3, and terminating a cluster with an active recording will result in losing that entire recording. Listen to recordingStatusChanged event to know when a recording has been successfully uploaded to S3.

To enable S3 recording storage configure the following properties in the .env file at OpenVidu Server Pro Node installation path (default to /opt/openvidu)

OPENVIDU_PRO_RECORDING_STORAGE=s3
OPENVIDU_PRO_AWS_S3_BUCKET=your-bucket-name
OPENVIDU_PRO_AWS_ACCESS_KEY=your-aws-access-key
OPENVIDU_PRO_AWS_SECRET_KEY=your-aws-secret-key
OPENVIDU_PRO_AWS_REGION=eu-west-1

There is a complete description of these properties at OpenVidu Pro configuration. Take into account the following points:

  • Property OPENVIDU_PRO_AWS_S3_BUCKET can have a folder structure if you want OpenVidu Pro to upload recordings to a specific folder of your bucket.
  • AWS credential properties OPENVIDU_PRO_AWS_ACCESS_KEY and OPENVIDU_PRO_AWS_SECRET_KEY can be omitted if you have default AWS credentials configured in your OpenVidu Server Pro Node machine. The internal AWS S3 client managed by OpenVidu Server Pro will try to use them if no keys are provided. One way or the other, the credentials finally used must provide read and write access to the bucket.
  • Property OPENVIDU_PRO_AWS_REGION may not be necessary. AWS S3 buckets are not tied to a specific world region, and theoretically the internal S3 client should be able to autodiscover the AWS region from the bucket's name only. But this has been proven to may not be possible in some occasions, and the property must be specified explicitly in these cases.



Local recording in the browser 🔗

OpenVidu Browser offers an extremely simple API to record Streams directly in the client's browser. Check it out here.