RU::002-API::009-API видео чатов Header: API видео чатов ====== Comet Video API - Вступление ====== Ссылка на [[https://codepen.io/Levhav/pen/MooOzd/|онлайн демо]] для нетерпеливых ---- Можно выделить два подхода к организации видео чатов на базе 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 секунд в зависимости от конфигурации ретрансляторов и настроек качества) Если обнаружатся проблемы в настройке или в работе или пробелы в документации, не стесняйтесь [[https://gitter.im/CppComet/Lobby|задавать вопросы]] и [[https://github.com/CppComet/comet-server/issues|писать баг репорты.]] ====== Демо видео конференций ====== {{ :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/|Онлайн демо]]

See the Pen CppComet video chat example by Trapenok Victor (@Levhav) on CodePen.

====== Концепция API видео чатов ====== {{ :comet:video:video-api.gif |Comet Video API}} * Для работы видео чатов комет сервер использует возможности FreeSwitch просто взаимодействуя с ним по АПИ. * Комет сервер в состоянии распределять видео и аудио звонки по множеству серверов с FreeSwitch. * Работа с FreeSwitch полностью скрывается за апи комет сервера. ====== CometQL API ====== В CometQL добавлена таблица conference, которая содержит информацию о активных конференциях. Чтобы создать новую конференцию и добавить в неё участника, надо выполнить запрос INSERT INTO conference (name, user_id, caller_id, message, profile)VALUES('1', 2, 2, "", "video"); Тут параметры: * 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]] Выборка данных из таблицы conference select * from `conference` where name = "101"; Удаление данных из таблицы conference delete from `conference` where name = "101" and user_id = 29130; В запросах оператор `and` работает в ограниченном режиме. Он работает только для таблиц `conference` и `conference_members` только для запроса `delete` и только с полями `name` и `user_id` Полноценная поддержка оператора `and` в синтаксисе запросов будет реализована позже, так как и без него есть куда более важные задачи и работе отсутствие оператора end не мешает. Запрос выборки из таблицы `conference` только покажет, кому были отправлены приглашения в конференцию. select * from `conference` where name = "101"; Вовсе не факт, что все эти люди до сих пор в этой конференции находятся. Чтобы узнать, кто разговаривает в данный момент надо сделать запрос к таблице `conference_members` select * from `conference_members` В данный момент таблица `conference_members` доступна только для чтения и содержит такие поля * name - имя конференции * user_id - идентификатор пользователя * join_time - количество секунд прошедшее с момента подключения пользователя * last_talking - количество секунд прошедшее с того момента, когда он что-то говорил в конференции. ====== 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]] после чего для обработки событий входящего звонка, подключения и отключения надо выполнить следующий код // Иницируем активацию 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) }, }) ====== Настройка бэкенда для видео звонков ====== Дальнейшие инструкции по настройке комет сервера и сопутствующего ПО нужны только для пользователей Open Source версии, в SaaS версии уже всё настроено ===== Настройка comet.ini ===== Секция [freeswitch] в comet.ini поднимает на указанном порту и ip адресе http интерфейс который отвечает за механизм единой с freeswitch авторизации пользователей. [freeswitch] ip = 0.0.0.0 thread_num = 3 statistics = 10 port = 84 Важно что этот интерфейс не должен быть доступен из внешнй сети. На данный момент не реализована поддержка авторизации (планируется в следующих релизах) и соответственно во избежание утечки данных авторизации надо разрешить доступ к этому порту только доверенным ip адресам с вашими серверами FreeSwitch. Ограничить доступ можно средствами фаервола. Секция [sip] содержит список адресов и портов серверов freeswitch которые готовы обрабатывать видео и аудио звонки. [sip] port = 7443 host = ecort-n1.comet.su ; pipesalt = pipeSecretSalt ===== Настройка FreeSwitch ===== Есть [[https://hub.docker.com/r/cppcomet/freeswitch-video/|docker образ]] с нужными настройками для работы FreeSwitch с комет сервером. Скачать образ docker pull cppcomet/freeswitch-video Запустить docker run -v /root/FreeSwitch-in-docker/conf:/usr/local/freeswitch/conf -v /root/FreeSwitch-in-docker/certs:/usr/local/freeswitch/certs --net host -it cppcomet/freeswitch-video Нужно указать доступ к ssl сертификату и папке с файлами конфигурации. ===== Сборка 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 Итоговый скрипт для сборки с нужными модулями 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 Потом надо выполнить инструкции [[https://freeswitch.org/confluence/display/FREESWITCH/Debian+Post-Install+Tasks|Debian+Post-Install+Tasks]] ===== Включение модулей в автозагрузку ===== Для включения в автозагрузку модулей надо убедится, что в файле /usr/local/freeswitch/conf/autoload_configs/modules.conf.xml есть следующие строки ==== Настройка xml_curl.conf на freeswitch ==== В файле /usr/local/freeswitch/conf/autoload_configs/xml_curl.conf.xml надо вписать порт и адрес для подключения к комет серверу с реквизитами, которые мы задали в секции [freeswitch]                                Эта настройка отвечает за то, чтобы пользователи, которые авторизованы на комет сервере могли по тем же данным авторизации подключится к 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 то в настройки профиля конференции можно вписать команду: С указанием вашего nginx c nginx-rtmp-module ==== Настройка dialplan/default.xml на freeswitch ==== Файл /usr/local/freeswitch/conf/dialplan/default.xml содержит планы набора номеров. Он используется для определения что надо делать при звонке на конкретные номера. В секцию надо добавить extension для набора видео конференции ==== Настройка vars.xml на freeswitch ==== Полезно в vars.xml задать стойкий пароль в строке, он будет использоваться комет сервером для api вызовов. И надо установить переменную domain=FSdefaultDomain ==== Настройка event_socket.conf на freeswitch ==== В event_socket.conf настраиваем на каком порту и с каким паролем freeswitch будет позволять подключиться для выполнения api команд. ==== Настройка https на freeswitch ==== Обычно после установки freeswitch в папке /usr/local/freeswitch/certs/wss.pem лежит само-подписанный сертификат. Для работы видео и аудио чатов их надо заменить на валидные так как иначе с https сайта не получится подключится к freeswitch по websockets для обмена sip командами с freeswitch Для получения сертификатов удобно использовать Let's Encrypt. Я использую [[https://habrahabr.ru/post/318952/|эту инструкцию]] А в качестве post-hook для обновления сертификата такую команду: 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 ======Настройка трансляций в nginx ===== Для трансляций надо собрать nginx с модулем nginx-rtmp-module вот [[https://www.dmosk.ru/instruktions.php?object=nginx-rtmp#build|неплохая инструкция]] Вот пример конфигурации nginx 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; } } Полезными могут быть статьи * https://github.com/arut/nginx-rtmp-module/wiki/Directives * https://habrahabr.ru/post/162237/#workers