Versions Compared

Key

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

...

To analyze the code, let's take the version of file manager.js, which is available here and can be downloaded with corresponding build 0.5.28.27472753.126.

1. Initialization of the API.

Flashphoner.init() code

Code Block
languagejs
themeRDark
        Flashphoner.init({
            screenSharingExtensionId: extensionId,
            flashMediaProviderSwfLocation: '../../../../media-provider.swf',
            mediaProvidersReadyCallback: function (mediaProviders) {
                //hide remote video if current media provider is Flash
                if (mediaProviders[0] == "Flash") {
                    $("#fecForm").hide();
                    $("#stereoForm").hide();
                    $("#sendAudioBitrateForm").hide();
                    $("#cpuOveruseDetectionForm").hide();
                }
                if (Flashphoner.isUsingTemasys()) {
                    $("#audioInputForm").hide();
                    $("#videoInputForm").hide();
                }
            }
        })

2. List available input media devices.

Flashphoner.getMediaDevices() кодcode

When input media devices are listed, drop-down lists of microphones and cameras on client page are filled.

Code Block
languagejs
themeRDark
    Flashphoner.getMediaDevices(null, true).then(function (list) {
        list.audio.forEach(function (device) {
            ...
        });
        list.video.forEach(function (device) {
            ...
        });
        ...
    }).catch(function (error) {
        $("#notifyFlash").text("Failed to get media devices");
    });

3. Get audio and video publishing constraints from client page

getConstraints() code

Publishing sources:

  • camera (sendVideo)
  • microphone (sendAudio)
  • HTML5 Canvas (sendCanvasStream)

...

 List available output media devices

Flashphoner.getMediaDevices() code

When output media devices are listed, drop-down lists of spakers and headphones on client page are filled.

Code Block
languagejs
themeRDark
    constraints = Flashphoner.getMediaDevices(null, true, MEDIA_DEVICE_KIND.OUTPUT).then(function (list) {
        audio: $("#sendAudio").is(':checked'),list.audio.forEach(function (device) {
        video: $("#sendVideo").is(':checked'),    ...
        });
        ...
    }).catch(function (error) {
        customStream: $("#sendCanvasStream#notifyFlash").is(':checked')text("Failed to get media devices");
    });

Audio constraints:

...

4. Get audio and video publishing constraints from client page

getConstraints() code

Publishing sources:

  • camera (sendVideo)
  • microphone (sendAudio)
Code Block
languagejs
themeRDark
    if (constraints.audio)constraints = {
        constraints.audio = {: $("#sendAudio").is(':checked'),
            deviceIdvideo: $('#audioInput'"#sendVideo").valis(':checked'),
    };

Audio constraints:

  • microphone choise (deviceId)
  • error correction for Opus codec (fec)
  • stereo mode (stereo)
  • audio bitrate (bitrate)
Code Block
languagejs
themeRDark
    }; if (constraints.audio) {
        if ($(constraints.audio = {
            deviceId: $('#audioInput').val()
        };
        if ($("#fec").is(':checked'))
            constraints.audio.fec = $("#fec").is(':checked');
        if ($("#sendStereoAudio").is(':checked'))
            constraints.audio.stereo = $("#sendStereoAudio").is(':checked');
        if (parseInt($('#sendAudioBitrate').val()) > 0)
            constraints.audio.bitrate = parseInt($('#sendAudioBitrate').val());
    }

...

Code Block
languagejs
themeRDark
            constraints.video = {
                deviceId: {exact: $('#videoInput').val()},
                width: parseInt($('#sendWidth').val()),
                height: parseInt($('#sendHeight').val())
            };
            if (Browser.isSafariWebRTC() && Browser.isiOS() && Flashphoner.getMediaProviders()[0] === "WebRTC") {
                constraints.video.widthdeviceId = {minexact: parseInt($('#sendWidth#videoInput').val()), max: 640};
            }
    constraints.video.height  = {min: parseInt($('#sendHeight').val()), max: 480};
            }
            if (parseInt($('#sendVideoMinBitrate').val()) > 0)
                constraints.video.minBitrate = parseInt($('#sendVideoMinBitrate').val());
            if (parseInt($('#sendVideoMaxBitrate').val()) > 0)
                constraints.video.maxBitrate = parseInt($('#sendVideoMaxBitrate').val());
            if (parseInt($('#fps').val()) > 0)
                constraints.video.frameRate = parseInt($('#fps').val());

45. Get access to media devices for local test

Flashphoner.getMediaAccess() code

Audio and video constraints and <div>-element to display captured video are passed to the method.

Code Block
languagejs
themeRDark
    Flashphoner.getMediaAccess(getConstraints(), localVideo).then(function (disp) {
        $("#testBtn").text("Release").off('click').click(function () {
            $(this).prop('disabled', true);
            stopTest();
        }).prop('disabled', false);
        ...
        testStarted = true;
    }).catch(function (error) {
        $("#testBtn").prop('disabled', false);
        testStarted = false;
    });

56. Connecting to the server

Flashphoner.createSession() code

Code Block
languagejs
themeRDark
    Flashphoner.createSession({urlServer: url, timeout: tm}).on(SESSION_STATUS.ESTABLISHED, function (session) {
        //session connected, start streamingsetStatus("#connectStatus", session.status());
        startStreamingonConnected(session);
    }).on(SESSION_STATUS.DISCONNECTED, function () {
        setStatus("#connectStatus", SESSION_STATUS.DISCONNECTED);
        onStoppedonDisconnected();
    }).on(SESSION_STATUS.FAILED, function () {
        setStatus("#connectStatus", SESSION_STATUS.FAILED);
        onStoppedonDisconnected();
    });

67. Receiving the event confirming successful connection

ConnectionStatusEvent ESTABLISHED code

Code Block
languagejs
themeRDark
    Flashphoner.createSession({urlServer: url, timeout: tm}).on(SESSION_STATUS.ESTABLISHED, function (session) {
        //session connected, start streamingsetStatus("#connectStatus", session.status());
        startStreamingonConnected(session);
    }).on(SESSION_STATUS.DISCONNECTED, function () {
        ...
    }).on(SESSION_STATUS.FAILED, function () {
        ...
    });

...

;

8. Stream publishing

session.createStream(), publishStream.publish() code

Code Block
languagejs
themeRDark
    publishStream = session.createStream({
        name: streamName,
        display: localVideo,
        cacheLocalResources: true,
        constraints: constraints,
        mediaConnectionConstraints: mediaConnectionConstraints,
        ...sdpHook: rewriteSdp,
    });    transport: transportInput,
    publishStream.publish();

...

     cvoExtension: cvo,
        stripCodecs: strippedCodecs
        ...
    });
    publishStream.publish();

9. Receiving the event confirming successful streaming

StreamStatusEvent PUBLISHING code

On receiving the event, the preview stream is created with session.createStream() method and play() is called to play it

Code Block
languagejs
themeRDark
    publishStream = session.createStream({
({
        ...
    }).on(STREAM_STATUS.PUBLISHING, function (stream) {
        $("#testBtn").prop('disabled', true);
        var video = document.getElementById(stream.id());
        //resize local if resolution is available
        if (video.videoWidth > 0 && video.videoHeight > 0) {
            resizeLocalVideo({target: video});
        }
        enablePublishToggles(true);
        if ($("#muteVideoToggle").is(":checked")) {
            muteVideo();
        }
        if ($("#muteAudioToggle").is(":checked")) {
            muteAudio();
        }
        //remove resize listener in case this video was cached earlier
        video.removeEventListener('resize', resizeLocalVideo);
        video.addEventListener('resize', resizeLocalVideo);
        publishStream.setMicrophoneGain(currentGainValue);
        setStatus("#publishStatus", STREAM_STATUS.PUBLISHING);
        onPublishing(stream);
    }).on(STREAM_STATUS.UNPUBLISHED, function () {
        ...
    }).on(STREAM_STATUS.FAILED, function () {
        ...
    });
    publishStream.publish();

10. Stream playback

session.createStream(), previewStream.play() code

Code Block
languagejs
themeRDark
    previewStream = session.createStream({
        name: streamName,
        display: remoteVideo,
        constraints: constraints,
        transport: transportOutput,
        stripCodecs: strippedCodecs
        ...
    });
    previewStream.play();

11. Receiving the event confirming successful playback

StreamStatusEvent PLAYING code

Code Block
languagejs
themeRDark
    previewStream = session.createStream({
        ...
    }).on(STREAM_STATUS.PLAYING, function (stream) {
        playConnectionQualityStat.connectionQualityUpdateTimestamp = new Date().valueOf();
        setStatus("#playStatus", stream.status());
        onPlaying(stream);
        document.getElementById(stream.id()).addEventListener('resize', function (event) {
            $("#playResolution").text(event.target.videoWidth + "x" + event.target.videoHeight);
            resizeVideo(event.target);
        });
        //wait for incoming stream
        if (Flashphoner.getMediaProviders()[0] == "WebRTC") {
            setTimeout(function () {
                detectSpeech(stream);
            }, 3000);
        }
        ...
    });
    previewStream.play();

12. Stop stream playback

stream.stop() code

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

13. Receiving the event confirming successful playback stop

StreamStatusEvent STOPPED code

Code Block
languagejs
themeRDark
    previewStream = session.createStream({
        ...
    }).on(STREAM_STATUS.STOPPED, function () {
        setStatus("#playStatus", STREAM_STATUS.STOPPED);
        onStopped();
        ...
    });
    previewStream.play();

14. Stop stream publishing

stream.stop() code

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

15. Receiving the event confirming successful publishsing stop

StreamStatusEvent UNPUBLISHED code

Code Block
languagejs
themeRDark
    publishStream = session.createStream({
        ...
    }).on(STREAM_STATUS.UNPUBLISHED, function () {
        setStatus("#publishStatus", STREAM_STATUS.UNPUBLISHED);
        onUnpublished();
        ...
    });
    publishStream.publish();

16. Mute publisher audio

code:

Code Block
languagejs
themeRDark
        if ($("#muteAudioToggle").is(":checked")) {
            muteAudio();
        }

17. Mute publisher video

code:

Code Block
languagejs
themeRDark
        if ($("#muteVideoToggle").is(":checked")) {
            muteVideo();
        }

18. Show WebRTC stream publishing statistics

stream.getStats() code:

Code Block
languagejs
themeRDark
        publishStream.getStats(function (stats) {
            if (stats && stats.outboundStream) {
                if (stats.outboundStream.video) {
                    showStat(stats.outboundStream.video, "outVideoStat");
                    let vBitrate = (stats.outboundStream.video.bytesSent - videoBytesSent) * 8;
                    if ($('#outVideoStatBitrate').length == 0) {
                        let html = "<div>Bitrate: " + "<span id='outVideoStatBitrate' style='font-weight: normal'>" + vBitrate + "</span>" + "</div>";
                        $("#outVideoStat").append(html);
                    } else {
              name: streamName,
        display: localVideo, $('#outVideoStatBitrate').text(vBitrate);
        cacheLocalResources: true,
        constraints: constraints,
  }
      mediaConnectionConstraints: mediaConnectionConstraints
    }).on(STREAM_STATUS.PUBLISHING, function (publishStream) {
      videoBytesSent  $("#testBtn").prop('disabled', true)= stats.outboundStream.video.bytesSent;
        var  video = document.getElementById(publishStream.id());
        //resize local if resolution is available
...
             if (video.videoWidth > 0}

 && video.videoHeight > 0) {
           if resizeLocalVideo({target: video});
stats.outboundStream.audio) {
            }
        enableMuteToggles(trueshowStat(stats.outboundStream.audio, "outAudioStat");
        if ($("#muteVideoToggle").is(":checked")) {
          let aBitrate muteVideo();
= (stats.outboundStream.audio.bytesSent - audioBytesSent) * 8;
         }
           if ($("#muteAudioToggle").is(":checked")'#outAudioStatBitrate').length == 0) {
            muteAudio();
        }
    let html =  //remove resize listener in case this video was cached earlier
        video.removeEventListener('resize', resizeLocalVideo)"<div>Bitrate: " + "<span id='outAudioStatBitrate' style='font-weight: normal'>" + aBitrate + "</span>" + "</div>";
        video.addEventListener('resize', resizeLocalVideo);
        setStatus(STREAM_STATUS.PUBLISHING);

        //play preview$("#outAudioStat").append(html);
        var constraints = {
         }   audio: $("#playAudio").is(':checked'),
else {
                  video:      $("#playVideo"'#outAudioStatBitrate').is(':checked')text(aBitrate);
        };
          if (constraints.video) {}
            constraints.video = {
      audioBytesSent = stats.outboundStream.audio.bytesSent;
        width: (!$("#receiveDefaultSize").is(":checked")) ? parseInt($('#receiveWidth').val()) : 0,
        }
            }
      height: (!$("#receiveDefaultSize").is(":checked")) ? parseInt($('#receiveHeight').val()) : 0,
      ...
        });

19. Show WebRTC stream playback statistics

stream.getStats() code:

Code Block
languagejs
themeRDark
        previewStream.getStats(function (stats) {
         bitrate: (!$("#receiveDefaultBitrate").is(":checked")) ? $("#receiveBitrate").val() : 0,   if (stats && stats.inboundStream) {
                quality:if (!$("#receiveDefaultQuality").is(":checked")) ? $('#quality').val() : 0stats.inboundStream.video) {
            };
        }
        previewStream = session.createStream({
  showStat(stats.inboundStream.video, "inVideoStat");
          name: streamName,
         let vBitrate  display: remoteVideo,
   = (stats.inboundStream.video.bytesReceived - videoBytesReceived) * 8;
         constraints: constraints
            ...
        });if ($('#inVideoStatBitrate').length == 0) {
        previewStream.play();
    }).on(STREAM_STATUS.UNPUBLISHED, function () {
              ...
let html =  }).on(STREAM_STATUS.FAILED, function () {
        ...
    });
    publishStream.publish();

9. Preview stream playback stop

previewStream.stop() code

Code Block
languagejs
themeRDark
    $("#publishBtn").text("Stop").off('click').click(function () {
"<div>Bitrate: " + "<span id='inVideoStatBitrate' style='font-weight: normal'>" + vBitrate + "</span>" + "</div>";
                        $(this).prop('disabled', true"#inVideoStat").append(html);
        previewStream.stop();
    }).prop('disabled', false);

10. Receiving the event confirming successful playback stop

StreamStatusEvent STOPPED code

Code Block
languagejs
themeRDark
       } previewStream = session.createStream(else {
            name: streamName,
            display: remoteVideo,$('#inVideoStatBitrate').text(vBitrate);
            constraints: constraints
        }).on(STREAM_STATUS.PLAYING, function (previewStream) {
}
               ...
     videoBytesReceived   }).on(STREAM_STATUS.STOPPED, function () {= stats.inboundStream.video.bytesReceived;
            publishStream.stop();
        }).on(STREAM_STATUS.FAILED, function () {
...
                ...}

        });
        if previewStream.play();

11. Streaming stop after preview playback stopped

publishStream.stop() code

Code Block
languagejs
themeRDark
(stats.inboundStream.audio) {
                   previewStream = session.createStream({ showStat(stats.inboundStream.audio, "inAudioStat");
            name:  streamName,
      let aBitrate = (stats.inboundStream.audio.bytesReceived - audioBytesReceived) display: remoteVideo,* 8;
            constraints: constraints
        }).on(STREAM_STATUS.PLAYING, function (previewStream) {
            ...
if ($('#inAudioStatBitrate').length == 0) {
           }).on(STREAM_STATUS.STOPPED, function () {
          let  publishStream.stop();
        }).on(STREAM_STATUS.FAILED, function () {
    html = "<div style='font-weight: bold'>Bitrate: " + "<span id='inAudioStatBitrate' style='font-weight: normal'>" + aBitrate + "</span>" + "</div>";
        ...
        });
        previewStream.play();

12. Receiving the event confirming successful streaming stop

StreamStatusEvent UNPUBLISHED код

Code Block
languagejs
themeRDark
    publishStream = session.createStream({
$("#inAudioStat").append(html);
            name: streamName,
       } display:else localVideo,
{
              cacheLocalResources: true,
        constraints: constraints, $('#inAudioStatBitrate').text(aBitrate);
        mediaConnectionConstraints: mediaConnectionConstraints
    }).on(STREAM_STATUS.PUBLISHING, function (publishStream) {
    }
    ...
    }).on(STREAM_STATUS.UNPUBLISHED, function () {
            audioBytesReceived  setStatus(STREAM_STATUS.UNPUBLISHED)= stats.inboundStream.audio.bytesReceived;
        //enable start button
      }
  onStopped();
    }).on(STREAM_STATUS.FAILED, function () {
        ...
    });
        }
     publishStream.publish(   });