# Forword

This document has been written by us (Doubango Telecom) 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.
If you want to get help or have some feedbacks then please visit the developer's website or subscribe to our developer mailing list.
We highly recommend checking other SIPML5 components: webrtc2sip, click-to-call, webrtc4all and SIP TelePresence (Video Group chat) client.
The complete API is available here

- Programing with the API
  - Class diagram
  - Download the API
  - Initialize the engine
  - Register/login
  - Making/receiving audio/video call
  - Sharing your screen/desktop
  - Send/receive SIP MESSAGE (SMS-like)
  - Publish presence status
  - Subscribe for presence status change
- Technical Help

# Programing with the API

This section is a quick overview of the main features and may lack details. For more information on each function please click on it.
A fully featured demo is hosted at http://sipml5.org/call.htm.
Below, a very compact code showing how to initialize the engine, start the stack and make video call from bob to alice in less than 15 lines:

                SIPml.init(
                        function(e){
                            var stack =  new SIPml.Stack({realm: 'example.org', impi: 'bob', impu: 'sip:bob@example.org', password: 'mysecret',
                                events_listener: { events: 'started', listener: function(e){
                                            var callSession = stack.newSession('call-audiovideo', {
                                                    video_local: document.getElementById('video-local'),
                                                    video_remote: document.getElementById('video-remote'),
                                                    audio_remote: document.getElementById('audio-remote')
                                                });
                                            callSession.call('alice');
                                        }
                                    }
                            });
                            stack.start();
                        }
                );

## Class diagram

Below, the image is an overview of the main classes and functions:

Class diagram

## Download the API

The API is a single javascript file which could be downloaded here. This file is generated as explained here.

## Initialize the engine

This is the first function to call in order to initialize the media and signaling engines.

                var readyCallback = function(e){
                    createSipStack(); // see next section
                };
                var errorCallback = function(e){
                    console.error('Failed to initialize the engine: ' + e.message);
                }
                SIPml.init(readyCallback, errorCallback);

## Create a SIP stack

A SIP stack 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.

                var sipStack;
                var eventsListener = function(e){
                    if(e.type == 'started'){
                        login();
                    }
                    else if(e.type == 'i_new_message'){ // incoming new SIP MESSAGE (SMS-like)
                        acceptMessage(e);
                    }
                    else if(e.type == 'i_new_call'){ // incoming audio/video call
                        acceptCall(e);
                    }
                }

                function createSipStack(){
                    sipStack = new SIPml.Stack({
                            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.start();

## Register/login

Registering to the server is not required in order to be able to make audio/video call or send messages.

                var registerSession;
                var eventsListener = function(e){
                    console.info('session event = ' + e.type);
                    if(e.type == 'connected' && e.session == registerSession){
                        makeCall();
                        sendMessage();
                        publishPresence();
                        subscribePresence('johndoe'); // watch johndoe's presence status change
                    }
                }
                var login = function(){
                    registerSession = sipStack.newSession('register', {
                        events_listener: { events: '*', listener: eventsListener } // optional: '*' means all events
                    });
                    registerSession.register();
                }

## Making/receiving audio/video call

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.

                var callSession;
                var eventsListener = function(e){
                    console.info('session event = ' + e.type);
                }
                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 } // optional: '*' means all events
                    });
                    callSession.call('johndoe');
                }

To accept incoming audio/video call:

                var acceptCall = function(e){
                    e.newSession.accept(); // e.newSession.reject() to reject the call
                }

## Sharing your screen/desktop

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 (call-screenshare instead of call-audiovideo).
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.
Please check here for more information about screen/desktop sharing.

## Send/receive SIP MESSAGE (SMS-like)

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.

                var messageSession;
                var eventsListener = function(e){
                    console.info('session event = ' + e.type);
                }
                var sendMessage = function(){
                    messageSession = sipStack.newSession('message', {
                        events_listener: { events: '*', listener: eventsListener } // optional: '*' means all events
                    });
                    messageSession.send('johndoe', 'Pêche à la moule', 'text/plain;charset=utf-8');
                }

To accept incoming SIP MESSAGE:

                var acceptMessage = function(e){
                    e.newSession.accept(); // e.newSession.reject(); to reject the message
                    console.info('SMS-content = ' + e.getContentString() + ' and SMS-content-type = ' + e.getContentType());
                }

## Publish presence status

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.
Presence publication is used to indicate your presence (e.g. online), mood (e.g. happy) 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.

                var publishSession;
                var eventsListener = function(e){
                    console.info('session event = ' + e.type);
                }
                var publishPresence = function(){
                    publishSession = sipStack.newSession('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.publish(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' }
                                     ]
                    });
                }

## Subscribe for presence status

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.
Below, the code shows how to subscribe for johndoe's presence status and parse the content of the NOTIFY request received from the server.

                var subscribeSession;
                var eventsListener = function(e){
                    console.info('session event = ' + e.type);
                    if(e.type == 'i_notify'){
                        console.info('NOTIFY content = ' + e.getContentString());
                        console.info('NOTIFY content-type = ' + e.getContentType());

                        if (e.getContentType() == 'application/pidf+xml') {
                            if (window.DOMParser) {
                                var parser = new DOMParser();
                                var xmlDoc = parser ? parser.parseFromString(e.getContentString(), "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 = sipStack.newSession('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 'connected' to be sure that the request has been accepted by the server)
                    subscribeSession.subscribe(to);
                }

# Technical Help

Please check our issue tracker or developer group if you have any problem.