Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

Пример видеочата с отображением экрана

Данный пример может использоваться для видеочата между двумя участниками на Web Call Server с отображением экрана одного из участников.
Участник видеочата может публиковать следующие типы потоков

  • WebRTC
  • RTMFP
  • RTMP

Пример окна клиента, публикующего свой экран в браузере Chrome:


Пример окна клиента, получающего поток с экрана в браузере Chrome


Настройка расширения для публикации экрана браузера Chrome описана в примере Screen Sharing.

Код примера

Код данного примера находится на WCS-сервере по следующему пути:

/usr/local/FlashphonerWebCallServer/client2/examples/demo/streaming/video-chat-and-screen-sharing/

video-chat.css - файл стилей
video-chat-and-screen-sharing.html - страница участника чата
video-chat-and-screen-sharing.js - скрипт, обеспечивающий работу чата

Тестировать данный пример можно по следующему адресу:

https://host:8888/client2/examples/demo/streaming/video-chat-and-screen-sharing/video-chat-and-screen-sharing.html

Здесь host - адрес WCS-сервера.

Работа с кодом примера

Для разбора кода возьмем версию файла video-chat-and-screen-sharing.js с хешем c306c1bbf49bfcbd8e24be927ae95f63b7dbaaba, которая находится здесь и доступна для скачивания в соответствующей сборке 0.5.28.2747.

1. Инициализация API.

Flashphoner.init() код

Flashphoner.init({
flashMediaProviderSwfLocation: '../../../../media-provider.swf',
screenSharingExtensionId: extensionId
});


2. Подключение к серверу.

Flashphoner.roomApi.connect() код

connection = Flashphoner.roomApi.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();
});


3. Получение от сервера события, подтверждающего успешное соединение

ConnectionStatusEvent ESTABLISHED код

connection = Flashphoner.roomApi.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();
});


4. Присоединение к комнате.

connection.join() код

При присоединении передается имя "комнаты" конференции (берется из параметра в URL страницы клиента, или генерируется случайное имя).

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;
}
room_ = room;
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);
}).on(ROOM_EVENT.JOINED, function(participant){
installParticipant(participant);
addMessage(participant.name(), "joined");
}).on(ROOM_EVENT.LEFT, function(participant){
//remove participant
removeParticipant(participant);
addMessage(participant.name(), "left");
}).on(ROOM_EVENT.PUBLISHED, function(participant){
playParticipantsStream(participant);
}).on(ROOM_EVENT.FAILED, function(room, info){
connection.disconnect();
$('#failedInfo').text(info);
}).on(ROOM_EVENT.MESSAGE, function(message){
addMessage(message.from.name(), message.text);
});


5. Получение от сервера события, описывающего статус комнаты

RoomStatusEvent STATE код

При получении данного события:

  • определяется количество участников конференции с помощью метода room.getParticipants(), который возвращает массив объектов participant,
  • если к конференции уже присоединилось максимально допустимое количество участников, производится выход из "комнаты" при помощи room.leave()
  • если количество участников меньше максимально допустимого, начинается публикация видеопотока
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;
}
room_ = room;
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);
}).on(ROOM_EVENT.JOINED, function(participant){
installParticipant(participant);
addMessage(participant.name(), "joined");
}).on(ROOM_EVENT.LEFT, function(participant){
//remove participant
removeParticipant(participant);
addMessage(participant.name(), "left");
}).on(ROOM_EVENT.PUBLISHED, function(participant){
playParticipantsStream(participant);
}).on(ROOM_EVENT.FAILED, function(room, info){
connection.disconnect();
$('#failedInfo').text(info);
}).on(ROOM_EVENT.MESSAGE, function(message){
addMessage(message.from.name(), message.text);
});


6. Публикация видеопотока с экрана.

room.publish() код

При публикации передаются параметры:

  • параметры видео: ширина, высота, количество кадров в секунду, источник (экран)
  • элемент страницы для отображения превью
var constraints = {
video: {
width: parseInt($('#width').val()),
height: parseInt($('#height').val()),
frameRate: parseInt($('#fps').val()),
},
audio: $("#useMic").prop('checked')
};
constraints.video.type = "screen";
if (Browser.isFirefox()){
constraints.video.mediaSource = "screen";
}
room.publish({
display: document.getElementById("preview"),
constraints: constraints,
name: "screenShare",
cacheLocalResources: false
}).on(STREAM_STATUS.FAILED, function (stream) {
console.warn("Local stream failed!");
onStopSharing();
}).on(STREAM_STATUS.PUBLISHING, function (stream) {
/*
* User can stop sharing screen capture using Chrome "stop" button.
* Catch onended video track event and stop publishing.
*/
document.getElementById(stream.id()).srcObject.getVideoTracks()[0].onended = function (e) {
stream.stop();
};
document.getElementById(stream.id()).addEventListener('resize', function(event){
resizeVideo(event.target);
});
onStartSharing(stream);
}).on(STREAM_STATUS.UNPUBLISHED, function(stream) {
onStopSharing();
});


7. Получение от сервера события, сигнализирующего о присоединении пользователя к чат-комнате

RoomStatusEvent JOINED код

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;
}
room_ = room;
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);
}).on(ROOM_EVENT.JOINED, function(participant){
installParticipant(participant);
addMessage(participant.name(), "joined");
}).on(ROOM_EVENT.LEFT, function(participant){
//remove participant
removeParticipant(participant);
addMessage(participant.name(), "left");
}).on(ROOM_EVENT.PUBLISHED, function(participant){
playParticipantsStream(participant);
}).on(ROOM_EVENT.FAILED, function(room, info){
connection.disconnect();
$('#failedInfo').text(info);
}).on(ROOM_EVENT.MESSAGE, function(message){
addMessage(message.from.name(), message.text);
});


8. Получение от сервера события, сигнализирующего о публикации видеопотока другим участником

RoomStatusEvent PUBLISHED код

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;
}
room_ = room;
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);
}).on(ROOM_EVENT.JOINED, function(participant){
installParticipant(participant);
addMessage(participant.name(), "joined");
}).on(ROOM_EVENT.LEFT, function(participant){
//remove participant
removeParticipant(participant);
addMessage(participant.name(), "left");
}).on(ROOM_EVENT.PUBLISHED, function(participant){
playParticipantsStream(participant);
}).on(ROOM_EVENT.FAILED, function(room, info){
connection.disconnect();
$('#failedInfo').text(info);
}).on(ROOM_EVENT.MESSAGE, function(message){
addMessage(message.from.name(), message.text);
});


9. Воспроизведение видеопотока от другого участника

participant.play() код

Параметром передается div-элемент, в котором будет отображаться видео, в зависимости от источника - веб-камера или экран

function playParticipantsStream(participant) {
if (participant.getStreams().length > 0) {
for (var i=0; i<participant.getStreams().length; i++) {
$("[id$=Name]").each(function (index, value) {
if ($(value).text() == participant.name()) {
var p = value.id.replace('Name', '');
var pDisplay = p + 'Display';
// check if we already play this stream
if (document.getElementById(participant.getStreams()[i].id()) == null) {
// setup 1st stream to main div
if (participant.getStreams()[i].streamName().indexOf("screenShare") == -1) {
participant.getStreams()[i].play(document.getElementById(pDisplay)).on(STREAM_STATUS.PLAYING, function (playingStream) {
document.getElementById(playingStream.id()).addEventListener('resize', function (event) {
resizeVideo(event.target);
});
});
} else {
participant.getStreams()[i].play(document.getElementById("sharedDisplay")).on(STREAM_STATUS.PLAYING, function (playingStream) {
document.getElementById(playingStream.id()).addEventListener('resize', function (event) {
resizeVideo(event.target);
});
});
}
}
}
});
}
}
}


10. Остановка публикации видеопотока.

stream.stop() код

function onMediaPublished(stream) {
$("#localStopBtn").text("Stop").off('click').click(function(){
$(this).prop('disabled', true);
stream.stop();
}).prop('disabled', false);
$("#localAudioToggle").text("Mute A").off('click').click(function(){
if (stream.isAudioMuted()) {
$(this).text("Mute A");
stream.unmuteAudio();
} else {
$(this).text("Unmute A");
stream.muteAudio();
}
}).prop('disabled', false);
$("#localVideoToggle").text("Mute V").off('click').click(function() {
if (stream.isVideoMuted()) {
$(this).text("Mute V");
stream.unmuteVideo();
} else {
$(this).text("Unmute V");
stream.muteVideo();
}
}).prop('disabled',false);
$("#shareBtn").prop('disabled',false);
}


11. Получение от сервера события, подтверждающего остановку публикации.

StreamStatusEvent UNPUBLISHED код

room.publish({
display: document.getElementById("preview"),
constraints: constraints,
name: "screenShare",
cacheLocalResources: false
}).on(STREAM_STATUS.FAILED, function (stream) {
console.warn("Local stream failed!");
onStopSharing();
}).on(STREAM_STATUS.PUBLISHING, function (stream) {
/*
* User can stop sharing screen capture using Chrome "stop" button.
* Catch onended video track event and stop publishing.
*/
document.getElementById(stream.id()).srcObject.getVideoTracks()[0].onended = function (e) {
stream.stop();
};
document.getElementById(stream.id()).addEventListener('resize', function(event){
resizeVideo(event.target);
});
onStartSharing(stream);
}).on(STREAM_STATUS.UNPUBLISHED, function(stream) {
onStopSharing();
});


12. Выход из комнаты чата.

room.leave() код

function onJoined(room) {
$("#joinBtn").text("Leave").off('click').click(function(){
$(this).prop('disabled', true);
room.leave().then(onLeft, onLeft);
}).prop('disabled', false);
$("#shareBtn").prop('disabled',false);
$('#sendMessageBtn').off('click').click(function(){
var message = field('message');
addMessage(connection.username(), message);
$('#message').val("");
//broadcast message
var participants = room.getParticipants();
for (var i = 0; i < participants.length; i++) {
participants[i].sendMessage(message);
}
}).prop('disabled',false);
$('#failedInfo').text("");
}
  • No labels