Audio and video recording
The Quobis Communication Platform supports the recording of the audio and video streams. Call recording can be used in a number of situations such as to meet regulatory requirements, verify accuracy, review quality of the customer service, employee training, etc… This page describes the different configuration options in order to choose what to record, how to record, who has the right to start a recording and the characteristics of the recorded files.
What can be recorded
Recording of one to one calls and multi-party calls is supported both for video and audio streams. Likewise, if you are developing an application using the SDKs, you can record any conference room that has been created with the invitation method. Recording of of meetings is also permitted if specified by the user who created the meeting. Recording of public rooms is not allowed. Since v5.14, partial recording of calls is allowed, allowing the users to start or stop recording at any time during the course of the call.
Who can record: recording permissions
Administrators can set up domain-wide and per-user policies in order to decide which users are able to record their outbound calls they make and/or setup mandatory recording by default. In addition, administrators can decide whether incoming calls from PSTN or a SIP trunk are recorder with a system-wide configuration.
Permissions for recording of internal calls
The ability to make a recording of a one to one call or multiparty call relies on a set of two permissions, named recordingProfile
and recordingType
, which are grouped into the recording permission named RecordingPermissions
. The following table explains the available values of hese two fields:
Field |
Meaning |
Values |
---|---|---|
|
Indicates which media streams can be recorded |
|
|
Indicates the recording policy for this user or domain |
|
Please note that these permissions are related to the user who starts the call (the caller) and to the domain that this user belongs to. In other words, the decision about whether a call can be recorded or not has nothing to do with the rest of participants involved in the call, it only involves the caller who initiates the call.
The RecordingPermissions are set, updated and retrieved via the following REST API endpoints:
/permissions
: endpoint to manage user permissions. Restricted to the user performing the request/permissions/domain/{id}
: endpoint to manage domain permissions. Restricted to the domain administrator
The following code snippet shows and example of a “GET” query answer of the permissions of a user, which are returned in a JSON file format
{
"recording": {
"recordingType": "all",
"recordingProfile": "always"
}
Please note that the system does not have any permissions created by default.
Warning
With the implementation of partial recording it is important to note that the setting of the recordRecordingAnStart parameter will affect how recordings work. For more information, see the partial recording section.
Permissions for recording of SIP calls
The permissions for incoming calls explained above does not apply for the recording of incoming calls. There is a parameter which controls whether incoming SIP calls can be recorded (from PSTN or from a SIP trunk) or not. This parameter (recordIncomingPSTN
) can be found in the QSS.trunk service. If this parameter is set to true, every incoming SIP call will be recorded regardless of the user permissions. If this parameter is set to false, incoming calls from PSTN won’t be recorded. Its default value is set to false.
Please note that this is a system-wide parameter and only affects incoming calls, not outgoing calls. It’s configuration is explained in the upgrade section.
Warning
Please note that currently the ‘recordIncomingPSTN: true’ setting is incompatible with the ‘recordRecordingAtStart: false’ setting related to partial recording. For more information, see the partial recording section.
Permissions precedence
In addition to the permissions explained above, there is a generic system-wide parameter in the QSS.rooms services which defines whether the system can record or not in the absence of permissions (in other words, it only applies when there are no permissions configured). This parameter is configured in the config.json file of the QSS configuration as explained here
... other parameters
record = none, all, video, audio
...
with the following options available:
none
: no call will be recordedall
: every call will be recordedvideo
: video stream will be recordedaudio
: audio stream will be recorded
Internal calls
The recording permissions apply both to the user and to the domain, being the user permission the most restrictive one. That means that, in case of conflict between the user and domain permissions, the user permissions are the ones that apply. On the other hand, when the user has no recording permissions, the domain permissions apply as a fallback. Beyond that, if there are neither user nor domain permissions, there is a generic configuration that applies to the entire system in the QSS configuration (see section “Configuration” below).
In summary, the precedence for internal calls is as follows: user permissions –> domain permissions —> system configuration. As an example, if a system is provisioned with the following domain permissions, every call made by Alice will be automatically recorded. On the other hand, calls started from other users without any permissions won’t be recorded.
Domain permissions: [recordingType = “none”, recordingProfile = “skip”]
User “Alice” permissions: [recordingType = “all”, recordingProfile = “always”]
External SIP calls
In this case, there is no precedence as the only valid configuration parameter is recordIncomingPSTN
. Once a call is set to be recorded, this information is populated in the “createRoom” message and the parameter “record” is set to TRUE.
Partial recording
Since wac 5.14.0, partial recording functionality has been implemented, which introduces changes to the decision of which part of the call will be recorded and gives users the possibility to start/stop recording manually.
Versions prior to 5.14
Once a call is set to be recorded, it is recorded from the beginning (“start time”) until the end (“end time”). Stopping the recording once it has started it’s not possible in the current version. The start time is computed when the callee answer the call. The end time is calculated as follows:
In one-to-one calls, where there is only two participantes, the end time is when any of them hangs up.
In multiparty calls, the end time when one of the last two remaining users leaves the call (which will mean that the system hangs up the remaining user automatically).
The recording includes the actual audio and video streams and metadata such as start time, end time and conference room ID.
Partial recording (v.5.14)
New endpoints to start/stop recording There are two new endpoints in the wrapper ws api that allow you to start/stop recording an ongoing call:
startRoomRecording: Allows the user to start the call recording
{"type":"message","socketId":"0c3ce7ea-3743-4648-8884-3de1af2668d4","data":"{\"type\":\"request\",\"payload\":{\"endpoint\":\"startRoomRecording\",\"payload\":{},\"id\":\"yyl8SNpGnS8uUzHh-rKr5\"}}"}
stopRoomRecording: Allows the user to stop the call recording
Who can start/stop recording?
In order for a user to be able to start/stop recording a call, they must have the recordingProfile: always recording permission and be:
the user who starts the call in the case of direct calls (both one-to-one and multi-party)
the creator in the case of meetings
These options will not be available in public rooms.
recordRecordingAtStart
The parameter “recordRecordingAtStart” has been added to the sfu-wrapper configuration, which allows us to indicate whether recording will start automatically when the call is established: * If set to true, the same behavior will occur as in previous versions, starting automatically when the call is established. * If set to false, the recording will not start until the “startRoomRecording” request is sent by the client.
This setting affects both direct calls and meetings.
Warning
Please note that currently the “recordRecordingAtStart:false” setting is incompatible with the “recordIncomingPSTN: true” because the call recording will not start when the call is established and no user will be able to start this recording manually using the startRoomRecording endpoint because the room creator is the PSTN user.
Meetings recording
Recording of meetings is also allowed. The way meeting recording works is similar to the way call recording works: * For a meeting to be recorded, the user who created the meeting must have the “recordingProfile: always” permission. * If we have configured the “startRecordingAtStart:true” parameter in the sfu-wrapper, the creator of the meeting can indicate when the meeting is called that he wants it to be recorded by checking the recording option when it is created. * The creator of the meeting can start/stop the recording of the meeting at any time using the partial recording endpoints.
Meeting recording can only be activated by the user who created the meeting, this user must have the “recordingProfile: always permission”.
What is recorded
With the implementation of partial recording, call recording no longer has to be done strictly from the start to the end of the call but can be set which part of the call will be recorded using the settings and endpoints mentioned above.
Recordings start when:
Automatically when the call is established if you set the parameter “recordRecordingAtStart: true”
The “startRoomRecording” endpoint is used
Recording stops when:
The call ends
The “stopRoomRecording” endpoint is used
Creating multiple recording segments during a single ongoing call is allowed. We generate for each segment its own properly numbered recording file. Each of these files is post-processed at the time the recording is stopped.
It is important to note that regardless of whether a user has the “recordingProfile: always” permission set, if “recordRecordingAtStart: false” is set and the “startRoomRecording” endpoint is not used there will be no recording of the call.
The recording includes the actual audio and video streams and metadata such as start time, end time and conference room ID.
Output format
Once the call is over, the system will process the audio and video streams and generate the recording files according to the Service configuration.. It may take more or less time depending on the configuration options that are explained below. Developers can check that the recordings are ready as a event is generated and sent into the queue as configured in the processedQueue
parameter.
The system can provide the recording in two output formats:
Split: each video stream is provided separately
Merged: all video streams are provided mixed into a single matrix view
Please note that these output formats are mutually exclusive, which means that only one configuration can be active. In addition, this is a system-wide configuration which means that
The default output format, when no one is configured by the administrator, is “merged”.
Split
This is the most straightforward option, where the video of each participant is provided in a separate video file. These files will have different size in the case of multiparty calls, as not every participant might had spent the same amount of time in the conference. On the audio side, all the audio streams come mixed from the audiomixer so its provided into a single audio file. Additionally, a JSON file is provided to relate all these files together along with the conference metadata. In summary, in a multiparty call with N participants, the system will generate:
One WAV audio file, containing all the mixed audio streams
N videos files (webm or mp4), each of them containing the video stream from each participant
One JSON file with conference metadata
The format of the JSON file is as follows, where we can find the list of video files and the audio file along with its corresponding start and end time.
1{
2 "uuid": "61408347",
3 "startTime": "2020-05-25T07:42:28.633Z",
4 "stopTime": "2020-05-25T07:42:43.826Z",
5 "shouldRecordAudio": true,
6 "shouldRecordVideo": true,
7 "videos": [
8 {
9 "startTime": "2020-05-25T07:42:29.126Z",
10 "stopTime": "2020-05-25T07:42:43.756Z",
11 "filename": "/recording/postprocessed/61408347-c48eb251b24289c951345fa3c57f123e4ee2/rec-20200525-074229-5dde2b2fbd53a5c690.webm",
12 "size": "0.123412412341MB",
13 "userID": "5dde2b2fbd53a5c690"
14 },
15 {
16 "startTime": "2020-05-25T07:42:36.126Z",
17 "stopTime": "2020-05-25T07:42:43.756Z",
18 "filename": "/recording/postprocessed/61408347-c48eb251b24289c951345fa3c57f123e4ee2/rec-20200525-074229-074229-5f2av4415c2e44f681.webm",
19 "size": "0.323412412341MB",
20 "userID": "5f2av4415c2e44f681"
21 },
22 ],
23 "audio": {
24 "filename": "/recording/postprocessed/roomId-confbridgeId/rec-20200525-074229-roomId-confbridgeID.wav",
25 "startTime": "2020-05-25T07:42:28.633Z",
26 "stopTime": "2020-05-25T07:42:43.826Z",
27 "size" : "0.23412412341MB"
28 }
29}
The selection of this output format is done by setting split_recording_output
to true in the recording service configuration.
Merged
When this output format is selected, the server will generate a single video file containing a matrix that will show all the participants in the screen, adding and removing them according to the time when they have joined or left the conference. This output format requires a post-processing of the raw recording files so it might not be suitable in case that the recordings need to be available right after the call has finished.
The maximum number of participants than this matrix can show is 9 participants (which gives a matrix of 3x3 participants). The number of participants in the matrix has an upper bound that is set by the mix_limit
parameter. If a conference has more participants than this value, or its value is higher that 9, then the output format will be split instead of merged (even if split_recording_output
parameter is set to false). Also note that, if split_recording_output
is set to true, the output format will always be splitted.
The following video shows an actual recording of a call with four participants, where you can see how the new participants are added to the matrix:
Play the above video to see an example of a recording with four participants in merged mode
The selection of this output format is done by setting split_recording_output
to false in the recording service configuration (this is the default configuration).
Recording quality
All the supported audio and video codecs for making calls are also available for recording. The quality of the recorded files can be configured in order to suit the recording requirements and also taking into account the resulting file size, which can have impact on the storage requirements.
On the audio side, files are stored as WAV file (128 kb/s, 8 bits per sample) quality. As an example, one minute of audio recording generates a 1Mb WAV audio file.
On the video side, an important point that needs to be taken into account is that VP9 provides a better quality when recorded and consumes less disk space, but it processing takes longer that VP8. The recording quality can be configured by choosing three quality levels: low, medium and high. As a rule of thumb, a one minute video processed with low quality takes 2 MBytes of disk space, while the same video with high quality takes 4Mbytes of disk space.
The following images compare a screenshot of a the same conference call, one recorded with low quality
(left) and another one recorded with high quality
, using VP8 codec:
Note
Please note that the video size is fixed to 640x480 pixels, regardless of the video quality.
Encryption
Recordings can also encrypted for better security and integrity using GPG encryption. In order to use the GPG encryption, the administrator will need to provide a public GPG key. This can be done by using the open source software available at GPG
Decryption is done by using the gpg command with the --decrypt
option The private key to which the message was encrypted is needed:
gpg --output video_unencrypted --decrypt video_encripted.gpg
The encrypted recordings are protected even if the servers are compromised and an attacker is able to download the recording files. The encryption takes places immediately after the call is finished. The private key must be protected in a secure device.
Service configuration
The configuration of this service is described in the upgrade notes.
Available logs
These are the main log messages generated by this service:
debug: File encryption is disabled (enabled)
info: FilenameGenerator configured with: {"filenameFormat":"rec-{{uuid}}-{{confbridgeid}}"}
debug: Recording started
debug: Received a process recording event with id: confbridgeID and recording info recording_info.
This log is printed when a conference ends, an event is broadcasted and the postprocessing starts.debug: Processing video: /sippo-recording/raw_files/test/janus-test-userId1-sfuvideo-1615975667821-video.mjr.
For each video in the conference, there will be a log indicating the preprocess of the videos (conversion from .mjr to .webm or .mp4)debug: Trying to encrypt file: /sippo-recording/postprocessed/rec-20200525-074229-test-test.webm
debug: Recording with ID 23423432 processed correctly
.
Known limitations
Once a call has started, recording configuration cannot be changed and recording can not be activated or deactivated.
If a user call is recorded, the complete call is recorded: from first user join to last leave is recorded. No matter that a rec-skip user will be involved.
Implementation details
This service generates media recordings from the media captured in the SFU and audiomixer. When a conference room is created with the recording activated, two things happen:
the audiomixer will save all the audios mixed in a single file (by default, the audio file will be stored in /var/spool/asterisk/monitor in asterisk machine with name recording-${confbridgeId}.wav).
the SFU will save all the videos flows from all the participants who joined the conference and published video (from a webcam or by sharing the screen).
These files will be persisted in .mjr format (this is a custom format where each file then basically just contains a structured dump of the RTP packets exactly as they arrived). When a conference with recording activated ends, wrapper service will emit an event to the message broker with all the conference information.
Example of such an event:
{
"conferenceId":"conferenceId",
"recordingInfo":
{
"uuid":"conferenceUuid",
"completed":"2020-05-25T07:42:43.826Z",
"video":
{
"video1":
{
"sfuvideo":
{
"1590392556275":
{
"filename":"/test/test-video-1.mjr",
"stopTime":"2020-05-25T07:42:43.826Z",
"startTime":"2020-05-25T07:42:36.277Z"
}
}
},
"video2":
{
"sfuvideo":
{
"1590392549123":
{
"filename":"/test/test-video-2.mjr",
"stopTime":"2020-05-25T07:42:43.756Z",
"startTime":"2020-05-25T07:42:29.126Z"
}
}
}
},
"audio":
{
"asterisk":
{
"sipcall":
{
"1590392548633":
{
"filename":"audio.wav",
"stopTime":"2020-05-25T07:42:43.826Z",
"startTime":"2020-05-25T07:42:28.633Z"
}
}
}
}
}
When the recording services receives this event, it will start processing the recordings. This processs is divided into three steps:
Preprocessing
This step is in charge of preprocessing all the .mjr files and converting them to the corresponding media file. To do this, the service will use a binary file offered by janus, called janus-pp-rec. Janus-pp-rec actually only dumps the RTP frames it receives to a file in a structured way, so that they can be post-processed later on to extract playable media files. This utility allows you to process those files, in order to get a working media file you can playout with an external player. The tool will generate a .webm if the recording includes VP8 frames, an .opus if the recording includes Opus frames, an .mp4 if the recording includes H.264 frames, and a .wav file if the recording includes G.711 (mu-law or a-law) frames.
After this step, all .mjr files will be converted to .webm files or .mp4 files (in our case, conference could use vp8 or h264 as video codecs).
Processing Data
This step is in charge of process all data received in the event emitted by wrapper and generating all the info needed in the postprocessoring to crete the final file. This will generate a list of intervals, where each interval ends when a display layout changes (participant enters or leaves the conference will produce a change in this layout).
Postprocessing
This step will received the intervals calculated for the previous step and:
Create a partial video for each interval received.
Once all partial videos are created, the postprocessor concatenates them in a single video file.
Then mix concatenated video with the audio generating the final file.
Move final file to destination folder.
If clean_temporary_files is activated, all temporary files related with processing will be deleted.
An event will be emmited to rabbitmq indicating the processed conference.
Ack to rabbitmq to remove this task from it.
Things to keep in mind
Some things to keep in mind:
If the recording services fails in any of the previous steps, it will emit an event to rabbitmq (in the failure_queue) indicating the error and the conference that fails. In this case, although the clean_temporary_files is active, the temporary files will not be deleted, in order to do not lose these files without having a processed final file.
If conference has no audio (or some problem ocurred saving the audio by the asterisk), a final file will be generated with all the concatenated videos but without audio.
The processed file will have this format: recording-${confbridgeId}-${roomUuid}.webm
For the recording to work correctly, it will need to have access to the media files persisted by the audiomixer and by the SFU (this can be done created shared volumes between containers, using a NFS network…).
System configuration
The following parameters in the QSS config.json
configuration file defines what to do regarding recording when there are no permissions defined in the system:
Default value for “record” parameter
none
.Default value for “recordIncomingPSTN” parameter is
false
// skipped code
"rooms": {
"record": all,video,audio,none
},
“trunk”:{
“recordIncomingPSTN”: true
}
The following parameter is needed in the audiomixer confbridge.conf
configuration files:
// skipped code
record_file_timestamp = no
// skipped code
The following parameter is needed in the audiomixer modules.conf
configuration files:
// skipped code
load = app_mixmonitor.so
// skipped code
The following parameters are needed in the recording service configuration file recording.toml
located at sippo-recording/config/
:
{
"recordings_path": "/sippo-recording/raw_files/",
"audio_path": "/sippo-recording/raw_audio/",
"destination_path": "/sippo-recording/postprocessed/",
"processing_queue": "processing_queue",
"failure_queue": "failure_queue",
"processed_queue": "processed_queue",
"webm_codec": "vp8",
"quality": "low",
"clean_temporary_files": false,
"fileformat": "rec-{{year}}{{month}}{{day}}-{{hours}}{{minutes}}{{seconds}}-{{uuid}}-{{confbridgeid}}",
"should_encrypt" : true,
"encryption_key" : "/sippo-recording/encryption/key.asc",
"encryption_mail" : "mail@domain.com",
"split_recording_output" : true,
"mix_limit" : 9
}
The default.toml config file needs to have the following fields:
[log]
level = "debug"
relativePaths = true
[rabbitmq]
address = "amqp://rabbitmq"
The meaning and default values of each field is explained in the table below:
Field |
Comment |
Default value |
---|---|---|
|
Available fields that will compose the filename of the recordings, must be placed between double brackets: year, month, day, hours, minutes, seconds, uuid and confbridgeid |
rec-{{year}}{{month}}{{day}}-{{hours}}{{minutes}}{{seconds}}-{{uuid}}-{{confbridgeid}} |
|
Path where the logs of the post-process will be saved. |
/sippo-recording/logs/ |
|
Path where the raw video recordings will be stored. |
/sippo-recording/raw_files/ |
|
Path where the raw audio recordings will be stored. |
/sippo-recording/raw_audio/ |
|
Path where the post-processed file will be saved |
/sippo-recording/postprocessed/ |
|
Codec that will be used when processing a video that has been recorded in VP8 or VP9. Choices: vp8 or vp9. Please note that the final codec is always WEBM |
vp8 |
|
Quality of the processed videos. Choices: low, medium or high |
low |
|
Name of the queue used for receive processing events |
processing_queue |
|
Queue where correctly processed messages will be placed |
processed_queue |
|
Name of the queue used for failures events |
failure_queue |
|
Boolean field. If it is true, when a recording is processed correctly, all clean_temporary_files related with this conference will be deleted. |
true |
|
Boolean field. If it is true, encryption is applied to the final processed recording files. |
false |
|
Path of the PGP encryption key. |
/sippo-recording/encryption/key.asc”, |
|
Email address used for the encryption process. |