Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

This example can be used to organize video conference for three participants on Web Call Server.
Each participant can publish a stream of one of the following types

  • WebRTC
  • RTMFP
  • RTMP

WebRTC stream

On the screenshot below the participant is connected, publishing a stream and playing streams from the other two participants.

Image RemovedImage Added


Three videos are played on the page

  • video from the camera of this participant (Alice) - the lower one
  • videos from the other participants (Bob and Cindy)

Link to the "room" is displayed in the Invite field.

Code of the example

The path to the source code of the example on WCS server is:

...

To analyze the code, let's take the version of file conference.js with hash 456b1c7ecbadc3, which is available here and can be downloaded with corresponding build 2.0.201212.

Script for video conference uses roomApi designed for video chats, video conferences, webinars and other applications that involve presence of users in one virtual "room". To use RoomApi, the script flashphoner-room-api.js should be included

...


1. Initialization of the API.

Flashphoner.init() code

Code Block
languagejs
themeRDark
Flashphoner.init();

2. Connection to server.

RoomApi.connect() code

Code Block
languagejs
themeRDark
connection = 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();
...
});

3. Receiving the event confirming successful connection

ConnectionStatusEvent ESTABLISHED code

Code Block
languagejs
themeRDark
connection = RoomApi.connect({urlServer: url, username: username}).on(SESSION_STATUS.ESTABLISHEDFAILED, function(session) {
    ...
}).on(SESSION_STATUS.DISCONNECTED, function(session) {
    ...
}).on(SESSION_STATUS.ESTABLISHED, function(session) {
    setStatus('#status', session.status());
    joinRoom();
});

3. Receiving the event confirming successful connection

ConnectionStatusEvent ESTABLISHED code4. Joining a conference.

connection.join() code

To join, name of the conference room is passed to the method. (The name can be specified as parameter in the URL of the client page; otherwise, random name will be generated.)

Code Block
languagejs
themeRDark
connection = RoomApi.connectjoin({urlServername: urlgetRoomName(), usernamerecord: usernameisRecord()}).on(SESSIONROOM_STATUSEVENT.FAILEDSTATE, function(sessionroom){
    ...
}).on(SESSION_STATUS.DISCONNECTED, function(session) {
    ...
;

5. Receiving the event describing chat room state

RoomStatusEvent STATE code

On this event:

  • the length of the array of Participant objects returned by method Room.getParticipants() is determined to get the number of already connected participants
  • if the maximum allowed number of participants had already been reached, the user leaves the "room" (line 85)
  • otherwise, the user starts publishing video stream
Code Block
languagejs
themeRDark
connection.join({name: getRoomName(), record: isRecord()}).on(SESSIONROOM_STATUSEVENT.ESTABLISHEDSTATE, function(sessionroom) {
    setStatus('#status', session.status())var participants = room.getParticipants();
    joinRoom();
});

4. Joining a conference.

connection.join() code

To join, name of the conference room is passed to the method. (The name can be specified as parameter in the URL of the client page; otherwise, random name will be generated.)

Code Block
languagejs
themeRDark
connection.join({name: getRoomName(), record: isRecord()}).on(ROOM_EVENT.STATE, function(room){
    ...
});

5. Receiving the event describing chat room state

RoomStatusEvent STATE code

On this event:

  • the length of the array of Participant objects returned by method Room.getParticipants() is determined to get the number of already connected participants
  • if the maximum allowed number of participants had already been reached, the user leaves the "room" (line 85)
  • otherwise, the user starts publishing video stream
Code Block
languagejs
themeRDark
connection.join({name: getRoomName(), record: isRecord()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);
}).on(ROOM_EVENT.JOINED, function(participant){
     ...
}).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){
     ...
});

6. Low Power Mode checking before publishing on mobile device

Flashphoner.playFirstVideo() code

Code Block
languagejs
themeRDark
    if (Browser.isSafariWebRTC()) {
        var display = document.getElementById("localDisplay");
        Flashphoner.playFirstVideo(display, true, PRELOADER_URL).then(function() {
            publishLocalMedia(room);
        }).catch(function (error) {
            console.log("Can't atomatically publish local stream, use Publish button");
            for (var i = 0; i < display.children.length; i++) {
                if (display.children[i]) {
                    console.log("remove cached instance id " + display.children[i].id);
                    display.removeChild(display.children[i]);
                }
            }
            onMediaStopped(room);
        });
    }

7. Video streaming.

room.publish() code

<div> element 'localDisplay', in which video from camera will be displayed, is passed to the room.publish() method

Code Block
languagejs
themeRDark
    room.publish({
        display: display,
        constraints: constraints,
        record: false,
        receiveVideo: false,
        receiveAudio: false
    }).on(STREAM_STATUS.FAILED, function (stream) {
        console.warn("Local stream failed!");
        setStatus("#localStatus", stream.status());
        onMediaStopped(room);
    }).on(STREAM_STATUS.PUBLISHING, function (stream) {
        setStatus("#localStatus", stream.status());
        onMediaPublished(stream);
    }).on(STREAM_STATUS.UNPUBLISHED, function(stream) {
        setStatus("#localStatus", stream.status());
        onMediaStopped(room);
    });

8. Receiving the event notifying that other participant joined to the room

RoomStatusEvent JOINED code

Code Block
languagejs
themeRDark
connection.join({name: getRoomName(), record: isRecord()}).on(ROOM_EVENT.STATE, function(room){
     ...
}).on(ROOM_EVENT.JOINED, function(participant){
     installParticipant(participant);
     addMessage(participant.name(), "joined");
}).on(ROOM_EVENT.STATELEFT, function(roomparticipant){
    var participants = room.getParticipants();
    console.log("Current number of participants in the room: " + participants.length);
    if (participants.length >= _participants) .
}).on(ROOM_EVENT.PUBLISHED, function(participant){
        console.warn("Current room is full");...
}).on(ROOM_EVENT.FAILED, function(room, info){
        $("#failedInfo"...
}).text("Current room is full.");on(ROOM_EVENT.MESSAGE, function(message){
     ...
});

9. Receiving the event notifying that other participant published video stream

RoomStatusEvent PUBLISHED code

Code Block
languagejs
themeRDark
connection.join({name: getRoomName(), record: room.leaveisRecord()}).then(onLefton(ROOM_EVENT.STATE, onLeftfunction(room);{
        return false;
    }
    setInviteAddress(room.name());...
}).on(ROOM_EVENT.JOINED, function(participant){
    if (participants.length > 0)  ...
}).on(ROOM_EVENT.LEFT, function(participant){
     ...
}).on(ROOM_EVENT.PUBLISHED, function(participant){
  var chatState = "participants: ";
        for (var i = 0; i < participants.length; i++)  playParticipantsStream(participant);
}).on(ROOM_EVENT.FAILED, function(room, info){
     ...
}).on(ROOM_EVENT.MESSAGE, function(message){
        ...
});

10. Low Power Mode checking before playback on mobile device

Flashphoner.playFirstVideo() code

Code Block
languagejs
themeRDark
    installParticipant(participants[i]);
            chatState += participants[i].name();if (Browser.isSafariWebRTC()) {
         if (i != participants.length - 1) {
            chatState += ",";Flashphoner.playFirstVideo(pDisplay, false, PRELOADER_URL).then(function() {
         }
      }
         addMessageplayStream("chat"participant, chatStatepDisplay);
      } else {
         addMessage("chat", " room is empty"); }).catch(function (error) {
     }
         publishLocalMedia(room);
     onJoined(room);
}).on(ROOM_EVENT.JOINED, function(participant){
     ...
}).on(ROOM_EVENT.LEFT, function(participant){
     ...
}).on(ROOM_EVENT.PUBLISHED, function(participant){
     ...
}).on(ROOM_EVENT.FAILED, function(room, info){
     // Low Power Mode detected, user action is needed to start playback in this mode #WCS-2639
                        ...
}).on(ROOM_EVENT.MESSAGE, function(message){
     ...
});

6. Video streaming.

room.publish() code

<div> element 'localDisplay', in which video from camera will be displayed, is passed to the room.publish() method

Code Block
languagejs
themeRDark
    room.publish({
console.log("Can't atomatically play participant" + participant.name() + " stream, use Play button");
              display: display,
        constraints: constraints,
for (var i = 0; i <  record: false,
pDisplay.children.length; i++) {
          receiveVideo: false,
        receiveAudio: false
    }).on(STREAM_STATUS.FAILED, function (stream    if (pDisplay.children[i]) {
         console.warn("Local stream failed!");
        setStatus("#localStatus", stream.status());
        onMediaStopped(room);
    })console.on(STREAM_STATUS.PUBLISHING, function (stream) {
log("remove cached instance id " + pDisplay.children[i].id);
         setStatus("#localStatus", stream.status());
        onMediaPublished(stream);
    }).on(STREAM_STATUS.UNPUBLISHED, function(stream) {
        setStatus("#localStatus", stream.status())pDisplay.removeChild(pDisplay.children[i]);
        onMediaStopped(room);
    });

7. Receiving the event notifying that other participant joined to the room

RoomStatusEvent JOINED code

Code Block
languagejs
themeRDark
connection.join({name: getRoomName(), record: isRecord()}).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){
       ...
});

8. Receiving the event notifying that other participant published video stream

RoomStatusEvent PUBLISHED code

Code Block
languagejs
themeRDark
connection.join({name: getRoomName(), record: isRecord()}).on(ROOM_EVENT.STATE, function(room){
        ...
}).on(ROOM_EVENT.JOINED, function onParticipantStopped(participant){;
      ...
}).on(ROOM_EVENT.LEFT, function(participant){
        ...
}).on(ROOM_EVENT.PUBLISHED, function(participant){
     playParticipantsStream(participant});
}).on(ROOM_EVENT.FAILED, function(room, info){
          ...
}).on(ROOM_EVENT.MESSAGE, function(message){
     ...
});

911. Playback of video stream.

participant.play() code
<div> element, in which the video will be displayed, is passed to the participant.play() method.

Code Block
languagejs
themeRDark
function playParticipantsStream(participant) {
    if (participant.play) {
        $("[id$=Name]").each(function (index, value) {
            if ($(value).text() == participant.name()) {
                var p = value.id.replace('Name', '');
                var pDisplay = p + 'Display';
                participant.play(document.getElementById(pDisplay)).on(STREAM_STATUS.PLAYING, function (playingStream) {
                    document.getElementById(playingStream.id()).addEventListener('resize', function (event) {
                        resizeVideo(event.target);
                    });
                });
            }
        });
    }
}

1012. Stop of streaming.

stream.stop() code

Code Block
languagejs
themeRDark
function onMediaPublished(stream) {
    $("#localStopBtn").text("Stop").off('click').click(function(){
        $(this).prop('disabled', true);
        stream.stop();
    }).prop('disabled', false);
    ...
}

1113.  Receiving Receiving the event confirming successful streaming stop

StreamStatusEvent UNPUBLISHED code

Code Block
languagejs
themeRDark
room.publish({
    display: display,
    constraints: constraints,
    record: false,
    receiveVideo: false,
    receiveAudio: false
}).on(STREAM_STATUS.FAILED, function (stream) {
    ...
}).on(STREAM_STATUS.PUBLISHING, function (stream) {
    ...
}).on(STREAM_STATUS.UNPUBLISHED, function(stream) {
    setStatus("#localStatus", stream.status());
    onMediaStopped(room);
});

1214. Leaving conference room

room.leave() code

Code Block
languagejs
themeRDark
function onJoined(room) {
    $("#joinBtn").text("Leave").off('click').click(function(){
        $(this).prop('disabled', true);
        room.leave().then(onLeft, onLeft);
    }).prop('disabled', false);
    ...
}

1315. Mute/unmute audio and video of the published stream

stream.isAudioMuted(), stream.isVideoMuted(), stream.muteAudio(), stream.unmuteAudio(), stream.muteVideo(), stream.unmuteVideo() code

Code Block
languagejs
themeRDark
function onMediaPublished(stream) {
    ...
    $("#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);
}

1416. Sending text message.

participant.sendMessage() code

When Send button is clicked,

...