Versions Compared

Key

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

Example of streamer with access to media devices

This streamer can be used to publish the following types of streams on Web Call Server

...

On the screenshot below a stream is being published from the client.

Image Modified

Two videos are played on the page

  • 'Local' - video from the camera
  • 'Preview' - the video as received from the server

Code of the example

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

...

Here host is the address of the WCS server.

Work with code of the streamer

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

1. Initialization of the API. line 10API is initialized after loading the page. For Flash support, the path to SWF file is passed to the

Flashphoner.init() method. code

Code Block
languagejs
themeRDark
       Flashphoner.init({
            flashMediaProviderSwfLocation: '../../../../media-provider.swf'});

2. List available media devices. line 16

After API initialization, list of available media devices (cameras and microphones) is requested.

Code Block
languagejs
themeRDark
Flashphoner.getMediaDevices(null,true).then(function(list){
    list.audio.forEach(function(device,
            mediaProvidersReadyCallback: function (mediaProviders) {
        var  audio = document.getElementById("audioInput");
    //hide remote video if varcurrent i;
media provider is Flash
     var deviceInList = false;
        forif (imediaProviders[0] = 0; i < audio.options.length; i++) {
= "Flash") {
                 if (audio.options[i].value == device.id) {
 $("#fecForm").hide();
                  deviceInList = true $("#stereoForm").hide();
                break    $("#sendAudioBitrateForm").hide();
            }
        }
$("#cpuOveruseDetectionForm").hide();
              if (!deviceInList) {}
              var option =if document(Flashphoner.createElementisUsingTemasys("option");)) {
            option.text = device.label || device.id;
    $("#audioInputForm").hide();
        option.value = device.id;
            audio.appendChild(option$("#videoInputForm").hide();
        }
    });
    list.video.forEach(function(device) {}
        console.log(device);
    }
     var video = document.getElementById("videoInput");
        var i;
        var deviceInList = false;
        for (i = 0; i < video.options.length; i++) { })

2. List available media devices.

Flashphoner.getMediaDevices() код

When media devices are listed, drop-down lists on client page are filled.

Code Block
languagejs
themeRDark
    Flashphoner.getMediaDevices(null, true).then(function (list) {
        list.audio.forEach(function (device) {
            ...
        });
    if (video.options[i].value == device.id    list.video.forEach(function (device) {
                deviceInList = true;...
        });
        break;...
            }
        }
        if (!deviceInList}).catch(function (error) {
            var option = document.createElement$("option#notifyFlash");
    .text("Failed to get media devices");
    });

3. Get audio and video constraints from client page

getConstraints() code

Code Block
languagejs
themeRDark
function getConstraints() {
  option.text = device.label || device.id;constraints = {
            option.value = device.id;audio: $("#sendAudio").is(':checked'),
            video.appendChild(option);video: $("#sendVideo").is(':checked'),
        }
    });
    //local and remote displays
    localVideo = document.getElementById("localVideo");
    remoteVideo = document.getElementById("remoteVideo");

    $("#url").val(setURL() + "/" + createUUID(8));
    //set initial button callback
    onStopped();
}).catch(function(error) {
    $("#notifyFlash").text("Failed to get media devices");
});

If the list of devices is received, drop-down lists on the page are filled.
In case of failure, warning "Failed to get access to media devices" is displayed.

3. Connection to server. line 100

Connection to server is established when Start button is clicked.

Code Block
languagejs
themeRDark
Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
    //session connected, start streaming
    startStreaming(session);
}).on(SESSION_STATUS.DISCONNECTED, function(){
    setStatus(SESSION_STATUS.DISCONNECTED);
    onStopped();
}).on(SESSION_STATUS.FAILED, function(){
    setStatus(SESSION_STATUS.FAILED);
    onStopped();
});

Session is created with method createSession(). Callback function, which will be called in case of successfully established connection (status SESSION_STATUS.ESTABLISHED), is added.

4. Access to media. line 125

After establishing connection to the server, access to media (audio and video from the selected camera and microphone) is requested.
The following parameters are passed to method Flashphoner.getMediaAccess() used to get the access

  • video constrains
  • localVideo - <div> element, in which video from the selected camera will be displayed
Code Block
languagejs
themeRDark
Flashphoner.getMediaAccess(constraints, localVideo).then(function(){
    session.createStream({
customStream: $("#sendCanvasStream").is(':checked')
    };

    if (constraints.audio) {
        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());
    }

    if (constraints.video) {
        if (constraints.customStream) {
            constraints.customStream = canvas.captureStream(30);
            constraints.video = false;
        } else {
            constraints.video = {
                deviceId: {exact: $('#videoInput').val()},
                name: streamName,
width: parseInt($('#sendWidth').val()),
           display: localVideo,
      height: parseInt($('#sendHeight').val())
       cacheLocalResources: true
    }).on(STREAM_STATUS.PUBLISHING, function(publishStream){;
        var video = document.getElementById(publishStream.id());
        //resize local if resolution is available
 if (Browser.isSafariWebRTC() && Browser.isiOS() && Flashphoner.getMediaProviders()[0] === "WebRTC") {
                if (constraints.video.videoWidthwidth >= 0 && video.videoHeight > 0) {
            resizeLocalVideo({target: video}){min: parseInt($('#sendWidth').val()), max: 640};
        }
        //remove resize listener in case this video was cached earlier
constraints.video.height = {min: parseInt($('#sendHeight').val()), max: 480};
           video.removeEventListener('resize', resizeLocalVideo); }
        video.addEventListener('resize', resizeLocalVideo);
        setStatus(STREAM_STATUS.PUBLISHING);
if (parseInt($('#sendVideoMinBitrate').val()) > 0)
         //play preview
      constraints.video.minBitrate  session.createStream({= parseInt($('#sendVideoMinBitrate').val());
            name: streamName,
  if (parseInt($('#sendVideoMaxBitrate').val()) > 0)
          display: remoteVideo
     constraints.video.maxBitrate   }= parseInt($('#sendVideoMaxBitrate').on(STREAM_STATUS.PLAYING, function(previewStream){
val());
            if document.getElementById(previewStream.id()).addEventListener('resize', function(event){
(parseInt($('#fps').val()) > 0)
                constraints.video.frameRate = resizeVideo(event.targetparseInt($('#fps').val());
        }
    });

            //enable stop button
            onStarted(publishStream, previewStream);
  return constraints;
}

4. 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").on(STREAM_STATUS.STOPPED, function()off('click').click(function () {
            publishStream.stop($(this).prop('disabled', true);
            }).on(STREAM_STATUS.FAILED, function(){stopTest();
        }).prop('disabled', false);
    //preview  failed, stop publishStream...
        testStarted = true;
   if (publishStream}).statuscatch() == STREAM_STATUS.PUBLISHINGfunction (error) {
                setStatus(STREAM_STATUS.FAILED$("#testBtn").prop('disabled', false);
        testStarted = false;
      publishStream.stop();
    });

5. Connecting to the server

Flashphoner.createSession() code

Code Block
languagejs
themeRDark
    Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function (session) {
        //session connected, start }streaming
        }).playstartStreaming(session);
    }).on(STREAMSESSION_STATUS.UNPUBLISHEDDISCONNECTED, function () {
        setStatus(STREAMSESSION_STATUS.UNPUBLISHEDDISCONNECTED);
        //enable start button
        onStopped()onStopped();
    }).on(STREAMSESSION_STATUS.FAILED, function () {
        setStatus(STREAMSESSION_STATUS.FAILED);
        //enable start button
        onStopped();
    }).publish();
}, function(error){
    console.warn("Failed to get access to media " + error);
    onStopped();
});

In case of failure to get the access, warning "Failed to get access to media " is displayed.
If the access is allowed, new video stream is created with method session.createStream(), and function publish() is called to publish the stream (line 126).
When stream is created, the following parameters are passed

  • streamName - name of the stream
  • localVideo - <div> element, in which video from the camera will be displayed

When stream is created, callback functions for events STREAM_STATUS.PUBLISHING, STREAM_STATUS.UNPUBLISHED, STREAM_STATUS.FAILED can be added.

STREAM_STATUS.PUBLISHING - when this status is received,

  •  function resizeLocalVideo() is called to change resolution of video from the camera in accordance to the specified on the client page and adapt to <div> element localVideo, in which the video will be displayed (line 134)
  • preview video stream is created with method session.createStream(), and function play() is called to start playback of the stream in <div> element remoteVideo (line 141)

When preview stream is created, callback functions for events STREAM_STATUS.PLAYING, STREAM_STATUS.STOPPED, STREAM_STATUS.FAILED are added.

STREAM_STATUS.PLAYING - when this status is received, function resizeVideo() is called, which is used in the examples to adapt resolution to the element, in which the video will be displayed.

STREAM_STATUS.UNPUBLISHED and STREAM_STATUS.FAILED - when one of these statuses is received, function onStopped() of the example is called to make appropriate changes in controls of the interface.

5. Stop of playback. line 67

The following method is called to stop playback of preview video stream

Code Block
languagejs
themeRDark
previewStream.stop();

After calling the method, status STREAM_STATUS.STOPPED should arrive to confirm stop of playback from the server side.

6. Stop of streaming after stop of preview playback. line 151

The following method is called to stop video streaming

Code Block
languagejs
themeRDark
publishStream.stop();

...

);

6. Receiving the event confirming successful connection

ConnectionStatusEvent ESTABLISHED code

Code Block
languagejs
themeRDark
    Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function (session) {
        //session connected, start streaming
        startStreaming(session);
    }).on(SESSION_STATUS.DISCONNECTED, function () {
        ...
    }).on(SESSION_STATUS.FAILED, function () {
        ...
    });

7. Stream publishing

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

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

8. 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({
        name: streamName,
        display: localVideo,
        cacheLocalResources: true,
        constraints: constraints,
        mediaConnectionConstraints: mediaConnectionConstraints
    }).on(STREAM_STATUS.PUBLISHING, function (publishStream) {
        $("#testBtn").prop('disabled', true);
        var video = document.getElementById(publishStream.id());
        //resize local if resolution is available
        if (video.videoWidth > 0 && video.videoHeight > 0) {
            resizeLocalVideo({target: video});
        }
        enableMuteToggles(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);
        setStatus(STREAM_STATUS.PUBLISHING);

        //play preview
        var constraints = {
            audio: $("#playAudio").is(':checked'),
            video: $("#playVideo").is(':checked')
        };
        if (constraints.video) {
            constraints.video = {
                width: (!$("#receiveDefaultSize").is(":checked")) ? parseInt($('#receiveWidth').val()) : 0,
                height: (!$("#receiveDefaultSize").is(":checked")) ? parseInt($('#receiveHeight').val()) : 0,
                bitrate: (!$("#receiveDefaultBitrate").is(":checked")) ? $("#receiveBitrate").val() : 0,
                quality: (!$("#receiveDefaultQuality").is(":checked")) ? $('#quality').val() : 0
            };
        }
        previewStream = session.createStream({
            name: streamName,
            display: remoteVideo,
            constraints: constraints
            ...
        });
        previewStream.play();
    }).on(STREAM_STATUS.UNPUBLISHED, function () {
        ...
    }).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 () {
        $(this).prop('disabled', true);
        previewStream.stop();
    }).prop('disabled', false);

10. Receiving the event confirming successful playback stop

StreamStatusEvent STOPPED code

Code Block
languagejs
themeRDark
        previewStream = session.createStream({
            name: streamName,
            display: remoteVideo,
            constraints: constraints
        }).on(STREAM_STATUS.PLAYING, function (previewStream) {
            ...
        }).on(STREAM_STATUS.STOPPED, function () {
            publishStream.stop();
        }).on(STREAM_STATUS.FAILED, function () {
            ...
        });
        previewStream.play();

11. Streaming stop after preview playback stopped

publishStream.stop() code

Code Block
languagejs
themeRDark
        previewStream = session.createStream({
            name: streamName,
            display: remoteVideo,
            constraints: constraints
        }).on(STREAM_STATUS.PLAYING, function (previewStream) {
            ...
        }).on(STREAM_STATUS.STOPPED, function () {
            publishStream.stop();
        }).on(STREAM_STATUS.FAILED, function () {
            ...
        });
        previewStream.play();

12. Receiving the event confirming successful streaming stop

StreamStatusEvent UNPUBLISHED код

Code Block
languagejs
themeRDark
    publishStream = session.createStream({
        name: streamName,
        display: localVideo,
        cacheLocalResources: true,
        constraints: constraints,
        mediaConnectionConstraints: mediaConnectionConstraints
    }).on(STREAM_STATUS.PUBLISHING, function (publishStream) {
        ...
    }).on(STREAM_STATUS.UNPUBLISHED, function () {
        setStatus(STREAM_STATUS.UNPUBLISHED);
        //enable start button
        onStopped();
    }).on(STREAM_STATUS.FAILED, function () {
        ...
    });
    publishStream.publish();