Versions Compared

Key

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

...

Supported platforms and browsers


Chrome

Firefox

Safari 11

Chromium Edge

Windows

+

+


+

Mac OS

+

+

+


Android

+

+


+

iOS

-

-

+ (iOS 14.6+)

+ (iOS 14.6+)

+


Supported codecs

  • Video: H.264, VP8
  • Audio: Opus, G.711

...

Below is the call flow when using the Conference example.

conference.html

conference.js

1. Participant 1 establishes a connection to the server.

FlashphonerRoomApi.roomApi.connect();   code

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

...


2. Participant 1 receives from the server an event confirming successful connection.

ConnectionStatusEvent ESTABLISHED ESTABLISHED code

Code Block
languagejs
themeRDark
    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. Participant 1 enters the chat room.

connection.join();   code

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

...

4. Participant 1 receives from the server an event describing the state of the room.

RoomStatusEvent STATE STATE code

Code Block
languagejs
themeRDark
    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. Participant 1 publishes the media stream.

room.publish();   code

Code Block
languagejs
themeRDark
    room.publish({
        display: display,
        constraints: constraints,
        record: false,
        receiveVideo: false,
        receiveAudio: false
        ...
    });

...

6. Participant 1 receives from the server an event confirming successful publishing of the stream.

StreamStatusEvent PUBLISHING PUBLISHING 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) {
        setStatus("#localStatus", stream.status());
        onMediaPublished(stream);
    }).on(STREAM_STATUS.UNPUBLISHED, function(stream) {
        ...
    });

...

12. Participant 1 receives from the server an event informing that participant 2 has joined.

RoomStatusEvent JOINED JOINED code

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

...

17. Participant 1 leaves the chat 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);
    ...
}

...

18. Participants of the room receive from the server an event informing that participant 1 has left the room.

RoomStatusEvent LEFT LEFT code

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

...

Then play output.mp4.file:

Room multiple streams recording to one file with subsequent mixing

Since WCS build 5.2.1012 and WebSDK build 2.0.190 it is possible to record all the room streams to one file, with automatic mixing after finishing a conference. To do this, a first participant should set room record option while creating a room:

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

In thei case, all the room streams will be reocrded to one file. When the room is finalized, the recording will also be stopped, and the script set in the following parameter will be automatically launched

Code Block
themeRDark
on_multiple_record_hook_script=on_multiple_record_hook.sh

The script will mix multiple streams recorded acoording to mixer settings defined in /usr/local/FlashphonerWebCallServer/conf/offline_mixer.json file, by default

Code Block
languagejs
themeRDark
{
  "hasVideo": "true",
  "hasAudio": "true",
  "mixerDisplayStreamName": true
}

Testing

1. For test we use:

  • WCS server, for example test1.flashphoner.com;
  • Conference web application example

2. Open Conference example in briowser, enter participant name Alice and set Record checkbox

Image Added

3. Click Join. Stream publishing will start

Image Added

4. Open Invite link in another browser window

Image Added

5. Enter participant name Bob and click Join

Image Added

6. Bob joined to the room

Image Added

7. Click Leave in Alice participant window

Image Added

and in Bob participant window

Image Added

8. Recording file mixing may take a long time depending on recording length, CPU and dick I/O performance. When miximg is done, download the file from /usr/local/FlashphonerWebCallServer/records folder or open in browser by /client/records link

Image Added

Room finalizing

Room exists until at leats one participant is connected. When the last participant calls room.leave() function, the room is finalized.

If the last participant refreshes web page or loses server connection without calling room.leave(), the room will be active during the time interval set by the following parameter in milliseconds

Code Block
themeRDark
room_idle_timeout=60000

By default, the interval is 60 seconds. When time is expired, the room is finalized.

Known issues

1. Non-latin characters should be encoded while messaging

Symptoms: when message sent contains non-latin characters, they are replaced with questionmarks on receiving end

Solution: use JavaScript functions encodeURIComponent() while sending a message

Code Block
languagejs
themeRDark
        var participants = room.getParticipants();
        for (var i = 0; i < participants.length; i++) {
            participants[i].sendMessage(encodeURIComponent(message));
        }

and decodeURIComponent() while receiving message

Code Block
languagejs
themeRDark
    ...
    }).on(ROOM_EVENT.MESSAGE, function(message){
        addMessage(message.from.name(), decodeURIComponent(message.text));
    });
    ...

2. When connection.join() and then room.leave() are called too fast. it is possible to send join command to the server while it still handles previous leave command for this user

Symptoms: when connection.join() is called right after room.leave(), client may receive a message

Code Block
themeRDark
Room already has user with such login

Solution: use at least 1 second interval between room.leave() and connection.join() subsequent calls