Real-Time Communication

Real-Time Communication in the Web, WebRTC in short, is a set of APIs allowing Web applications to send and receive streaming real-time video, audio and data to/from remote peers, without relying it through the centralized server. The server, implementing one of the specific signalling protocols, is needed for initial discovery and connection handshake, though. The APIs rely on the mediaStream object - see Audio & Video Capture.

API glimpse

connection = new RTCPeerConnection(configuration)
Creates a connection object that will be used to establish serverless connection between peers. The configuration may include the set of iceServers that will be used for discovery and connection handshake.
connection.addEventListener('icecandidate', listener)
An event fired when the signalling server registers a remote peer with which the connection may be established.
connection.addStream(localMediaStream)
Adds an existing local Media Stream (e.g. the local Web cam) to the remote peer connection.
connection.onaddstream = event => video.src = URL.createObjectURL(event.stream)
Registers an onaddstream event handler that, if and when called, retrieves the remote party's Media Stream and plugs it into a <video> tag video.
connection.createOffer(options)
Returns a Promise resolved when the remote peer connects to the connections and streams offered.
connection.createAnswer(options)
Accepts the connection offerred by the remote peer. Returns a Promise resolved when the connection is established.
dataChannel = connection.createDataChannel(label, configuration)
Opens a data channel for the connection, allowing it to transmit arbitrary types of data.
dataChannel.send(data)
Sends the data over the data channel to the remote peer.
dataChannel.addEventListener('message', listener)
An event fired when the data has been received via the data channel.

Live Demo

Local video

Remote video

Demo by Miguel Casas-Sanchez.

  • function getUserMedia(options, successCallback, failureCallback) {
      var api = navigator.getUserMedia || navigator.webkitGetUserMedia ||
        navigator.mozGetUserMedia || navigator.msGetUserMedia;
      if (api) {
        return api.bind(navigator)(options, successCallback, failureCallback);
      }
    }
    
    var pc1;
    var pc2;
    var theStreamB;
    
    function getStream() {
      if (!navigator.getUserMedia && !navigator.webkitGetUserMedia &&
        !navigator.mozGetUserMedia && !navigator.msGetUserMedia) {
        alert('User Media API not supported.');
        return;
      }
      
      var constraints = {
        video: true
      };
      getUserMedia(constraints, function (stream) {
        addStreamToVideoTag(stream, 'localVideo');
    
        // RTCPeerConnection is prefixed in Blink-based browsers.
        window.RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection;
        pc1 = new RTCPeerConnection(null);
        pc1.addStream(stream);
        pc1.onicecandidate = event => {
          if (event.candidate == null) return;
          pc2.addIceCandidate(new RTCIceCandidate(event.candidate));
        };
    
        pc2 = new RTCPeerConnection(null);
        pc2.onaddstream = event => {
          theStreamB = event.stream;
          addStreamToVideoTag(event.stream, 'remoteVideo');
        };
        pc2.onicecandidate = event => {
          if (event.candidate == null) return;
          pc1.addIceCandidate(new RTCIceCandidate(event.candidate));
        };
    
        pc1.createOffer({offerToReceiveVideo: 1})
          .then(desc => {
            pc1.setLocalDescription(desc);
            pc2.setRemoteDescription(desc);
            return pc2.createAnswer({offerToReceiveVideo: 1});
          })
          .then(desc => {
            pc1.setRemoteDescription(desc);
            pc2.setLocalDescription(desc);
          })
          .catch(err => {
            console.error('createOffer()/createAnswer() failed ' + err);
          });
      }, function (err) {
        alert('Error: ' + err);
      });
    }
    
    function addStreamToVideoTag(stream, tag) {
      var mediaControl = document.getElementById(tag);
      if (navigator.mozGetUserMedia) {
        mediaControl.mozSrcObject = stream;
      } else {
        mediaControl.srcObject = stream;
        mediaControl.src = (window.URL || window.webkitURL).createObjectURL(stream);
      }
    }
  • 
    <p><button class="btn btn-lg btn-default" onclick="getStream()">Grab video & start local peer connection</button></p>
    
    <p>Local video</p>
    <video autoplay id="localVideo" style="height:180px; width: 240px;" poster="https://image.freepik.com/free-icon/video-camera-symbol_318-40225.png"></video>
    
    <p>Remote video</p>
    <video autoplay id="remoteVideo" style="height:180px; width: 240px;"></video>
    
    <p><small>Demo by <a href="http://www.mcasas.tk/" target="_blank">Miguel Casas-Sanchez</a>.</small></p>

Resources