...
В сборке 5.2.1012 добавлена возможность записи нескольких потоков в один файл. В дальнейшем потоки могут быть извлечены из этого файла и смикшированы специальным инструментом. Несколько потоков могут быть записаны только в MP4 контейнер (H264 + AAC)или, начиная со сборки 5.2.1440, в MKV контейнер. Эта возможность предназначена, например, для записи видеоконференций. В отличие от MCU микшера, здесь микширование работает только при обработке уже записанного файла, и позволяет расходовать меньше ресурсов процессора непосредственно во время проведения конференции.
Запись нескольких потоков управляется по REST API.
Поддерживаемые кодеки
Контейнер MP4:
- H264
- AAC
Контейнер MKV:
- H264
- VP8
- Opus
- AAC
- PCMA
- PCMU
- G722
REST API для мультирекордера
REST-запрос должен быть HTTP/HTTPS POST запросом в таком виде:
...
- streaming.flashphoner.com - адрес WCS-сервера
- 8081 - стандартный REST / HTTP порт WCS-сервера
- 8444 - стандартный HTTPS порт
- rest-api - обязательный префикс
- /multipleRecorder/startup - используемый REST-вызов
REST-методы и статусы ответа
REST-метод | Пример тела REST-запроса | Пример тела REST-ответа | Статусы ответа | Описание | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|
/multipleRecorder/startup |
| 409 - Conflict 500 - Internal error | Запустить рекордер для записи нескольких потоков | ||||||||
/multipleRecorder/add |
| 404 - Not found 409 - Conflict 500 - Internal error | Добавить в рекордер поток из указанной медиасессии | ||||||||
/multipleRecorder/find_all |
| 404 - Not found 500 - Internal error | Найти все рекордеры | ||||||||
/multipleRecorder/remove |
| 404 - Not found 500 - Internal error | Удалить поток из рекордера | ||||||||
/multipleRecorder/terminate |
| 404 - Not found 500 - Internal error | Остановить рекордер |
...
Имя параметра | Описание | Пример |
---|---|---|
uri | URI рекордера | multi-recorder://test-record |
mediaSessionId | Идентификатор медиасессии потока | 866a9910-fbfe-11eb-aae4-6f99b0c80a3a |
filename | Имя файла, куда производится запись | multi-recorder___test-record.mp4 |
Имя записываемого файла
Имя файла для записи нескольких потоков формируется по шаблону. При этом:
1. Параметр {streamName} подставляется согласно URI рекордера, с заменой символов, не допустимых к использованию в именах файлов, на подчеркивания.
...
Выбор контейнера для записи
Данная возможность доступна, начиная со сборки 5.2.1440. По умолчанию, запись производится в контейнер MP4
Code Block | ||
---|---|---|
| ||
multi_recorder_type=MP4 |
При необходимости (например, при публикации VP8+Opus потоков в конференции), можно выбрать контейнер MKV
Code Block | ||
---|---|---|
| ||
multi_recorder_type=MKV |
Имя записываемого файла
Имя файла для записи нескольких потоков формируется по шаблону. При этом:
1. Параметр {streamName} подставляется согласно URI рекордера, с заменой символов, не допустимых к использованию в именах файлов, на подчеркивания.
2. Параметры {startTime}, {endTime} не могут быть определены, поскольку зависят от меток времени в потоке, а потоков в данном случае несколько. Поэтому рекомендуется для присвоения метки времени файлу использовать параметры {startTimeMillis}, {endTimeMillis}, которые проставляются согласно часам сервера.
...
Из файла с несколькими потоками внутри по умолчанию может быть воспроизведен только первый поток. Чтобы смотреть все потоки в файле, их необходимо смикшировать. Для этого предназначен инструмент OfflineMP4MixerOfflineMixerTool, запускаемый следующим образом:
...
Пример кадра из микшированного файла
...
Начиная со сборки 5.2.1481, микшируются потоки как из MP4, так и из MKV контейнеров. Результат всегда записывается в MP4 контейнер.
Получение информации о дорожках из записанного файла
...
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
[ { "durationInMS": "78978", "trackEdits": [ { "endInMs": "63050", "type": "pause", "startInMs": "0" }, { "endInMs": "78978", "type": "media", "startInMs": "63050" } ], "channels": "2", "trackType": "AUDIO", "trackId": "3", "timescale": "44100", "streamName": "test", "trackCodec": "mp4a", "sampleRate": "44100", "mediaSessionId": "fbbf5b50-20ee-11ec-bf06-ef6ec6048b2c" }, { "durationInMS": "39708", "trackEdits": [ { "endInMs": "23150", "type": "media", "startInMs": "0" } ], "channels": "2", "trackType": "AUDIO", "trackId": "1", "timescale": "44100", "streamName": "test", "trackCodec": "mp4a", "sampleRate": "44100", "mediaSessionId": "c7bc1460-20ee-11ec-bf06-ef6ec6048b2c" }, { "durationInMS": "39791", "trackEdits": [ { "endInMs": "23233", "type": "media", "startInMs": "0" } ], "trackType": "VIDEO", "trackId": "0", "width": "640", "timescale": "90000", "streamName": "test", "trackCodec": "avc1", "mediaSessionId": "c7bc1460-20ee-11ec-bf06-ef6ec6048b2c", "height": "360" }, { "durationInMS": "63050", "trackEdits": [ { "endInMs": "39791", "type": "pause", "startInMs": "0" }, { "endInMs": "50191", "type": "media", "startInMs": "39791" } ], "trackType": "VIDEO", "trackId": "2", "width": "640", "timescale": "90000", "streamName": "test", "trackCodec": "avc1", "mediaSessionId": "ed3ebda0-20ee-11ec-bf06-ef6ec6048b2c", "height": "360" } ] |
Скрипт для обработки записанных файлов
По окончании записи нескольких потоков в один файл, запускается cкрипт обработки, заданный настройкой
Code Block | ||
---|---|---|
| ||
on_multiple_record_hook_script=on_multiple_record_hook.sh |
...
Извлечение отдельных потоков из MKV контейнера
В сборке 5.2.1440 с помощью инструмента для микширования записанных потоков можно извлечь отдельные потоки из MKV контейнера:
Code Block | ||||
---|---|---|---|---|
| ||||
./offline_mixer_tool.sh |
...
--pull-streams ../records/multi-recorder___test-record.mkv |
При этом будут созданы MKV файлы для каждого из потоков:
Code Block | ||||
---|---|---|---|---|
| ||||
LOGGER_ENABLED=true |
Многопоточное кодирование при микшировании записанных потоков
В сборке 5.2.1089 добавлена возможность включить многопоточное кодирование при микшировании записанных потоков. Для этого в файл /usr/local/FlashphonerWebCallServer/conf/offline_mixer.json
необходимо добавить параметр
Code Block | ||||
---|---|---|---|---|
| ||||
{
...,
"multithreading": true
} |
При использовании многопоточного кодирования записанные потоки микшируются в среднем в два раза быстрее по сравнению с однопоточным.
Отправка данных о завершении записи нескольких потоков
В сборке 5.2.1123 добавлена возможность отправки POST запроса на указанный URL при завершении записи нескольких потоков в файл и микширования этой записи. Таким образом, можно получить информацию о том, в какой файл смикшированы записанные потоки из чат-комнаты.
URL для отправки запроса задается в файле /usr/local/FlashphonerWebCallServer/conf/offline_mixer.json
:
Code Block | ||||
---|---|---|---|---|
| ||||
{
...,
"callbackUrl": "http://backend.url/multiRecorderCallback"
} |
...
multi-recorder___test-record_fbbf5b50-20ee-11ec-bf06-ef6ec6048b2c.mkv
multi-recorder___test-record_c7bc1460-20ee-11ec-bf06-ef6ec6048b2c.mkv
multi-recorder___test-record_ed3ebda0-20ee-11ec-bf06-ef6ec6048b2c.mkv |
Если поток был удален из мультирекордера и повторно добавлен, или был добавлен позднее, чем другие потоки, получившиеся паузы по умолчанию будут заполнены, чтобы выровнять извлеченные потоки по времени. При необходимости, заполнение можно отключить
Code Block | ||
---|---|---|
| ||
multi_recorder_mkv_fill_gaps=false |
Скрипт для обработки записанных файлов
По окончании записи нескольких потоков в один файл, запускается cкрипт обработки, заданный настройкой
Code Block | ||
---|---|---|
| ||
on_multiple_record_hook_script=on_multiple_record_hook.sh |
...
По умолчанию, скрипт запускает offline_mixer_tool.sh
. Поэтому при установке сборки , передавая ему на вход имя записанного файла.
Начиная со сборки 5.2.1123 поверх предыдущей, или в том случае, если используется собственный 1023, скрипт on_multiple_record_hook.sh
, необходимо модифицировать его следующим образом:по умолчанию записывает в лог /usr/local/FlashphonerWebCallServer/logs/multi-record.log
только результат обработки, чтобы снизить нагрузку на диск во время работы инструмента микширования. При необходимости, можно включить подробное логирование для отладки, установив переменную в скрипте
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
# This script copies a recorded stream to client/records FILE_NAME=$1 CREATION_MODIFICATION_TIME=$2 DURATION_IN_MS=$3 RECORDER_URI=$4 WCS_HOME=/LOGGER_ENABLED=true |
Многопоточное кодирование при микшировании записанных потоков
В сборке 5.2.1089 добавлена возможность включить многопоточное кодирование при микшировании записанных потоков. Для этого в файл /usr/local/FlashphonerWebCallServer
...
/conf/offline_mixer
...
.json
необходимо добавить параметр
Code Block | ||||
---|---|---|---|---|
| ||||
{
...,
"multithreading": true
} |
При использовании многопоточного кодирования записанные потоки микшируются в среднем в два раза быстрее по сравнению с однопоточным.
Количество процессорных потоков при многопоточном кодировании
В сборке 5.2.1523 добавлена настройка количества процессорных потоков, используемых для многопоточного кодирования. По умолчанию, количество процессорных потоков равно половине доступных системе ядер CPU. Например, на сервере с 12 CPU по умолчанию буду использовать 6 потоков
Code Block | ||||
---|---|---|---|---|
| ||||
{
...,
"threadCount": 6
} |
Если микширование записе занимает долгое время, значение можно увеличить, но не рекомедуется указывать больше, чем количество ядер CPU на сервере, которое можно определить при помощи команды
Code Block | ||||
---|---|---|---|---|
| ||||
lscpu | grep -E "^CPU\(s\)" |
Отображение имени записанного потока
По умолчанию, в микшированной записи нескольких потоков отображается имя каждого потока. При необходимости, это можно отключить настройкой в файле /usr/local/FlashphonerWebCallServer/conf/offline_mixer.json
Code Block | ||||
---|---|---|---|---|
| ||||
{
...,
"mixerDisplayStreamName": false
} |
При записи потоков в конференции с использованием RoomApi, имя потока включает имя комнаты конференции и идентификатор потока участника, например room-1882a6-bob-037c
. В сборке 5.2.1642 добавлена возможность исключить имя комнаты при помощи настроек
Code Block | ||||
---|---|---|---|---|
| ||||
{
...,
"mixerDisplayStreamName": true,
"mixerTextDisplayRoom": false,
"labelReplaceRegex": "\\w+-\\w+-([^\\-]+)-\\w+",
"labelReplaceWith":""
} |
Здесь:
- labelReplaceRegex - регулярное выражение для замены элементов в имени потока
- labelReplaceWith - строка, которая должна заменить элементы, найденные по регулярному выражению, пустая строка исключает найденные элементы
В этом случае для указанного выше примера будет отображаться только имя участника bob.
Декодирование символов в имени записанного потока
В сборке 5.2.1751 добавлена возможность декодирования символов в имени потока, закодированных на стороне клиента при помощи encodeURIComponent()
Code Block | ||||
---|---|---|---|---|
| ||||
{
...,
"mixerDecodeStreamName": true
} |
В этом случае в изображении будут отображаться декодированные символы, если такие символы есть в используемом шрифте, или близкие к ним по начертанию.
Отправка данных о завершении записи нескольких потоков
В сборке 5.2.1123 добавлена возможность отправки POST запроса на указанный URL при завершении записи нескольких потоков в файл и микширования этой записи. Таким образом, можно получить информацию о том, в какой файл смикшированы записанные потоки из чат-комнаты.
URL для отправки запроса задается в файле /usr/local/FlashphonerWebCallServer/conf/offline_mixer.json
:
Code Block | ||||
---|---|---|---|---|
| ||||
{
...,
"callbackUrl": "http://backend.url/multiRecorderCallback"
} |
Данные для отправки передаются через скрипт /usr/local/FlashphonerWebCallServer/bin/on_multiple_record_hook.sh
при вызове offline_mixer_tool.sh
. Поэтому при установке сборки 5.2.1123 поверх предыдущей, или в том случае, если используется собственный скрипт on_multiple_record_hook.sh
, необходимо модифицировать его следующим образом:
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
# This script copies a recorded stream to client/records
FILE_NAME=$1
CREATION_MODIFICATION_TIME=$2
DURATION_IN_MS=$3
RECORDER_URI=$4
WCS_HOME=/usr/local/FlashphonerWebCallServer
LOG_FILE=$WCS_HOME/logs/multi-record.log
MIXER_TOOL=$WCS_HOME/tools/offline_mixer_tool.sh
# Set LOGGER_ENABLED to true to enable mixing debug logging
LOGGER_ENABLED=false
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Start mixing multiple recording file $FILE_NAME" >> $LOG_FILE
if $LOGGER_ENABLED; then
bash $MIXER_TOOL $FILE_NAME $CREATION_MODIFICATION_TIME $DURATION_IN_MS $RECORDER_URI >> $LOG_FILE 2>&1
else
bash $MIXER_TOOL $FILE_NAME $CREATION_MODIFICATION_TIME $DURATION_IN_MS $RECORDER_URI > /dev/null 2>&1
fi
CODE=$?
if [ "$CODE" -ne "0" ]; then
if [ "$CODE" -eq "64" ]; then
echo "ERROR: File to mix not found" >> $LOG_FILE
elif [ "$CODE" -eq "65" ]; then
echo "ERROR: Offline mixer config not found" >> $LOG_FILE
else
echo "ERROR: Offline mixer tool error code: $CODE" >> $LOG_FILE
fi
exit $CODE
fi
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Multiple recording file $FILE_NAME is mixed successfully" >> $LOG_FILE
exit 0 |
...
Code Block | ||
---|---|---|
| ||
v=0 o=- 1988962254 1988962254 IN IP4 0.0.0.0 c=IN IP4 0.0.0.0 t=0 0 a=sdplang:en m=audio 0 RTP/AVP 97 8 0 102 103 104 105 106 107 108 109 110 a=rtpmap:97 SPEEX/16000 a=rtpmap:8 PCMA/8000 a=sdplang:en m=audio rtpmap:0 RTP/AVP 97 8 0 102 103 104 105 106 107 108 109 110 a=rtpmap:97 SPEEX/16000PCMU/8000 a=rtpmap:102 mpeg4-generic/48000/1 a=rtpmap:103 mpeg4-generic/44100/1 a=rtpmap:104 mpeg4-generic/32000/1 a=rtpmap:105 mpeg4-generic/24000/1 a=rtpmap:106 mpeg4-generic/22050/1 a=rtpmap:107 mpeg4-generic/16000/1 a=rtpmap:108 mpeg4-generic/12000/1 a=rtpmap:109 mpeg4-generic/11025/1 a=rtpmap:8110 PCMAmpeg4-generic/8000 a=rtpmap:0 PCMU/8000 a=rtpmap:102 mpeg4-generic/48000/1 a=rtpmap:103 mpeg4-generic/44100/1 a=rtpmap:104 mpeg4-generic/32000/1 a=rtpmap:105 mpeg4-generic/24000/1 a=rtpmap:106 mpeg4-generic/22050/1 a=rtpmap:107 mpeg4-generic/16000/1 a=rtpmap:108 mpeg4-generic/12000/1 a=rtpmap:109 mpeg4-generic/11025/1 a=rtpmap:110 mpeg4-generic/8000/1 a=sendonly/1 a=sendonly |
11. Запись потока начинается только после получения хотя бы одного ключевого кадра
Симптомы: при старте записи (например, по REST API) файл не создается, ошибок в серверном логе при этом нет, и поток играет в браузере (до переподключения зрителя)
Решение: обеспечить периодическую отсылку ключевых кадров для WebRTC публикаций при помощи настройки
Code Block | ||
---|---|---|
| ||
periodic_fir_request=true |
для RTMP публикаций соответствующими настройками кодировщика
12. При воспроизведении потока, извлеченного из записи мультирекордера в формате MKV, проигрыватель проскакивает паузы в потоке
Симптомы: при проигрывании извлеченного потока в VLC, пауза в потоке пропускается
Решение: использовать настройку
Code Block | ||
---|---|---|
| ||
multi_recorder_mkv_fill_gaps=true |
13. Если WebRTC поток записывается одновременно в отдельный файл MKV и в мультирекордер MKV, рекомендуется обеспечить регулярное поступление ключевых фреймов
Симптомы: при проигрывании отдельного файла MKV VLC перескакивает на время добавление этого потока в мультирекордер
Решение: обеспечить периодическую отсылку ключевых кадров для WebRTC публикаций при помощи настройки
Code Block | ||
---|---|---|
| ||
periodic_fir_request=true |
14. При извлечении из файла мультирекордера в контейнере MKV потока с аудио G722 могут наблюдаться кратковременные искажения аудио
Симптомы: при проигрывании извлеченного файла с аудио G722, если поток был удален и снова добавлен в мультирекордер, слышны кратковременные искажения звука при добавлении потока
Решение: использовать аудиокодек Opus
15. При извлечении из файла мультирекордера в контейнере MKV потока с аудио PCMA после удаления потока из мультирекордера аудио завершается раньше, чем видео
Симптомы: при проигрывании извлеченного файла с аудио PCMA, если поток был удален из мультирекордера, аудио завершается раньше, чем видео
Решение: использовать аудиокодек Opus