Flussonic Media Server documentation

WebRTC Publishing

WebRTC Anchor Anchor x2

WebRTC is P2P protocol of communication between two clients, however it specifies only the data transfer by the already established connection. I.e. to communicate with each other by WebRTC, two browsers need to be connected some way, for example by opening the same website in the Internet, that will get them in touch. Connection can also be established by means of a mediator, so called signaling server.

So there are two clients and a signaling server, that connects these clients, in WebRTC. The process of establishing P2P connection between the two clients is the exchange of media streams textual descriptions in SDP format. The signaling server (the mediator) makes it possible to transfer SDP from one client to the other.

Standard scheme of P2P communication by WebRTC means that there should be two sessions arranged: audio-video stream from A client to B client, and vice versa – from B to A.

Flussonic can be the signaling server and the client at the same time, both getting and sending the video stream. Therefore here we may talk of video publishing on Flussonic by WebRTC and of video play by WebRTC.

Video and audio stream publishing by WebRTC Anchor Anchor x2

The procedure of connection establishment for the video and audio stream publishing to Flussonic by WebRTC is pretty much similar to video receiving. The principle here stays the same – participants should exchange SDP via the mediator (signaling server), and then start the direct data transfer. However in case with video publishing the information exchange with the signaling server goes in a slightly different manner. The process should be initiated and the SDP offer should be sent from the client’s end. This is the core difference.

Attention! Please note, that in some browsers WebRTC video and audio streams publishing is possible by secure connection only. I.e. browser can deny access to the camera and microphone from a page located not by HTTPS, but by HTTP address. This is allowed on local addresses (localhost, 127.0.0.1).

Like in case with the video sending, the result of SDP exchange by means of the signaling server should be a local PeerConnection object with LocalDescription and RemoteDescription given properties, that contains the local and the remote SDP description accordingly.

To initiate the WebRTC connection with Flussonic one should open WebSocket connection with Flussonic by the following address: ws://192.168.2.3:8080/STREAMNAME/webrtc, where 192.168.2.3:8080 is an example of your Flussonic’s address and port. Ws and wss protocols are supported. Для того, чтобы запустить процесс установления WebRTC соединения с Flussonic нужно открыть WebSocket соединение по адресу ws://192.168.2.3:8080/STREAMNAME/webrtc/publish где 192.168.2.3:8080 - это пример адреса и порта вашего Flussonic. Поддерживаются протоколы ws и wss.

For the further direct P2P connection setting one should create PeerConnection and set onicecandidate handler. After WebSocket connection is established, client should send SDP offer to the WebSocket, and the same offer should be set as LocalDescription. When the server gets the offer, it sends its identifier (SDP Answer) in return. This SDP answer should be processed on the client (it should be set as RemoteDescription for the previously created PeerConnection).

function openWebSocketConnection(options) {
  var url =
    options.protocol + "://" + 
    options.server + ":" +
    options.port + "/" +
    options.stream + "/webrtc/publish";

  websocket = new WebSocket(url);
  websocket.onopen = initPeerConnection;
  websocket.onmessage = onWebSocketMessage;
}

function initPeerConnection() {
  peerConnection = new window.RTCPeerConnection(null);
  peerConnection.stream_id = "local1";
  peerConnection.onicecandidate = gotIceCandidate;

  getMedia().then(gotMedia);
}

function sendWebSocketMessage(data) {
  websocket.send(JSON.stringify(data));
}

function onWebSocketMessage(event) {
  var message = JSON.parse(event.data);

  switch (message.type) {
    case "answer":
      var description = new window.RTCSessionDescription(message);
      peerConnection.setRemoteDescription(description);
    break;
    case "candidate":
      var candidate = new window.RTCIceCandidate(message.candidate);
      peerConnection.addIceCandidate(candidate);
    break;
  }
}

In onicecandidate handler of PeerConnection object it is required to implement IceCandidate message sending to the open Web Socket. After that Flussonic returns the message, that contains IceCandidate SDP, via the WebSocket. At this stage we can be sure, that both sides know each other’s SDP and the direct connection can be initiated.

function gotIceCandidate(event){
  var candidate = event.candidate;
  if (candidate) {
    sendWebSocketMessage({
      type: 'candidate',
      stream_id : "local1",
      label: candidate.sdpMLineIndex,
      id: candidate.sdpMid,
      candidate: candidate
    });
  }
}

As you can see, the code is almost identical to the one in WebRTC video receiving example. There is some difference though. When publishing video, we send SDP offer from the client’s end, and thus we should process the SDP answer, that comes from the server.

It is also necessary to get access to the device’s webcam and microphone in order to set video and audio streams to the server. This can be done with the help of navigator.mediaDevices API. We can also set srcObject property in the local HTML5 Video tag. It no way affects the mediastream sending to the server, but it allows to see the outgoing content.

function getMedia() {
  return navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true
  });
}

function gotMedia(stream) {
  video.srcObject = stream;
  peerConnection.addStream(stream);

  peerConnection.createOffer({
    "offerToReceiveAudio": true,
    "offerToReceiveVideo":true
  }).then(function(description) {
    return peerConnection.setLocalDescription(description);
  }).then(function() {
    sendWebSocketMessage(peerConnection.localDescription)
  })
}

The complete code of the example can be found here.