Это старая версия документа.


A PCRE internal error occured. This might be caused by a faulty plugin

<rst>RU::002-API::009-API видео чатов</rst> <rst>Header: API видео чатов</rst> ====== Вступление ====== Можно выделить два подхода к организации видео чатов на базе webRTC. Первый это передача сигнала от каждого участника конференции каждому. {{ :comet:video:full-mesh.png?direct |}} В такой конфигурации нет нужды в центральном сервере и её просто реализовать, но в тех случаях когда участники находятся за NAT надо всё равно трафик проксировать через turn сервер. ( [[https://toster.ru/q/138501#answer_399519|Ответ на toster о преодолении NAT]] ) Но есть ещё проблема в том что много человек в такую конференцию не добавить так как с каждым новым участником будет увеличиваться объём трафика. Так как для конференции на 5 человек вам надо будет отправлять свой поток четверым собеседниками. И получать четыре видео потока от них чтоб видеть всех сразу. В такой ситуации можно перейти к другому подходу. Когда все абоненты посылают свой сигнал на центральный сервер, а тот в свою очередь посылает каждому абоненту один результирующий видео поток. (Именно так и реализовано Video API в CppComet) {{ :comet:video:active_ring_topology.png?direct |}} Минусом такой схемы будет необходимость наличия центрального сервера. И ощутимая на него нагрузка. Но за то это открывает ряд возможностей. * Больше участников в конференции * Возможность записи конференции сервером в видео файл * Меньше нагрузка на сеть у каждого из участников * Возможности по управлению аудио и видео потоками средствами медиа сервера (можно API запросами к серверу отключать/включать видео и звук у отдельных пользователей, определять кого видят остальные пользователи, контролировать длительность разговора, отключать отдельных абонентов и многое другое) ====== Video API ====== В комет сервер встроена интеграция с FreeSwitch упрощающая создание видио конференций и видео чатов. (С возможностью использовать всё это в режиме кластера) Есть возможность совершать: * Видео/Аудио звонки (По WebRTC) * Видео/Аудио конференции на несколько участников (По WebRTC) * Видео трансляции для стриминга один ко многим (По WebRTC отправка видео от того кто видео поток публикует и доставка зрителям в форматах hls и mpeg-dash с задержкой от 5 секунд (теоретически минимально возможная задержка для hls потока) до 20 - 40 секунд в зависимости от конфигурации ретрансляторов и настроек качества) <note important>Если обнаружатся проблемы в настройке или в работе или пробелы в документации не стесняйтесь [[https://gitter.im/CppComet/Lobby|задавать вопросы]] и [[https://github.com/CppComet/comet-server/issues|писать баг репорты.]]</note> ====== Демо видео конференций ====== {{ :comet:video:video-demo-4.gif?direct |}} Ещё несколько более длинных gif анимаций * [[https://comet-server.com/wiki/lib/exe/fetch.php/comet:video:video-demo-1.gif|gif demo 1]] * [[https://comet-server.com/wiki/lib/exe/fetch.php/comet:video:video-demo-3.gif|gif demo 2]] * [[https://comet-server.com/wiki/lib/exe/fetch.php/comet:video:video-demo-5.gif|gif demo 3]] [[https://codepen.io/Levhav/pen/MooOzd/|Онлайн демо]] <html> <p data-height="700" data-theme-id="0" data-slug-hash="MooOzd" data-default-tab="result" data-user="Levhav" data-embed-version="2" data-pen-title="CppComet video chat example" class="codepen">See the Pen <a href="https://codepen.io/Levhav/pen/MooOzd/">CppComet video chat example</a> by Trapenok Victor (<a href="https://codepen.io/Levhav">@Levhav</a>) on <a href="https://codepen.io">CodePen</a>.</p> <script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script> </html> ====== Концепция API видео чатов ====== {{ :comet:video:video-api.gif |Comet Video API}} * Для работы видео чатов комет сервер использует возможности FreeSwitch просто взаимодействуя с ним по АПИ. * Комет сервер в состоянии распределять видео и аудио звонки по множеству серверов с FreeSwitch. * Работа с FreeSwitch полностью скрывается за апи комет сервера. ====== CometQL API ====== В CometQL добавлена таблица conference которая содержит информацию о активных конференциях. Чтобы создать новую конференцию и добавить в неё участника надо выполнить запрос <code sql> INSERT INTO conference (name, user_id, caller_id, message, profile)VALUES('1', 2, 2, "", "video"); </code> Тут параметры: * name - имя конференции (состоит только из цифр) * user_id - идентификатор добавляемого в конференцию пользователя * caller_id - идентификатор того пользователя который иницирует звонок (не обязательный параметр) * message - произвольное сообщение * profile - режим звонка возможны варианты "audio", "video" (В open source версии и по запросу в поддержку в saas версии можно создавать свои режимы видео конференций чтоб добавлять водяные знаки, показывать не просто говорящего в данный момет участника конференции, а всех сразу или настраивать правила показа участников конференции на общем холсте. Все возможности перечислены в документации на [[https://freeswitch.org/confluence/display/FREESWITCH/mod_conference|mod_conference]]) Чтоб добавить ещё одного участника надо выполнить такой же запрос только передать новый user_id и старый name. Соответственно создание конференции из 5 участников потребует 5 запросов вставки в таблицу conference Пример можно смотреть в файле [[https://github.com/CppComet/video-chat-example|call.php]] ====== JavaScript API ====== В js надо подключить файл [[https://github.com/CppComet/comet-server/tree/master/api|cometVideoApi.js]] и библиотеку [[https://github.com/CppComet/comet-server/blob/alfa/api/jssip.js|JsSIP v2.0.6]] после чего для обработки событий входящего звонка, подключения и отключения надо выполнить следующий код <code JavaScript> // Иницируем активацию cometVideoApi cometVideoApi.start({ // Колбек вызываемый перед началом подключения для звонка // Предполагается что в нём будут заданы настройки для близжайшего звонка // Такие как и параметры audio_remote, video_local, video_remote и возможно ещё какието. // А потом будет вызвана функция cometVideoApi.acceptCall(event) // А если не будет вызвана то значит мы не взяли трубку. onCall:function(callEvent) { $(".status").html("Входящий звонок, нажмите ответить."); if(!confirm("Ответить на вызов?")) { // Решили не отвечать на звонок $(".status").html("Решили не отвечать на звонок."); $(".StartCallBtn").show(); return } // Берём трубку если хотим cometVideoApi.acceptCall({ // Тип звонка 'audio' | 'video' type:'video', // Указываем целевой элемент для видео потока от собеседника video_remote: $("#video_remote")[0], // Указываем целевой элемент для аудио потока от собеседника audio_remote: $("#audio_remote")[0], // Указываем целевой элемент для видео потока от меня (моё собственное изображение из камеры) video_local: $("#video_local")[0], }) $(".status").html("Ожидаем ответа от других участников конференции"); }, /** * Колбек завершения звонка * @param {object} event * { * action:"", // Имя события * status:"", // Статус причины завершения звонка * callInfo:{}, // Информация о звонке * time:1000 // Время длительность звонка * type:"audio" // Тип вызова * } */ onCallEnd:function(event) { $(".root").removeClass("incall") $(".StartCallBtn").show(); $(".status").html("Вызов завершён"); log("onCallEnd", event) }, /** * Колбек поднятия трубки собеседником * @param {object} event * { * action:"accept", // Имя события * callInfo:{}, // Информация о звонке * type:"audio" // Тип вызова который выбран собеседником * } * * Колбек вызывается только один раз для первого ответившего собеседника */ onCallAccept: function(event) { $(".status").html("Получен ответ от другого участника конференции."); log("onAccept", event) }, /** * Колбек когда я и мой собеседник подключились к серверу * @param {object} event * { * action:"start", // Имя события * callInfo:{}, // Информация о звонке * type:"audio" // Тип вызова * } */ onCallStart: function(event) { $(".status").html("Подключение к медиасерверу выполнено. Разговор начался."); $(".root").addClass("incall") log("onCallStart", event) }, onOut: function(event) { // Выход участника из конференции $(".status").html("Один из собеседников покинул конференцию"); log("onOut", event) }, onIn: function(event) { // Вход участника в конференцию $(".status").html("К конференции присоединился ещё один человек."); log("onIn", event) }, }) </code> ====== Настройка бэкенда для видео звонков ====== <note important>Дальнейшие инструкции по настройке комет сервера и сопутствующего ПО нужны только для пользователей Open Source версии, в SaaS версии уже всё настроено</note> ===== Настройка comet.ini ===== Секция [freeswitch] в comet.ini поднимает на указанном порту и ip адресе http интерфейс который отвечает за механизм единой с freeswitch авторизации пользователей. <code ini> [freeswitch] ip = 0.0.0.0 thread_num = 3 statistics = 10 port = 84 </code> <note important>Важно что этот интерфейс не должен быть доступен из внешнй сети. На данный момент в реализована поддержка авторизации (планируется в следующих релизах) и соответственно во избежание утечки данных авторизации надо разрешить доступ к этому порту только доверенным ip адресам с вашими серверами FreeSwitch. Ограничить доступ можно средствами фаервола. </note> Секция [sip] содержит список адресов и портов серверов freeswitch которые готовы обрабатывать видео и аудио звонки. <code ini> [sip] port = 7443 host = ecort-n1.comet.su ; pipesalt = pipeSecretSalt </code> ===== Сборка FreeSwitch из исходников с нужными модулями ===== Нужно собрать FreeSwitch по инструкции [[https://freeswitch.org/confluence/display/FREESWITCH/Debian+8+Jessie#Debian8Jessie-BuildingFromSource|FreeSwitch Building from source]] Затем включить в сборку и в автозагрузку следующие модули * [[https://freeswitch.org/confluence/display/FREESWITCH/RTMP+Configuration+Files|mod_rtmp]] - позволит вести трансляции видео звонков и конференций * [[https://freeswitch.org/confluence/display/FREESWITCH/mod_xml_curl|mod_xml_curl]] - позволит FreeSwitch серверу использовать те же данные авторизации что имеются в комет сервере в таблице users_auth * mod_av * mod_sndfile * mod_shell_stream * mod_ilbc * mod_h26x * mod_siren * mod_isac Итоговый скрипт для сборки с нужными модулями <code bash> wget -O - https://files.freeswitch.org/repo/deb/debian/freeswitch_archive_g0.pub | apt-key add - echo "deb http://files.freeswitch.org/repo/deb/freeswitch-1.6/ jessie main" > /etc/apt/sources.list.d/freeswitch.list apt-get update apt-get install -y --force-yes freeswitch-video-deps-most # because we're in a branch that will go through many rebases it's # better to set this one, or you'll get CONFLICTS when pulling (update) git config --global pull.rebase true # then let's get the source. Use the -b flag to get a specific branch cd /usr/src/ git clone https://freeswitch.org/stash/scm/fs/freeswitch.git -bv1.6 freeswitch cd freeswitch ./bootstrap.sh -j sed -e "s/#codecs\/mod_isac/codecs\/mod_isac/g" /usr/src/freeswitch/modules.conf | sed -e "s/#applications\/mod_av/applications\/mod_av/g" | sed -e "s/#endpoints\/mod_rtmp/endpoints\/mod_rtmp/g" | sed -e "s/#xml_int\/mod_xml_curl/xml_int\/mod_xml_curl/g" | sed -e "s/#applications\/mod_av/applications\/mod_av/g"| sed -e "s/#formats\/mod_sndfile/formats\/mod_sndfile/g" | sed -e "s/#formats\/mod_shell_stream/formats\/mod_shell_stream/g" | sed -e "s/#codecs\/mod_ilbc/codecs\/mod_ilbc/g"| sed -e "s/#codecs\/mod_h26x/codecs\/mod_h26x/g" | sed -e "s/#codecs\/mod_siren/codecs\/mod_siren/g"| sed -e "s/#codecs\/mod_isac/codecs\/mod_isac/g" > /usr/src/freeswitch/modules.tmp cat /usr/src/freeswitch/modules.tmp > /usr/src/freeswitch/modules.conf rm -rf /usr/src/freeswitch/modules.tmp ./configure make make install # create user 'freeswitch' # add it to group 'freeswitch' # change owner and group of the freeswitch installation cd /usr/local groupadd freeswitch adduser --quiet --system --home /usr/local/freeswitch --gecos "FreeSWITCH open source softswitch" --ingroup freeswitch freeswitch --disabled-password chown -R freeswitch:freeswitch /usr/local/freeswitch/ chmod -R ug=rwX,o= /usr/local/freeswitch/ chmod -R u=rwx,g=rx /usr/local/freeswitch/bin/* sed -e "s/EnvironmentFile=-\/etc\/default\/freeswitch/EnvironmentFile=-\/etc\/freeswitch/g" /usr/src/freeswitch/debian/freeswitch-systemd.freeswitch.service | sed -e "s/PIDFile=\/run\/freeswitch\/freeswitch.pid/PIDFile=\/usr\/local\/freeswitch\/run\/freeswitch.pid/g" > /etc/systemd/system/freeswitch.service cp /usr/local/freeswitch/bin/freeswitch /usr/bin/freeswitch mkdir /run/freeswitch systemctl daemon-reload systemctl enable freeswitch </code> Потом надо выполнить инструкции [[https://freeswitch.org/confluence/display/FREESWITCH/Debian+Post-Install+Tasks|Debian+Post-Install+Tasks]] ===== Включение модулей в автозагрузку ===== Для включения в автозагрузку модулей надо убедится что в файле /usr/local/freeswitch/conf/autoload_configs/modules.conf.xml есть следующие строки <code xml> <load module="mod_av"/> <load module="mod_sndfile"/> <load module="mod_shell_stream"/> <load module="mod_rtmp"/> <load module="mod_xml_curl"/> <load module="mod_ilbc"/> <load module="mod_h26x"/> <load module="mod_siren"/> <load module="mod_isac"/> </code> ==== Настройка xml_curl.conf на freeswitch ==== В файле <code>/usr/local/freeswitch/conf/autoload_configs/xml_curl.conf.xml</code> надо вписать порт и адрес для подключения к комет серверу с реквизитами которые мы задали в секции [freeswitch] <code xml> <configuration name="xml_curl.conf" description="cURL XML Gateway">   <bindings>     <binding name="directory">       <param name="gateway-url" value="http://app.comet-server.ru:84/directory" bindings="directory"/>       <param name="method" value="GET" />     </binding>    </bindings> </configuration> </code> Эта настройка отвечает за то что бы пользователи которые авторизованы на комет сервере могли по тем же данным авторизации подключится к freeswitch для совершения звонка. Подробности по работе модуля тут [[https://freeswitch.org/confluence/display/FREESWITCH/mod_xml_curl+PHP+example|mod_xml_curl]] ==== Настройка conference.conf.xml на freeswitch ==== Для настройки разных профилей работы видео конференций надо отредактировать файл /usr/local/freeswitch/conf/autoload_configs/conference.conf.xml Документация на [[https://freeswitch.org/confluence/display/FREESWITCH/mod_conference|mod_conference]] настройки по умолчанию годятся. Если хотите транслировать конференцию зрителям по rtmp то в настройки профиля конференции можно вписать команду: <code> <param name="auto-record" value="rtmp://comet.su/cam1/${conference_name}"/> </code> С указанием вашего nginx c nginx-rtmp-module ==== Настройка dialplan/default.xml на freeswitch ==== Файл /usr/local/freeswitch/conf/dialplan/default.xml содержит планы набора номеров. Он используется для определения что надо делать при звонке на конкретные номера. В секцию <code xml><context name="default"></code> надо добавить extension для набора видео конференции <code xml> <extension name="comet_conferences"> <condition field="destination_number" expression="^([0-9]{1,9}\*[0-9A-z\-_]+)\*([0-9A-z\-_]+)$"> <!-- Надо проверить что номер абонента начинается на такие же 6 первых цифр что и номер конференции --> <!-- Надо проверить что у абонента есть доступ к конференции --> <action application="set" data="absolute_codec_string=PCMU,GSM"/> <action application="answer"/> <action application="conference" data="$1-${domain_name}@$2"/> </condition> </extension> </code> ==== Настройка vars.xml на freeswitch ==== Полезно в vars.xml задать стойкий пароль в строке, он будет использоваться комет сервером для api вызовов. <code xml> <X-PRE-PROCESS cmd="set" data="default_password=1234"/> </code> И надо установить переменную domain=FSdefaultDomain <code xml> <X-PRE-PROCESS cmd="set" data="domain=FSdefaultDomain"/> </code> ==== Настройка event_socket.conf на freeswitch ==== В event_socket.conf настраиваем на каком порту и с каким паролем freeswitch будет позволять подключиться для выполнения api команд. <code xml> <configuration name="event_socket.conf" description="Socket Client"> <settings> <param name="nat-map" value="false"/> <param name="listen-ip" value="0.0.0.0"/> <param name="listen-port" value="8021"/> <param name="password" value="MyPassword"/> <param name="apply-inbound-acl" value="0.0.0.0/32"/> </settings> </configuration> </code> ==== Настройка https на freeswitch ==== Обычно после установки freeswitch в папке <code>/usr/local/freeswitch/certs/wss.pem</code> лежит само-подписанный сертификат. Для работы видео и аудио чатов их надо заменить на валидные так как иначе с https сайта не получится подключится к freeswitch по websockets для обмена sip командами с freeswitch Для получения сертификатов удобно использовать Let's Encrypt. Я использую [[https://habrahabr.ru/post/318952/|эту инструкцию]] А в качестве post-hook для обновления сертификата такую команду: <code bash> cat /etc/letsencrypt/live/fs-n3.elevenow.com/fullchain.pem > /usr/local/freeswitch/certs/wss.pem && cat /etc/letsencrypt/live/fs-n3.elevenow.com/privkey.pem >> /usr/local/freeswitch/certs/wss.pem && cat /etc/letsencrypt/live/fs-n3.elevenow.com/fullchain.pem > /usr/local/freeswitch/certs/dtls-srtp.pem && cat /etc/letsencrypt/live/fs-n3.elevenow.com/privkey.pem >> /usr/local/freeswitch/certs/dtls-srtp.pem && systemctl stop freeswitch && rm -rf /var/lib/freeswitch/db && systemctl start freeswitch </code> ======Настройка трансляций в nginx ===== Для трансляций надо собрать nginx с модулем nginx-rtmp-module вот [[https://www.dmosk.ru/instruktions.php?object=nginx-rtmp#build|неплохая инструкция]] Вот пример конфигурации nginx <code> worker_processes 1; rtmp { server { live on; listen 1935; chunk_size 512; buflen 1s; idle_streams off; application cam1 { live on; record off; hls on; hls_path /tmp/hls; hls_fragment 2s; hls_playlist_length 20s; hls_type live; #hls_continuous on; hls_fragment_naming sequential; hls_nested on; dash on; dash_path /tmp/dash; dash_fragment 2s; dash_playlist_length 10s; dash_nested on; } } } server { listen 80 default_server; listen [::]:80 default_server; root /var/www/html; index index.html index.htm index.nginx-debian.html; server_name _; include acme; location /dash { root /tmp; add_header Access-Control-Allow-Origin *; add_header Cache-Control no-cache; } location / { add_header Cache-Control no-cache; add_header Access-Control-Allow-Origin *; root /tmp; } } server { listen 0.0.0.0:443; server_name comet-server.com; ssl on; ssl_certificate /etc/letsencrypt/live/stream-n1.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/stream-n1.example.com/privkey.pem; ssl_session_timeout 70m; keepalive_disable none; lingering_close always; send_timeout 3600s; client_max_body_size 100m; include acme; location /dash { root /tmp; add_header Access-Control-Allow-Origin *; add_header Cache-Control no-cache; } location / { add_header Cache-Control no-cache; add_header Access-Control-Allow-Origin *; root /tmp; } } </code> Полезными могут быть статьи * https://github.com/arut/nginx-rtmp-module/wiki/Directives * https://habrahabr.ru/post/162237/#workers

Обсуждение

Ваш комментарий. Вики-синтаксис разрешён:
E F X O L