Versions Compared

Key

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

...

Note that audio tracks are playing in a separate audio tags.

Example source code

To analyze the example source code, take the version available here, which can be downloaded with build 1.0.1.36

The source code consists of the following modules:

...

To analyze the example source code, take the file two-way-streaming.js version availablehere, which can be downloaded with build 1.0.41

1. Local variables

Local variables declaration to work with constants, SFU SDK, to display video and to work with client configuration

code

Code Block
languagejs
themeRDark
const constants = SFU.constants;
const sfu = SFU;
let mainConfig;
let localDisplay;
let remoteDisplay;
let publishState;
let playState;
const PUBLISH = "publish";
const PLAY = "play";
const STOP = "stop";
const PRELOADER_URL="../commons/media/silence.mp3"

...

Default room configuration and stream publishing configuration to use if there is no config.json file found

code

Code Block
languagejs
themeRDark
const defaultConfig = {
    room: {
        url: "wss://127.0.0.1:8888",
        name: "ROOM1",
        pin: "1234",
        nickName: "User1"
    },
    media: {
        audio: {
            tracks: [
                {
                    source: "mic",
                    channels: 1
                }
            ]
        },
        video: {
            tracks: [
                {
                    source: "camera",
                    width: 640,
                    height: 360,
                    codec: "H264",
                    encodings: [
                        { rid: "360p", active: true, maxBitrate: 500000 },
                        { rid: "180p", active: true, maxBitrate: 200000, scaleResolutionDownBy: 2 }
                    ]
                }
            ]
        }
    }
};

...

The object should keep Websocket session data, WebRTC connection data and room data, and shoukd form HTML tags ids to access them from code.

code

Code Block
languagejs
themeRDark
const CurrentState = function(prefix) {
    let state = {
        prefix: prefix,
        pc: null,
        session: null,
        room: null,
        timer: null,
        set: function(pc, session, room) {
            state.pc = pc;
            state.session = session;
            state.room = room;
        },
        clear: function() {
            state.stopWaiting();
            state.room = null;
            state.session = null;
            state.pc = null;
        },
        waitFor: function(div, timeout) {
            state.stopWaiting();
            state.timer = setTimeout(function () {
                if (div.innerHTML !== "") {
                    // Enable stop button
                    $("#" + state.buttonId()).prop('disabled', false);
                }
                else if (state.isConnected()) {
                    setStatus(state.errInfoId(), "No media capturing started in " + timeout + " ms, stopping", "red");
                    onStopClick(state);
                }
            }, timeout);        
        },
        stopWaiting: function() {
            if (state.timer) {
                clearTimeout(state.timer);
                state.timer = null;                
            }
        },
        buttonId: function() {
            return state.prefix + "Btn";
        },
        buttonText: function() {
            return (state.prefix.charAt(0).toUpperCase() + state.prefix.slice(1));
        },
        inputId: function() {
            return state.prefix + "Name";
        },
        statusId: function() {
            return state.prefix + "Status";
        },
        formId: function() {
            return state.prefix + "Form";
        },
        errInfoId: function() {
            return state.prefix + "ErrorInfo";
        },
        is: function(value) {
            return (prefix === value);
        },
        isActive: function() {
            return (state.room && state.pc);
        },
        isConnected: function() {
            return (state.session && state.session.state() == constants.SFU_STATE.CONNECTED);
        }
    };
    return state;
}

4. Initialization

init() code

The init() function is called on page load and:

...

connect(), SFU.createRoom() code

The connect() function is called by Publish or Play click:

...

6. Publishing or playback start after session establishing

onConnected() code

The onConnected() function:

...

publishStreams(), SFURoom.join() code

The publishStreams() function:

...

addTrackToPeerConnection(), PeerConnection.addTransceiver() code

Code Block
languagejs
themeRDark
const addTrackToPeerConnection = function(pc, stream, track, encodings) {
    pc.addTransceiver(track, {
        direction: "sendonly",
        streams: [stream],
        sendEncodings: encodings ? encodings : [] //passing encoding types for video simulcast tracks
    });
}

...

subscribeTrackToEndedEvent(), MediaTrack.addEventListener(), SFURoom.updateState() code

Code Block
languagejs
themeRDark
const subscribeTrackToEndedEvent = function(room, track, pc) {
    track.addEventListener("ended", function() {
        //track ended, see if we need to cleanup
        let negotiate = false;
        for (const sender of pc.getSenders()) {
            if (sender.track === track) {
                pc.removeTrack(sender);
                //track found, set renegotiation flag
                negotiate = true;
                break;
            }
        }
        if (negotiate) {
            //kickoff renegotiation
            room.updateState();
        }
    });
};

...

playStreams(), SFURoom.join() code

The playStreams() function:

...

Code Block
languagejs
themeRDark
const playStreams = function(state) {
    if (state.isConnected() && state.isActive()) {
        //create remote display item to show remote streams
        remoteDisplay = initRemoteDisplay({
            div: document.getElementById("remoteVideo"),
            room: state.room,
            peerConnection: state.pc
        });
        state.room.join(state.pc);
    }
    $("#" + state.buttonId()).prop('disabled', false);
}

...

unPublishStreams(), localDisplay.stop() code

Code Block
languagejs
themeRDark
const unPublishStreams = function(state) {
    if (localDisplay) {
        localDisplay.stop();
    }
}

...

stopStreams(), remoteDisplay.stop() code

Code Block
languagejs
themeRDark
const stopStreams = function(state) {
    if (remoteDisplay) {
        remoteDisplay.stop();
    }
}

...

onStartClick(), playFirstSound(), connect() code

The onStartClick() function:

...

onStopClick(), Session.disconnect() code

The onStopClick() function:

...

13. Websocket session disconnection actions

onDisconnected() code

The onDisconnected() functions:

...

14.1. Start publishing or playback

startStreaming() code

Code Block
languagejs
themeRDark
const startStreaming = function(state) {
    if (state.is(PUBLISH)) {
        publishStreams(state);
    } else if (state.is(PLAY)) {
        playStreams(state);
    }
}

14.2. Stop publishing or playback

stopStreaming() code

Code Block
languagejs
themeRDark
const stopStreaming = function(state) {
    state.stopWaiting();
    if (state.is(PUBLISH)) {
        unPublishStreams(state);
    } else if (state.is(PLAY)) {
        stopStreams(state);
    }
}