WebRTC Integrator's Guide
上QQ阅读APP看书,第一时间看更新

Description of the WebRTC client-server model

The components of a typical WebRTC SIP-based client include the following:

  • SIP stack, in the form of a JavaScript library, to perform signaling
  • Cascading Style Sheets (CSS) to style a page
  • WebRTC media API to render a peer-to-peer connection between the audio-video components of a page
  • An HTML5-based graphical interface to provide inputs such as registration parameters, self-URI (short for Uniform Resource Identifier), URI of the party to be called, and so on

The following diagram depicts the important components to set up a WebRTC infrastructure:

.

The client side must be linked to a server that runs on the network side to complete the signal flow. The components that must be deployed on the network side are as follows:

  • The WebRTC gateway to connect to the native SIP world
  • The SIP server to embed the SIP application/proxy logic

The web browser is the key component in WebRTC transactions. It is the client-side environment that pulls out the HTML content from a web server, interprets the HTML tags, and displays the web page to the user. A WebRTC-capable browser has the additional ability to access the user's input media devices, such as microphones and camera, and stream them across the network. In the preceding diagram, there are some key functions of WebRTC media API that are embedded in the browser. These include codecs for audio and video, noise reduction, image enhancements, jitter buffer, multiplexing, SRTP, ICE in STUN /TURN, and so on. The gateway is the internetworking node between WebRTC's SIP over WebSocket side and traditional SIP/IMS side. The traditional SIP-based network is depicted by the SIP server in the preceding diagram.

The parts for media handling between WebRTC and non-WebRTC clients, such as relay and transcoding, will be explained in depth in later chapters. Here, we shall look at an infrastructure compromising of only SIP and WebRTC. For now, consider a simple WebRTC client trying to communicate with another WebRTC client through the browser interface. There are many SIP and WebRTC implementations available today; we will consider sipML5 and jsSIP among these to make a simple WebRTC client, which will communicate via an SIP server.

The sipML5 WebRTC client

The sipML5 client is a library of SIP and Session Description Protocol (SDP) stacks written in JavaScript, using WebSocket as the network transport mechanism. It supports TCP, UDP, and TLS transports. It is provided under the BSD license. There are three ways of using SipML5 WebRTC client:

  • The first option is to use the online demo version available at http://sipml5.org/call.htm
  • The second option is to make use of the minified version of the JavaScript API and code that can be imported and loaded directly using the web server
  • The third option (recommended for integrators) is to get the developers' version of the sipML5 master that can be checked out from GitHub and used for development and debugging for enhanced operations

Let's begin the exercise using only the primitive and necessary sipML5 functions to make a call successfully from a web page without the need of backbone components such as web.xml and the Java source. To simplify things, we will not look into the enhanced features such as Presence (Subscribe, Notify), DTMF, and speed dialing at this point. These topics will be covered in Chapter 6, Basic Features of WebRTC over SIP.

Developing a minified webphone application using Tomcat

The steps to set up a Tomcat web server are described in this section.

  1. First is the installation of a web application server to host the web archive (war) that contains the WebRTC call page. We are using Apache Tomcat Version 7.0.50 here. It can be downloaded from https://tomcat.apache.org/.
  2. We must ensure that JAVA_HOME is set as an environmental variable for Tomcat in Windows (refer to the following screenshot).
  3. Start the Tomcat batch script after the preceding two steps. You will see the following output in the console:

The code for the web page that acts like a web-based phone using WebRTC calls (along with the explanation of various code snippets) is given as follows:

  1. Start the process by making a local copy of the SIP-signaling JavaScript file. Open an empty text file and import the sipml5-api JS library file from http://sipml5.googlecode.com/svn/trunk/release/SIPml-api.js.
  2. Write the following JavaScript functions to initialize the engine:
    var readyCallback = function(e){
      createSipStack();      // see next section
    };
    var errorCallback = function(e){   // stack failed to initialize
        console.error('Failed to initialize the engine:' + e.message);
    }
    SIPml.init(readyCallback, errorCallback);
  3. The following function shows how to define event reactions when the client has started and when a call arrives:
    var eventsListener = function(e){
      if(e.type == 'started'){
        login();
      }
    
      else if(e.type == 'i_new_call'){
     // incoming audio/video call acceptCall(e);
      }
    }
  4. The following is the JavaScript code to start an SIP stack with parameters in SIPml:
    var sipStack;
    function createSipStack(){
      sipStack = new SIPml.Stack({
        realm: 'sip2sip.info',   // mandatory : domain name
        impi: 'altanai',         // mandatory : IMS Private Identity
        impu: 'SIP:altanai@sip2sip.info',
        // mandatory  : IMS Public Identity
    
        password: '/*enter sip2sip.info account password*/',
        display_name: 'altanai',
        websocket_proxy_url: 'wss://sipml5.org:10062', 
        outbound_proxy_url: 'udp://example.org:5060', 
        enable_rtcweb_breaker: false, 
        events_listener: { events: '*', listener: eventsListener }, 
        //optional: '*' means all events
      });
    }
    sipStack.start();
  5. The declaration of the elements to make and receive a call is given as follows:
    var callSession;
    var makeCall = function(){
      callSession = sipStack.newSession('call-audiovideo', {
        video_local: document.getElementById('video-local'),
        video_remote: document.getElementById('video-remote'),
        audio_remote: document.getElementById('audio-remote'),
        events_listener: { events: '*', listener: eventsListener } 
    
      });
      callSession.call('johndoe');
    }
  6. The function definition to accept an incoming call using the sipML5 library is given as follows:
    var acceptCall = function(e){
      e.newSession.accept();
      // e.newSession.reject() to reject the call
    }
  7. Add HTML containers for local and remote videos as shown in the following lines of code:
    <video width="100%" height="100%" id="video_remote" 
    autoplay="autoplay"></video>
    
    <video class="video" width="88px" height="72px" id="video_local" autoplay="autoplay" muted="true">
  8. Make a folder under the webapps folder within the Tomcat folder. Name it miniSipml5phone, place the SIPml5-API.js file, and rename the file we created as index.html.
  9. Open http://<ip>:<port>/<foldername> in a browser to load the web page. To test whether this code is working on the machine or not, add http://localhost:8080/miniSipml5phone in the address bar to load the call page.

After developing the WebRTC client and deploying it over the Application Server, it's time to test its functions. The best way to do this is by inspecting the traces. Use the console screen of Chrome or Firefox to see the traces of SIP requests. The trace for an SIP stack initialization should be of the following structure.

SIPML5 API version = 1.3.214 
User-Agent=Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36 
WebSocket supported = yes 
SIP stack start: proxy='ns313841.ovh.net:12060', realm='<SIP:sip2sip.info>', impi='altanai', impu='<SIP:altanai@sip2sip.info>' 
Connecting to 'WS://ns313841.ovh.net:12060' 

__tsip_transport_WS_onopen 
State machine: c0000_Started_2_Outgoing_X_oINVITE PeerConnectionClass = function RTCPeerConnection() { [native code] } SessionDescriptionClass = function RTCSessionDescription() { [native code] } IceCandidateClass = function RTCIceCandidate() { [native code] } 

Video Constraints:{ /* video constrains added to WebRTC client appear here */}
ICE servers:[/* list of stun servers added to WebRTC client appear here */] 
onGetUserMediaSuccess 
createOffer

If an exception occurs for a missing resource such as an audio, a JavaScript, or an image file, the browser console depicts a notification for it. The following statement is a "GIF file not found" notification:

GET http://144.55.64.89:8080/WebRTCphone/images/.gif 404 (Not Found)

We must make amendments to the HTML content that points to the correct resource path so as to run the WebRTC client code unobstructed. In case the JavaScript file for SIP functions is not loaded properly, the web handshake and the subsequent communication operation will not take place.

The SIP requests and SDP can be viewed here; this can help in solving errors. The trace for the SIP INVITE request from the WebRTC client is of the following structure. The ICE candidates come in to play first. After this, the SIP INVITE request for a call is generated and sent to the other user along with SDP.

ICE GATHERING COMPLETED!
onIceGatheringCompleted 
SEND: INVITE SIP:testagent@sip2sip.info SIP/2.0
Via: SIP/2.0/WS df7jal23ls0d.invalid;branch=z9hG4bKSM7tGLdSUy3DpGehaPa78HHpvmir89Uh;rport
From: <SIP:altanai@sip2sip.info>;tag=2CEhe0X78NxVm7aRCaBa
To: <SIP:testagent@sip2sip.info>
Contact: "undefined"<SIP:altanai@df7jal23ls0d.invalid;rtcweb-breaker=no;click2call=no;transport=WS>
Call-ID: 16a15a79-e4a6-78a1-2310-1243ebafe826
CSeq: 59935 INVITE
Content-Type: application/sdp
Content-Length: 3984
Max-Forwards: 70

v=0
o=- 6574822970880695000 2 IN IP4 127.0.0.1
s=Doubango Telecom - chrome
t=0 0
a=group:BUNDLE audio video
m=audio 15856 RTP/SAVPF 111 103 104 0 8 106 105 13 126
c=IN IP4 103.253.172.143
a=ice-options:google-ice
a=mid:audio
a=sendrecv
a=ice-options:google-ice
a=mid:video
a=sendrecv
a=rtcp-mux

Tip

The SDP and SIP traces shown here are modified to depict only the important headers. Many other headers have been removed from traces for clarity.

Now that we have gained a bit of insight into WebRTC code components, let's use this to develop the complete JavaScript of the sipML5 library and constitute a dynamic web project, which will be later used to embed the logic of other features such as phonebook, call logs, voicemail, and user profile.

Developing our customized version of the sipML5 client

This section describes the process of building our own customized WebRTC client. It is built over the SIP library, WebRTC API, and the web-based Graphical User Interface (GUI) to enable the user to make and receive calls. The following steps outline the process of creating a customized WebRTC client using Dynamic Project wizard of Eclipse. This differs from the earlier approach, in which we were using the web-deployed sipML5 WebRTC web page.

Once we set up our own sipML5 web project, it is easy to make changes in the configurations and user interface.

  1. Download sipML5-master from GitHub (refer to https://github.com/sipml5). Unzip and extract the folder.
  2. Make an empty, dynamic, web project in Eclipse. Let's assume that the name of the project is WebRTCSimpl5.
  3. Copy the files under the release folder into the WebContent folder of Eclipse. Now, the project explorer should look like the following screenshot:
  4. Run call.htm on any web server such as Tomcat. Tomcatv7.0 is used on the localhost.
  5. Open the web page in a web browser that supports WebRTC. We must add our SIP credentials on this page for the server to register the WebRTC SIP client. An SIP client registration requires the authentication name, SIP URI, password, and domain name fields to be specified at the time of registration. The following screenshot shows the call.htm page that runs from the local Tomcat web server:
  6. Open the expert.htm page by clicking on the Expert mode? button. When using a public server such as iptel or SIP2SIP, the domain name entered in the registration section is enough to locate the server and connect the client with it. However, for self-configured servers, the server address of the WebSocket server must be entered in the WebSocket server URL field. For example, if the WebSocket SIP server is installed on the machine with IP 97.54.67.12 and the ws port is 443, then the ws URL will be ws://97.54.67.12:443. The following screenshot shows the Expert.htm page, where the server parameters are entered when the page is run from the local Tomcat web server:

    Expert.htm page, where server parameters are entered while the page is run from local Tomcat web server

  7. Register the client with the SIP server by clicking on the Register button. The browser console can be monitored at this stage; the console depicts the registration SIP request being generated and sent to the SIP server.

    Check browser console traces to find out any server errors of components and missing exceptions on the web page.

Similarly, a jsSIP WebRTC client can also be configured to use a WebRTC-supported SIP server.

The jsSIP WebRTC client

The jsSIP client is a JavaScript library of the SIP stack and SDP, much similar to sipML5.It can also be used in the following three ways:

  • The first option is to use the online demo of the jsSIP WebRTC client that can be found at http://tryit.jssip.net/.
  • The second option is to use the minified version of the jsSIP JavaScript API, and the code.
  • The third option is to get the developer's version of the jsSIP master from GitHub and use it for development and debugging.

Developing our version of the jsSIP client

To integrate the SIP WebRTC functionality into an existing web application, it is required that you develop the WebRTC client from basic components so that it can be customized later. We can perform the following steps to make a Dynamic Web Project of the jsSIP WebRTC client using Eclipse Wizard, similar to the sipML5 project:

  1. Download jsSIP-demo-master from GitHub (http://jssip.net/download/) and unzip it.
  2. Make an empty dynamic web project in Eclipse. Let's assume that we name it WebRTCJssip.
  3. Copy the files into WebContent of the project in Eclipse. The project explorer should look like the following screenshot:
  4. Open the index.html file to add the reference to the latest jssip-0.3.0.js library file using the following line of code:
    <script src="http://jssip.net/download/jssip-0.3.0.js" type="text/javascript"></script>
  5. Instantiate the following config parameters now or add them later:
    $(document).ready(function(){
    
      // Default settings.
      var default_SIP_uri = "jmillan@jssip.net";
      var default_SIP_password = '';
      var outbound_proxy_set = {
        host: "tryit.jssip.net:10080",
    WS_path:'WS',
    WS_query: 'wwdf'
      };
    JSsipPhone = new JsSIP.UA(configuration);
  6. Use the existing event definition or add your own under the existing function's body. The event definition is as follows:
    //WebSocket connection events
    JSsipphone.on('connected', function(e){ });
    JSsipphone.on('disconnected', function(e){ });
    
    //New incoming or outgoing call event
    JSsipphone.on('newRTCSession', function(e){ });
    
    //New incoming or outgoing IM message event
    JSsipphone.on('newMessage', function(e){ });
    
    //SIP registration events
    JSsipphone.on('registered', function(e){ });
    JSsipphone.on('unregistered', function(e){ });
    JSsipphone.on('registrationFailed', function(e){ });
  7. The following functions describe how to make an outgoing or receive an incoming audio/video call. Use the existing function calls to add your Graphical User Interface (GUI) response with the help of CSS and jQuery, such as show remote and local video captured in the video div and print console info traces for tracing.
  8. The following are the HTML5 <video> elements in which local and remote videos will be shown:
    var selfView = document.getElementById('my-video');
    var remoteView = document.getElementById('peer-video');
  9. Register callbacks to the desired call events using the following lines of code:
    var eventHandlers = {
      'progress':   function(e){ },
      'failed':     function(e){ },
      'started':    function(e){
        var rtcSession = e.sender;
  10. Attach local stream to selfView using the following lines of code:
    if (rtcSession.getLocalStreams().length > 0) {
      selfView.src = window.URL.createObjectURL(rtcSession.getLocalStreams()[0]);
    }
  11. Attach remote stream to remoteView using the following lines of code:
    if (rtcSession.getRemoteStreams().length > 0) {
      remoteView.src = window.URL.createObjectURL(rtcSession.getRemoteStreams()[0]);
    }},
      'ended': function(e){ /* Your code here */ }
    };
    
    var options = {
      'eventHandlers': eventHandlers,
      'extraHeaders': [ 'X-Foo: foo', 'X-Bar: bar' ],
      'mediaConstraints': {'audio': true, 'video': true}
    };
    JSsipPhone.call('SIP:bob@somedomain.com', options);
  12. The event handlers for messages are similar to the event handlers for a call. To send or receive messages, use the existing function calls to add your GUI responses, such as open a new window or show an alert on successful sending of messages using the following lines of code:
    var text = 'Hello';
    
    // Register callbacks to desired message events
    var eventHandlers = {
      'succeeded': function(e){ },
      'failed': function(e){ };
    };
    
    var options = {
      'eventHandlers': eventHandlers
    };
    
    JSsipPhone.sendMessage('SIP:bob@somedomain.com', text, options);
  13. Run index.html that contains the phone elements and uses the jsSIP call functions on any web server, such as JBoss or Apache.
  14. Open the web page in the Google Chrome or Firefox web browser.
  15. Register the client with SIP server-supporting WebSockets, such as Kamailio, or use a WebSocket gateway as OverSIP.
  16. Monitor the WebRTC client traces on Wireshark.

In a similar fashion, other SIP stacks can also be integrated with WebRTC media APIs to make a ready script to make and receive WebRTC calls over SIP.

Note

The SIP stack can also be a proprietary C code or adopted from freely available version of the Internet. JavaScript will aim to invoke the functions from an HTML-based web page. WebRTC browser media APIs will provide a way to capture and route the media.