mixer_in_buffering_ms Синхронизация видео и звука.

Alesia

New Member
Добрый день, мы используем свои кастомные темлпейты. Для звука у нас есть отдельный аудио микшер. Для видео - мы просто используем стримы.

Для того, чтобы у пользователей с низким интернетом не было прерываний или фризов в звуке, мы добавили буферизацию mixer_in_buffering_ms = 600 (помогло, фризы пропали).
Но из-за этого аудио идет позже видео и нет синхронизации.
Подскажите, пожалуйста, можно ли как-то добавить такую же задержку для видео стримов? (Но они не добавляются в микшер). Или как-то синхронизировать звук и видео.


Я уже присылала вам наши настройки, но может быть вы еще что-то подскажите? Вы посоветовали добавить
#mixer_type=MULTI_THREADED_NATIVE
#mixer_mcu_multithreaded_mix=true
#mixer_audio_threads=10
#mixer_video_threads=4


для того, чтобы избавится от фризов в звуке и убрать mixer_in_buffering_ms = 600, но при добавлении фризы остались. Используем инстанс AWS m6i.32xlarge 128 512




codecs =opus,alaw,ulaw,g729,speex16,g722,mpeg4-generic,telephone-event,h264,vp8,flv,mpv
codecs_exclude_sip =mpeg4-generic,flv,mpv
codecs_exclude_streaming =flv,telephone-event
codecs_exclude_sip_rtmp =opus,g729,g722,mpeg4-generic,vp8,mpv

#cors
disable_rest_auth=true
disable_manager_rmi=false
rest_access_control_allow_origin=*
rest_access_control_allow_headers=content-type,x-requested-with
rest_access_control_allow_methods=POST


client_mode=false

ice_timeout = 60
rtc_ice_add_local_component=true

turn_life_time = 60

rtp_receive_buffer_size=131072
rtp_send_buffer_size =131072

#rest_max_connections=20

#custom mixer settings
#mixer_type=MULTI_THREADED_NATIVE
#mixer_mcu_multithreaded_mix=true
#mixer_audio_threads=10
#mixer_video_threads=4


mixer_realtime=true
mixer_lossless_video_processor_enabled=false
mixer_idle_timeout=900000
mixer_voice_activity=false
mixer_show_separate_audio_frame=false
mixer_mcu_audio=true
mixer_mcu_video=false
mixer_mcu_multithreaded_delivery=true
mixer_in_buffering_ms=600
#mixer_video_background_filename=/opt/media/white.png
mixer_video_desktop_fullscreen=true
mixer_video_enabled=false
#mixer_video_enabled=false
#mixer_video_bitrate_kbps=4000
#stream_record_policy_template=stream-{mediaSessionId}-{startTime}

#stream distribution optimization
streaming_distributor_subgroup_enabled=true
streaming_distributor_subgroup_size=50
streaming_distributor_audio_subgroup_size=500
streaming_distributor_subgroup_queue_size=300
streaming_distributor_subgroup_queue_max_waiting_time=5000
streaming_distributor_audio_subgroup_queue_size=300
streaming_distributor_audio_subgroup_queue_max_waiting_time=5000

#cdn
cdn_enabled=true
cdn_ip=
cdn_nodes_resolve_ip=true
cdn_role=origin

#webrtc_aes_crypto_provider=JCE

#logs
#client_log_level=DEBUG

#padding
mixer_video_desktop_layout_inline_padding=0
mixer_video_desktop_layout_padding=0
mixer_video_grid_layout_middle_padding=0
mixer_video_grid_layout_padding=0
 
Last edited:

Max

Administrator
Staff member
Добрый день.
В дальнейшем, когда приводите настройки, убирайте домены и IP-адреса. Мы не можем отредактировать Ваш пост, только удалить, но в этом случае тема пропадет.
Подскажите, пожалуйста, можно ли как-то добавить такую же задержку для видео стримов? (Но они не добавляются в микшер). Или как-то синхронизировать звук и видео.
WebRTC не предусматривает буферизацию входящего потока, поэтому задержку в видео добавить нельзя.
Синхронизировать для различных источника медиа невозможно в принципе. То есть, если Вы публикуете с каждого клиента отдельно стрим только с видео и отдельно только с аудио, синхронизации между этими стримами не будет, поскольку браузер проставляет в медиапакетах для каждого стрима свое значение синхронизации.
Чтобы видео и аудио участника были синхронизированы, надо публиковать один стрим с двумя составляющими: видео+аудио. Этот стрим уже можно заводить в микшер.
Настройки, которые мы рекомендовали, касаются доставки MCU-потоков пользователям, они не помогают в случае проблем с каналом у публикующего клиента. Судя по достаточно большому значению буфера, которое Вы используете (600 мс), у публикующих клиентов могут быть потери на канале и недостаточная пропускная способность. Избавиться от потерь поможет переключение на TCP транспорт, а для того, чтобы уложиться в пропускную способность, следует снижать разрешение и битрейт на стороне браузера при публикации
Code:
session.createStream({
    name: streamName,
    display: localVideo,
    constraints: {
        video: {
            width: 320,
            height: 180,
            maxBitrate: 100
        },
        audio: true
    },
    transport: "TCP"
    ...
}).publish();
 

Alesia

New Member
Добрый день, мы используем turn server, так как некоторые наши пользователи используют vpn и без терна их стрим не включается. По-моему, нашл терн tcp, и когда мы использовали tcp в стримах - стримы валились с ошибкой. Когда мы исправили стримы на udp - ошибка убралась.
Может быть, вы можете подсказать еще что-нибудь?
 

Alesia

New Member
И еще такой вопрос: мы используем кастомные темплейты, то есть мы берем каждый стрим видео и вставляем его в компонент, если он есть, то есть мы не будем использовать микшер, чтобы показать камеры / декстопы юзера.

если мы будем использовать стрим вида video-id#mixer-roomId, в этом стриме будут настройки микшера? В том числе буферизация?
 

Max

Administrator
Staff member
Добрый день, мы используем turn server,
В этом случае TCP транспорт не нужен: во-первых, ни один TURN сервер его не поддерживает (ни coturn, ни наш встроенный), во-вторых, при использовании TURN медиа трафик от клиента и так идет по TCP.
И еще такой вопрос: мы используем кастомные темплейты, то есть мы берем каждый стрим видео и вставляем его в компонент, если он есть, то есть мы не будем использовать микшер, чтобы показать камеры / декстопы юзера.
Уточните, что такое кастомные темплейты:
- элементы страницы в браузере на стороне клиента
- шаблоны размещения картинок в микшере?
Если первое, тогда получается, что играющий клиент получает все видеопотоки. В таком случае непонятно, зачем используется аудиомикшер: если Вы занимаете канал клиента видео, то можно и все аудиопотоки отправить клиенту, т.к. аудио заведомо занимает меньшую полосу.
Если микшер нужен только для записи, то опять же, лучше будет направлять туда и аудио, и видео. Но в этом случае можно отключить поддержку MCU совсем, она требуется только для того, чтобы убрать собственное аудио участника и таким образом избавиться от эха.
если мы будем использовать стрим вида video-id#mixer-roomId, в этом стриме будут настройки микшера? В том числе буферизация?
В этом случае будет использоваться микшер, и стрим будет заходить туда. К микшеру будут применяться настройки буферизации. Но, повторим, если аудио и видео заходит в микшер отдельными стримами, то синхронизации между ними не будет, как объяснено в этом посте.
 

Alesia

New Member
У нас есть различные темплейты для видео и декстопа, и мы просто используем стрим юзера и "вставляем" его в компонент.
1656930118220.png

А микшер мы используем, чтобы уменьшить нагрузку. Потому что мы заметили, что когда мы используем несколько стримов аудио, нагрузка становится гораздо сильнее (ну это логично, мне кажется, один стрим микшера прослушивать легче чем допустим 30)

Поэтому мы не можем убрать микшер звука. Но если вы скажете, что мы можем просто прослушивать по 30 стримов аудио и это будет равносильно 1 микшеру, то тогда супер, мы заменим микшер на стримы
 

Max

Administrator
Staff member
Поэтому мы не можем убрать микшер звука. Но если вы скажете, что мы можем просто прослушивать по 30 стримов аудио и это будет равносильно 1 микшеру, то тогда супер, мы заменим микшер на стримы
С точки зрения нагрузки на канал, это возможно. Допустим, битрейт одного потока аудио 60 кбит/с, тогда 30 потоков аудио займут 1800 кбит/с (как один поток видео в хорошем качестве). Понятно, что канала клиента должно хватать и для аудио, и для видео, т.е. полоса на download должна быть не менее 6 Мбит/с (один видео стрим + 30 аудио стримов).
Но вот производительности браузера может не хватить на проигрывание 30 потоков.
Поэтому да, если Вам нужно играть 30 аудио дорожек + 1-2 дорожки видео, микшер становится предпочтительнее. Но синхронизация между аудио и видео будет только в следующем случае:
- аудио+видео от спикера (если на картинке приведен пример спикера в нижнем правом углу) должны идти одним стримом
- стримы должны заходить в один микшер
Если у Вас видео от участника может то подключаться, то отключаться, возможно, имеет смысл публиковать потоки как SFU, в этом случае можно добавлять/удалять видео дорожку без переподключения участника. Но в микшер аудио и видео от такого участника зайдут отдельными стримами.
 

Alesia

New Member
Добрый вечер, если пользователь запускает видео (что бывает редко) - мы создаем стрим с аудио и видео, а главный аудио стрим в микшере мьютим - таким образом мы избавились в разнице аудио с видео.

Подскажите, пожалуйста, корректные ли настройки для создания аудио и видео стрима?


return {
deviceId: currentVideoId,
name: this.getStreamId(roomGuid),
display: this.localVideo,
cacheLocalResources: true,
receiveVideo: false,
receiveAudio: false,
transport: 'UDP',
constraints: {
audio: {
bitrate: 20000,
deviceId: currentAudioId,
echoCancellation: true,
googEchoCancellation: true,
autoGainControl: true,
googAutoGainControl: true,
noiseSuppression: true,
googNoiseSuppression: true,
latency: 0,
},
video: {
// const DEFAULT_WIDTH = 640
// const DEFAULT_HEIGHT = 480
deviceId: currentVideoId,
width: `${DEFAULT_WIDTH}`,
height: `${DEFAULT_HEIGHT}`,
frameRate: 15,
minBitrate: 0,
maxBitrate: 10000,
cacheLocalResources: true,
videoContentHint: 'motion',
},
},
}
 

Max

Administrator
Staff member
audio: {
bitrate: 20000,
...
echoCancellation: true,
googEchoCancellation: true,
Низкий битрейт аудио и включенное эхоподавление будут приводить к низкому качеству звука: может булькать и прерываться. Рекомендуем аудио битрейт хотя бы 30000 и отключить эхоподавление
Code:
audio: {
    bitrate: 30000,
    ...
    echoCancellation: false,
    googEchoCancellation: false,
    ...
}
minBitrate: 0,
maxBitrate: 10000,
Не следует ставить слишком низкий минимальный битрейт видео и слишком высокий максимальный. В коридоре между minBitrate и maxBitrate сервер активно управляет битрейтом, постоянно высылая клиенту REMB-команды на снижение/повышение битрейта. При не очень широком канале это приведет к тому, что весь канал забьется служебными командами, что приведет к фризам в видео трафике.
Для 640x480 можно выставить
Code:
maxBitrate: 500
а нижнюю границу оставить по умолчанию, чтобы браузер мог сбросить битрейт при нехватке канала до сервера. Обратите внимание, что битрейт задается в кбит/с
cacheLocalResources: true,
videoContentHint: 'motion',
Эти параметры указываются не в констрейнтах, а в опциях потока при его создании
Code:
name: this.getStreamId(roomGuid),
display: this.localVideo,
cacheLocalResources: true,
receiveVideo: false,
receiveAudio: false,
transport: 'UDP',
videoContentHint: 'motion',
constraints: {
    ...
}
Параметр videoContentHint: 'motion' разрешает браузеру снижать разрешение и битрейт, но удерживать заданный FPS при изменении параметров канала. Если необходимо удерживать разрешение (например, при публикации экрана), нужно выставить
Code:
...
videoContentHint: 'detail',
...
 
Last edited:

Alesia

New Member
Добрый день, при интернете:
1657804307553.png


стрим видео довольно часто прерывается и надолго заедает (аудио в хорошем качестве - но иногда присутствуют прерывания как и в видео. Может вы еще что-то сможете посоветовать? (На самом деле в гугл мите при таком интернете качество стрима гораздо хуже, но при этом зум работает замечательно. Мы понимаем, что у нас веб версия и нельзя сравнивать. Дело в том, что наш главный заказчик живет в швейцарской деревеньке - и даже в ней все должно работать хорошо :( )


if (this.useVirtualBackground) {
const canvasStream = await this.CanvasStreamController.getCanvasStream(
DEFAULT_WIDTH,
DEFAULT_HEIGHT,
currentVideoId || ''
)
return {
deviceId: currentVideoId,
name: this.getStreamId(roomGuid),
display: this.localVideo,
cacheLocalResources: true,
receiveVideo: false,
receiveAudio: false,
transport: 'UDP',
videoContentHint: 'motion',
constraints: {
audio: {
bitrate: 30000,
deviceId: currentAudioId,
echoCancellation: false,
googEchoCancellation: true,
autoGainControl: true,
googAutoGainControl: true,
noiseSuppression: true,
googNoiseSuppression: true,
latency: 0,
},
customStream:
// @ts-ignore
canvasStream.captureStream(15),
},
}
}

return {
deviceId: currentVideoId,
name: this.getStreamId(roomGuid),
display: this.localVideo,
receiveVideo: false,
receiveAudio: false,
transport: 'UDP',
cacheLocalResources: true,
videoContentHint: 'motion',
constraints: {
audio: {
// const DEFAULT_WIDTH = 640
// const DEFAULT_HEIGHT = 480
bitrate: 30000,
deviceId: currentAudioId,
echoCancellation: false,
googEchoCancellation: true,
autoGainControl: true,
googAutoGainControl: true,
noiseSuppression: true,
googNoiseSuppression: true,
latency: 0,
},
video: {
deviceId: currentVideoId,
width: `${DEFAULT_WIDTH}`,
height: `${DEFAULT_HEIGHT}`,
frameRate: 15,
minBitrate: 0,
maxBitrate: 500,
},
},
}
}
 

Max

Administrator
Staff member
Измерения, проведенные с помощью Speedtest, к сожалению, не показатель. Эти измерения отображают пропускную способность канала до какого-то определенного сервера или серверов, размещенных в каком-то датацентре, но не до Вашего сервера WCS. Кроме того, здесь не отображаются потери пакетов, которые могут быть при публикации WebRTC по UDP.
Более точно качество канала можно оценить по разнице битрейтов: опубликованного на стороне клиента и полученного сервером: Контроль качества канала при публикации и воспроизведении
Как правило, помогает переключение на TCP транспорт:
Code:
...
name: this.getStreamId(roomGuid),
display: this.localVideo,
receiveVideo: false,
receiveAudio: false,
transport: 'TCP' 
...
Также в настройках есть неточности:
return {
deviceId: currentVideoId,
name: this.getStreamId(roomGuid),
display: this.localVideo,
cacheLocalResources: true,
receiveVideo: false,
receiveAudio: false,
transport: 'UDP',
deviceId принимается только в constraints.audio или constraints.video. В опциях стрима этот параметр не используется.
googEchoCancellation: true,
Этот параметр нужно выставить в false, как мы рекомендовали выше
minBitrate: 0,
maxBitrate: 500,
minBitrate нужно убрать совсем, чтобы применялась нижняя граница по умолчанию (30 кбит/с)
 
Top