Versions Compared

Key

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

...

On demand, WCS can capture a WebRTC video stream published by another WCS server. The captured stream can be than broadcast to to any of supported platforms using using any of supported technologytechnologies. Managing of WebRTC stream capturing is performed using REST API.

...

  1. The browser connects to the WCS1 server via Websocket and sends the publish command.
  2. The browser captures the microphone and the camera and sends the WebRTC stream to the server.
  3. The REST client sends to the WCS2 server the /pull/pull query.
  4. WCS2 requests the stream from WCS1.
  5. WCS2 receives the WebRTC stream from WCS1.
  6. The second browser establishes a connection to the WCS2 server via Websokcet and sends the play command.
  7. The second browser receives the WebRTC stream and plays this stream on the page.

REST-queries

 RESTREST-query must be an HTTP/HTTPS POST request as follows:

  • - HTTP: http://test.flashphoner.com:

...

  • 8081/rest-api/pull/rtmp/pull
  • - HTTPS: https://test.flashphoner.com:

...

  • 8444/rest-api/pull/rtmp/pull

Where:

  • test.flashphoner.com - is the address of the WCS server
  • -

...

  • 8081 - is the standard REST / HTTP port of the WCS server

...

  • 8444 - is the standard HTTPS port
  • rest-api - is the required part of the URL
  • - /pull/rtmp/pull - is the REST method used

 REST-methods and response statuses

REST-method

Example of REST-query

Example of REST response

Response status

Description

/pull/pull

Code Block
languagejs
themeRDark
{  
   "uri":"wss://demo.flashphoner.com:8443",
   "localStreamName": "testStream",
   "remoteStreamName": "testStream"
}

409 - Conflict

500 - Internal error


Pull the WebRTC stream at the specified URL


/pull/find_all


Code Block
languagejs
themeRDark
{
"localMediaSessionId": "5a072377-73c1-4caf-abd3",
"remoteMediaSessionId": null,
"localStreamName": "testStream",
"remoteStreamName": "testStream",
"uri": "wss://demo.flashphoner.com:8443",
"status": "NEW"

200 – streams are found

500 - Internal error

Find all pulled WebRTC streams

/pull/terminate

Code Block
languagejs
themeRDark
{  
   "uri":"wss://demo.flashphoner.com:8443",
   "localStreamName": "testStream",
   "remoteStreamName": "testStream"
}

200 - stream terminated

500 - Internal error

Terminate the pulled WebRTC stream

Parameters

Parameter name

Description

Example

uri

Websocket URL of

the WebRTC stream

WCS server

wss://demo.flashphoner.com:8443

localMediaSessionId

Session identifier

5a072377-73c1-4caf-abd3

remoteMediaSessionId

Session identifier on the remote server

12345678-abcd-dead-beaf

localStreamName

Local name assigned to the captured stream. By this name the stream can be requested from the WCS server

testStream

remoteStreamName

Captured stream name on the remote server

testStream

status

Current stream status

NEW

Quick manual on testing

1. For this test we use:

  • two WCS servers;
  • the Chrome browser and a REST-client to send queries to the server;
  • the Two Way Streaming web application to publish the stream;
  • the Player web application to play the captured stream in the browser.

2. Open the Two Way Streaming web application and publish the stream on the server

Image Removed

3. Open the REST client. Send the /pull/pull query and specify the following parameters:

  • URL of the WCS server the stream is captured from;
  • stream name published on the server
  • local stream name

Image Removed

4. Make sure the server captured the stream. To do this, send the /pull/find_all query:

Image Removed

Image Removed

5. Open the Player web application and put in the local stream name into the Stream field, then click Start

Image Removed

Configuration

By default, WebRTC stream is pulled over unsecure Websocket connection, i.e. WCS server URL has to be set as ws://demo.flashphoner.com:8080. To use Secure Websocket, the parameter must be set in file flashphoner.properties

Code Block
languagebash
themeRDark
wcs_agent_ssl=true

This change has to be made on both WCS servers: the server that publishes the stream and the server the stream is pulled to.

Quick manual on testing

1. For this test we use:

  • two WCS servers;
  • the Chrome browser and a REST-client to send queries to the server;
  • the Two Way Streaming web application to publish the stream;
  • the Player web application to play the captured stream in the browser.

2. Open the Two Way Streaming web application and publish the stream on the server

Image Added


3. Open the REST client. Send the /pull/pull query and specify the following parameters:

  • URL of the WCS server the stream is captured from;
  • stream name published on the server
  • local stream name

Image Added


4. Make sure the server captured the stream. To do this, send the /pull/find_all query:

Image Added


Image Added


5. Open the Player web application and put in the local stream name into the Stream field, then click Start

Image Added

Call flow

Below is the call flow when using the Two Way Streaming example to publish a stream on one WCS server and playing that stream on another WCS server

...

Code Block
languagejs
themeRDark
    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. Publishing the stream.

...

Code Block
languagejs
themeRDark
    session.createStream({
        name: streamName,
        display: localVideo,
        cacheLocalResources: true,
        receiveVideo: false,
        receiveAudio: false
    }).on(STREAM_STATUS.PUBLISHING, function (stream) {
        setStatus("#publishStatus", STREAM_STATUS.PUBLISHING);...
        onPublishing(stream);
    }).on}).on(STREAM_STATUS.UNPUBLISHED, function () {
        setStatus("#publishStatus", STREAM_STATUS.UNPUBLISHED);
    ...
    onUnpublished();
    }).on(STREAM_STATUS.FAILED, function () {
        setStatus("#publishStatus", STREAM_STATUS.FAILED);...
        onUnpublished}).publish();
    }).publish();


4. Receiving from the server an event confirming successful publishing of the stream.

...

Code Block
languagejs
themeRDark
    session.createStream({
        name: streamName,
        display: localVideo,
        cacheLocalResources: true,
        receiveVideo: false,
        receiveAudio: false
    }).on(STREAM_STATUS.PUBLISHING, function (stream) {
        setStatus("#publishStatus", STREAM_STATUS.PUBLISHING);
        onPublishing(stream);
    }).on(STREAM_STATUS.UNPUBLISHED, function () {
        setStatus("#publishStatus", STREAM_STATUS.UNPUBLISHED);
    ...
    onUnpublished();
    }).on(STREAM_STATUS.FAILED, function () {
        setStatus("#publishStatus", STREAM_STATUS.FAILED);...
        onUnpublished}).publish();
    }).publish();


5. Sending the audio- video stream via WebRTC to the server

...

Flashphoner.createSession(); code

Code Block

stream.play(); code

Code Block
languagejs
themeRDark
    stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) {
        var video = document.getElementById(stream.id());
        if (!video.hasListeners) {
            video.hasListeners = true;
            video.addEventListener('playing', function () {
                $("#preloader").hide();
            });
            video.addEventListener('resize', function (event) {
                var streamResolution = stream.videoResolution();
                if (Object.keys(streamResolution).length === 0) {
                    resizeVideo(event.target);
                } else {
                    // Change aspect ratio to prevent video stretching
                    var ratio = streamResolution.width / streamResolution.height;
                    var newHeight = Math.floor(options.playWidth / ratio);
                    resizeVideo(event.target, options.playWidth, newHeight);
                }
            });
        }
    }).on(STREAM_STATUS.PLAYING, function(stream) {
        $("#preloader").show();
        setStatus(stream.status());
        onStarted(stream);
    }).on(STREAM_STATUS.STOPPED, function() {
        setStatus(STREAM_STATUS.STOPPED);
        onStopped();
    }).on(STREAM_STATUS.FAILED, function(stream) {
        setStatus(STREAM_STATUS.FAILED, stream);
        onStopped();
    }).on(STREAM_STATUS.NOT_ENOUGH_BANDWIDTH, function(stream){
        console.log("Not enough bandwidth, consider using lower video resolution or bitrate. Bandwidth " + (Math.round(stream.getNetworkBandwidth() / 1000)) + " bitrate " + (Math.round(stream.getRemoteBitrate() / 1000)));
    });
    stream.play();

12. Receiving from the server an event confirming successful capturing and playing of the stream.

StreamStatusEvent, status PLAYING code

stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) { var video = document.getElementById(stream.id()); if (!video.hasListeners) { video.hasListeners = true; video.addEventListener('playing', function () { $("#preloader").hide(); }); video.addEventListener('resize', function (event) { var streamResolution = stream.videoResolution(); if (Object.keys(streamResolution).length === 0) { resizeVideo(event.target); } else { // Change aspect ratio to prevent video stretching
Code Block
languagejs
themeRDark
languagejs
themeRDark
    Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
        setStatus(session.status());
        //session connected, start playback
        playStream(session);
    }).on(SESSION_STATUS.DISCONNECTED, function(){
        setStatus(SESSION_STATUS.DISCONNECTED);
        onStopped();
    }).on(SESSION_STATUS.FAILED, function(){
        setStatus(SESSION_STATUS.FAILED);
        onStopped();
    });

10. Receiving from the server and event confirming successful connection.

ConnectionStatusEvent ESTABLISHED code

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

...

RDark
    Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
        setStatus(session.status());
        //session connected, start playback
         var ratio = streamResolution.width / streamResolution.height playStream(session);
    }).on(SESSION_STATUS.DISCONNECTED, function(){
        setStatus(SESSION_STATUS.DISCONNECTED);
        var newHeight = Math.floor(options.playWidth / ratio);
onStopped();
    }).on(SESSION_STATUS.FAILED, function(){
        setStatus(SESSION_STATUS.FAILED);
             resizeVideo(event.target, options.playWidth, newHeightonStopped();
    });


10. Receiving from the server and event confirming successful connection.

ConnectionStatusEvent ESTABLISHED code

Code Block
languagejs
themeRDark
            }Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
            }setStatus(session.status());
        }
    }).on(STREAM_STATUS.PLAYING, function(stream) {//session connected, start playback
        $playStream("#preloader").show()session);
        setStatus(stream.status());}).on(SESSION_STATUS.DISCONNECTED, function(){
        onStarted(stream);...
    }).on(STREAMSESSION_STATUS.STOPPEDFAILED, function() {
        ...
   setStatus(STREAM_STATUS.STOPPED);
 });


11. Requesting to play the stream.

stream.play(); code

Code Block
languagejs
themeRDark
    stream    onStopped();
    })= session.createStream(options).on(STREAM_STATUS.FAILEDPENDING, function(stream) {
        setStatus(STREAM_STATUS.FAILED, stream);
        onStopped();
    }).on(STREAM_STATUS.NOT_ENOUGH_BANDWIDTH, function(stream){
var video = document.getElementById(stream.id());
        if console.log("Not enough bandwidth, consider using lower video resolution or bitrate. Bandwidth " + (Math.round(stream.getNetworkBandwidth() / 1000)) + " bitrate " + (Math.round(stream.getRemoteBitrate() / 1000)));
    });
    stream.play();

13. Sending the audio- video stream via WebRTC

14. Stopping playback of the stream

stream.stop(); code

Code Block
languagejs
themeRDark
function onStarted(stream) {
(!video.hasListeners) {
            video.hasListeners = true;
            video.addEventListener('playing', function () {
                $("#playBtn#preloader").text("Stop").off('click').click(function()hide();
            });
            video.addEventListener('resize', function (event) {
        $(this).prop('disabled', true);
        var streamResolution = stream.stopvideoResolution();
    }).prop('disabled', false);
      $("#fullScreenBtn").off('click').click(function(){
      if stream(Object.fullScreenkeys();
streamResolution).length === 0) {
     }).prop('disabled', false);
    $("#volumeControl").slider("enable");
    stream.setVolume(currentVolumeValue);
}

15. Receiving from the server an event confirming successful unpublishing of the stream.

StreamStatusEvent, status STOPPED code

Code Block
languagejs
themeRDark
    stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) {
resizeVideo(event.target);
                } else {
                 var   // Change aspect ratio to prevent video = document.getElementById(stream.id());
stretching
         if (!video.hasListeners) {
         var ratio = videostreamResolution.hasListenerswidth =/ truestreamResolution.height;
            video.addEventListener('playing', function () {
             var newHeight = Math.floor(options.playWidth / ratio);
           $("#preloader").hide();
         resizeVideo(event.target,   }options.playWidth, newHeight);
            video.addEventListener('resize', function (event) {    }
                var streamResolution = stream.videoResolution(});
        }
        if (Object.keys(streamResolution).length === 0) {...
    });
    stream.play();


12. Receiving from the server an event confirming successful capturing and playing of the stream.

StreamStatusEvent, status PLAYING code

Code Block
languagejs
themeRDark
    stream = session.createStream(options).on(STREAM_STATUS.PENDING, function(stream) {
        resizeVideo(event.target);...
    }).on(STREAM_STATUS.PLAYING, function(stream) {
          } else {$("#preloader").show();
        setStatus(stream.status());
          onStarted(stream);
  // Change aspect ratio to prevent video stretching
 }).on(STREAM_STATUS.STOPPED, function() {
        ...
    }).on(STREAM_STATUS.FAILED, function(stream) {
        ...
 var ratio = streamResolution.width / streamResolution.height; }).on(STREAM_STATUS.NOT_ENOUGH_BANDWIDTH, function(stream){
        ...
    });
        var newHeight = Math.floor(options.playWidth / ratio);
                    resizeVideo(event.target, options.playWidth, newHeight);stream.play();


13. Sending the audio- video stream via WebRTC

14. Stopping playback of the stream

stream.stop(); code

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


15. Receiving from the server an event confirming successful unpublishing of the stream.

StreamStatusEvent, status STOPPED code

Code Block
languagejs
themeRDark
    stream    }
    }= session.createStream(options).on(STREAM_STATUS.PLAYINGPENDING, function(stream) {
        $("#preloader").show();
        setStatus(stream.status());(stream) {
        onStarted(stream);...
    }).on(STREAM_STATUS.STOPPEDPLAYING, function(stream) {
        setStatus(STREAM_STATUS.STOPPED);...
        onStopped();
    }).on(STREAM_STATUS.FAILEDSTOPPED, function(stream) {
        setStatus(STREAM_STATUS.FAILED, streamSTOPPED);
        onStopped();
    }).on(STREAM_STATUS.NOT_ENOUGH_BANDWIDTH, function(stream){
        console.log("Not enough bandwidth, consider using lower video resolution or bitrate. Bandwidth " + (Math.round(stream.getNetworkBandwidth() / 1000)) + " bitrate " + (Math.round(stream.getRemoteBitrate() / 1000)));FAILED, function(stream) {
        ...
    }).on(STREAM_STATUS.NOT_ENOUGH_BANDWIDTH, function(stream){
        ...
    });
    stream.play();


16. Stopping publishing the stream.

...

Code Block
languagejs
themeRDark
   session.createStream({
        name: streamName,
        display: localVideo,
        cacheLocalResources: true,
        receiveVideo: false,
        receiveAudio: false
    }).on(STREAM_STATUS.PUBLISHING, function (stream) {
        setStatus("#publishStatus", STREAM_STATUS.PUBLISHING);...
        onPublishing(stream);
    }).on(STREAM_STATUS.UNPUBLISHED, function () {
        setStatus("#publishStatus", STREAM_STATUS.UNPUBLISHED);
        onUnpublished();
    }).on(STREAM_STATUS.FAILED, function () {
        setStatus("#publishStatus", STREAM_STATUS.FAILED);...
        onUnpublished();
    }).publish();