Ver código fonte

Add sipml5 an optional webrtc client.

Mark Crane 12 anos atrás
pai
commit
08c8db731a
59 arquivos alterados com 1772 adições e 0 exclusões
  1. 0 0
      sipml5/SIPml-api.js
  2. 8 0
      sipml5/assets/css/bootstrap-responsive.css
  3. 8 0
      sipml5/assets/css/bootstrap.css
  4. 0 0
      sipml5/assets/css/docs.css
  5. BIN
      sipml5/assets/ico/apple-touch-icon-114-precomposed.png
  6. BIN
      sipml5/assets/ico/apple-touch-icon-57-precomposed.png
  7. BIN
      sipml5/assets/ico/apple-touch-icon-72-precomposed.png
  8. BIN
      sipml5/assets/img/browsers.png
  9. BIN
      sipml5/assets/img/github-16px.png
  10. BIN
      sipml5/assets/img/glyphicons-halflings-white.png
  11. BIN
      sipml5/assets/img/glyphicons-halflings.png
  12. BIN
      sipml5/assets/img/glyphicons/glyphicons_009_magic.png
  13. BIN
      sipml5/assets/img/glyphicons/glyphicons_042_group.png
  14. BIN
      sipml5/assets/img/glyphicons/glyphicons_079_podium.png
  15. BIN
      sipml5/assets/img/glyphicons/glyphicons_082_roundabout.png
  16. BIN
      sipml5/assets/img/glyphicons/glyphicons_155_show_thumbnails.png
  17. BIN
      sipml5/assets/img/glyphicons/glyphicons_163_iphone.png
  18. BIN
      sipml5/assets/img/glyphicons/glyphicons_214_resize_small.png
  19. BIN
      sipml5/assets/img/glyphicons/glyphicons_266_book_open.png
  20. BIN
      sipml5/assets/img/grid-18px-masked.png
  21. BIN
      sipml5/assets/img/icon-css3.png
  22. BIN
      sipml5/assets/img/icon-github.png
  23. BIN
      sipml5/assets/img/icon-html5.png
  24. BIN
      sipml5/assets/img/icon-twitter.png
  25. BIN
      sipml5/assets/img/less-logo-large.png
  26. BIN
      sipml5/assets/img/less-small.png
  27. BIN
      sipml5/assets/img/responsive-illustrations.png
  28. 0 0
      sipml5/assets/js/application.js
  29. 1 0
      sipml5/assets/js/bootstrap-alert.js
  30. 1 0
      sipml5/assets/js/bootstrap-button.js
  31. 0 0
      sipml5/assets/js/bootstrap-carousel.js
  32. 1 0
      sipml5/assets/js/bootstrap-collapse.js
  33. 1 0
      sipml5/assets/js/bootstrap-dropdown.js
  34. 0 0
      sipml5/assets/js/bootstrap-modal.js
  35. 1 0
      sipml5/assets/js/bootstrap-popover.js
  36. 1 0
      sipml5/assets/js/bootstrap-scrollspy.js
  37. 1 0
      sipml5/assets/js/bootstrap-tab.js
  38. 0 0
      sipml5/assets/js/bootstrap-tooltip.js
  39. 1 0
      sipml5/assets/js/bootstrap-transition.js
  40. 0 0
      sipml5/assets/js/bootstrap-typeahead.js
  41. 1 0
      sipml5/assets/js/google-code-prettify/prettify.css
  42. 0 0
      sipml5/assets/js/google-code-prettify/prettify.js
  43. 1 0
      sipml5/assets/js/jquery.js
  44. 1202 0
      sipml5/call.htm
  45. 107 0
      sipml5/contact.htm
  46. 14 0
      sipml5/error.htm
  47. 169 0
      sipml5/expert.htm
  48. BIN
      sipml5/images/classes.bmp
  49. BIN
      sipml5/images/qmark-16x16.png
  50. BIN
      sipml5/images/rectangle_256x256.png
  51. BIN
      sipml5/images/sipml-180x204.png
  52. BIN
      sipml5/images/sipml-34x39.png
  53. BIN
      sipml5/images/sipml-360x405.png
  54. BIN
      sipml5/images/sipml-45x51.png
  55. BIN
      sipml5/images/sipml-90x102.png
  56. 254 0
      sipml5/index.php
  57. BIN
      sipml5/sounds/dtmf.wav
  58. BIN
      sipml5/sounds/ringbacktone.wav
  59. BIN
      sipml5/sounds/ringtone.wav

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
sipml5/SIPml-api.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 8 - 0
sipml5/assets/css/bootstrap-responsive.css


Diferenças do arquivo suprimidas por serem muito extensas
+ 8 - 0
sipml5/assets/css/bootstrap.css


Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
sipml5/assets/css/docs.css


BIN
sipml5/assets/ico/apple-touch-icon-114-precomposed.png


BIN
sipml5/assets/ico/apple-touch-icon-57-precomposed.png


BIN
sipml5/assets/ico/apple-touch-icon-72-precomposed.png


BIN
sipml5/assets/img/browsers.png


BIN
sipml5/assets/img/github-16px.png


BIN
sipml5/assets/img/glyphicons-halflings-white.png


BIN
sipml5/assets/img/glyphicons-halflings.png


BIN
sipml5/assets/img/glyphicons/glyphicons_009_magic.png


BIN
sipml5/assets/img/glyphicons/glyphicons_042_group.png


BIN
sipml5/assets/img/glyphicons/glyphicons_079_podium.png


BIN
sipml5/assets/img/glyphicons/glyphicons_082_roundabout.png


BIN
sipml5/assets/img/glyphicons/glyphicons_155_show_thumbnails.png


BIN
sipml5/assets/img/glyphicons/glyphicons_163_iphone.png


BIN
sipml5/assets/img/glyphicons/glyphicons_214_resize_small.png


BIN
sipml5/assets/img/glyphicons/glyphicons_266_book_open.png


BIN
sipml5/assets/img/grid-18px-masked.png


BIN
sipml5/assets/img/icon-css3.png


BIN
sipml5/assets/img/icon-github.png


BIN
sipml5/assets/img/icon-html5.png


BIN
sipml5/assets/img/icon-twitter.png


BIN
sipml5/assets/img/less-logo-large.png


BIN
sipml5/assets/img/less-small.png


BIN
sipml5/assets/img/responsive-illustrations.png


Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
sipml5/assets/js/application.js


+ 1 - 0
sipml5/assets/js/bootstrap-alert.js

@@ -0,0 +1 @@
+!function(c){var b='[data-dismiss="alert"]',a=function(d){c(d).on("click",b,this.close)};a.prototype={constructor:a,close:function(i){var h=c(this),f=h.attr("data-target"),g;if(!f){f=h.attr("href");f=f&&f.replace(/.*(?=#[^\s]*$)/,"")}g=c(f);g.trigger("close");i&&i.preventDefault();g.length||(g=h.hasClass("alert")?h:h.parent());g.trigger("close").removeClass("in");function d(){g.trigger("closed").remove()}c.support.transition&&g.hasClass("fade")?g.on(c.support.transition.end,d):d()}};c.fn.alert=function(d){return this.each(function(){var f=c(this),e=f.data("alert");if(!e){f.data("alert",(e=new a(this)))}if(typeof d=="string"){e[d].call(f)}})};c.fn.alert.Constructor=a;c(function(){c("body").on("click.alert.data-api",b,a.prototype.close)})}(window.jQuery);

+ 1 - 0
sipml5/assets/js/bootstrap-button.js

@@ -0,0 +1 @@
+!function(b){var a=function(d,c){this.$element=b(d);this.options=b.extend({},b.fn.button.defaults,c)};a.prototype={constructor:a,setState:function(f){var h="disabled",c=this.$element,e=c.data(),g=c.is("input")?"val":"html";f=f+"Text";e.resetText||c.data("resetText",c[g]());c[g](e[f]||this.options[f]);setTimeout(function(){f=="loadingText"?c.addClass(h).attr(h,h):c.removeClass(h).removeAttr(h)},0)},toggle:function(){var c=this.$element.parent('[data-toggle="buttons-radio"]');c&&c.find(".active").removeClass("active");this.$element.toggleClass("active")}};b.fn.button=function(c){return this.each(function(){var f=b(this),e=f.data("button"),d=typeof c=="object"&&c;if(!e){f.data("button",(e=new a(this,d)))}if(c=="toggle"){e.toggle()}else{if(c){e.setState(c)}}})};b.fn.button.defaults={loadingText:"loading..."};b.fn.button.Constructor=a;b(function(){b("body").on("click.button.data-api","[data-toggle^=button]",function(d){var c=b(d.target);if(!c.hasClass("btn")){c=c.closest(".btn")}c.button("toggle")})})}(window.jQuery);

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
sipml5/assets/js/bootstrap-carousel.js


+ 1 - 0
sipml5/assets/js/bootstrap-collapse.js

@@ -0,0 +1 @@
+!function(a){var b=function(d,c){this.$element=a(d);this.options=a.extend({},a.fn.collapse.defaults,c);if(this.options.parent){this.$parent=a(this.options.parent)}this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var c=this.$element.hasClass("width");return c?"width":"height"},show:function(){var f=this.dimension(),c=a.camelCase(["scroll",f].join("-")),e=this.$parent&&this.$parent.find(".in"),d;if(e&&e.length){d=e.data("collapse");e.collapse("hide");d||e.data("collapse",null)}this.$element[f](0);this.transition("addClass","show","shown");this.$element[f](this.$element[0][c])},hide:function(){var c=this.dimension();this.reset(this.$element[c]());this.transition("removeClass","hide","hidden");this.$element[c](0)},reset:function(c){var d=this.dimension();this.$element.removeClass("collapse")[d](c||"auto")[0].offsetWidth;this.$element[c?"addClass":"removeClass"]("collapse");return this},transition:function(g,d,e){var f=this,c=function(){if(d=="show"){f.reset()}f.$element.trigger(e)};this.$element.trigger(d)[g]("in");a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,c):c()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};a.fn.collapse=function(c){return this.each(function(){var f=a(this),e=f.data("collapse"),d=typeof c=="object"&&c;if(!e){f.data("collapse",(e=new b(this,d)))}if(typeof c=="string"){e[c]()}})};a.fn.collapse.defaults={toggle:true};a.fn.collapse.Constructor=b;a(function(){a("body").on("click.collapse.data-api","[data-toggle=collapse]",function(h){var g=a(this),c,f=g.attr("data-target")||h.preventDefault()||(c=g.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),d=a(f).data("collapse")?"toggle":g.data();a(f).collapse(d)})})}(window.jQuery);

+ 1 - 0
sipml5/assets/js/bootstrap-dropdown.js

@@ -0,0 +1 @@
+!function(d){var b='[data-toggle="dropdown"]',a=function(f){var e=d(f).on("click.dropdown.data-api",this.toggle);d("html").on("click.dropdown.data-api",function(){e.parent().removeClass("open")})};a.prototype={constructor:a,toggle:function(j){var i=d(this),f=i.attr("data-target"),h,g;if(!f){f=i.attr("href");f=f&&f.replace(/.*(?=#[^\s]*$)/,"")}h=d(f);h.length||(h=i.parent());g=h.hasClass("open");c();!g&&h.toggleClass("open");return false}};function c(){d(b).parent().removeClass("open")}d.fn.dropdown=function(e){return this.each(function(){var g=d(this),f=g.data("dropdown");if(!f){g.data("dropdown",(f=new a(this)))}if(typeof e=="string"){f[e].call(g)}})};d.fn.dropdown.Constructor=a;d(function(){d("html").on("click.dropdown.data-api",c);d("body").on("click.dropdown.data-api",b,a.prototype.toggle)})}(window.jQuery);

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
sipml5/assets/js/bootstrap-modal.js


+ 1 - 0
sipml5/assets/js/bootstrap-popover.js

@@ -0,0 +1 @@
+!function(b){var a=function(d,c){this.init("popover",d,c)};a.prototype=b.extend({},b.fn.tooltip.Constructor.prototype,{constructor:a,setContent:function(){var e=this.tip(),d=this.getTitle(),c=this.getContent();e.find(".popover-title")[b.type(d)=="object"?"append":"html"](d);e.find(".popover-content > *")[b.type(c)=="object"?"append":"html"](c);e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var d,c=this.$element,e=this.options;d=c.attr("data-content")||(typeof e.content=="function"?e.content.call(c[0]):e.content);d=d.toString().replace(/(^\s*|\s*$)/,"");return d},tip:function(){if(!this.$tip){this.$tip=b(this.options.template)}return this.$tip}});b.fn.popover=function(c){return this.each(function(){var f=b(this),e=f.data("popover"),d=typeof c=="object"&&c;if(!e){f.data("popover",(e=new a(this,d)))}if(typeof c=="string"){e[c]()}})};b.fn.popover.Constructor=a;b.fn.popover.defaults=b.extend({},b.fn.tooltip.defaults,{placement:"right",content:"",template:'<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'})}(window.jQuery);

+ 1 - 0
sipml5/assets/js/bootstrap-scrollspy.js

@@ -0,0 +1 @@
+!function(b){function a(f,e){var g=b.proxy(this.process,this),c=b(f).is("body")?b(window):b(f),d;this.options=b.extend({},b.fn.scrollspy.defaults,e);this.$scrollElement=c.on("scroll.scroll.data-api",g);this.selector=(this.options.target||((d=b(f).attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""))||"")+" .nav li > a";this.$body=b("body").on("click.scroll.data-api",this.selector,g);this.refresh();this.process()}a.prototype={constructor:a,refresh:function(){this.targets=this.$body.find(this.selector).map(function(){var c=b(this).attr("href");return/^#\w/.test(c)&&b(c).length?c:null});this.offsets=b.map(this.targets,function(c){return b(c).position().top})},process:function(){var f=this.$scrollElement.scrollTop()+this.options.offset,e=this.offsets,c=this.targets,g=this.activeTarget,d;for(d=e.length;d--;){g!=c[d]&&f>=e[d]&&(!e[d+1]||f<=e[d+1])&&this.activate(c[d])}},activate:function(d){var c;this.activeTarget=d;this.$body.find(this.selector).parent(".active").removeClass("active");c=this.$body.find(this.selector+'[href="'+d+'"]').parent("li").addClass("active");if(c.parent(".dropdown-menu")){c.closest("li.dropdown").addClass("active")}}};b.fn.scrollspy=function(c){return this.each(function(){var f=b(this),e=f.data("scrollspy"),d=typeof c=="object"&&c;if(!e){f.data("scrollspy",(e=new a(this,d)))}if(typeof c=="string"){e[c]()}})};b.fn.scrollspy.Constructor=a;b.fn.scrollspy.defaults={offset:10};b(function(){b('[data-spy="scroll"]').each(function(){var c=b(this);c.scrollspy(c.data())})})}(window.jQuery);

+ 1 - 0
sipml5/assets/js/bootstrap-tab.js

@@ -0,0 +1 @@
+!function(b){var a=function(c){this.element=b(c)};a.prototype={constructor:a,show:function(){var g=this.element,e=g.closest("ul:not(.dropdown-menu)"),d=g.attr("data-target"),f,c;if(!d){d=g.attr("href");d=d&&d.replace(/.*(?=#[^\s]*$)/,"")}if(g.parent("li").hasClass("active")){return}f=e.find(".active a").last()[0];g.trigger({type:"show",relatedTarget:f});c=b(d);this.activate(g.parent("li"),e);this.activate(c,c.parent(),function(){g.trigger({type:"shown",relatedTarget:f})})},activate:function(e,d,h){var c=d.find("> .active"),g=h&&b.support.transition&&c.hasClass("fade");function f(){c.removeClass("active").find("> .dropdown-menu > .active").removeClass("active");e.addClass("active");if(g){e[0].offsetWidth;e.addClass("in")}else{e.removeClass("fade")}if(e.parent(".dropdown-menu")){e.closest("li.dropdown").addClass("active")}h&&h()}g?c.one(b.support.transition.end,f):f();c.removeClass("in")}};b.fn.tab=function(c){return this.each(function(){var e=b(this),d=e.data("tab");if(!d){e.data("tab",(d=new a(this)))}if(typeof c=="string"){d[c]()}})};b.fn.tab.Constructor=a;b(function(){b("body").on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(c){c.preventDefault();b(this).tab("show")})})}(window.jQuery);

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
sipml5/assets/js/bootstrap-tooltip.js


+ 1 - 0
sipml5/assets/js/bootstrap-transition.js

@@ -0,0 +1 @@
+!function(a){a(function(){a.support.transition=(function(){var c=document.body||document.documentElement,d=c.style,b=d.transition!==undefined||d.WebkitTransition!==undefined||d.MozTransition!==undefined||d.MsTransition!==undefined||d.OTransition!==undefined;return b&&{end:(function(){var e="TransitionEnd";if(a.browser.webkit){e="webkitTransitionEnd"}else{if(a.browser.mozilla){e="transitionend"}else{if(a.browser.opera){e="oTransitionEnd"}}}return e}())}})()})}(window.jQuery);

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
sipml5/assets/js/bootstrap-typeahead.js


+ 1 - 0
sipml5/assets/js/google-code-prettify/prettify.css

@@ -0,0 +1 @@
+.com{color:#93a1a1}.lit{color:#195f91}.pun,.opn,.clo{color:#93a1a1}.fun{color:#dc322f}.str,.atv{color:#D14}.kwd,.linenums .tag{color:#1e347b}.typ,.atn,.dec,.var{color:teal}.pln{color:#48484c}.prettyprint{padding:8px;background-color:#f7f7f9;border:1px solid #e1e1e8}.prettyprint.linenums{-webkit-box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0;-moz-box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0;box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0}ol.linenums{margin:0 0 0 33px}ol.linenums li{padding-left:12px;color:#bebec5;line-height:18px;text-shadow:0 1px 0 #fff}

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
sipml5/assets/js/google-code-prettify/prettify.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
sipml5/assets/js/jquery.js


+ 1202 - 0
sipml5/call.htm

@@ -0,0 +1,1202 @@
+<!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 live demo</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 name="author" content="Doubango Telecom" />
+
+    <!-- SIPML5 API:
+    DEBUG VERSION: 'SIPml-api.js'
+    RELEASE VERSION: 'release/SIPml-api.js'
+    -->
+    <script src="SIPml-api.js?svn=179" type="text/javascript"> </script>
+
+    <!-- Styles -->
+    <link href="./assets/css/bootstrap.css" rel="stylesheet" />
+    <style type="text/css">
+        body{
+            padding-top: 80px;
+            padding-bottom: 40px;
+        }
+        .navbar-inner-red {
+          background-color: #600000;
+          background-image: none;
+          background-repeat: no-repeat;
+          filter: none;
+        }
+        .full-screen{
+            position: absolute;
+            left: 0;
+            top: 0;
+            width: 100%;
+            height: 100%;
+            overflow: hidden;
+        }
+        .normal-screen{
+            position: relative;
+        }
+        .call-options {
+          padding: 5px;
+          background-color: #f0f0f0;
+          border: 1px solid #eee;
+          border: 1px solid rgba(0, 0, 0, 0.08);
+          -webkit-border-radius: 4px;
+          -moz-border-radius: 4px;
+          border-radius: 4px;
+          -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+          -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+          -webkit-transition-property: opacity;
+          -moz-transition-property: opacity; 
+          -o-transition-property: opacity; 
+          -webkit-transition-duration: 2s;
+          -moz-transition-duration: 2s;
+          -o-transition-duration: 2s;
+        }
+        .tab-video,
+        .div-video{
+            width: 100%; 
+            height: 0px; 
+            -webkit-transition-property: height;
+            -moz-transition-property: height;
+            -o-transition-property: height;
+            -webkit-transition-duration: 2s;
+            -moz-transition-duration: 2s;
+            -o-transition-duration: 2s;
+        }
+        .label-align {
+            display: block;
+            padding-left: 15px;
+            text-indent: -15px;
+        }
+        .input-align {
+            width: 13px;
+            height: 13px;
+            padding: 0;
+            margin:0;
+            vertical-align: bottom;
+            position: relative;
+            top: -1px;
+            *overflow: hidden;
+        }
+        .glass-panel{
+            z-index: 99;
+            position: fixed;
+            width: 100%;
+            height: 100%;
+            margin: 0;
+            padding: 0;
+            top: 0;
+            left: 0;
+            opacity: 0.8;
+            background-color: Gray;
+        }
+        .div-keypad {
+            z-index: 100;
+            position: fixed;
+            -moz-transition-property: left top;
+            -o-transition-property: left top;
+            -webkit-transition-duration: 2s;
+            -moz-transition-duration: 2s;
+            -o-transition-duration: 2s;
+        }
+        
+    </style>
+    <link href="./assets/css/bootstrap-responsive.css" rel="stylesheet" />
+    <!-- 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>
+<!-- Javascript code -->
+<script type="text/javascript">
+
+    // to avoid caching
+    //if (window.location.href.indexOf("svn=") == -1) {
+    //    window.location.href += (window.location.href.indexOf("?") == -1 ? "?svn=13" : "&svn=13");
+    //}
+
+    var sTransferNumber;
+    var oRingTone, oRingbackTone;
+    var oSipStack, oSipSessionRegister, oSipSessionCall, oSipSessionTransferCall;
+    var videoRemote, videoLocal, audioRemote;
+    var bFullScreen = false;
+    var oNotifICall;
+    var oReadyStateTimer;
+    var bDisableVideo = false;
+    var viewVideoLocal, viewVideoRemote; // <video> (webrtc) or <div> (webrtc4all)
+
+    C = 
+    {
+        divKeyPadWidth: 220
+    };
+
+    window.onload = function () {
+        videoLocal = document.getElementById("video_local");
+        videoRemote = document.getElementById("video_remote");
+        audioRemote = document.getElementById("audio_remote");
+
+        document.onkeyup = onKeyUp;
+        document.body.onkeyup = onKeyUp;
+        divCallCtrl.onmousemove = onDivCallCtrlMouseMove;
+
+        loadCredentials();
+        loadCallOptions();
+
+        oReadyStateTimer = setInterval(function () {
+            if (document.readyState === "complete") {
+                clearInterval(oReadyStateTimer);
+                // initialize SIPML5
+                SIPml.init(postInit);
+            }
+        },
+        500);
+    };
+
+    function postInit() {
+        // check webrtc4all version
+        if (SIPml.isWebRtc4AllSupported() && SIPml.isWebRtc4AllPluginOutdated()) {            
+            if (confirm("Your WebRtc4all extension is outdated. A new version(" +SIPml.getWebRtc4AllVersion()+") with critical bug fix is available. Do you want to install it?\nIMPORTANT: You must restart your browser after the installation.")) {
+                window.location = 'http://code.google.com/p/webrtc4all/downloads/list';
+                return;
+            }
+        }
+
+        // check for WebRTC support
+        if (!SIPml.isWebRtcSupported()) {
+            // is it chrome?
+            if (SIPml.getNavigatorFriendlyName() == 'chrome') {
+                    if (confirm("You're using an old Chrome version or WebRTC is not enabled.\nDo you want to see how to enable WebRTC?")) {
+                        window.location = 'http://www.webrtc.org/running-the-demos';
+                    }
+                    else {
+                        window.location = "index.html";
+                    }
+                    return;
+            }
+                
+            // for now the plugins (WebRTC4all only works on Windows)
+            if (SIPml.getSystemFriendlyName() == 'windows') {
+                // Internet explorer
+                if (SIPml.getNavigatorFriendlyName() == 'ie') {
+                    // Check for IE version 
+                    if (parseFloat(SIPml.getNavigatorVersion()) < 9.0) {
+                        if (confirm("You are using an old IE version. You need at least version 9. Would you like to update IE?")) {
+                            window.location = 'http://windows.microsoft.com/en-us/internet-explorer/products/ie/home';
+                        }
+                        else {
+                            window.location = "index.html";
+                        }
+                    }
+
+                    // check for WebRTC4all extension
+                    if (!SIPml.isWebRtc4AllSupported()) {
+                        if (confirm("webrtc4all extension is not installed. Do you want to install it?\nIMPORTANT: You must restart your browser after the installation.")) {
+                            window.location = 'http://code.google.com/p/webrtc4all/downloads/list';
+                        }
+                        else {
+                            // Must do nothing: give the user the chance to accept the extension
+                            // window.location = "index.html";
+                        }
+                    }
+                    // break page loading ('window.location' won't stop JS execution)
+                    if (!SIPml.isWebRtc4AllSupported()) {
+                        return;
+                    }
+                }
+                else if (SIPml.getNavigatorFriendlyName() == "safari" || SIPml.getNavigatorFriendlyName() == "firefox" || SIPml.getNavigatorFriendlyName() == "opera") {
+                    if (confirm("Your browser don't support WebRTC.\nDo you want to install WebRTC4all extension to enjoy audio/video calls?\nIMPORTANT: You must restart your browser after the installation.")) {
+                        window.location = 'http://code.google.com/p/webrtc4all/downloads/list';
+                    }
+                    else {
+                        window.location = "index.html";
+                    }
+                    return;
+                }
+            }
+            // OSX, Unix, Android, iOS...
+            else {
+                if (confirm('WebRTC not supported on your browser.\nDo you want to download a WebRTC-capable browser?')) {
+                    window.location = 'https://www.google.com/intl/en/chrome/browser/';
+                }
+                else {
+                    window.location = "index.html";
+                }
+                return;
+            }
+        }
+
+        // checks for WebSocket support
+        if (!SIPml.isWebSocketSupported() && !SIPml.isWebRtc4AllSupported()) {
+            if (confirm('Your browser don\'t support WebSockets.\nDo you want to download a WebSocket-capable browser?')) {
+                window.location = 'https://www.google.com/intl/en/chrome/browser/';
+            }
+            else {
+                window.location = "index.html";
+            }
+            return;
+        }
+
+        // FIXME: displays must be per session
+
+        // attachs video displays
+        if (SIPml.isWebRtc4AllSupported()) {
+            viewVideoLocal = document.getElementById("divVideoLocal");
+            viewVideoRemote = document.getElementById("divVideoRemote");
+            WebRtc4all_SetDisplays(viewVideoLocal, viewVideoRemote); // FIXME: move to SIPml.* API
+        }
+        else{
+            viewVideoLocal = videoLocal;
+            viewVideoRemote = videoRemote;
+        }
+
+        if (!SIPml.isWebRtc4AllSupported() && !SIPml.isWebRtcSupported()) {
+            if (confirm('Your browser don\'t support WebRTC.\naudio/video calls will be disabled.\nDo you want to download a WebRTC-capable browser?')) {
+                window.location = 'https://www.google.com/intl/en/chrome/browser/';
+            }
+        }
+
+        btnRegister.disabled = false;
+        document.body.style.cursor = 'default';
+    }
+
+
+    function loadCallOptions() {
+        if (window.localStorage) {
+            var s_value;
+            if ((s_value = window.localStorage.getItem('org.doubango.call.phone_number'))) txtPhoneNumber.value = s_value;
+            bDisableVideo = (window.localStorage.getItem('org.doubango.expert.disable_video') == "true");
+
+            txtCallStatus.innerHTML = '<i>Video ' + (bDisableVideo ? 'disabled' : 'enabled') + '</i>';
+        }
+    }
+
+    function saveCallOptions() {
+        if (window.localStorage) {
+            window.localStorage.setItem('org.doubango.call.phone_number', txtPhoneNumber.value);
+            window.localStorage.setItem('org.doubango.expert.disable_video', bDisableVideo ? "true" : "false");
+        }
+    }
+
+    function loadCredentials() {
+        if (window.localStorage) {
+            // IE retuns 'null' if not defined
+            var s_value;
+            if ((s_value = window.localStorage.getItem('org.doubango.identity.display_name'))) txtDisplayName.value = s_value;
+            if ((s_value = window.localStorage.getItem('org.doubango.identity.impi'))) txtPrivateIdentity.value = s_value;
+            if ((s_value = window.localStorage.getItem('org.doubango.identity.impu'))) txtPublicIdentity.value = s_value;
+            if ((s_value = window.localStorage.getItem('org.doubango.identity.password'))) txtPassword.value = s_value;
+            if ((s_value = window.localStorage.getItem('org.doubango.identity.realm'))) txtRealm.value = s_value;
+        }
+        else {
+            /*txtDisplayName.value = "005";
+            txtPrivateIdentity.value = "005";
+            txtPublicIdentity.value = "sip:[email protected]";
+            txtPassword.value = "005";
+            txtRealm.value = "192.168.0.42";
+            txtPhoneNumber.value = "005";*/
+        }
+    };
+
+    function saveCredentials() {
+        if (window.localStorage) {
+            window.localStorage.setItem('org.doubango.identity.display_name', txtDisplayName.value);
+            window.localStorage.setItem('org.doubango.identity.impi', txtPrivateIdentity.value);
+            window.localStorage.setItem('org.doubango.identity.impu', txtPublicIdentity.value);
+            window.localStorage.setItem('org.doubango.identity.password', txtPassword.value);
+            window.localStorage.setItem('org.doubango.identity.realm', txtRealm.value);
+        }
+    };
+
+    // sends SIP REGISTER request to login
+    function sipRegister() {
+        // catch exception for IE (DOM not ready)
+        try {
+            btnRegister.disabled = true;
+            if (!txtRealm.value || !txtPrivateIdentity.value || !txtPublicIdentity.value) {
+                txtRegStatus.innerHTML = '<b>Please fill madatory fields (*)</b>';
+                btnRegister.disabled = false;
+                return;
+            }
+            var o_impu = tsip_uri.prototype.Parse(txtPublicIdentity.value);
+            if (!o_impu || !o_impu.s_user_name || !o_impu.s_host) {
+                txtRegStatus.innerHTML = "<b>[" + txtPublicIdentity.value + "] is not a valid Public identity</b>";
+                btnRegister.disabled = false;
+                return;
+            }
+
+            // enable notifications if not already done
+            if (window.webkitNotifications && window.webkitNotifications.checkPermission() != 0) {
+                window.webkitNotifications.requestPermission();
+            }
+
+            // save credentials
+            saveCredentials();
+
+            // create SIP stack
+            oSipStack = new SIPml.Stack({
+                    realm: txtRealm.value,
+                    impi: txtPrivateIdentity.value,
+                    impu: txtPublicIdentity.value,
+                    password: txtPassword.value,
+                    display_name: txtDisplayName.value,
+                    websocket_proxy_url: (window.localStorage ? window.localStorage.getItem('org.doubango.expert.websocket_server_url') : null),
+                    outbound_proxy_url: (window.localStorage ? window.localStorage.getItem('org.doubango.expert.sip_outboundproxy_url') : null),
+                    ice_servers: (window.localStorage ? window.localStorage.getItem('org.doubango.expert.ice_servers') : null),
+                    enable_rtcweb_breaker: (window.localStorage ? window.localStorage.getItem('org.doubango.expert.enable_rtcweb_breaker') == "true" : false),
+                    events_listener: { events: '*', listener: onSipEventStack },
+                    sip_headers: [
+                            { name: 'User-Agent', value: 'IM-client/OMA1.0 sipML5-v1.2013.05.24' },
+                            { name: 'Organization', value: 'Doubango Telecom' }
+                    ]
+                }
+            );
+            if (oSipStack.start() != 0) {
+                txtRegStatus.innerHTML = '<b>Failed to start the SIP stack</b>';
+            }
+            else return;
+        }
+        catch (e) {
+            txtRegStatus.innerHTML = "<b>2:" + e + "</b>";
+        }
+        btnRegister.disabled = false;
+    }
+
+    // sends SIP REGISTER (expires=0) to logout
+    function sipUnRegister() {
+        if (oSipStack) {
+            oSipStack.stop(); // shutdown all sessions
+        }
+    }
+
+    // makes a call (SIP INVITE)
+    function sipCall() {
+        // call configuration
+        var oConf = {
+            audio_remote: audioRemote,
+            video_local: viewVideoLocal,
+            video_remote: viewVideoRemote,
+            events_listener: { events: '*', listener: onSipEventSession },
+            sip_caps: [
+                            { name: '+g.oma.sip-im' },
+                            { name: '+sip.ice' },
+                            { name: 'language', value: '\"en,fr\"' }
+                        ]
+        };
+        if (oSipStack && !oSipSessionCall && !tsk_string_is_null_or_empty(txtPhoneNumber.value)) {
+            btnCall.disabled = true;
+            btnHangUp.disabled = false;
+
+            // check whether video is disabled or not
+            bDisableVideo = (window.localStorage && window.localStorage.getItem('org.doubango.expert.disable_video') == "true");
+            // create call session
+            oSipSessionCall = oSipStack.newSession(bDisableVideo ? 'call-audio' : 'call-audiovideo', oConf);
+            // make call
+            if (oSipSessionCall.call(txtPhoneNumber.value) != 0) {
+                oSipSessionCall = null;
+                txtCallStatus.value = 'Failed to make call';
+                btnCall.disabled = false;
+                btnHangUp.disabled = true;
+                return;
+            }
+            saveCallOptions();
+        }
+        else if (oSipSessionCall) {
+            txtCallStatus.innerHTML = '<i>Connecting...</i>';
+            oSipSessionCall.accept(oConf);
+        }
+    }
+
+    // transfers the call
+    function sipTransfer() {
+        if (oSipSessionCall) {
+            var s_destination = prompt('Enter destination number', '');
+            if (!tsk_string_is_null_or_empty(s_destination)) {
+                btnTransfer.disabled = true;
+                if (oSipSessionCall.transfer(s_destination) != 0) {
+                    txtCallStatus.innerHTML = '<i>Call transfer failed</i>';
+                    btnTransfer.disabled = false;
+                    return;
+                }
+                txtCallStatus.innerHTML = '<i>Transfering the call...</i>';
+            }
+        }
+    }
+    
+    // holds or resumes the call
+    function sipToggleHoldResume() {
+        if (oSipSessionCall) {
+            var i_ret;
+            btnHoldResume.disabled = true;
+            txtCallStatus.innerHTML = oSipSessionCall.bHeld ? '<i>Resuming the call...</i>' : '<i>Holding the call...</i>';
+            i_ret = oSipSessionCall.bHeld ? oSipSessionCall.resume() : oSipSessionCall.hold();
+            if (i_ret != 0) {
+                txtCallStatus.innerHTML = '<i>Hold / Resume failed</i>';
+                btnHoldResume.disabled = false;
+                return;
+            }
+        }
+    }
+
+    // terminates the call (SIP BYE or CANCEL)
+    function sipHangUp() {
+        if (oSipSessionCall) {
+            txtCallStatus.innerHTML = '<i>Terminating the call...</i>';
+            oSipSessionCall.hangup({events_listener: { events: '*', listener: onSipEventSession }});
+        }
+    }
+
+    function sipSendDTMF(c){
+        if(oSipSessionCall && c){
+            if(oSipSessionCall.dtmf(c) == 0){
+                try { dtmfTone.play(); } catch(e){ }
+            }
+        }
+    }
+
+    function startRingTone() {
+        try { ringtone.play(); }
+        catch (e) { }
+    }
+
+    function stopRingTone() {
+        try { ringtone.pause(); }
+        catch (e) { }
+    }
+
+    function startRingbackTone() {
+        try { ringbacktone.play(); }
+        catch (e) { }
+    }
+
+    function stopRingbackTone() {
+        try { ringbacktone.pause(); }
+        catch (e) { }
+    }
+
+    function toggleFullScreen() {
+        if (videoRemote.webkitSupportsFullscreen) {
+            fullScreen(!videoRemote.webkitDisplayingFullscreen);
+        }
+        else {
+            fullScreen(!bFullScreen);
+        }
+    }
+
+    function openKeyPad(){
+        divKeyPad.style.visibility = 'visible';
+        divKeyPad.style.left = ((document.body.clientWidth - C.divKeyPadWidth) >> 1) + 'px';
+        divKeyPad.style.top = '70px';
+        divGlassPanel.style.visibility = 'visible';
+    }
+
+    function closeKeyPad(){
+        divKeyPad.style.left = '0px';
+        divKeyPad.style.top = '0px';
+        divKeyPad.style.visibility = 'hidden';
+        divGlassPanel.style.visibility = 'hidden';
+    }
+
+    function fullScreen(b_fs) {
+        bFullScreen = b_fs;
+        if (tsk_utils_have_webrtc4native() && bFullScreen && videoRemote.webkitSupportsFullscreen) {
+            if (bFullScreen) {
+                videoRemote.webkitEnterFullScreen();
+            }
+            else {
+                videoRemote.webkitExitFullscreen();
+            }
+        }
+        else {
+            if (tsk_utils_have_webrtc4npapi()) {
+                try { if(window.__o_display_remote) window.__o_display_remote.setFullScreen(b_fs); }
+                catch (e) { divVideo.setAttribute("class", b_fs ? "full-screen" : "normal-screen"); }
+            }
+            else {
+                divVideo.setAttribute("class", b_fs ? "full-screen" : "normal-screen");
+            }
+        }
+    }
+
+    function showNotifICall(s_number) {
+        // permission already asked when we registered
+        if (window.webkitNotifications && window.webkitNotifications.checkPermission() == 0) {
+            if (oNotifICall) {
+                oNotifICall.cancel();
+            }
+            oNotifICall = window.webkitNotifications.createNotification('images/sipml-34x39.png', 'Incaming call', 'Incoming call from ' + s_number);
+            oNotifICall.onclose = function () { oNotifICall = null; };
+            oNotifICall.show();
+        }
+    }
+
+    function onKeyUp(evt) {
+        evt = (evt || window.event);
+        if (evt.keyCode == 27) {
+            fullScreen(false);
+        }
+        else if (evt.ctrlKey && evt.shiftKey) { // CTRL + SHIFT
+            if (evt.keyCode == 65 || evt.keyCode == 86) { // A (65) or V (86)
+                bDisableVideo = (evt.keyCode == 65);
+                txtCallStatus.innerHTML = '<i>Video ' + (bDisableVideo ? 'disabled' : 'enabled') + '</i>';
+                window.localStorage.setItem('org.doubango.expert.disable_video', bDisableVideo);
+            }
+        }
+    }
+
+    function onDivCallCtrlMouseMove(evt) {
+        try { // IE: DOM not ready
+            if (tsk_utils_have_stream()) {
+                btnCall.disabled = (!tsk_utils_have_stream() || !oSipSessionRegister || !oSipSessionRegister.is_connected());
+                document.getElementById("divCallCtrl").onmousemove = null; // unsubscribe
+            }
+        }
+        catch (e) { }
+    }
+
+    function uiOnConnectionEvent(b_connected, b_connecting) { // should be enum: connecting, connected, terminating, terminated
+        btnRegister.disabled = b_connected || b_connecting;
+        btnUnRegister.disabled = !b_connected && !b_connecting;
+        btnCall.disabled = !(b_connected && tsk_utils_have_webrtc() && tsk_utils_have_stream());
+        btnHangUp.disabled = !oSipSessionCall;
+    }
+
+    function uiVideoDisplayEvent(b_local, b_added) {
+        //if (!bDisableVideo) {
+            var o_elt_video = b_local ? videoLocal : videoRemote;
+
+            if (b_added) {
+                if (SIPml.isWebRtc4AllSupported()) {
+                    if (b_local){ if(window.__o_display_local) window.__o_display_local.style.visibility = "visible"; }
+                    else { if(window.__o_display_remote) window.__o_display_remote.style.visibility = "visible"; }
+                   
+                }
+                else {
+                    o_elt_video.style.opacity = 1;
+                }
+                uiVideoDisplayShowHide(true);
+            }
+            else {
+                if (SIPml.isWebRtc4AllSupported()) {
+                    if (b_local){ if(window.__o_display_local) window.__o_display_local.style.visibility = "hidden"; }
+                    else { if(window.__o_display_remote) window.__o_display_remote.style.visibility = "hidden"; }
+                }
+                else{
+                    o_elt_video.style.opacity = 0;
+                }
+                fullScreen(false);
+            }
+        //}
+    }
+
+    function uiVideoDisplayShowHide(b_show) {
+        if (b_show) {
+            tdVideo.style.height = '340px';
+            divVideo.style.height = navigator.appName == 'Microsoft Internet Explorer' ? '100%' : '340px';
+        }
+        else {
+            tdVideo.style.height = '0px';
+            divVideo.style.height = '0px';
+        }
+        btnFullScreen.disabled = !b_show;
+    }
+
+    function uiCallTerminated(s_description){
+        btnCall.value = 'Call';
+        btnHangUp.value = 'HangUp';
+        btnHoldResume.value = 'hold';
+        btnCall.disabled = false;
+        btnHangUp.disabled = true;
+
+        oSipSessionCall = null;
+
+        stopRingbackTone();
+        stopRingTone();
+
+        txtCallStatus.innerHTML = "<i>" + s_description + "</i>";
+        uiVideoDisplayShowHide(false);
+        divCallOptions.style.opacity = 0;
+
+        if (oNotifICall) {
+            oNotifICall.cancel();
+            oNotifICall = null;
+        }
+
+        uiVideoDisplayEvent(true, false);
+        uiVideoDisplayEvent(false, false);
+
+        setTimeout(function () { if (!oSipSessionCall) txtCallStatus.innerHTML = ''; }, 2500);
+    }
+
+    // Callback function for SIP Stacks
+    function onSipEventStack(e /*SIPml.Stack.Event*/) {
+        tsk_utils_log_info('==stack event = ' + e.type);
+        switch (e.type) {
+            case 'started':
+                {
+                    // catch exception for IE (DOM not ready)
+                    try {
+                        // LogIn (REGISTER) as soon as the stack finish starting
+                        oSipSessionRegister = this.newSession('register', {
+                            expires: 200,
+                            events_listener: { events: '*', listener: onSipEventSession },
+                            sip_caps: [
+                                        { name: '+g.oma.sip-im', value: null },
+                                        { name: '+audio', value: null },
+                                        { name: 'language', value: '\"en,fr\"' }
+                                ]
+                        });
+                        oSipSessionRegister.register();
+                    }
+                    catch (e) {
+                        txtRegStatus.value = txtRegStatus.innerHTML = "<b>1:" + e + "</b>";
+                        btnRegister.disabled = false;
+                    }
+                    break;
+                }
+            case 'stopping': case 'stopped': case 'failed_to_start': case 'failed_to_stop':
+                {
+                    var bFailure = (e.type == 'failed_to_start') || (e.type == 'failed_to_stop');
+                    oSipStack = null;
+                    oSipSessionRegister = null;
+                    oSipSessionCall = null;
+
+                    uiOnConnectionEvent(false, false);
+
+                    stopRingbackTone();
+                    stopRingTone();
+
+                    uiVideoDisplayShowHide(false);
+                    divCallOptions.style.opacity = 0;
+
+                    txtCallStatus.innerHTML = '';
+                    txtRegStatus.innerHTML = bFailure ? "<i>Disconnected: <b>" + e.description + "</b></i>" : "<i>Disconnected</i>";
+                    break;
+                }
+
+            case 'i_new_call':
+                {
+                    if (oSipSessionCall) {
+                        // do not accept the incoming call if we're already 'in call'
+                        e.newSession.hangup(); // comment this line for multi-line support
+                    }
+                    else {
+                        oSipSessionCall = e.newSession;
+
+                        btnCall.value = 'Answer';
+                        btnHangUp.value = 'Reject';
+                        btnCall.disabled = false;
+                        btnHangUp.disabled = false;
+
+                        startRingTone();
+
+                        var sRemoteNumber = (oSipSessionCall.getRemoteFriendlyName() || 'unknown');
+                        txtCallStatus.innerHTML = "<i>Incoming call from [<b>" + sRemoteNumber + "</b>]</i>";
+                        showNotifICall(sRemoteNumber);
+                    }
+                    break;
+                }
+
+            case 'm_permission_requested':
+                {
+                    divGlassPanel.style.visibility = 'visible';
+                    break;
+                }
+            case 'm_permission_accepted':
+            case 'm_permission_refused':
+                {
+                    divGlassPanel.style.visibility = 'hidden';
+                    if(e.type == 'm_permission_refused'){
+                        uiCallTerminated('Media stream permission denied');
+                    }
+                    break;
+                }
+
+            case 'starting': default: break;
+        }
+    };
+
+    // Callback function for SIP sessions (INVITE, REGISTER, MESSAGE...)
+    function onSipEventSession(e /* SIPml.Session.Event */) {
+        tsk_utils_log_info('==session event = ' + e.type);
+
+        switch (e.type) {
+            case 'connecting': case 'connected':
+                {
+                    var bConnected = (e.type == 'connected');
+                    if (e.session == oSipSessionRegister) {
+                        uiOnConnectionEvent(bConnected, !bConnected);
+                        txtRegStatus.innerHTML = "<i>" + e.description + "</i>";
+                    }
+                    else if (e.session == oSipSessionCall) {
+                        btnHangUp.value = 'HangUp';
+                        btnCall.disabled = true;
+                        btnHangUp.disabled = false;
+                        btnTransfer.disabled = false;
+
+                        if (bConnected) {
+                            stopRingbackTone();
+                            stopRingTone();
+
+                            if (oNotifICall) {
+                                oNotifICall.cancel();
+                                oNotifICall = null;
+                            }
+                        }
+
+                        txtCallStatus.innerHTML = "<i>" + e.description + "</i>";
+                        divCallOptions.style.opacity = bConnected ? 1 : 0;
+
+                        if (SIPml.isWebRtc4AllSupported()) { // IE don't provide stream callback
+                            uiVideoDisplayEvent(true, true);
+                            uiVideoDisplayEvent(false, true);
+                        }
+                    }
+                    break;
+                } // 'connecting' | 'connected'
+            case 'terminating': case 'terminated':
+                {
+                    if (e.session == oSipSessionRegister) {
+                        uiOnConnectionEvent(false, false);
+
+                        oSipSessionCall = null;
+                        oSipSessionRegister = null;
+
+                        txtRegStatus.innerHTML = "<i>" + e.description + "</i>";
+                    }
+                    else if (e.session == oSipSessionCall) {
+                        uiCallTerminated(e.description);
+                    }
+                    break;
+                } // 'terminating' | 'terminated'
+
+            case 'm_stream_video_local_added':
+                {
+                    if (e.session == oSipSessionCall) {
+                        uiVideoDisplayEvent(true, true);
+                    }
+                    break;
+                }
+            case 'm_stream_video_local_removed':
+                {
+                    if (e.session == oSipSessionCall) {
+                        uiVideoDisplayEvent(true, false);
+                    }
+                    break;
+                }
+            case 'm_stream_video_remote_added':
+                {
+                    if (e.session == oSipSessionCall) {
+                        uiVideoDisplayEvent(false, true);
+                    }
+                    break;
+                }
+            case 'm_stream_video_remote_removed':
+                {
+                    if (e.session == oSipSessionCall) {
+                        uiVideoDisplayEvent(false, false);
+                    }
+                    break;
+                }
+
+            case 'm_stream_audio_local_added':
+            case 'm_stream_audio_local_removed':
+            case 'm_stream_audio_remote_added':
+            case 'm_stream_audio_remote_removed':
+                {
+                    break;
+                }
+
+            case 'i_ect_new_call':
+                {
+                    oSipSessionTransferCall = e.session;
+                    break;
+                }
+
+            case 'i_ao_request':
+                {
+                    if(e.session == oSipSessionCall){
+                        var iSipResponseCode = e.getSipResponseCode();
+                        if (iSipResponseCode == 180 || iSipResponseCode == 183) {
+                            startRingbackTone();
+                            txtCallStatus.innerHTML = '<i>Remote ringing...</i>';
+                        }
+                    }
+                    break;
+                }
+
+            case 'm_early_media':
+                {
+                    if(e.session == oSipSessionCall){
+                        stopRingbackTone();
+                        stopRingTone();
+                        txtCallStatus.innerHTML = '<i>Early media started</i>';
+                    }
+                    break;
+                }
+
+            case 'm_local_hold_ok':
+                {
+                    if(e.session == oSipSessionCall){
+                        if (oSipSessionCall.bTransfering) {
+                            oSipSessionCall.bTransfering = false;
+                            // this.AVSession.TransferCall(this.transferUri);
+                        }
+                        btnHoldResume.value = 'Resume';
+                        btnHoldResume.disabled = false;
+                        txtCallStatus.innerHTML = '<i>Call placed on hold</i>';
+                        oSipSessionCall.bHeld = true;
+                    }
+                    break;
+                }
+            case 'm_local_hold_nok':
+                {
+                    if(e.session == oSipSessionCall){
+                        oSipSessionCall.bTransfering = false;
+                        btnHoldResume.value = 'Hold';
+                        btnHoldResume.disabled = false;
+                        txtCallStatus.innerHTML = '<i>Failed to place remote party on hold</i>';
+                    }
+                    break;
+                }
+            case 'm_local_resume_ok':
+                {
+                    if(e.session == oSipSessionCall){
+                        oSipSessionCall.bTransfering = false;
+                        btnHoldResume.value = 'Hold';
+                        btnHoldResume.disabled = false;
+                        txtCallStatus.innerHTML = '<i>Call taken off hold</i>';
+                        oSipSessionCall.bHeld = false;
+
+                        if (SIPml.isWebRtc4AllSupported()) { // IE don't provide stream callback yet
+                            uiVideoDisplayEvent(true, true);
+                            uiVideoDisplayEvent(false, true);
+                        }
+                    }
+                    break;
+                }
+            case 'm_local_resume_nok':
+                {
+                    if(e.session == oSipSessionCall){
+                        oSipSessionCall.bTransfering = false;
+                        btnHoldResume.disabled = false;
+                        txtCallStatus.innerHTML = '<i>Failed to unhold call</i>';
+                    }
+                    break;
+                }
+            case 'm_remote_hold':
+                {
+                    if(e.session == oSipSessionCall){
+                        txtCallStatus.innerHTML = '<i>Placed on hold by remote party</i>';
+                    }
+                    break;
+                }
+            case 'm_remote_resume':
+                {
+                    if(e.session == oSipSessionCall){
+                        txtCallStatus.innerHTML = '<i>Taken off hold by remote party</i>';
+                    }
+                    break;
+                }
+
+            case 'o_ect_trying':
+                {
+                    if(e.session == oSipSessionCall){
+                        txtCallStatus.innerHTML = '<i>Call transfer in progress...</i>';
+                    }
+                    break;
+                }
+            case 'o_ect_accepted':
+                {
+                    if(e.session == oSipSessionCall){
+                        txtCallStatus.innerHTML = '<i>Call transfer accepted</i>';
+                    }
+                    break;
+                }
+            case 'o_ect_completed':
+            case 'i_ect_completed':
+                {
+                    if(e.session == oSipSessionCall){
+                        txtCallStatus.innerHTML = '<i>Call transfer completed</i>';
+                        btnTransfer.disabled = false;
+                        if (oSipSessionTransferCall) {
+                            oSipSessionCall = oSipSessionTransferCall;
+                        }
+                        oSipSessionTransferCall = null;
+                    }
+                    break;
+                }
+            case 'o_ect_failed':
+            case 'i_ect_failed':
+                {
+                    if(e.session == oSipSessionCall){
+                        txtCallStatus.innerHTML = '<i>Call transfer failed</i>';
+                        btnTransfer.disabled = false;
+                    }
+                    break;
+                }
+            case 'o_ect_notify':
+            case 'i_ect_notify':
+                {
+                    if(e.session == oSipSessionCall){
+                        txtCallStatus.innerHTML = "<i>Call Transfer: <b>" + e.getSipResponseCode() + " " + e.description + "</b></i>";
+                        if (e.getSipResponseCode() >= 300) {
+                            if (oSipSessionCall.bHeld) {
+                                oSipSessionCall.resume();
+                            }
+                            btnTransfer.disabled = false;
+                        }
+                    }
+                    break;
+                }
+            case 'i_ect_requested':
+                {
+                    if(e.session == oSipSessionCall){                        
+                        var s_message = "Do you accept call transfer to [" + e.getTransferDestinationFriendlyName() + "]?";//FIXME
+                        if (confirm(s_message)) {
+                            txtCallStatus.innerHTML = "<i>Call transfer in progress...</i>";
+                            oSipSessionCall.acceptTransfer();
+                            break;
+                        }
+                        oSipSessionCall.rejectTransfer();
+                    }
+                    break;
+                }
+        }
+    }
+
+</script>
+<body style="cursor:wait">
+    <div class="navbar navbar-fixed-top">
+        <div id="divNavbarInner" 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>
+                <img alt="sipML5" class="brand" src="./images/sipml-34x39.png" />
+                <div class="nav-collapse">
+                    <ul class="nav">
+                        <li class="active"><a href="index.html?svn=179">Home</a></li>
+                    </ul>
+                </div>
+                <!--/.nav-collapse -->
+            </div>
+        </div>
+    </div>
+    <div class="container">
+        <div class="row-fluid">
+            <div class="span4 well">
+                <label style="width: 100%;" align="center" id="txtRegStatus">
+                </label>
+                <h2>
+                    Registration</h2>
+                <br />
+                <table style='width: 100%'>
+                    <tr>
+                        <td>
+                            <label style="height: 100%">
+                                Display Name:</label>
+                        </td>
+                        <td>
+                            <input type="text" style="width: 100%; height: 100%" id="txtDisplayName" value=""
+                                placeholder="e.g. John Doe" />
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <label style="height: 100%">
+                                Private Identity<sup>*</sup>:</label>
+                        </td>
+                        <td>
+                            <input type="text" style="width: 100%; height: 100%" id="txtPrivateIdentity" value=""
+                                placeholder="e.g. +33600000000" />
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <label style="height: 100%">
+                                Public Identity<sup>*</sup>:</label>
+                        </td>
+                        <td>
+                            <input type="text" style="width: 100%; height: 100%" id="txtPublicIdentity" value=""
+                                placeholder="e.g. sip:[email protected]" />
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <label style="height: 100%">Password:</label>
+                        </td>
+                        <td>
+                            <input type="password" style="width: 100%; height: 100%" id="txtPassword" value="" />
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <label style="height: 100%">Realm<sup>*</sup>:</label>
+                        </td>
+                        <td>
+                            <input type="text" style="width: 100%; height: 100%" id="txtRealm" value="" placeholder="e.g. doubango.org" />
+                        </td>
+                    </tr>
+                    <tr>
+                        <td colspan="2" align="right">
+                            <input type="button" class="btn-success" id="btnRegister" value="LogIn" disabled onclick='sipRegister();' />
+                            &nbsp;
+                            <input type="button" class="btn-danger" id="btnUnRegister" value="LogOut" disabled onclick='sipUnRegister();' />
+                        </td>
+                    </tr>
+                    <tr>
+                        <td colspan="3">
+                            <p class="small"><sup>*</sup> <i>Mandatory Field</i></p>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td colspan="3">
+                            <a class="btn" href="http://code.google.com/p/sipml5/wiki/Public_SIP_Servers" target="_blank">Need SIP account?</a>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td colspan="3">
+                            <a class="btn" href="./expert.htm" target="_blank">Expert mode?</a>
+                        </td>
+                    </tr>
+                </table>
+            </div>
+            <div id="divCallCtrl" class="span7 well" style='display:table-cell; vertical-align:middle'>
+                <label style="width: 100%;" align="center" id="txtCallStatus">
+                </label>
+                <h2>
+                    Call control
+                </h2>
+                <br />
+                <table style='width: 100%;'>
+                    <tr>
+                        <td style="white-space:nowrap;">
+                            <input type="text" style="width: 100%; height:100%" id="txtPhoneNumber" value="" placeholder="Enter phone number to call" />                            
+                        </td>
+                    </tr>
+                    <tr>
+                        <td colspan="1" align="right">
+                            <input type="button" class="btn-primary" style="" id="btnCall" value="Call" onclick='sipCall();' disabled /> &nbsp;
+                            <input type="button" class="btn-primary" style="" id="btnHangUp" value="HangUp" onclick='sipHangUp();' disabled />
+                        </td>
+                    </tr>
+                    <tr>
+                        <td id="tdVideo" class='tab-video'>
+                            <div id="divVideo" class='div-video'>
+                                <div id="divVideoRemote" style='border:1px solid #000; height:100%; width:100%'>
+                                    <video class="video" width="100%" height="100%" id="video_remote" autoplay="autoplay" style="opacity: 0; 
+                                        background-color: #000000; -webkit-transition-property: opacity; -webkit-transition-duration: 2s;">
+                                    </video>
+                                </div>
+                                <div id="divVideoLocal" style='border:0px solid #000'>
+                                    <video class="video" width="88px" height="72px" id="video_local" autoplay="autoplay" muted="true" style="opacity: 0;
+                                        margin-top: -80px; margin-left: 5px; background-color: #000000; -webkit-transition-property: opacity;
+                                        -webkit-transition-duration: 2s;">
+                                    </video>
+                                </div>
+                            </div>
+                        </td>
+                    </tr>
+                    <tr>
+                       <td align='center'>
+                            <div id='divCallOptions' class='call-options' style='opacity: 0; margin-top: 3px'>
+                                <input type="button" class="btn" style="" id="btnFullScreen" value="FullScreen" disabled onclick='toggleFullScreen();' /> &nbsp;
+                                <input type="button" class="btn" style="" id="btnHoldResume" value="Hold" onclick='sipToggleHoldResume();' /> &nbsp;
+                                <input type="button" class="btn" style="" id="btnTransfer" value="Transfer" onclick='sipTransfer();' /> &nbsp;
+                                <input type="button" class="btn" style="" id="btnKeyPad" value="KeyPad" onclick='openKeyPad();' />
+                            </div>
+                        </td>
+                    </tr>
+                </table>
+            </div>
+        </div>
+        
+        <br />
+        <footer>
+            <p>&copy; Doubango Telecom 2012-2013 <br />
+            <i>Inspiring the future</i>
+            </p>
+            <!-- Creates all ATL/COM objects right now 
+                Will open confirmation dialogs if not already done
+            -->
+            <object id="fakeVideoDisplay" classid="clsid:5C2C407B-09D9-449B-BB83-C39B7802A684" style="visibility:hidden;"> </object>
+            <object id="fakeLooper" classid="clsid:7082C446-54A8-4280-A18D-54143846211A" style="visibility:hidden;"> </object>
+            <object id="fakeSessionDescription" classid="clsid:DBA9F8E2-F9FB-47CF-8797-986A69A1CA9C" style="visibility:hidden;"> </object>
+            <object id="fakeNetTransport" classid="clsid:5A7D84EC-382C-4844-AB3A-9825DBE30DAE" style="visibility:hidden;"> </object>
+            <object id="fakePeerConnection" classid="clsid:56D10AD3-8F52-4AA4-854B-41F4D6F9CEA3" style="visibility:hidden;"> </object>
+            <!-- 
+                NPAPI  browsers: Safari, Opera and Firefox
+            -->
+            <!--embed id="WebRtc4npapi" type="application/w4a" width='1' height='1' style='visibility:hidden;' /-->
+        </footer>
+    </div>
+    <!-- /container -->
+
+    <!-- Glass Panel -->
+    <div id='divGlassPanel' class='glass-panel' style='visibility:hidden'></div>
+    <!-- KeyPad Div -->
+    <div id='divKeyPad' class='span2 well div-keypad' style="left:0px; top:0px; width:250; height:240; visibility:hidden">
+        <table style="width: 100%; height: 100%">
+            <tr><td><input type="button" style="width: 33%" class="btn" value="1" onclick="sipSendDTMF('1');"/><input type="button" style="width: 33%" class="btn" value="2" onclick="sipSendDTMF('2');"/><input type="button" style="width: 33%" class="btn" value="3" onclick="sipSendDTMF('3');"/></td></tr>
+            <tr><td><input type="button" style="width: 33%" class="btn" value="4" onclick="sipSendDTMF('4');"/><input type="button" style="width: 33%" class="btn" value="5" onclick="sipSendDTMF('5');"/><input type="button" style="width: 33%" class="btn" value="6" onclick="sipSendDTMF('6');"/></td></tr>
+            <tr><td><input type="button" style="width: 33%" class="btn" value="7" onclick="sipSendDTMF('7');"/><input type="button" style="width: 33%" class="btn" value="8" onclick="sipSendDTMF('8');"/><input type="button" style="width: 33%" class="btn" value="9" onclick="sipSendDTMF('9');"/></td></tr>
+            <tr><td><input type="button" style="width: 33%" class="btn" value="*" onclick="sipSendDTMF('*');"/><input type="button" style="width: 33%" class="btn" value="0" onclick="sipSendDTMF('0');"/><input type="button" style="width: 33%" class="btn" value="#" onclick="sipSendDTMF('#');"/></td></tr>
+            <tr><td colspan=3><input type="button" style="width: 100%" class="btn btn-medium btn-danger" value="close" onclick="closeKeyPad();" /></td></tr>
+        </table>
+    </div>
+
+    <!-- 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>
+
+    <!-- Audios -->
+    <audio id="audio_remote" autoplay="autoplay" />
+    <audio id="ringtone" loop src="sounds/ringtone.wav" />
+    <audio id="ringbacktone" loop src="sounds/ringbacktone.wav" />
+    <audio id="dtmfTone" src="sounds/dtmf.wav" />
+
+    <!-- 
+        Microsoft Internet Explorer extension
+        For now we use msi installer as we don't have trusted certificate yet :(
+    -->
+    <!--object id="webrtc4ieLooper" classid="clsid:7082C446-54A8-4280-A18D-54143846211A" CODEBASE="http://sipml5.org/deploy/webrtc4all.CAB"> </object-->
+
+    <!-- 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>

+ 107 - 0
sipml5/contact.htm

@@ -0,0 +1,107 @@
+<!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 lang="en">
+<head>
+    <meta charset="utf-8" />
+    <title>Contact</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <meta name="Keywords" content="doubango, VoIP, HTML5, WebRTC, RTCWeb, SIP, IMS, Video chat, VP8 " />
+    <meta name="Description" content="HTML5 SIP client using WebRTC framework" />
+    <meta name="author" content="Doubango Telecom" />
+    <!-- Le styles -->
+    <link href="./assets/css/bootstrap.css" rel="stylesheet" />
+    <style type="text/css">
+        body
+        {
+            padding-top: 102px;
+            padding-bottom: 40px;
+        }
+    </style>
+</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>
+                <img alt="sipML5" class="brand" src="./images/sipml-34x39.png" />
+                <div class="nav-collapse">
+                    <ul class="nav">
+                        <li><a href="index.html">Home</a></li>
+                        <li><a href="http://code.google.com/p/sipml5/source/checkout" target="_blank">Source code</a></li>
+                        <li class="active"><a href="contact.htm">Contact</a></li>
+                    </ul>
+                </div>
+                <!--/.nav-collapse -->
+            </div>
+        </div>
+    </div>
+    <div class="container">
+        <p>
+            <!-- Obfuscated using: http://womeninbusiness.about.com/gi/o.htm?zi=1/XJ&zTi=1&sdn=womeninbusiness&cdn=money&tm=24&f=10&su=p284.13.342.ip_p554.21.342.ip_&tt=2&bt=1&bts=0&zu=http%3A//www.seowebsitepromotion.com/obfuscate_email.asp -->
+            For non-technical questions, please <a href="&#109;&#97;&#105;&#108;&#116;&#111;:&#x69;&#x6E;&#x66;&#111;&#64;&#x64;&#111;&#x75;&#x62;&#x61;&#110;&#103;&#x6F;&#x2E;&#111;&#x72;&#x67;?subject=&#115;&#105;&#x70;&#77;&#76;&#53;"
+                title="&#x53;&#x65;&#x6E;&#x64;&#32;&#x75;&#x73;&#32;&#x61;&#32;&#x6D;&#x61;&#105;&#x6C;">
+                &#83;&#x65;&#110;&#x64;&#x20;&#117;&#x73;&#32;&#97;&#x20;&#x6D;&#97;&#105;&#x6C;</a><br />
+            You can also open <a target=_blank href="http://click2dial.org/u/ZGlvcG1hbWFkb3VAZG91YmFuZ28ub3Jn">this link</a> or press on the green button on the right side to call us on our mobile (or landline) phone.
+        </p>
+        <hr />
+        <p>
+            For technical questions, please subscribe to our <a href="https://groups.google.com/group/doubango" target=_blank>developer's mailing list</a>:
+        </p>
+        <table border="0" style="background-color: #fff; padding: 5px;" cellspacing="0">
+            <tr>
+                <td>
+                    <img src="http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif" height="30"
+                        width="140" alt="Google Groups" />
+                </td>
+            </tr>
+            <form action="http://groups.google.com/group/doubango/boxsubscribe">
+            <tr>
+                <td style="padding-left: 5px;">
+                    Email:
+                    <input type="text" name="email" />
+                    <input type="submit" name="sub" value="Subscribe" />
+                </td>
+            </tr>
+            </form>
+            
+            <tr>
+                <td>
+                <hr />
+                <p>
+                    Doubango Telecom<br />
+                    12 Rue Vivienne Lot 3<br />
+                    75002 Paris<br />
+                    FRANCE<br />
+                </p>
+                </td>
+            </tr>
+        </table>
+        <hr />
+        <footer>
+            <p>
+                &copy; Doubango Telecom 2012-2013</p>
+            <i>Inspiring the future</i>
+        </footer>
+    </div>
+
+    <!-- click-to-call widget -->
+    <script type='text/javascript' src='http://click2dial.org/c2c-api.js'></script>
+    <script type='text/javascript'>
+	    c2c.from = 'ZGlvcG1hbWFkb3VAZG91YmFuZ28ub3Jn';
+	    c2c.text = 'call us &raquo;';
+	    c2c.class = 'btn btn-large btn-success';
+	    c2c.config = {
+    		    http_service_url: null,
+    		    websocket_proxy_url: null,
+    		    sip_outbound_proxy_url: null
+	    };
+	    c2c.init();
+    </script>
+</body>
+</html>

+ 14 - 0
sipml5/error.htm

@@ -0,0 +1,14 @@
+<!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 lang="en">
+<head>
+    <title>Error</title>
+</head>
+<body>
+
+</body>
+</html>

+ 169 - 0
sipml5/expert.htm

@@ -0,0 +1,169 @@
+<!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 lang="en">
+<head>
+    <meta charset="utf-8" />
+    <title>sipML5 - Expert mode</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <meta name="Keywords" content="doubango, VoIP, HTML5, WebRTC, RTCWeb, SIP, IMS, Video chat, VP8 " />
+    <meta name="Description" content="HTML5 SIP client using WebRTC framework" />
+    <meta name="author" content="Doubango Telecom" />
+    <!-- Le styles -->
+    <link href="./assets/css/bootstrap.css" rel="stylesheet" />
+    <style type="text/css">
+        body
+        {
+            padding-top: 80px;
+            padding-bottom: 40px;
+        }
+    </style>
+    <link href="./assets/css/bootstrap-responsive.css" rel="stylesheet" />
+    <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
+    <!--[if lt IE 9]>
+      <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+    <![endif]-->
+    <!-- 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>
+
+<script type="text/javascript">
+
+    var cbVideoDisable;
+    var cbAVPFDisable;
+    var txtWebsocketServerUrl;
+    var txtSIPOutboundProxyUrl;
+    var txtInfo;
+
+    window.onload = function () {
+        cbVideoDisable = document.getElementById("cbVideoDisable");
+        cbRTCWebBreaker = document.getElementById("cbRTCWebBreaker");
+        txtWebsocketServerUrl = document.getElementById("txtWebsocketServerUrl");
+        txtSIPOutboundProxyUrl = document.getElementById("txtSIPOutboundProxyUrl");
+        txtInfo = document.getElementById("txtInfo");
+
+        txtWebsocketServerUrl.disabled = !window.WebSocket;
+        document.getElementById("btnSave").disabled = !window.localStorage;
+        document.getElementById("btnRevert").disabled = !window.localStorage;
+
+        if(window.localStorage){
+            settingsRevert(true);
+        }
+    }
+
+    function settingsSave() {
+        window.localStorage.setItem('org.doubango.expert.disable_video', cbVideoDisable.checked ? "true" : "false");
+        window.localStorage.setItem('org.doubango.expert.enable_rtcweb_breaker', cbRTCWebBreaker.checked ? "true" : "false");
+        if (!txtWebsocketServerUrl.disabled) {
+            window.localStorage.setItem('org.doubango.expert.websocket_server_url', txtWebsocketServerUrl.value);
+        }
+        window.localStorage.setItem('org.doubango.expert.sip_outboundproxy_url', txtSIPOutboundProxyUrl.value);
+        window.localStorage.setItem('org.doubango.expert.ice_servers', txtIceServers.value);
+
+        txtInfo.innerHTML = '<i>Saved</i>';
+    }
+
+    function settingsRevert(bNotUserAction) {
+        cbVideoDisable.checked = (window.localStorage.getItem('org.doubango.expert.disable_video') == "true");
+        cbRTCWebBreaker.checked = (window.localStorage.getItem('org.doubango.expert.enable_rtcweb_breaker') == "true");
+        txtWebsocketServerUrl.value = (window.localStorage.getItem('org.doubango.expert.websocket_server_url') || "");
+        txtSIPOutboundProxyUrl.value = (window.localStorage.getItem('org.doubango.expert.sip_outboundproxy_url') || "");
+        txtIceServers.value = (window.localStorage.getItem('org.doubango.expert.ice_servers') || "");
+
+        if (!bNotUserAction) {
+            txtInfo.innerHTML = '<i>Reverted</i>';
+        }
+    }
+</script>
+
+<body>
+    <div class="container">
+        <div class="span7 well">
+            <label align="center" id="txtInfo"> </label>
+            <h2> Expert settings</h2>
+            <br />
+            <table style='width: 100%'>
+                <tr>
+                    <td>
+                        <label style="height: 100%">Disable Video:</label>
+                    </td>
+                    <td>
+                        <input type='checkbox' id='cbVideoDisable' />
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <label style="height: 100%">Enable RTCWeb Breaker<sup><a href="#aRTCWebBreaker">[1]</a></sup>:</label>
+                    </td>
+                    <td>
+                        <input type='checkbox' id='cbRTCWebBreaker' />
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <label style="height: 100%">WebSocket Server URL<sup><a href="#aWebSocketServerURL">[2]</a></sup>:</label>
+                    </td>
+                    <td>
+                        <input type="text" style="width: 100%; height: 100%" id="txtWebsocketServerUrl" value="" placeholder="e.g. ws://sipml5.org:5062" />
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <label style="height: 100%">SIP outbound Proxy URL<sup><a href="#aSIPOutboundProxyURL">[3]</a></sup>:</label>
+                    </td>
+                    <td>
+                        <input type="text" style="width: 100%; height: 100%" id="txtSIPOutboundProxyUrl" value="" placeholder="e.g. udp://sipml5.org:5060" />
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <label style="height: 100%">ICE Servers<sup><a href="#aIceServers">[4]</a></sup>:</label>
+                    </td>
+                    <td>
+                        <input type="text" style="width: 100%; height: 100%" id="txtIceServers" value="" placeholder="e.g. [{ url: 'stun:stun.l.google.com:19302'}, { url:'turn:[email protected]', credential:'myPassword'}]" />
+                    </td>
+                </tr>
+
+                <tr>
+                    <td colspan="2" align="right">
+                        <input type="button" class="btn-success" id="btnSave" value="Save" onclick='settingsSave();' />
+                        &nbsp;
+                        <input type="button" class="btn-danger" id="btnRevert" value="Revert" onclick='settingsRevert();' />
+                    </td>
+               </tr>
+            </table>
+        </div>
+    </div>
+
+    <hr />
+    <footer>
+        
+            <a name="aRTCWebBreaker"><sup><b>[1]</b></sup></a> The <b>RTCWeb Breaker</b> is used to enable audio and video transcoding when the endpoints do not support the same codecs or the remote server is not RTCWeb-compliant. Please note that the <b>Media Coder</b> will most likely be disabled on the <b>sipml5.org</b> hosted server.<br />
+            For example, you can enable this feature if:
+            <ul>
+                <li>You want to make call from/to <b>Chrome</b> to/from <b>Firefox Nightly</b></li>
+                <li>You're using any RTCWeb-capable browser and trying to call the PSTN network</li>
+                <li>You're using any RTCWeb-capable browser and trying to call any SIP client (e.g. <b>xlite</b>) not implementing some mandatory features (e.g. <b>ICE</b>, <b>DTLS-SRTP</b>...)</li>
+                <li>You're using <b>Google Chrome</b> which only support VP8 codec and trying to call a SIP-legacy client supporting only <b>H.264</b>, <b>H.263</b>, <b>Theora</b> or <b>MP4V-ES</b></li>
+                <li>Making audio/video calls from/to <a href="https://www.google.com/intl/en/chrome/browser/">Google Chrome</a> to/from <a href="https://labs.ericsson.com/apps/bowser">Ericsson Bowser</a></li>
+                <li>Your media server is not RTCWeb-capable (e.g. <b>FreeSWITCH</b>)</li>
+            </ul>
+            Please check the <a href="http://webrtc2sip.org/technical-guide-1.0.pdf">Technical guide</a> for more information about the <b>RTCWeb Breaker</b> and <b>Media Coder</b>.<br />
+
+            <a name="aWebSocketServerURL"><sup><b>[2]</b></sup></a> The <b>WebSocket Server URL</b> is only required if you're a developer and using your own SIP Proxy gateway not publicly reachable. <br />
+
+            <a name="aSIPOutboundProxyURL"><sup><b>[3]</b></sup></a> The <b>SIP outbound Proxy URL</b> is used to set the destination IP address and Port to use for all outgoing requests regardless the <i>domain name</i> (a.k.a <i>realm</i>).
+            This is a good option for developers using a SIP domain name without valid DNS A/NAPTR/SRV records. <br />
+
+            <a name="aIceServers"><sup><b>[4]</b></sup></a> This must be an array of STUN/TURN servers to use. The format is as explained at <a href="http://www.w3.org/TR/webrtc/#rtciceserver-type">http://www.w3.org/TR/webrtc/#rtciceserver-type</a> <br />
+            Example: <i>[{ url: 'stun:stun.l.google.com:19302'}, { url:'turn:[email protected]', credential:'myPassword'}]</i>
+        
+    </footer>
+</body>
+</html>

BIN
sipml5/images/classes.bmp


BIN
sipml5/images/qmark-16x16.png


BIN
sipml5/images/rectangle_256x256.png


BIN
sipml5/images/sipml-180x204.png


BIN
sipml5/images/sipml-34x39.png


BIN
sipml5/images/sipml-360x405.png


BIN
sipml5/images/sipml-45x51.png


BIN
sipml5/images/sipml-90x102.png


+ 254 - 0
sipml5/index.php

@@ -0,0 +1,254 @@
+<?php
+
+require_once "root.php";
+require_once "resources/require.php";
+require_once "resources/check_auth.php";
+
+?>
+<!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 lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <title>sipML5 - The world's first open source HTML5 SIP client</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <meta name="Keywords" content="doubango, VoIP, HTML5, WebRTC, RTCWeb, SIP, IMS, Video chat, VP8 " />
+    <meta name="Description" content="HTML5 SIP client using WebRTC framework" />
+    <meta name="author" content="Doubango Telecom" />
+
+    <!-- Le styles -->
+    <link href="./assets/css/bootstrap.css" rel="stylesheet" />
+    <style type="text/css">
+      body {
+        padding-top: 80px;
+        padding-bottom: 40px;
+      }
+      tr.spaceUnder > td {
+        padding-bottom: 2em;
+      }
+    </style>
+    <link href="./assets/css/bootstrap-responsive.css" rel="stylesheet" />
+
+    <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
+    <!--[if lt IE 9]>
+      <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+    <![endif]-->
+
+    <!-- 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" />
+    
+    <script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
+  </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 class="active"><a href="index.html?svn=179">Home</a></li>
+              <li><a href="http://code.google.com/p/sipml5/source/checkout" target="_blank">Source code</a></li>
+              <li><a href="docgen/index.html?svn=179">Programmer's Guide</a></li>
+              <li><a href="contact.htm">Contact</a></li>
+            </ul>
+          </div><!--/.nav-collapse -->
+        </div>
+      </div>
+    </div>
+
+    <div class="container">
+
+      <!-- Main hero unit for a primary marketing message or call to action -->
+      <div class="hero-unit">
+        <h2>World's first HTML5 SIP client</h2>
+        <p>This is the world's first open source (<a target=_blank href="http://opensource.org/licenses/BSD-3-Clause">BSD license</a>) HTML5 SIP client entirely written in javascript for integration in social networks (FaceBook, Twitter, Google+), online games, e-commerce websites, email signatures... No extension, plugin or gateway is needed. The media stack rely on <a href="http://en.wikipedia.org/wiki/WebRTC" target="_blank">WebRTC</a>.<br />
+         The client can be used to connect to any SIP or IMS network from your preferred browser to make and receive audio/video calls and instant messages.<br />
+        </p>
+        <p><a class="btn btn-primary btn-large" href="call.htm?svn=179" target="_blank">Enjoy our live demo &raquo;</a></p>
+      </div>
+
+
+      <table>
+          <tr class="spaceUnder"><td>
+                <table>
+                  <tr><td><h2><a name="aSipSdpStack">Javascript SIP/SDP stack</a></h2></td></tr>
+                  <tr class="spaceUnder"><td>
+                       <p>The SIP and SDP stacks (<b>~1 Mo</b>) are entirely written in javascript and the network transport uses WebSockets as per <a href="http://tools.ietf.org/html/draft-ibc-sipcore-sip-websocket">draft-ibc-sipcore-sip-websocket</a>.
+                       The <a href="call.htm?svn=179" target="_blank">live demo</a> doesn't require any installation and can be used to connect to any SIP server using UDP, TCP or TLS transports.
+                       </p>
+                       <p>Short but not exhaustive list of supported features:</p>
+                      <ul>
+                        <li><b>Works on Chrome, Firefox, IE, Safari, Opera and Bowser</b></li>
+                        <li>Audio / Video call</li>
+                        <li>Instant messaging</li>
+                        <li>Presence</li>
+                        <li>Call Hold / Resume</li>
+                        <li>Explicit Call transfer</li>
+                        <li>Multi-line and multi-account</li>
+                        <li>Dual-tone multi-frequency signaling (DTMF) using SIP INFO</li>
+                        <li><a href="http://click2dial.org" target=_blank>Click-to-Call</a></li>
+                      </ul>
+                      <p><a class="btn" href="http://code.google.com/p/sipml5/" target="_blank">View details &raquo;</a></p>       
+                   </td></tr>
+                  <tr><td align="center"><img alt="SIP Proxy architecture" src="http://webrtc2sip.googlecode.com/svn/trunk/documentation/images/architecture.png"/></td></tr>
+                  <tr><td align="center"><i><u>sipML5 global solution architecture</u></i></td></tr>
+              </table>
+         </td></tr>
+
+         <tr><td>
+                <table>
+                  <tr><td><h2><a name="aMediaStack">Media Stack</a></h2></td></tr>
+                  <tr><td>
+                       <p>The media stack depends on <a href="http://en.wikipedia.org/wiki/WebRTC">WebRTC (Web Real Time Communication)</a> which is natively provided by the web browser.
+                       <b>sipML5</b> should work on any web browser supporting WebRTC but we highly recommend using <a target=_blank href="https://www.google.com/intl/en/chrome/browser/">Google Chrome</a> or <a target=_blank href="http://nightly.mozilla.org/">Firefox Nightly</a> for testing. <br />
+                       For <b>Safari</b>, <b>Firefox</b>, <b>Opera</b> and <b>IE</b> you will need to install <a href="http://code.google.com/p/webrtc4all/downloads/list" target="_blank"> webrtc4all</a> extension. <br />
+                       </p>     
+                   </td></tr>
+              </table>
+         </td></tr>
+
+         <tr><td>
+                <table>
+                  <tr><td><h2><a name="aInteroperability">Interoperability</a></h2></td></tr>
+                  <tr><td>
+                     <p>Using sipml5 and <a href="http://webrtc2sip.org">webrtc2sip.org</a> you can call any SIP-legacy endpoint or PSTN network. </p>
+                  </td></tr>
+              </table>
+         </td></tr>
+
+         <tr><td>
+                <table>
+                  <tr><td><h2><a name="aLicense">License</a></h2></td></tr>
+                  <tr><td>
+                     <p>The code is released under <a target=_blank href="http://opensource.org/licenses/BSD-3-Clause">BSD terms</a>. For more information: <a href="https://code.google.com/p/sipml5/wiki/License" target=_blank>https://code.google.com/p/sipml5/wiki/License</a> </p>
+                  </td></tr>
+              </table>
+         </td></tr>
+
+         <tr class="spaceUnder"><td>
+                <table>
+                  <tr><td><h2><a name="aInteroperability">Programing with sipML5 API</a></h2></td></tr>
+                  <tr class="spaceUnder"><td>
+                     <p>
+                          The <a href="docgen/index.html">API</a> is designed with love to make it easy to develop rich and robust HTML5 applications in few lines of code. <br />
+                          No need to know how SIP work to start writing your code. Using this <a href="docgen/index.html">API</a>, it will be a piece of cake to write HTML5 VoIP applications. <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:[email protected]', 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>
+                  </td></tr>
+              </table>
+         </td></tr>
+
+     </table>
+
+    <table>
+        <tr>
+            <td>
+                <iframe id="ytplayer" type="text/html" width="512" height="312"
+                    src="http://www.youtube.com/embed/ro3FFNx7d-g?autoplay=0&origin=http://sipml5.org"
+                    frameborder="0"> </iframe>&nbsp;&nbsp;
+            </td>
+            <td>
+                <iframe id="Iframe1" type="text/html" width="512" height="312"
+                    src="http://www.youtube.com/embed/7HEMyxAnATI?autoplay=0&origin=http://sipml5.org"
+                    frameborder="0"> </iframe>
+            </td>
+        </tr>
+        <tr>
+            <td align="center"><i>Call between Google Chrome and iPad device</i></td>
+            <td align="center"><i>Call between Google Chrome and Android device</i></td>
+        </tr>
+    </table>
+         
+    <hr />
+    <g:plus href="https://plus.google.com/107177632824809995368" rel="author"></g:plus> <br />
+    <a href="https://twitter.com/DoubangoTelecom" class="twitter-follow-button" data-show-count="false" data-size="large">Follow @DoubangoTelecom</a>  
+    <hr />     
+    <footer>
+        <p>
+            &copy; Doubango Telecom 2012-2013</p>
+        <i>Inspiring the future</i>
+    </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>
+
+    <!-- click-to-call widget -->
+    <script type='text/javascript' src='http://click2dial.org/c2c-api.js'></script>
+    <script type='text/javascript'>
+	    c2c.from = 'ZGlvcG1hbWFkb3VAZG91YmFuZ28ub3Jn';
+	    c2c.text = 'call us &raquo;';
+	    c2c.cls = 'btn btn-large btn-success';
+        c2c.glass = true;
+	    c2c.config = {
+    		    http_service_url: null,
+    		    websocket_proxy_url: null,
+    		    sip_outbound_proxy_url: null
+	    };
+	    c2c.init();
+    </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>
+    
+     <!-- TWITTER -->     
+     <script type='text/javascript'>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
+
+  </body>
+</html>

BIN
sipml5/sounds/dtmf.wav


BIN
sipml5/sounds/ringbacktone.wav


BIN
sipml5/sounds/ringtone.wav


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff