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

Version 1 Current »

A streamer example with publishing automatic restore

This example shows how to restore stream publishing automatically by changing codec to VP8 if H264 stream publishing fails. Streaminh can be restored if browser did not reload the page, and Javascript can be executed. The publishing problems are detected by bitrate dropping to 0.

Code of the example

The example code is available on WCS server by the following path:

/usr/local/FlashphonerWebCallServer/client2/examples/demo/streaming/stream-auto-restore

stream-auto-restore.css - styles file
stream-auto-restore.html - client page
stream-auto-restore.js - main script to work

The example can be tested by the following URL:

https://host:8888/client2/examples/demo/streaming/stream_filter/stream-auto-restore.html

Where host - WCS server address.

Analyzing the code

To analyze the code take the file stream_filter.js version with hash f2862b9 which is available here and can be downloaded with SDK build 2.0.207.

1. API initializing.

Flashphoner.init() code

Flashphoner.init();

2. Connecting to the server.

Flashphoner.createSession() code

Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
    setStatus("#connectStatus", session.status());
    onConnected(session);
}).on(SESSION_STATUS.DISCONNECTED, function(){
    setStatus("#connectStatus", SESSION_STATUS.DISCONNECTED);
    onDisconnected();
}).on(SESSION_STATUS.FAILED, function(){
    setStatus("#connectStatus", SESSION_STATUS.FAILED);
    onDisconnected();
});

3. Receiving the event confirming successful connection.

ConnectionStatusEvent ESTABLISHED code

Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
    setStatus("#connectStatus", session.status());
    onConnected(session);
}).on(SESSION_STATUS.DISCONNECTED, function(){
    ...
}).on(SESSION_STATUS.FAILED, function(){
    ...
});

4. Video streaming.

session.createStream(), publish() code

The following parameters are passed:

  • streamName - stream name
  • localVideo - div tag to display video from camera
  • stripCodecs - codec to exclude from publishing
session.createStream({
    name: streamName,
    display: localVideo,
    cacheLocalResources: true
    receiveVideo: false,
    receiveAudio: false,
    stripCodecs: stripCodecs
    ...
}).publish();

5. Receiving the event confirming successful streaming.

StreamStatusEvent PUBLISHING code

session.createStream({
    ...
}).on(STREAM_STATUS.PUBLISHING, function(stream){
    setStatus("#publishStatus", STREAM_STATUS.PUBLISHING);
    onPublishing(stream);
}).on(STREAM_STATUS.UNPUBLISHED, function(){
    ...
}).on(STREAM_STATUS.FAILED, function(){
    ...
}).publish();

6. Stream playback.

session.createStream(), play() code.

When stream is created, the following parameters are passed

  • streamName - name of the stream (including the stream published on step above)
  • remoteVideo - <div> element, in which video playback will be displayed
session.createStream({
    name: streamName,
    display: remoteVideo
    ...
}).play();

7. Receiving the event confirming successful stream playback.

StreamStatusEvent PLAYING code

session.createStream({
    name: streamName,
    display: remoteVideo
    ...
}).on(STREAM_STATUS.PLAYING, function(stream) {
    setStatus("#playStatus", stream.status());
    onPlaying(stream);
}).on(STREAM_STATUS.STOPPED, function() {
    ...
}).on(STREAM_STATUS.FAILED, function() {
    ...
}).play();

8. Stream playback stop.

stream.stop() code

function onPlaying(stream) {
    $("#playBtn").text("Stop").off('click').click(function(){
        $(this).prop('disabled', true);
        stream.stop();
    }).prop('disabled', false);
    $("#playInfo").text("");
}

9. Receiving the event confirming successful playback stop.а.

StreamStatusEvent STOPPED code

session.createStream({
    ...
}).on(STREAM_STATUS.PLAYING, function(stream) {
    ...
}).on(STREAM_STATUS.STOPPED, function() {
    setStatus("#playStatus", STREAM_STATUS.STOPPED);
    onStopped();
}).on(STREAM_STATUS.FAILED, function() {
    ...
}).play();

10. Streaming stop.

stream.stop() code

function onPublishing(stream) {
    $("#publishBtn").text("Stop").off('click').click(function(){
        $(this).prop('disabled', true);
		stream.stop();
    }).prop('disabled', false);
    $("#publishInfo").text("");
    ...
}

11. Receiving the event confirming successful streaming stop.

StreamStatusEvent UNPUBLISHED code

session.createStream({
    ...
}).on(STREAM_STATUS.PUBLISHING, function(stream){
    ...
}).on(STREAM_STATUS.UNPUBLISHED, function(){
    setStatus("#publishStatus", STREAM_STATUS.UNPUBLISHED);
    onUnpublished();
}).on(STREAM_STATUS.FAILED, function(){
    ...
}).publish();

12. Publishing bitrate checking parameters.

code

var statPublishFailureDetector = {
    failed: false,
    codec: "",
    lastBytesSent: 0,
    counter: {
        value: 0,
        threshold: PUBLISH_FAILURE_DETECTOR_MAX_TRIES
    }
};

13. Publishing bitrate chacking start by STREAM_STATUS.PUBLISHING event.

code

function onPublishing(stream) {
    ...
    if(Browser.isChrome()) {
        detectPublishFailure(stream, PUBLISH_FAILURE_DETECTOR_INTERVAL, PUBLISH_FAILURE_DETECTOR_MAX_TRIES);
    }        
}

14. WebRTC statistics gathering from browser, current publishing codec and bitrate detection, publishing stopping if bitrate is constantly drops to 0.

code

        stream.getStats(function(stat) {
            let videoStats = stat.outboundStream.video;
            if(!videoStats) {
                return;
            }
            let codec = videoStats.codec;
            let bytesSent = videoStats.bytesSent;
            let bitrate = (bytesSent - statPublishFailureDetector.lastBytesSent) * 8;
            if (bitrate == 0) {
                statPublishFailureDetector.counter.value++;
                console.log("Bitrate is 0 (" + statPublishFailureDetector.counter.value + ")");
                if (statPublishFailureDetector.counter.value >= statPublishFailureDetector.counter.threshold) {
                    statPublishFailureDetector.failed = true;
                    console.log("Publishing seems to be failed, stop the stream");
                    stream.stop();
                }
            } else {
                statPublishFailureDetector.counter.value = 0;
            }
            statPublishFailureDetector.lastBytesSent = bytesSent;
            statPublishFailureDetector.codec = codec;
            $("#publishInfo").text(statPublishFailureDetector.codec);
        });

15. Bitrate checking timer stopping and streaming restart function invokation by STREAM_STATUS.UNPUBLISHED event

code

function onUnpublished() {
    ...
    if (publishFailureIntervalID) {
        clearInterval(publishFailureIntervalID);
        publishFailureIntervalID = null;
    }
    checkPublishFailureConditions();
}

16. Restart publishing with VP8 codec

code

function checkPublishFailureConditions() {
    if (statPublishFailureDetector.failed) {
        $("#publishInfo").text("Failed to publish " + statPublishFailureDetector.codec);    
        if (statPublishFailureDetector.codec == "H264") {
            console.log("H264 publishing seems to be failed, trying VP8 by stripping H264");
            let stripCodecs = "H264";
            publishBtnClick(stripCodecs);
        } else if (statPublishFailureDetector.codec == "VP8") {
            console.log("VP8 publishing seems to be failed, giving up");
        }
    }
}
  • No labels