...
Объявление конфигурации комнаты и публикации потоков по умолчанию, на случай, если нет файла конфигурации config.json
code
Клиент настраивается на соединение с сервером по WSS по адресу localhost для входа в комнату "ROOM1" с пин-кодом "1234" под именем "Alice". Секция media задает публикацию аудио и видео дорожек. Видео публикуется двумя дорожками с качествами high (h) и medium (m)
Code Block |
---|
|
const defaultConfig = {
room: {
url: "wss://127.0.0.1:8888",
name: "ROOM1",
pin: "1234",
nickName: "Alice"
},
media: {
audio: {
tracks: [
{
source: "mic",
channels: 1
}
]
},
video: {
tracks: [
{
source: "camera",
width: 1280,
height: 720,
codec: "H264",
encodings: [
{ rid: "mh", active: true, maxBitrate: 300000, scaleResolutionDownBy:900000 2},
{ rid: "hm", active: true, maxBitrate: 900000 300000, scaleResolutionDownBy: 2 }
]
}
]
}
}
}; |
Отметим, что, начиная со сборки 2.0.248, качества должны быть перечислены по возрастанию
3. Инициализация
init() code
Функция init() вызывается после того, как страница загрузится. Функция загружает config.json или конфигурацию по умолчанию, создает элемент для отображения локального видео и открывает модальное окно входа
Code Block |
---|
|
/**
* Loadload track configurationconfig and show entrance modal
*/
const init = function () {
//read config
$.getJSON("config.json", function (config) {
cControls = createControls(config);
}).fail(function () {
//use default config
cControls = createControls(defaultConfig);
});
//create local display to show local streams
localDisplay = initLocalDisplay(document.getElementById("localDisplay"));
//open entrance modal
$('#entranceModal').modal('show');
} |
4. Соединение с сервером и создание либо вход в комнату
connect() code
Функция вызывается по щелчку пользователя по кнопке Enter в модальном окне входа
Code Block |
---|
|
/**
* Connectconnect to server and publish preconfigured streams
*/
async function connect() {
// hide modal
$('#entranceModal').modal('hide');
// disable controls
cControls.muteInput();
//create peer connection
const pc = new RTCPeerConnection();
//get config object for room creation
const roomConfig = cControls.roomConfig();
//kick off connect roomConfig.pc = pc;
//kick off connect to server and local room creation
try {
const session = await sfu.createRoom(roomConfig);
session.on(constants.SFU_EVENT.CONNECTED, function(room) {
// Now we //connected to the server
(if no exception was thrown)
const chatDiv = sessiondocument.on(constants.SFU_EVENT.FAILED, function (e) {getElementById('messages');
const chatInput if (e.status && e.statusText) {
= document.getElementById('localMessage');
const chatButton = document.getElementById('sendMessage');
displayError("CONNECTION FAILED: " + e.status + " " + e.statusText);//create and bind chat to the new room
createChat(room, chatDiv, } else if (e.type && e.info) {chatInput, chatButton);
room.on(constants.SFU_ROOM_EVENT.FAILED, function(e) {
displayError("CONNECTION FAILED: " + e.info const errField = document.getElementById("errorMsg");
} else {
errField.style.color = "red";
errField.innerText = e;
displayError("CONNECTION FAILED: " + e);
}
}).on(constants.SFU_ROOM_EVENT.DISCONNECTEDOPERATION_FAILED, function (e) {
displayError("DISCONNECTED. Refresh the page to enter the room againconst errField = document.getElementById("errorMsg");
});
errField.style.color = "red";
const room = session.room();
room.on(constants.SFU_ROOM_EVENT.FAILED, function (e) {
errField.innerText = e.operation + " failed: " + e.error;
displayError(e});
}).on(constants.SFU_ROOM_EVENT.OPERATION_FAILED, function (e) {
//setup remote display for showing remote audio/video tracks
const displayError(e.operation + " failed: " + e.errorremoteDisplay = document.getElementById("display");
})initRemoteDisplay(room, remoteDisplay, pc);
//get createconfigured local display to show local video streams
let localDisplaystreams = initLocalDisplay(documentcControls.getElementByIdgetVideoStreams("localDisplay"));
//combine displaylocal audiovideo andstreams videowith controlaudio tablesstreams
awaitstreams.push.apply(streams, cControls.displayTablesgetAudioStreams());
cControls.onTrack(async function (s) {
//add our local streams to the room (to PeerConnection)
await publishNewTrack(room, pc, s);
streams.forEach(function (s) {
});
//createadd andlocal bind chatstream to thelocal newdisplay
room
const chatDiv = documentlocalDisplay.getElementById('messages'add(s.stream.id, "local", s.stream);
const chatInput = document.getElementById('localMessage'); //add each track to PeerConnection
const chatButton = document.getElementById('sendMessage');
s.stream.getTracks().forEach((track) => {
createChat(room, chatDiv, chatInput, chatButton);
addTrackToPeerConnection(pc, s.stream, track, s.encodings);
//setup remote display for showing remote audio/video tracks
subscribeTrackToEndedEvent(room, track, pc);
const remoteDisplay = document.getElementById("display" });
initDefaultRemoteDisplay(room, remoteDisplay, {quality: true},{thresholds: [
});
//add callback for the new local stream to the local controls
{parameter: "nackCount", maxLeap: 10},
cControls.onTrack(function (s) {
{parameter: "freezeCount", maxLeap: 10},
//add local stream to local display
{parameter: "packetsLost", maxLeap: 10}
localDisplay.add(s.stream.id, "local", s.stream);
//add each ],track abrKeepOnGoodQuality: ABR_KEEP_ON_QUALITY, abrTryForUpperQuality: ABR_TRY_UPPER_QUALITY, interval: ABR_QUALITY_CHECK_PERIOD});
//get configured local video streams
to PeerConnection
s.stream.getTracks().forEach((track) => {
let streams = cControls.getVideoStreams(addTrackToPeerConnection(pc, s.stream, track, s.encodings);
//combine local video streams with audio streams
streams.push.apply(streams, cControls.getAudioStreams()subscribeTrackToEndedEvent(room, track, pc);
// Publish preconfigured streams});
publishPreconfiguredStreams(room, pc, streams);
//kickoff renegotiation
} catch (e) {
consoleroom.errorupdateState(e);
displayError(e});
//join room
room.join();
});
} |
5. Подробнее о функции connect()
Скрытие модального окна входа и отключение полей ввода до установки соединения с сервером
code
Code Block |
---|
|
//hide modal
$('#entranceModal').modal('hide');
//disable controls
cControls.muteInput(); |
Создание объекта PeerConnection и подготовка объекта конфигурации комнаты
code
Code Block |
---|
|
//create peer connection
const pc = new RTCPeerConnection();
//get config object for room creation
const roomConfig = cControls.roomConfig();
roomConfig.pc = pc; |
Создание сессии и установка соединения с сервером
code
Code Block |
---|
|
const session = await sfu.createRoom(roomConfig); |
Подписка на события событие сессии "CONNECTED"
code
Code Block |
---|
|
session.on(constants.SFU_EVENT.FAILEDCONNECTED, function (eroom) {
if (e.status && e.statusText) {
|
Инициализация чата после установки соединения
code
Code Block |
---|
|
//connected to server
const chatDiv = document.getElementById('messages');
const chatInput = document.getElementById('localMessage');
const chatButton = document.getElementById('sendMessage');
//create and bind chat to the new room
createChat(room, chatDiv, chatInput, chatButton); |
Подписка на сообщения об ошибках комнаты
code
Code Block |
---|
|
room.on(constants.SFU_ROOM_EVENT.FAILED, function(e) {
const errField = document.getElementById("errorMsg");
errField.style.color = "red";
errField.innerText = e;
}).on(constants.SFU_ROOM_EVENT.OPERATION_FAILED, function (e) {
const errField = document.getElementById("errorMsg");
errField.style.color = "red";
errField.innerText = e.operation + " failed: " + e.error;
}) |
Инициализация объекта для отображения потоков от других участников
code
Code Block |
---|
|
//setup remote display for showing remote audio/video tracks
const remoteDisplay = document.getElementById("display");
initRemoteDisplay(room, remoteDisplay, pc); |
Получение настроек публикации локального медиа
code
Code Block |
---|
|
//get configured local video streams
let streams = cControls.getVideoStreams();
//combine local video streams with audio streams
streams.push.apply(streams, cControls.getAudioStreams()); |
Добавление каждого потока в объект localDisplay для отображения и в объект PeerConnection для публикации
code
Code Block |
---|
|
//add our local streams to the room displayError("CONNECTION FAILED: " + e.status + " " + e.statusText);
to PeerConnection)
} else if (e.type && e.infostreams.forEach(function (s) {
//add local stream to displayError("CONNECTION FAILED: " + e.info);local display
} else {
localDisplay.add(s.stream.id, "local", s.stream);
displayError("CONNECTION FAILED: " + e);//add each track to PeerConnection
}
s.stream.getTracks().forEach((track) => {
}).on(constants.SFU_EVENT.DISCONNECTED, function (e) {
if displayError("DISCONNECTED. Refresh the page to enter the room again");
(s.source === "screen") {
}); |
Создание объекта комнаты и подписка на его события
code
Code Block |
---|
|
config[track.id] = s.source;
const room = session.room();
room.on(constants.SFU_ROOM_EVENT.FAILED, function (e) {}
displayError(eaddTrackToPeerConnection(pc, s.stream, track, s.encodings);
}).on(constants.SFU_ROOM_EVENT.OPERATION_FAILED, function (e) {
subscribeTrackToEndedEvent(room, track, pc);
displayError(e.operation + " failed: " + e.error});
}) |
...
Добавление слушателя, чтобы определить, когда клиент добавляет новые потоки для публикации. Получив новый поток, необходимо добавить его в localDisplay для отображения, добавить в PeerConnection для публикации и обновить состояние комнаты
code
Code Block |
---|
|
localDisplay = initLocalDisplay(document.getElementById("localDisplay"));
//add displaycallback audiofor andthe videonew controllocal tables
stream to the await cControls.displayTables();local controls
cControls.onTrack(async function (s) {
await publishNewTrack(room, pc, s);
let config = {};
}); |
Создание чата
code
Code Block |
---|
|
//add local stream to local constdisplay
chatDiv = document.getElementById('messages');
const chatInput = document.getElementById('localMessage' localDisplay.add(s.stream.id, "local", s.stream);
const chatButton = document.getElementById('sendMessage');
//add each track to PeerConnection
createChat(room, chatDiv, chatInput, chatButton); |
Инициализация объекта для отображения потоков от других участников
code
Code Block |
---|
|
s.stream.getTracks().forEach((track) => {
const remoteDisplay = document.getElementById("display");
if initDefaultRemoteDisplay(room, remoteDisplay, {quality: true},{thresholds: [s.source === "screen") {
{parameter: "nackCount", maxLeap: 10},
config[track.id] = s.source;
{parameter: "freezeCount", maxLeap: 10},
{parameter: "packetsLost", maxLeap: 10}addTrackToPeerConnection(pc, s.stream, track, s.encodings);
], abrKeepOnGoodQuality: ABR_KEEP_ON_QUALITY, abrTryForUpperQuality: ABR_TRY_UPPER_QUALITY, interval: ABR_QUALITY_CHECK_PERIOD}); |
Получение настроек публикации локального медиа и публикация треков согласно настройкам
code
Code Block |
---|
|
subscribeTrackToEndedEvent(room, track, pc);
let streams = cControls.getVideoStreams(});
//combine local video streams with audio streams
kickoff renegotiation
streams.push.apply(streams, cControls.getAudioStreams());
room.updateState(config);
}); |
Настройка WebRTC соединения в комнате
code
Code Block |
---|
|
//join Publish preconfigured streams
publishPreconfiguredStreams(room, pc, streams);room
room.join(pc, null, config); |
6. Завершение публикации потока
...