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;
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)
},
})
====== Настройка бэкенда для видео звонков ======
[freeswitch]
ip = 0.0.0.0
thread_num = 3
statistics = 10
port = 84
[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