<!DOCTYPE html> <!-- * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * License: BSD * This file is part of Open Source sipML5 solution <http://www.sipml5.org> --> <html> <!-- head --> <head> <meta charset="utf-8" /> <title>sipML5 Programmer's guide</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="Keywords" content="doubango, sipML5, VoIP, HTML5, WebRTC, RTCWeb, SIP, IMS, Video chat, VP8, live demo " /> <meta name="Description" content="HTML5 SIP client using WebRTC framework" /> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <meta name="author" content="Doubango Telecom" /> <!-- Styles --> <link href="assets/css/bootstrap.css" rel="stylesheet" /> <link href="assets/css/bootstrap-responsive.css" rel="stylesheet" /> <style type="text/css"> body{ padding-top: 60px; padding-bottom: 40px; } </style> <!-- Le fav and touch icons --> <link rel="shortcut icon" href="assets/ico/favicon.ico" /> <link rel="apple-touch-icon-precomposed" sizes="114x114" href="assets/ico/apple-touch-icon-114-precomposed.png" /> <link rel="apple-touch-icon-precomposed" sizes="72x72" href="assets/ico/apple-touch-icon-72-precomposed.png" /> <link rel="apple-touch-icon-precomposed" href="assets/ico/apple-touch-icon-57-precomposed.png" /> </head> <body> <div class="navbar navbar-fixed-top"> <div class="navbar-inner"> <div class="container"> <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span> </a> <a class="brand" href="./index.html">Doubango Telecom</a> <div class="nav-collapse"> <ul class="nav"> <li><a href="../index.html?svn=20">Home</a></li> </ul> </div> <!--/.nav-collapse --> </div> </div> </div> <div class="container"> <h1>Forword</h1> <p> This document has been written by us (<a href="http://www.doubango.org">Doubango Telecom</a>) to help developers to quickly create innovative multimedia applications for the desktop and mobile platforms. If you are a developer and is looking for the best way to develop a plugin-free NGN (VoIP, Messaging, Video Conferencing, ...) applications for these platforms then, your are at the right place. <br /> If you want to get help or have some feedbacks then please visit the <a href="http://code.google.com/p/sipml5/">developer's website</a> or subscribe to our <a href="http://groups.google.com/group/doubango/"> developer mailing list</a>. <br /> We highly recommend checking other SIPML5 components: <a target=_blank href="http://www.webrtc2sip.org">webrtc2sip</a>, <a target=_blank href="http://click2dial.org">click-to-call</a>, <a target=_blank href="http://code.google.com/p/webrtc4all/">webrtc4all</a> and <a target=_blank href="http://conf-call.org/">SIP TelePresence (Video Group chat) client</a>. <br /> <br /> <font size="3"> <strong>The complete API is available <a href="docgen/symbols/SIPml.html">here</a></strong><br/> </font> </p> <hr /> <ul> <li> <a href="#ProgramingwiththeAPI">Programing with the API</a> <ul> <li><a href="#ClassDiagram">Class diagram</a></li> <li><a href="#DownloadtheAPI">Download the API</a></li> <li><a href="#Initializetheengine">Initialize the engine</a></li> <li><a href="#login">Register/login</a></li> <li><a href="#makeCall">Making/receiving audio/video call</a></li> <li><a href="#screenShare">Sharing your screen/desktop</a></li> <li><a href="#sendMessage">Send/receive SIP MESSAGE (SMS-like)</a></li> <li><a href="#publishPresence">Publish presence status</a></li> <li><a href="#subscribePresence">Subscribe for presence status change</a></li> </ul> </li> <li><a href="#TechnicalHelp">Technical Help</a></li> </ul> <hr /> <a name="ProgramingwiththeAPI"></a> <h1>Programing with the API</h1> <p> This section is a quick overview of the main features and may lack details. For more information on each function please click on it. <br /> A fully featured demo is hosted at <a href="http://sipml5.org/call.htm">http://sipml5.org/call.htm</a>.<br /> Below, a very compact code showing how to initialize the engine, start the stack and make video call from <i>bob</i> to <i>alice</i> in <b>less than 15 lines</b>: </p> <pre><code> <a href="docgen/symbols/SIPml.html#.init">SIPml.init</a>( function(e){ var stack = new <a href="docgen/symbols/SIPml.Stack.html#constructor">SIPml.Stack</a>({realm: 'example.org', impi: 'bob', impu: 'sip:bob@example.org', password: 'mysecret', events_listener: { events: 'started', listener: function(<a href="docgen/symbols/SIPml.Stack.Event.html">e</a>){ var callSession = stack.<a href="docgen/symbols/SIPml.Stack.html#newSession">newSession</a>('call-audiovideo', { video_local: document.getElementById('video-local'), video_remote: document.getElementById('video-remote'), audio_remote: document.getElementById('audio-remote') }); callSession.<a href="docgen/symbols/SIPml.Session.Call.html#call">call</a>('alice'); } } }); stack.<a href="docgen/symbols/SIPml.Stack.html#start">start</a>(); } ); </code></pre> <hr /> <a name="ClassDiagram"></a> <h2>Class diagram</h2> <p> Below, the image is an overview of the main classes and functions: <br /> </p> <table> <tr><td><img src="images/classes.bmp" alt="Class overview"/></td></tr> <tr><td align='center'><u>Class diagram</u></td></tr> </table> <hr /> <a name="DownloadtheAPI"></a> <h2>Download the API</h2> <p> The API is a single javascript file which could be downloaded <a href="http://sipml5.googlecode.com/svn/trunk/release/SIPml-api.js">here</a>. This file is generated as explained <a href="http://code.google.com/p/sipml5/wiki/FAQ#How_to_reduce_the_size_of_the_scripts_before_deploying">here</a>. </p> <hr /> <h2>Initialize the engine</h2> <a name="Initializetheengine"></a> This is the first function to call in order to initialize the media and signaling engines. <pre><code> var readyCallback = function(e){ <a href="#CreateaSIPstackFunc">createSipStack()</a>; // see <a href="#CreateaSIPstack">next section</a> }; var errorCallback = function(e){ console.error('Failed to initialize the engine: ' + e.message); } <a href="docgen/symbols/SIPml.html#.init">SIPml.init</a>(readyCallback, errorCallback); </code></pre> <hr /> <a name="CreateaSIPstack"></a> <h2>Create a SIP stack</h2> <p> A <a href="docgen/symbols/SIPml.Stack.html">SIP stack</a> is a base object and must be created before any attempt to make/receive calls, send messages or manage presence. This section shows how to create a stack and start it. Starting a stack is an asynchronous function which mean you have to use an event listener to be notified for the state change. </p> <pre><code> var sipStack; var eventsListener = function(<a href="docgen/symbols/SIPml.Stack.Event.html">e</a>){ if(e.<a href="docgen/symbols/SIPml.Event.html#type">type</a> == 'started'){ <a href="#loginFunc">login</a>(); } else if(e.<a href="docgen/symbols/SIPml.Event.html#type">type</a> == 'i_new_message'){ // incoming new SIP MESSAGE (SMS-like) <a href="#acceptMessageFunc">acceptMessage</a>(e); } else if(e.<a href="docgen/symbols/SIPml.Event.html#type">type</a> == 'i_new_call'){ // incoming audio/video call <a href="#acceptCallFunc">acceptCall</a>(e); } } <a name="CreateaSIPstackFunc"></a> function createSipStack(){ sipStack = new <a href="docgen/symbols/SIPml.Stack.html#constructor">SIPml.Stack</a>({ realm: 'example.org', // mandatory: domain name impi: 'bob', // mandatory: authorization name (IMS Private Identity) impu: 'sip:bob@example.org', // mandatory: valid SIP Uri (IMS Public Identity) password: 'mysecret', // optional display_name: 'Bob legend', // optional websocket_proxy_url: 'wss://sipml5.org:10062', // optional outbound_proxy_url: 'udp://example.org:5060', // optional enable_rtcweb_breaker: false, // optional events_listener: { events: '*', listener: eventsListener }, // optional: '*' means all events sip_headers: [ // optional { name: 'User-Agent', value: 'IM-client/OMA1.0 sipML5-v1.0.0.0' }, { name: 'Organization', value: 'Doubango Telecom' } ] } ); } sipStack.<a href="docgen/symbols/SIPml.Stack.html#start">start</a>(); </code></pre> <hr /> <a name="login"></a> <h2>Register/login</h2> <p> Registering to the server is not required in order to be able to make audio/video call or send messages. </p> <pre><code> <a name="loginFunc"></a> var registerSession; var eventsListener = function(<a href="docgen/symbols/SIPml.Session.Event.html">e</a>){ console.info('session event = ' + e.<a href="docgen/symbols/SIPml.Event.html#type">type</a>); if(e.<a href="docgen/symbols/SIPml.Event.html#type">type</a> == 'connected' && e.<a href="docgen/symbols/SIPml.Session.Event.html#session">session</a> == registerSession){ <a href="#makeCallFunc">makeCall</a>(); <a href="#sendMessageFunc">sendMessage</a>(); <a href="#publishPresenceFunc">publishPresence</a>(); <a href="#subscribePresenceFunc">subscribePresence</a>('johndoe'); // watch johndoe's presence status change } } var login = function(){ registerSession = <a href="docgen/symbols/SIPml.Stack.html#newSession">sipStack.newSession</a>('register', { events_listener: { events: '*', listener: eventsListener } // optional: '*' means all events }); registerSession.<a href="docgen/symbols/SIPml.Session.Registration.html#register">register</a>(); } </code></pre> <hr /> <a name="makeCall"></a> <h2>Making/receiving audio/video call</h2> <p> It's not required to login in order to make audio/video calls but it is highly recommended if you're not using the stack in p2p mode. </p> <pre><code> <a name="makeCallFunc"></a> var callSession; var eventsListener = function(e){ console.info('session event = ' + e.type); } var makeCall = function(){ callSession = <a href="docgen/symbols/SIPml.Stack.html#newSession">sipStack.newSession</a>('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 } // optional: '*' means all events }); callSession.call('johndoe'); } </code></pre> <p>To accept incoming audio/video call:</p> <pre><code> <a name="acceptCallFunc"></a> var acceptCall = function(<a href="docgen/symbols/SIPml.Stack.Event.html">e</a>){ e.<a href="docgen/symbols/SIPml.Stack.Event.html#newSession">newSession</a>.<a href="docgen/symbols/SIPml.Session.html#accept">accept</a>(); // e.newSession.<a href="docgen/symbols/SIPml.Session.html#reject">reject()</a> to reject the call } </code></pre> <hr /> <a name="screenShare"></a> <h2>Sharing your screen/desktop</h2> <p> Sharing your screen or desktop with any SIP client is just like making a video call and the only difference is the session call type (<b>call-screenshare</b> instead of <i>call-audiovideo</i>). <br /> A screen/desktop sharing session doesn't contain audio stream which means you'll need to make a second audio-only call to speak to the remote party. You don't need to open another page as multi-line is supported. <br /> Please check <a href="https://code.google.com/p/sipml5/wiki/ScreenShare" target=_blank>here</a> for more information about screen/desktop sharing. <hr /> <a name="sendMessage"></a> <h2>Send/receive SIP MESSAGE (SMS-like)</h2> <p> It's not required to login in order to send SIP MESSAGEs (SMS-like) but it's highly recommended if you're not using the stack in p2p mode. </p> <pre><code> <a name="sendMessageFunc"></a> var messageSession; var eventsListener = function(<a href="docgen/symbols/SIPml.Session.Event.html">e</a>){ console.info('session event = ' + e.<a href="docgen/symbols/SIPml.Session.Event.html#type">type</a>); } var sendMessage = function(){ messageSession = <a href="docgen/symbols/SIPml.Stack.html#newSession">sipStack.newSession</a>('message', { events_listener: { events: '*', listener: eventsListener } // optional: '*' means all events }); messageSession.<a href="docgen/symbols/SIPml.Session.Message.html#send">send</a>('johndoe', 'Pêche à la moule', 'text/plain;charset=utf-8'); } </code></pre> <p>To accept incoming SIP MESSAGE:</p> <pre><code> <a name="acceptMessageFunc"></a> var acceptMessage = function(<a href="docgen/symbols/SIPml.Stack.Event.html">e</a>){ e.<a href="docgen/symbols/SIPml.Stack.Event.html#newSession">newSession</a>.<a href="docgen/symbols/SIPml.Session.html#accept">accept</a>(); // e.newSession.<a href="docgen/symbols/SIPml.Session.html#reject">reject</a>(); to reject the message console.info('SMS-content = ' + e.<a href="docgen/symbols/SIPml.Event.html#getContentString">getContentString</a>() + ' and SMS-content-type = ' + e.<a href="docgen/symbols/SIPml.Event.html#getContentType">getContentType</a>()); } </code></pre> <hr /> <a name="publishPresence"></a> <h2>Publish presence status</h2> <p> It's not required to login in order to publish your presence status but it's highly recommended if you're not using the stack in p2p mode. <br /> Presence publication is used to indicate your presence (e.g. <i>online</i>), mood (e.g. <i>happy</i>) or any personal information to your wtachers (most likely the contacts in your address book). In the coming versions the presence feature will be combined with XCAP to allow developing fully-featured RCS-e applications.<br /> </p> <pre><code> <a name="publishPresenceFunc"></a> var publishSession; var eventsListener = function(<a href="docgen/symbols/SIPml.Session.Event.html">e</a>){ console.info('session event = ' + e.<a href="docgen/symbols/SIPml.Session.Event.html#type">type</a>); } var publishPresence = function(){ publishSession = <a href="docgen/symbols/SIPml.Stack.html#newSession">sipStack.newSession</a>('publish', { events_listener: { events: '*', listener: eventsListener } // optional: '*' means all events }); var contentType = 'application/pidf+xml'; var content = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n' + '<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n' + ' xmlns:im=\"urn:ietf:params:xml:ns:pidf:im\"' + ' entity=\"sip:bob@example.com\">\n' + '<tuple id=\"s8794\">\n' + '<status>\n'+ ' <basic>open</basic>\n' + ' <im:im>away</im:im>\n' + '</status>\n' + '<contact priority=\"0.8\">tel:+33600000000</contact>\n' + '<note xml:lang=\"fr\">Bonjour de Paris :)</note>\n' + '</tuple>\n' + '</presence>'; // send the PUBLISH request publishSession.<a href="docgen/symbols/SIPml.Session.Publish.html#publish">publish</a>(content, contentType,{ expires: 200, sip_caps: [ { name: '+g.oma.sip-im' }, { name: '+sip.ice' }, { name: 'language', value: '\"en,fr\"' } ], sip_headers: [ { name: 'Event', value: 'presence' }, { name: 'Organization', value: 'Doubango Telecom' } ] }); } </code></pre> <a name="subscribePresence"></a> <h2>Subscribe for presence status</h2> <p> Subscription is used to watch the status of a SIP entity. This SIP entity could be contact from your address book, an rls-service, a voice mail, etc. When the entity status change, the subscriber will be notified using SIP NOTIFY request. <br /> Below, the code shows how to subscribe for <i>johndoe</i>'s presence status and parse the content of the NOTIFY request received from the server. <br /> </p> <pre><code> <a name="subscribePresenceFunc"></a> var subscribeSession; var eventsListener = function(<a href="docgen/symbols/SIPml.Session.Event.html">e</a>){ console.info('session event = ' + e.<a href="docgen/symbols/SIPml.Session.Event.html#type">type</a>); if(e.<a href="docgen/symbols/SIPml.Session.Event.html#type">type</a> == 'i_notify'){ console.info('NOTIFY content = ' + e.<a href="docgen/symbols/SIPml.Event.html#getContentString">getContentString</a>()); console.info('NOTIFY content-type = ' + e.<a href="docgen/symbols/SIPml.Event.html#getContentType">getContentType</a>()); if (e.<a href="docgen/symbols/SIPml.Event.html#getContentType">getContentType</a>() == 'application/pidf+xml') { if (window.DOMParser) { var parser = new <a href="https://developer.mozilla.org/en-US/docs/DOM/DOMParser">DOMParser</a>(); var xmlDoc = parser ? parser.parseFromString(e.<a href="docgen/symbols/SIPml.Event.html#getContentString">getContentString</a>(), "text/xml") : null; var presenceNode = xmlDoc ? xmlDoc.getElementsByTagName ("presence")[0] : null; if(presenceNode){ var entityUri = presenceNode.getAttribute ("entity"); var tupleNode = presenceNode.getElementsByTagName ("tuple")[0]; if(entityUri && tupleNode){ var statusNode = tupleNode.getElementsByTagName ("status")[0]; if(statusNode){ var basicNode = statusNode.getElementsByTagName ("basic")[0]; if(basicNode){ console.info('Presence notification: Uri = ' + entityUri + ' status = ' + basicNode.textContent); } } } } } } } } var subscribePresence = function(to){ subscribeSession = <a href="docgen/symbols/SIPml.Stack.html#newSession">sipStack.newSession</a>('subscribe', { expires: 200, events_listener: { events: '*', listener: eventsListener }, sip_headers: [ { name: 'Event', value: 'presence' }, // only notify for 'presence' events { name: 'Accept', value: 'application/pidf+xml' } // supported content types (COMMA-sparated) ], sip_caps: [ { name: '+g.oma.sip-im', value: null }, { name: '+audio', value: null }, { name: 'language', value: '\"en,fr\"' } ] }); // start watching for entity's presence status (You may track event type <b>'connected'</b> to be sure that the request has been accepted by the server) subscribeSession.<a href="docgen/symbols/SIPml.Session.Subscribe.html#subscribe">subscribe</a>(to); } </code></pre> <hr /> <a name="TechnicalHelp"></a> <h1>Technical Help</h1> <p> Please check our <a href="http://code.google.com/p/sipml5/issues/list">issue tracker</a> or <a href="https://groups.google.com/group/doubango">developer group</a> if you have any problem. </p> <br /> <footer> <p>© Doubango Telecom 2012 <br /> <i>Inspiring the future</i> </p> </footer> </div> <!-- /container --> <!-- Le javascript ================================================== --> <!-- Placed at the end of the document so the pages load faster --> <script type="text/javascript" src="assets/js/jquery.js"></script> <script type="text/javascript" src="assets/js/bootstrap-transition.js"></script> <script type="text/javascript" src="assets/js/bootstrap-alert.js"></script> <script type="text/javascript" src="assets/js/bootstrap-modal.js"></script> <script type="text/javascript" src="assets/js/bootstrap-dropdown.js"></script> <script type="text/javascript" src="assets/js/bootstrap-scrollspy.js"></script> <script type="text/javascript" src="assets/js/bootstrap-tab.js"></script> <script type="text/javascript" src="assets/js/bootstrap-tooltip.js"></script> <script type="text/javascript" src="assets/js/bootstrap-popover.js"></script> <script type="text/javascript" src="assets/js/bootstrap-button.js"></script> <script type="text/javascript" src="assets/js/bootstrap-collapse.js"></script> <script type="text/javascript" src="assets/js/bootstrap-carousel.js"></script> <script type="text/javascript" src="assets/js/bootstrap-typeahead.js"></script> <!-- GOOGLE ANALYTICS --> <script type="text/javascript"> var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); </script> <script type="text/javascript"> try { var pageTracker = _gat._getTracker("UA-6868621-19"); pageTracker._trackPageview(); } catch (err) { } </script> </body> </html>