...
Поддерживаемые платформы и браузеры
Chrome | Firefox | Safari 11 | Chromium Edge | |
---|---|---|---|---|
Windows | + | + | + | |
Mac OS | + | + | + | |
Android | + | + | + | |
iOS |
-
+ (iOS 14.6+) | + (iOS 14.6+) | + |
Поддерживаемые кодеки
- Видео: H.264, VP8
- Аудио: Opus, G.711
...
Ниже описана последовательность вызовов при использовании примера Conference
1. Установка участником 1 соединения с сервером.
FlashphonerRoomApi.roomApi.connect(); code
Code Block | ||||
---|---|---|---|---|
| ||||
connection = Flashphoner.roomApiRoomApi.connect({urlServer: url, username: username}).on(SESSION_STATUS.FAILED, function(session){ setStatus('#status', session.status()); onLeft(); }).on(SESSION_STATUS.DISCONNECTED, function(session) { setStatus('#status', session.status()); onLeft(); }).on(SESSION_STATUS.ESTABLISHED, function(session) { setStatus('#status', session.status()); joinRoom(); }); |
...
ConnectionStatusEvent ESTABLISHED code
Code Block | ||||
---|---|---|---|---|
| ||||
connection = Flashphoner.roomApiRoomApi.connect({urlServer: url, username: username}).on(SESSION_STATUS.FAILED, function(session){ ... }).on(SESSION_STATUS.DISCONNECTED, function(session) { ... }).on(SESSION_STATUS.ESTABLISHED, function(session) { setStatus('#status', session.status()); joinRoom(); }); |
...
3. Вход в чат-комнату участника 1.
connection.join(); code
Code Block | ||||
---|---|---|---|---|
| ||||
connection.join({name: getRoomName()}).on(ROOM_EVENT.STATE, function(room){ ... }); |
...
4. Получение участником 1 от сервера события, описывающего состояние комнаты.
RoomStatusEvent STATE STATE code
Code Block | ||||
---|---|---|---|---|
| ||||
connection.join({name: getRoomName()}).on(ROOM_EVENT.STATE, function(room){ var participants = room.getParticipants(); console.log("Current number of participants in the room: " + participants.length); if (participants.length >= _participants) { console.warn("Current room is full"); $("#failedInfo").text("Current room is full."); room.leave().then(onLeft, onLeft); return false; } setInviteAddress(room.name()); if (participants.length > 0) { var chatState = "participants: "; for (var i = 0; i < participants.length; i++) { installParticipant(participants[i]); chatState += participants[i].name(); if (i != participants.length - 1) { chatState += ","; } } addMessage("chat", chatState); } else { addMessage("chat", " room is empty"); } publishLocalMedia(room); onJoined(room); ... }); |
...
5. Публикация медиапотока участником 1.
room.publish(); code
Code Block | ||||
---|---|---|---|---|
| ||||
room.publish({ display: display, constraints: constraints, record: false, receiveVideo: false, receiveAudio: false ... }); |
...
StreamStatusEvent PUBLISHING code
Code Block | ||||
---|---|---|---|---|
| ||||
room.publish({ display: display, constraints: constraints, record: false, receiveVideo: false, receiveAudio: false }).on(STREAM_STATUS.FAILED, function (stream) { ... }).on(STREAM_STATUS.PUBLISHING, function (stream) { setStatus("#localStatus", stream.status()); onMediaPublished(stream); }).on(STREAM_STATUS.UNPUBLISHED, function(stream) { ... }); |
...
12. Получение участником 1 от сервера события о присоединении участника 2.
RoomStatusEvent JOINED code
Code Block | ||||
---|---|---|---|---|
| ||||
connection.join({name: getRoomName()}).on(ROOM_EVENT.STATE, function(room){ ... }).on(ROOM_EVENT.JOINED, function(participant){ installParticipant(participant); addMessage(participant.name(), "joined"); }).on(ROOM_EVENT.LEFT, function(participant){ ... }).on(ROOM_EVENT.PUBLISHED, function(participant){ ... }).on(ROOM_EVENT.FAILED, function(room, info){ ... }).on(ROOM_EVENT.MESSAGE, function(message){ ... }); |
...
15. Получение участником 2 от сервера события, подтверждающегог подтверждающего успешную публикацию потока.
...
17. Выход участника 1 из чат-комнаты.
room.leave(); code
Code Block | ||||
---|---|---|---|---|
| ||||
function onJoined(room) { $("#joinBtn").text("Leave").off('click').click(function(){ $(this).prop('disabled', true); room.leave().then(onLeft, onLeft); }).prop('disabled', false); ... } |
...
18. Получение участниками комнаты от сервера события о выходе участника 1.
RoomStatusEvent LEFT code
Code Block | ||||
---|---|---|---|---|
| ||||
connection.join({name: getRoomName()}).on(ROOM_EVENT.STATE, function(room){ ... }).on(ROOM_EVENT.JOINED, function(participant){ ... }).on(ROOM_EVENT.LEFT, function(participant){ //remove participant removeParticipant(participant); addMessage(participant.name(), "left"); }).on(ROOM_EVENT.PUBLISHED, function(participant){ ... }).on(ROOM_EVENT.FAILED, function(room, info){ ... }).on(ROOM_EVENT.MESSAGE, function(message){ ... }); |
...
Воспроизведите файл output.mp4:
Запись потоков комнаты в один файл с последующим микшированием
В сборке WCS 5.2.1012 и сборке WebSDK 2.0.190 добавлена возможность записывать все потоки комнаты в один файл, с его автоматическим микшированием по окончании конференции. Для этого первый участник при создании комнаты должен указать опцию record:
Code Block | ||||
---|---|---|---|---|
| ||||
connection.join({
name: getRoomName(),
record: true
}).on(ROOM_EVENT.STATE, function(room){
...
}); |
В этом случае все потоки в комнате будут записаны в один файл. При завершении комнаты запись также будет завершена, и автоматически запустится скрипт, указанный в настройке
Code Block | ||
---|---|---|
| ||
on_multiple_record_hook_script=on_multiple_record_hook.sh |
который смикширует потоки в соответствии с настройками микшера, заданными в файле /usr/local/FlashphonerWebCallServer/conf/offline_mixer.json, по умолчанию
Code Block | ||||
---|---|---|---|---|
| ||||
{
"hasVideo": "true",
"hasAudio": "true",
"mixerDisplayStreamName": true
} |
Тестирование
1. Для теста используем:
- ваш WCS сервер, например test1.flashphoner.com;
- веб-приложение Conference
2. Откройте пример Conference в браузере, введите имя участника Alice и взведите переключатель Record
3. Нажмите Join. Начнется публикация потока
4. В другом окна браузера откройте ссылку из поля Invite
5. Введите имя пользователя Bob и нажмите Join
6. Bob присоединился к комнате
7. Нажмите Leave в окне пользователя Alice
и в окне пользователя Bob
8. Микширование может занять продолжительное время. в зависимости от длительности записи, производительности процессора и жесткого диска сервера. По его окончании, загрузите файл из каталога /usr/local/FlashphonerWebCallServer/records или откройте в браузере по ссылке
Завершение комнаты
Комната существует на сервере до тех пор, пока в ней есть хотя бы один участник. Когда последний участник вызывает функцию room.leave(), комната завершается.
Если последний участник обновляет страницу или теряет соединение с сервером без вызова функции room.leave(), комната остается активной в течение времени, заданного настройкой в миллисекундах
Code Block | ||
---|---|---|
| ||
room_idle_timeout=60000 |
По умолчанию, время составляет 60 секунд. По истечении этого времени, комната завершается.
Известные проблемы
1. При обмене текстовыми сообщениями необходимо кодирование не-латинских символов
Симптомы: при отправке сообщения, содержащего не-латинские символы, эти символы преобразуются в знаки вопроса при получении
Решение: использовать функции JavaScript encodeURIComponent() при отправке сообщения
Code Block | ||||
---|---|---|---|---|
| ||||
var participants = room.getParticipants();
for (var i = 0; i < participants.length; i++) {
participants[i].sendMessage(encodeURIComponent(message));
} |
и decodeURIComponent() при его получении
Code Block | ||||
---|---|---|---|---|
| ||||
...
}).on(ROOM_EVENT.MESSAGE, function(message){
addMessage(message.from.name(), decodeURIComponent(message.text));
});
... |
2. При быстром вызове connection.join() и затем room.leave() возможна отправка серверу команды join, в то время как сервер еще не обработал предыдущую команду leave для этого пользователя
Симптомы: при вызове connection.join() сразу после room.leave() клиент получает сообщение
Code Block | ||
---|---|---|
| ||
Room already has user with such login |
Решение: использовать интервал не менее 1 секунды между последовательными вызовами room.leave() и connection.join()