index.php 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313
  1. <?php
  2. require_once "root.php";
  3. require_once "resources/require.php";
  4. require_once "resources/check_auth.php";
  5. require_once "resources/header.php";
  6. ?>
  7. <!--
  8. * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org>
  9. * License: BSD
  10. * This file is part of Open Source sipML5 solution <http://www.sipml5.org>
  11. */
  12. -->
  13. <!-- SIPML5 API:
  14. DEBUG VERSION: 'SIPml-api.js'
  15. RELEASE VERSION: 'release/SIPml-api.js'
  16. -->
  17. <script src="SIPml-api.js?svn=224" type="text/javascript"> </script>
  18. <!-- Styles -->
  19. <link href="./assets/css/bootstrap.css" rel="stylesheet" />
  20. <style type="text/css">
  21. body{
  22. padding-top: 80px;
  23. padding-bottom: 40px;
  24. }
  25. .navbar-inner-red {
  26. background-color: #600000;
  27. background-image: none;
  28. background-repeat: no-repeat;
  29. filter: none;
  30. }
  31. .full-screen{
  32. position: absolute;
  33. left: 0;
  34. top: 0;
  35. width: 100%;
  36. height: 100%;
  37. overflow: hidden;
  38. }
  39. .normal-screen{
  40. position: relative;
  41. }
  42. .call-options {
  43. padding: 5px;
  44. background-color: #f0f0f0;
  45. border: 1px solid #eee;
  46. border: 1px solid rgba(0, 0, 0, 0.08);
  47. -webkit-border-radius: 4px;
  48. -moz-border-radius: 4px;
  49. border-radius: 4px;
  50. -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
  51. -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
  52. box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
  53. -webkit-transition-property: opacity;
  54. -moz-transition-property: opacity;
  55. -o-transition-property: opacity;
  56. -webkit-transition-duration: 2s;
  57. -moz-transition-duration: 2s;
  58. -o-transition-duration: 2s;
  59. }
  60. .tab-video,
  61. .div-video{
  62. width: 100%;
  63. height: 0px;
  64. -webkit-transition-property: height;
  65. -moz-transition-property: height;
  66. -o-transition-property: height;
  67. -webkit-transition-duration: 2s;
  68. -moz-transition-duration: 2s;
  69. -o-transition-duration: 2s;
  70. }
  71. .label-align {
  72. display: block;
  73. padding-left: 15px;
  74. text-indent: -15px;
  75. }
  76. .input-align {
  77. width: 13px;
  78. height: 13px;
  79. padding: 0;
  80. margin:0;
  81. vertical-align: bottom;
  82. position: relative;
  83. top: -1px;
  84. *overflow: hidden;
  85. }
  86. .glass-panel{
  87. z-index: 99;
  88. position: fixed;
  89. width: 100%;
  90. height: 100%;
  91. margin: 0;
  92. padding: 0;
  93. top: 0;
  94. left: 0;
  95. opacity: 0.8;
  96. background-color: Gray;
  97. }
  98. .div-keypad {
  99. z-index: 100;
  100. position: fixed;
  101. -moz-transition-property: left top;
  102. -o-transition-property: left top;
  103. -webkit-transition-duration: 2s;
  104. -moz-transition-duration: 2s;
  105. -o-transition-duration: 2s;
  106. }
  107. </style>
  108. <link href="./assets/css/bootstrap-responsive.css" rel="stylesheet" />
  109. <!-- Le fav and touch icons -->
  110. <link rel="shortcut icon" href="./assets/ico/favicon.ico" />
  111. <link rel="apple-touch-icon-precomposed" sizes="114x114" href="./assets/ico/apple-touch-icon-114-precomposed.png" />
  112. <link rel="apple-touch-icon-precomposed" sizes="72x72" href="./assets/ico/apple-touch-icon-72-precomposed.png" />
  113. <link rel="apple-touch-icon-precomposed" href="./assets/ico/apple-touch-icon-57-precomposed.png" />
  114. </head>
  115. <!-- Javascript code -->
  116. <script type="text/javascript">
  117. // to avoid caching
  118. //if (window.location.href.indexOf("svn=") == -1) {
  119. // window.location.href += (window.location.href.indexOf("?") == -1 ? "?svn=224" : "&svn=224");
  120. //}
  121. var sTransferNumber;
  122. var oRingTone, oRingbackTone;
  123. var oSipStack, oSipSessionRegister, oSipSessionCall, oSipSessionTransferCall;
  124. var videoRemote, videoLocal, audioRemote;
  125. var bFullScreen = false;
  126. var oNotifICall;
  127. var bDisableVideo = false;
  128. var viewVideoLocal, viewVideoRemote; // <video> (webrtc) or <div> (webrtc4all)
  129. var oConfigCall;
  130. var oReadyStateTimer;
  131. C =
  132. {
  133. divKeyPadWidth: 220
  134. };
  135. window.onload = function () {
  136. if(window.console) {
  137. window.console.info("location=" + window.location);
  138. }
  139. videoLocal = document.getElementById("video_local");
  140. videoRemote = document.getElementById("video_remote");
  141. audioRemote = document.getElementById("audio_remote");
  142. document.onkeyup = onKeyUp;
  143. document.body.onkeyup = onKeyUp;
  144. divCallCtrl.onmousemove = onDivCallCtrlMouseMove;
  145. // set debug level
  146. SIPml.setDebugLevel((window.localStorage && window.localStorage.getItem('org.doubango.expert.disable_debug') == "true") ? "error" : "info");
  147. loadCredentials();
  148. loadCallOptions();
  149. // Initialize call button
  150. uiBtnCallSetText("Call");
  151. var getPVal = function (PName) {
  152. var query = window.location.search.substring(1);
  153. var vars = query.split('&');
  154. for (var i = 0; i < vars.length; i++) {
  155. var pair = vars[i].split('=');
  156. if (decodeURIComponent(pair[0]) === PName) {
  157. return decodeURIComponent(pair[1]);
  158. }
  159. }
  160. return null;
  161. }
  162. var preInit = function() {
  163. // set default webrtc type (before initialization)
  164. var s_webrtc_type = getPVal("wt");
  165. if (s_webrtc_type) {
  166. if(window.console) {
  167. window.console.info("s_webrtc_type=" + s_webrtc_type);
  168. }
  169. SIPml.setWebRtcType(s_webrtc_type);
  170. }
  171. // initialize SIPML5
  172. SIPml.init(postInit);
  173. }
  174. oReadyStateTimer = setInterval(function () {
  175. if (document.readyState === "complete") {
  176. clearInterval(oReadyStateTimer);
  177. // initialize SIPML5
  178. preInit();
  179. }
  180. },
  181. 500);
  182. /*if (document.readyState === "complete") {
  183. preInit();
  184. }
  185. else {
  186. document.onreadystatechange = function () {
  187. if (document.readyState === "complete") {
  188. preInit();
  189. }
  190. }
  191. }*/
  192. };
  193. function postInit() {
  194. // check webrtc4all version
  195. if (SIPml.isWebRtc4AllSupported() && SIPml.isWebRtc4AllPluginOutdated()) {
  196. if (confirm("Your WebRtc4all extension is outdated ("+SIPml.getWebRtc4AllVersion()+"). A new version with critical bug fix is available. Do you want to install it?\nIMPORTANT: You must restart your browser after the installation.")) {
  197. window.location = 'http://code.google.com/p/webrtc4all/downloads/list';
  198. return;
  199. }
  200. }
  201. // check for WebRTC support
  202. if (!SIPml.isWebRtcSupported()) {
  203. // is it chrome?
  204. if (SIPml.getNavigatorFriendlyName() == 'chrome') {
  205. if (confirm("You're using an old Chrome version or WebRTC is not enabled.\nDo you want to see how to enable WebRTC?")) {
  206. window.location = 'http://www.webrtc.org/running-the-demos';
  207. }
  208. else {
  209. window.location = "index.html";
  210. }
  211. return;
  212. }
  213. // for now the plugins (WebRTC4all only works on Windows)
  214. if (SIPml.getSystemFriendlyName() == 'windows') {
  215. // Internet explorer
  216. if (SIPml.getNavigatorFriendlyName() == 'ie') {
  217. // Check for IE version
  218. if (parseFloat(SIPml.getNavigatorVersion()) < 9.0) {
  219. if (confirm("You are using an old IE version. You need at least version 9. Would you like to update IE?")) {
  220. window.location = 'http://windows.microsoft.com/en-us/internet-explorer/products/ie/home';
  221. }
  222. else {
  223. window.location = "index.html";
  224. }
  225. }
  226. // check for WebRTC4all extension
  227. if (!SIPml.isWebRtc4AllSupported()) {
  228. if (confirm("webrtc4all extension is not installed. Do you want to install it?\nIMPORTANT: You must restart your browser after the installation.")) {
  229. window.location = 'http://code.google.com/p/webrtc4all/downloads/list';
  230. }
  231. else {
  232. // Must do nothing: give the user the chance to accept the extension
  233. // window.location = "index.html";
  234. }
  235. }
  236. // break page loading ('window.location' won't stop JS execution)
  237. if (!SIPml.isWebRtc4AllSupported()) {
  238. return;
  239. }
  240. }
  241. else if (SIPml.getNavigatorFriendlyName() == "safari" || SIPml.getNavigatorFriendlyName() == "firefox" || SIPml.getNavigatorFriendlyName() == "opera") {
  242. 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.")) {
  243. window.location = 'http://code.google.com/p/webrtc4all/downloads/list';
  244. }
  245. else {
  246. window.location = "index.html";
  247. }
  248. return;
  249. }
  250. }
  251. // OSX, Unix, Android, iOS...
  252. else {
  253. if (confirm('WebRTC not supported on your browser.\nDo you want to download a WebRTC-capable browser?')) {
  254. window.location = 'https://www.google.com/intl/en/chrome/browser/';
  255. }
  256. else {
  257. window.location = "index.html";
  258. }
  259. return;
  260. }
  261. }
  262. // checks for WebSocket support
  263. if (!SIPml.isWebSocketSupported() && !SIPml.isWebRtc4AllSupported()) {
  264. if (confirm('Your browser don\'t support WebSockets.\nDo you want to download a WebSocket-capable browser?')) {
  265. window.location = 'https://www.google.com/intl/en/chrome/browser/';
  266. }
  267. else {
  268. window.location = "index.html";
  269. }
  270. return;
  271. }
  272. // FIXME: displays must be per session
  273. // attachs video displays
  274. if (SIPml.isWebRtc4AllSupported()) {
  275. viewVideoLocal = document.getElementById("divVideoLocal");
  276. viewVideoRemote = document.getElementById("divVideoRemote");
  277. WebRtc4all_SetDisplays(viewVideoLocal, viewVideoRemote); // FIXME: move to SIPml.* API
  278. }
  279. else{
  280. viewVideoLocal = videoLocal;
  281. viewVideoRemote = videoRemote;
  282. }
  283. if (!SIPml.isWebRtc4AllSupported() && !SIPml.isWebRtcSupported()) {
  284. if (confirm('Your browser don\'t support WebRTC.\naudio/video calls will be disabled.\nDo you want to download a WebRTC-capable browser?')) {
  285. window.location = 'https://www.google.com/intl/en/chrome/browser/';
  286. }
  287. }
  288. btnRegister.disabled = false;
  289. document.body.style.cursor = 'default';
  290. oConfigCall = {
  291. audio_remote: audioRemote,
  292. video_local: viewVideoLocal,
  293. video_remote: viewVideoRemote,
  294. bandwidth: { audio:undefined, video:undefined },
  295. video_size: { minWidth:undefined, minHeight:undefined, maxWidth:undefined, maxHeight:undefined },
  296. events_listener: { events: '*', listener: onSipEventSession },
  297. sip_caps: [
  298. { name: '+g.oma.sip-im' },
  299. { name: '+sip.ice' },
  300. { name: 'language', value: '\"en,fr\"' }
  301. ]
  302. };
  303. }
  304. function loadCallOptions() {
  305. if (window.localStorage) {
  306. var s_value;
  307. if ((s_value = window.localStorage.getItem('org.doubango.call.phone_number'))) txtPhoneNumber.value = s_value;
  308. bDisableVideo = (window.localStorage.getItem('org.doubango.expert.disable_video') == "true");
  309. txtCallStatus.innerHTML = '<i>Video ' + (bDisableVideo ? 'disabled' : 'enabled') + '</i>';
  310. }
  311. }
  312. function saveCallOptions() {
  313. if (window.localStorage) {
  314. window.localStorage.setItem('org.doubango.call.phone_number', txtPhoneNumber.value);
  315. window.localStorage.setItem('org.doubango.expert.disable_video', bDisableVideo ? "true" : "false");
  316. }
  317. }
  318. function loadCredentials() {
  319. if (window.localStorage) {
  320. // IE retuns 'null' if not defined
  321. var s_value;
  322. if ((s_value = window.localStorage.getItem('org.doubango.identity.display_name'))) txtDisplayName.value = s_value;
  323. if ((s_value = window.localStorage.getItem('org.doubango.identity.impi'))) txtPrivateIdentity.value = s_value;
  324. if ((s_value = window.localStorage.getItem('org.doubango.identity.impu'))) txtPublicIdentity.value = s_value;
  325. if ((s_value = window.localStorage.getItem('org.doubango.identity.password'))) txtPassword.value = s_value;
  326. if ((s_value = window.localStorage.getItem('org.doubango.identity.realm'))) txtRealm.value = s_value;
  327. }
  328. else {
  329. /*txtDisplayName.value = "005";
  330. txtPrivateIdentity.value = "005";
  331. txtPublicIdentity.value = "sip:[email protected]";
  332. txtPassword.value = "005";
  333. txtRealm.value = "192.168.0.28";
  334. txtPhoneNumber.value = "005";*/
  335. }
  336. };
  337. function saveCredentials() {
  338. if (window.localStorage) {
  339. window.localStorage.setItem('org.doubango.identity.display_name', txtDisplayName.value);
  340. window.localStorage.setItem('org.doubango.identity.impi', txtPrivateIdentity.value);
  341. window.localStorage.setItem('org.doubango.identity.impu', txtPublicIdentity.value);
  342. window.localStorage.setItem('org.doubango.identity.password', txtPassword.value);
  343. window.localStorage.setItem('org.doubango.identity.realm', txtRealm.value);
  344. }
  345. };
  346. // sends SIP REGISTER request to login
  347. function sipRegister() {
  348. // catch exception for IE (DOM not ready)
  349. try {
  350. btnRegister.disabled = true;
  351. if (!txtRealm.value || !txtPrivateIdentity.value || !txtPublicIdentity.value) {
  352. txtRegStatus.innerHTML = '<b>Please fill madatory fields (*)</b>';
  353. btnRegister.disabled = false;
  354. return;
  355. }
  356. var o_impu = tsip_uri.prototype.Parse(txtPublicIdentity.value);
  357. if (!o_impu || !o_impu.s_user_name || !o_impu.s_host) {
  358. txtRegStatus.innerHTML = "<b>[" + txtPublicIdentity.value + "] is not a valid Public identity</b>";
  359. btnRegister.disabled = false;
  360. return;
  361. }
  362. // enable notifications if not already done
  363. if (window.webkitNotifications && window.webkitNotifications.checkPermission() != 0) {
  364. window.webkitNotifications.requestPermission();
  365. }
  366. // save credentials
  367. saveCredentials();
  368. // update debug level to be sure new values will be used if the user haven't updated the page
  369. SIPml.setDebugLevel((window.localStorage && window.localStorage.getItem('org.doubango.expert.disable_debug') == "true") ? "error" : "info");
  370. // create SIP stack
  371. oSipStack = new SIPml.Stack({
  372. realm: txtRealm.value,
  373. impi: txtPrivateIdentity.value,
  374. impu: txtPublicIdentity.value,
  375. password: txtPassword.value,
  376. display_name: txtDisplayName.value,
  377. websocket_proxy_url: (window.localStorage ? window.localStorage.getItem('org.doubango.expert.websocket_server_url') : null),
  378. outbound_proxy_url: (window.localStorage ? window.localStorage.getItem('org.doubango.expert.sip_outboundproxy_url') : null),
  379. ice_servers: (window.localStorage ? window.localStorage.getItem('org.doubango.expert.ice_servers') : null),
  380. enable_rtcweb_breaker: (window.localStorage ? window.localStorage.getItem('org.doubango.expert.enable_rtcweb_breaker') == "true" : false),
  381. events_listener: { events: '*', listener: onSipEventStack },
  382. enable_early_ims: (window.localStorage ? window.localStorage.getItem('org.doubango.expert.disable_early_ims') != "true" : true), // Must be true unless you're using a real IMS network
  383. enable_media_stream_cache: (window.localStorage ? window.localStorage.getItem('org.doubango.expert.enable_media_caching') == "true" : false),
  384. bandwidth: (window.localStorage ? tsk_string_to_object(window.localStorage.getItem('org.doubango.expert.bandwidth')) : null), // could be redefined a session-level
  385. video_size: (window.localStorage ? tsk_string_to_object(window.localStorage.getItem('org.doubango.expert.video_size')) : null), // could be redefined a session-level
  386. sip_headers: [
  387. { name: 'User-Agent', value: 'IM-client/OMA1.0 sipML5-v1.2014.04.18' },
  388. { name: 'Organization', value: 'Doubango Telecom' }
  389. ]
  390. }
  391. );
  392. if (oSipStack.start() != 0) {
  393. txtRegStatus.innerHTML = '<b>Failed to start the SIP stack</b>';
  394. }
  395. else return;
  396. }
  397. catch (e) {
  398. txtRegStatus.innerHTML = "<b>2:" + e + "</b>";
  399. }
  400. btnRegister.disabled = false;
  401. }
  402. // sends SIP REGISTER (expires=0) to logout
  403. function sipUnRegister() {
  404. if (oSipStack) {
  405. oSipStack.stop(); // shutdown all sessions
  406. }
  407. }
  408. // makes a call (SIP INVITE)
  409. function sipCall(s_type) {
  410. if (oSipStack && !oSipSessionCall && !tsk_string_is_null_or_empty(txtPhoneNumber.value)) {
  411. if(s_type == 'call-screenshare') {
  412. if(!SIPml.isScreenShareSupported()) {
  413. alert('Screen sharing not supported. Are you using chrome 26+?');
  414. return;
  415. }
  416. if (!location.protocol.match('https')){
  417. if (confirm("Screen sharing requires https://. Do you want to be redirected?")) {
  418. sipUnRegister();
  419. window.location = 'https://ns313841.ovh.net/call.htm';
  420. }
  421. return;
  422. }
  423. }
  424. btnCall.disabled = true;
  425. btnHangUp.disabled = false;
  426. if(window.localStorage) {
  427. oConfigCall.bandwidth = tsk_string_to_object(window.localStorage.getItem('org.doubango.expert.bandwidth')); // already defined at stack-level but redifined to use latest values
  428. oConfigCall.video_size = tsk_string_to_object(window.localStorage.getItem('org.doubango.expert.video_size')); // already defined at stack-level but redifined to use latest values
  429. }
  430. // create call session
  431. oSipSessionCall = oSipStack.newSession(s_type, oConfigCall);
  432. // make call
  433. if (oSipSessionCall.call(txtPhoneNumber.value) != 0) {
  434. oSipSessionCall = null;
  435. txtCallStatus.value = 'Failed to make call';
  436. btnCall.disabled = false;
  437. btnHangUp.disabled = true;
  438. return;
  439. }
  440. saveCallOptions();
  441. }
  442. else if (oSipSessionCall) {
  443. txtCallStatus.innerHTML = '<i>Connecting...</i>';
  444. oSipSessionCall.accept(oConfigCall);
  445. }
  446. }
  447. // transfers the call
  448. function sipTransfer() {
  449. if (oSipSessionCall) {
  450. var s_destination = prompt('Enter destination number', '');
  451. if (!tsk_string_is_null_or_empty(s_destination)) {
  452. btnTransfer.disabled = true;
  453. if (oSipSessionCall.transfer(s_destination) != 0) {
  454. txtCallStatus.innerHTML = '<i>Call transfer failed</i>';
  455. btnTransfer.disabled = false;
  456. return;
  457. }
  458. txtCallStatus.innerHTML = '<i>Transfering the call...</i>';
  459. }
  460. }
  461. }
  462. // holds or resumes the call
  463. function sipToggleHoldResume() {
  464. if (oSipSessionCall) {
  465. var i_ret;
  466. btnHoldResume.disabled = true;
  467. txtCallStatus.innerHTML = oSipSessionCall.bHeld ? '<i>Resuming the call...</i>' : '<i>Holding the call...</i>';
  468. i_ret = oSipSessionCall.bHeld ? oSipSessionCall.resume() : oSipSessionCall.hold();
  469. if (i_ret != 0) {
  470. txtCallStatus.innerHTML = '<i>Hold / Resume failed</i>';
  471. btnHoldResume.disabled = false;
  472. return;
  473. }
  474. }
  475. }
  476. // terminates the call (SIP BYE or CANCEL)
  477. function sipHangUp() {
  478. if (oSipSessionCall) {
  479. txtCallStatus.innerHTML = '<i>Terminating the call...</i>';
  480. oSipSessionCall.hangup({events_listener: { events: '*', listener: onSipEventSession }});
  481. }
  482. }
  483. function sipSendDTMF(c){
  484. if(oSipSessionCall && c){
  485. if(oSipSessionCall.dtmf(c) == 0){
  486. try { dtmfTone.play(); } catch(e){ }
  487. }
  488. }
  489. }
  490. function startRingTone() {
  491. try { ringtone.play(); }
  492. catch (e) { }
  493. }
  494. function stopRingTone() {
  495. try { ringtone.pause(); }
  496. catch (e) { }
  497. }
  498. function startRingbackTone() {
  499. try { ringbacktone.play(); }
  500. catch (e) { }
  501. }
  502. function stopRingbackTone() {
  503. try { ringbacktone.pause(); }
  504. catch (e) { }
  505. }
  506. function toggleFullScreen() {
  507. if (videoRemote.webkitSupportsFullscreen) {
  508. fullScreen(!videoRemote.webkitDisplayingFullscreen);
  509. }
  510. else {
  511. fullScreen(!bFullScreen);
  512. }
  513. }
  514. function openKeyPad(){
  515. divKeyPad.style.visibility = 'visible';
  516. divKeyPad.style.left = ((document.body.clientWidth - C.divKeyPadWidth) >> 1) + 'px';
  517. divKeyPad.style.top = '70px';
  518. divGlassPanel.style.visibility = 'visible';
  519. }
  520. function closeKeyPad(){
  521. divKeyPad.style.left = '0px';
  522. divKeyPad.style.top = '0px';
  523. divKeyPad.style.visibility = 'hidden';
  524. divGlassPanel.style.visibility = 'hidden';
  525. }
  526. function fullScreen(b_fs) {
  527. bFullScreen = b_fs;
  528. if (tsk_utils_have_webrtc4native() && bFullScreen && videoRemote.webkitSupportsFullscreen) {
  529. if (bFullScreen) {
  530. videoRemote.webkitEnterFullScreen();
  531. }
  532. else {
  533. videoRemote.webkitExitFullscreen();
  534. }
  535. }
  536. else {
  537. if (tsk_utils_have_webrtc4npapi()) {
  538. try { if(window.__o_display_remote) window.__o_display_remote.setFullScreen(b_fs); }
  539. catch (e) { divVideo.setAttribute("class", b_fs ? "full-screen" : "normal-screen"); }
  540. }
  541. else {
  542. divVideo.setAttribute("class", b_fs ? "full-screen" : "normal-screen");
  543. }
  544. }
  545. }
  546. function showNotifICall(s_number) {
  547. // permission already asked when we registered
  548. if (window.webkitNotifications && window.webkitNotifications.checkPermission() == 0) {
  549. if (oNotifICall) {
  550. oNotifICall.cancel();
  551. }
  552. oNotifICall = window.webkitNotifications.createNotification('images/sipml-34x39.png', 'Incaming call', 'Incoming call from ' + s_number);
  553. oNotifICall.onclose = function () { oNotifICall = null; };
  554. oNotifICall.show();
  555. }
  556. }
  557. function onKeyUp(evt) {
  558. evt = (evt || window.event);
  559. if (evt.keyCode == 27) {
  560. fullScreen(false);
  561. }
  562. else if (evt.ctrlKey && evt.shiftKey) { // CTRL + SHIFT
  563. if (evt.keyCode == 65 || evt.keyCode == 86) { // A (65) or V (86)
  564. bDisableVideo = (evt.keyCode == 65);
  565. txtCallStatus.innerHTML = '<i>Video ' + (bDisableVideo ? 'disabled' : 'enabled') + '</i>';
  566. window.localStorage.setItem('org.doubango.expert.disable_video', bDisableVideo);
  567. }
  568. }
  569. }
  570. function onDivCallCtrlMouseMove(evt) {
  571. try { // IE: DOM not ready
  572. if (tsk_utils_have_stream()) {
  573. btnCall.disabled = (!tsk_utils_have_stream() || !oSipSessionRegister || !oSipSessionRegister.is_connected());
  574. document.getElementById("divCallCtrl").onmousemove = null; // unsubscribe
  575. }
  576. }
  577. catch (e) { }
  578. }
  579. function uiOnConnectionEvent(b_connected, b_connecting) { // should be enum: connecting, connected, terminating, terminated
  580. btnRegister.disabled = b_connected || b_connecting;
  581. btnUnRegister.disabled = !b_connected && !b_connecting;
  582. btnCall.disabled = !(b_connected && tsk_utils_have_webrtc() && tsk_utils_have_stream());
  583. btnHangUp.disabled = !oSipSessionCall;
  584. }
  585. function uiVideoDisplayEvent(b_local, b_added) {
  586. var o_elt_video = b_local ? videoLocal : videoRemote;
  587. if (b_added) {
  588. if (SIPml.isWebRtc4AllSupported()) {
  589. if (b_local){ if(window.__o_display_local) window.__o_display_local.style.visibility = "visible"; }
  590. else { if(window.__o_display_remote) window.__o_display_remote.style.visibility = "visible"; }
  591. }
  592. else {
  593. o_elt_video.style.opacity = 1;
  594. }
  595. uiVideoDisplayShowHide(true);
  596. }
  597. else {
  598. if (SIPml.isWebRtc4AllSupported()) {
  599. if (b_local){ if(window.__o_display_local) window.__o_display_local.style.visibility = "hidden"; }
  600. else { if(window.__o_display_remote) window.__o_display_remote.style.visibility = "hidden"; }
  601. }
  602. else{
  603. o_elt_video.style.opacity = 0;
  604. }
  605. fullScreen(false);
  606. }
  607. }
  608. function uiVideoDisplayShowHide(b_show) {
  609. if (b_show) {
  610. tdVideo.style.height = '340px';
  611. divVideo.style.height = navigator.appName == 'Microsoft Internet Explorer' ? '100%' : '340px';
  612. }
  613. else {
  614. tdVideo.style.height = '0px';
  615. divVideo.style.height = '0px';
  616. }
  617. btnFullScreen.disabled = !b_show;
  618. }
  619. function uiDisableCallOptions() {
  620. if(window.localStorage) {
  621. window.localStorage.setItem('org.doubango.expert.disable_callbtn_options', 'true');
  622. uiBtnCallSetText('Call');
  623. alert('Use expert view to enable the options again (/!\\requires re-loading the page)');
  624. }
  625. }
  626. function uiBtnCallSetText(s_text) {
  627. switch(s_text) {
  628. case "Call":
  629. {
  630. var bDisableCallBtnOptions = (window.localStorage && window.localStorage.getItem('org.doubango.expert.disable_callbtn_options') == "true");
  631. btnCall.value = btnCall.innerHTML = bDisableCallBtnOptions ? 'Call' : 'Call <span id="spanCaret" class="caret">';
  632. btnCall.setAttribute("class", bDisableCallBtnOptions ? "btn btn-primary" : "btn btn-primary dropdown-toggle");
  633. btnCall.onclick = bDisableCallBtnOptions ? function(){ sipCall(bDisableVideo ? 'call-audio' : 'call-audiovideo'); } : null;
  634. ulCallOptions.style.visibility = bDisableCallBtnOptions ? "hidden" : "visible";
  635. if(!bDisableCallBtnOptions && ulCallOptions.parentNode != divBtnCallGroup){
  636. divBtnCallGroup.appendChild(ulCallOptions);
  637. }
  638. else if(bDisableCallBtnOptions && ulCallOptions.parentNode == divBtnCallGroup) {
  639. document.body.appendChild(ulCallOptions);
  640. }
  641. break;
  642. }
  643. default:
  644. {
  645. btnCall.value = btnCall.innerHTML = s_text;
  646. btnCall.setAttribute("class", "btn btn-primary");
  647. btnCall.onclick = function(){ sipCall(bDisableVideo ? 'call-audio' : 'call-audiovideo'); };
  648. ulCallOptions.style.visibility = "hidden";
  649. if(ulCallOptions.parentNode == divBtnCallGroup){
  650. document.body.appendChild(ulCallOptions);
  651. }
  652. break;
  653. }
  654. }
  655. }
  656. function uiCallTerminated(s_description){
  657. uiBtnCallSetText("Call");
  658. btnHangUp.value = 'HangUp';
  659. btnHoldResume.value = 'hold';
  660. btnCall.disabled = false;
  661. btnHangUp.disabled = true;
  662. oSipSessionCall = null;
  663. stopRingbackTone();
  664. stopRingTone();
  665. txtCallStatus.innerHTML = "<i>" + s_description + "</i>";
  666. uiVideoDisplayShowHide(false);
  667. divCallOptions.style.opacity = 0;
  668. if (oNotifICall) {
  669. oNotifICall.cancel();
  670. oNotifICall = null;
  671. }
  672. uiVideoDisplayEvent(true, false);
  673. uiVideoDisplayEvent(false, false);
  674. setTimeout(function () { if (!oSipSessionCall) txtCallStatus.innerHTML = ''; }, 2500);
  675. }
  676. // Callback function for SIP Stacks
  677. function onSipEventStack(e /*SIPml.Stack.Event*/) {
  678. tsk_utils_log_info('==stack event = ' + e.type);
  679. switch (e.type) {
  680. case 'started':
  681. {
  682. // catch exception for IE (DOM not ready)
  683. try {
  684. // LogIn (REGISTER) as soon as the stack finish starting
  685. oSipSessionRegister = this.newSession('register', {
  686. expires: 200,
  687. events_listener: { events: '*', listener: onSipEventSession },
  688. sip_caps: [
  689. { name: '+g.oma.sip-im', value: null },
  690. { name: '+audio', value: null },
  691. { name: 'language', value: '\"en,fr\"' }
  692. ]
  693. });
  694. oSipSessionRegister.register();
  695. }
  696. catch (e) {
  697. txtRegStatus.value = txtRegStatus.innerHTML = "<b>1:" + e + "</b>";
  698. btnRegister.disabled = false;
  699. }
  700. break;
  701. }
  702. case 'stopping': case 'stopped': case 'failed_to_start': case 'failed_to_stop':
  703. {
  704. var bFailure = (e.type == 'failed_to_start') || (e.type == 'failed_to_stop');
  705. oSipStack = null;
  706. oSipSessionRegister = null;
  707. oSipSessionCall = null;
  708. uiOnConnectionEvent(false, false);
  709. stopRingbackTone();
  710. stopRingTone();
  711. uiVideoDisplayShowHide(false);
  712. divCallOptions.style.opacity = 0;
  713. txtCallStatus.innerHTML = '';
  714. txtRegStatus.innerHTML = bFailure ? "<i>Disconnected: <b>" + e.description + "</b></i>" : "<i>Disconnected</i>";
  715. break;
  716. }
  717. case 'i_new_call':
  718. {
  719. if (oSipSessionCall) {
  720. // do not accept the incoming call if we're already 'in call'
  721. e.newSession.hangup(); // comment this line for multi-line support
  722. }
  723. else {
  724. oSipSessionCall = e.newSession;
  725. // start listening for events
  726. oSipSessionCall.setConfiguration(oConfigCall);
  727. uiBtnCallSetText('Answer');
  728. btnHangUp.value = 'Reject';
  729. btnCall.disabled = false;
  730. btnHangUp.disabled = false;
  731. startRingTone();
  732. var sRemoteNumber = (oSipSessionCall.getRemoteFriendlyName() || 'unknown');
  733. txtCallStatus.innerHTML = "<i>Incoming call from [<b>" + sRemoteNumber + "</b>]</i>";
  734. showNotifICall(sRemoteNumber);
  735. }
  736. break;
  737. }
  738. case 'm_permission_requested':
  739. {
  740. divGlassPanel.style.visibility = 'visible';
  741. break;
  742. }
  743. case 'm_permission_accepted':
  744. case 'm_permission_refused':
  745. {
  746. divGlassPanel.style.visibility = 'hidden';
  747. if(e.type == 'm_permission_refused'){
  748. uiCallTerminated('Media stream permission denied');
  749. }
  750. break;
  751. }
  752. case 'starting': default: break;
  753. }
  754. };
  755. // Callback function for SIP sessions (INVITE, REGISTER, MESSAGE...)
  756. function onSipEventSession(e /* SIPml.Session.Event */) {
  757. tsk_utils_log_info('==session event = ' + e.type);
  758. switch (e.type) {
  759. case 'connecting': case 'connected':
  760. {
  761. var bConnected = (e.type == 'connected');
  762. if (e.session == oSipSessionRegister) {
  763. uiOnConnectionEvent(bConnected, !bConnected);
  764. txtRegStatus.innerHTML = "<i>" + e.description + "</i>";
  765. }
  766. else if (e.session == oSipSessionCall) {
  767. btnHangUp.value = 'HangUp';
  768. btnCall.disabled = true;
  769. btnHangUp.disabled = false;
  770. btnTransfer.disabled = false;
  771. if (bConnected) {
  772. stopRingbackTone();
  773. stopRingTone();
  774. if (oNotifICall) {
  775. oNotifICall.cancel();
  776. oNotifICall = null;
  777. }
  778. }
  779. txtCallStatus.innerHTML = "<i>" + e.description + "</i>";
  780. divCallOptions.style.opacity = bConnected ? 1 : 0;
  781. if (SIPml.isWebRtc4AllSupported()) { // IE don't provide stream callback
  782. uiVideoDisplayEvent(true, true);
  783. uiVideoDisplayEvent(false, true);
  784. }
  785. }
  786. break;
  787. } // 'connecting' | 'connected'
  788. case 'terminating': case 'terminated':
  789. {
  790. if (e.session == oSipSessionRegister) {
  791. uiOnConnectionEvent(false, false);
  792. oSipSessionCall = null;
  793. oSipSessionRegister = null;
  794. txtRegStatus.innerHTML = "<i>" + e.description + "</i>";
  795. }
  796. else if (e.session == oSipSessionCall) {
  797. uiCallTerminated(e.description);
  798. }
  799. break;
  800. } // 'terminating' | 'terminated'
  801. case 'm_stream_video_local_added':
  802. {
  803. if (e.session == oSipSessionCall) {
  804. uiVideoDisplayEvent(true, true);
  805. }
  806. break;
  807. }
  808. case 'm_stream_video_local_removed':
  809. {
  810. if (e.session == oSipSessionCall) {
  811. uiVideoDisplayEvent(true, false);
  812. }
  813. break;
  814. }
  815. case 'm_stream_video_remote_added':
  816. {
  817. if (e.session == oSipSessionCall) {
  818. uiVideoDisplayEvent(false, true);
  819. }
  820. break;
  821. }
  822. case 'm_stream_video_remote_removed':
  823. {
  824. if (e.session == oSipSessionCall) {
  825. uiVideoDisplayEvent(false, false);
  826. }
  827. break;
  828. }
  829. case 'm_stream_audio_local_added':
  830. case 'm_stream_audio_local_removed':
  831. case 'm_stream_audio_remote_added':
  832. case 'm_stream_audio_remote_removed':
  833. {
  834. break;
  835. }
  836. case 'i_ect_new_call':
  837. {
  838. oSipSessionTransferCall = e.session;
  839. break;
  840. }
  841. case 'i_ao_request':
  842. {
  843. if(e.session == oSipSessionCall){
  844. var iSipResponseCode = e.getSipResponseCode();
  845. if (iSipResponseCode == 180 || iSipResponseCode == 183) {
  846. startRingbackTone();
  847. txtCallStatus.innerHTML = '<i>Remote ringing...</i>';
  848. }
  849. }
  850. break;
  851. }
  852. case 'm_early_media':
  853. {
  854. if(e.session == oSipSessionCall){
  855. stopRingbackTone();
  856. stopRingTone();
  857. txtCallStatus.innerHTML = '<i>Early media started</i>';
  858. }
  859. break;
  860. }
  861. case 'm_local_hold_ok':
  862. {
  863. if(e.session == oSipSessionCall){
  864. if (oSipSessionCall.bTransfering) {
  865. oSipSessionCall.bTransfering = false;
  866. // this.AVSession.TransferCall(this.transferUri);
  867. }
  868. btnHoldResume.value = 'Resume';
  869. btnHoldResume.disabled = false;
  870. txtCallStatus.innerHTML = '<i>Call placed on hold</i>';
  871. oSipSessionCall.bHeld = true;
  872. }
  873. break;
  874. }
  875. case 'm_local_hold_nok':
  876. {
  877. if(e.session == oSipSessionCall){
  878. oSipSessionCall.bTransfering = false;
  879. btnHoldResume.value = 'Hold';
  880. btnHoldResume.disabled = false;
  881. txtCallStatus.innerHTML = '<i>Failed to place remote party on hold</i>';
  882. }
  883. break;
  884. }
  885. case 'm_local_resume_ok':
  886. {
  887. if(e.session == oSipSessionCall){
  888. oSipSessionCall.bTransfering = false;
  889. btnHoldResume.value = 'Hold';
  890. btnHoldResume.disabled = false;
  891. txtCallStatus.innerHTML = '<i>Call taken off hold</i>';
  892. oSipSessionCall.bHeld = false;
  893. if (SIPml.isWebRtc4AllSupported()) { // IE don't provide stream callback yet
  894. uiVideoDisplayEvent(true, true);
  895. uiVideoDisplayEvent(false, true);
  896. }
  897. }
  898. break;
  899. }
  900. case 'm_local_resume_nok':
  901. {
  902. if(e.session == oSipSessionCall){
  903. oSipSessionCall.bTransfering = false;
  904. btnHoldResume.disabled = false;
  905. txtCallStatus.innerHTML = '<i>Failed to unhold call</i>';
  906. }
  907. break;
  908. }
  909. case 'm_remote_hold':
  910. {
  911. if(e.session == oSipSessionCall){
  912. txtCallStatus.innerHTML = '<i>Placed on hold by remote party</i>';
  913. }
  914. break;
  915. }
  916. case 'm_remote_resume':
  917. {
  918. if(e.session == oSipSessionCall){
  919. txtCallStatus.innerHTML = '<i>Taken off hold by remote party</i>';
  920. }
  921. break;
  922. }
  923. case 'o_ect_trying':
  924. {
  925. if(e.session == oSipSessionCall){
  926. txtCallStatus.innerHTML = '<i>Call transfer in progress...</i>';
  927. }
  928. break;
  929. }
  930. case 'o_ect_accepted':
  931. {
  932. if(e.session == oSipSessionCall){
  933. txtCallStatus.innerHTML = '<i>Call transfer accepted</i>';
  934. }
  935. break;
  936. }
  937. case 'o_ect_completed':
  938. case 'i_ect_completed':
  939. {
  940. if(e.session == oSipSessionCall){
  941. txtCallStatus.innerHTML = '<i>Call transfer completed</i>';
  942. btnTransfer.disabled = false;
  943. if (oSipSessionTransferCall) {
  944. oSipSessionCall = oSipSessionTransferCall;
  945. }
  946. oSipSessionTransferCall = null;
  947. }
  948. break;
  949. }
  950. case 'o_ect_failed':
  951. case 'i_ect_failed':
  952. {
  953. if(e.session == oSipSessionCall){
  954. txtCallStatus.innerHTML = '<i>Call transfer failed</i>';
  955. btnTransfer.disabled = false;
  956. }
  957. break;
  958. }
  959. case 'o_ect_notify':
  960. case 'i_ect_notify':
  961. {
  962. if(e.session == oSipSessionCall){
  963. txtCallStatus.innerHTML = "<i>Call Transfer: <b>" + e.getSipResponseCode() + " " + e.description + "</b></i>";
  964. if (e.getSipResponseCode() >= 300) {
  965. if (oSipSessionCall.bHeld) {
  966. oSipSessionCall.resume();
  967. }
  968. btnTransfer.disabled = false;
  969. }
  970. }
  971. break;
  972. }
  973. case 'i_ect_requested':
  974. {
  975. if(e.session == oSipSessionCall){
  976. var s_message = "Do you accept call transfer to [" + e.getTransferDestinationFriendlyName() + "]?";//FIXME
  977. if (confirm(s_message)) {
  978. txtCallStatus.innerHTML = "<i>Call transfer in progress...</i>";
  979. oSipSessionCall.acceptTransfer();
  980. break;
  981. }
  982. oSipSessionCall.rejectTransfer();
  983. }
  984. break;
  985. }
  986. }
  987. }
  988. </script>
  989. <body style="cursor:wait">
  990. <div class="container">
  991. <div class="row-fluid">
  992. <div class="span4 well">
  993. <label style="width: 100%;" align="center" id="txtRegStatus">
  994. </label>
  995. <h2>
  996. Registration</h2>
  997. <br />
  998. <table style='width: 100%'>
  999. <tr>
  1000. <td>
  1001. <label style="height: 100%">
  1002. Display Name:</label>
  1003. </td>
  1004. <td>
  1005. <input type="text" style="width: 100%; height: 100%" id="txtDisplayName" value=""
  1006. placeholder="e.g. John Doe" />
  1007. </td>
  1008. </tr>
  1009. <tr>
  1010. <td>
  1011. <label style="height: 100%">
  1012. Private Identity<sup>*</sup>:</label>
  1013. </td>
  1014. <td>
  1015. <input type="text" style="width: 100%; height: 100%" id="txtPrivateIdentity" value=""
  1016. placeholder="e.g. +33600000000" />
  1017. </td>
  1018. </tr>
  1019. <tr>
  1020. <td>
  1021. <label style="height: 100%">
  1022. Public Identity<sup>*</sup>:</label>
  1023. </td>
  1024. <td>
  1025. <input type="text" style="width: 100%; height: 100%" id="txtPublicIdentity" value=""
  1026. placeholder="e.g. sip:[email protected]" />
  1027. </td>
  1028. </tr>
  1029. <tr>
  1030. <td>
  1031. <label style="height: 100%">Password:</label>
  1032. </td>
  1033. <td>
  1034. <input type="password" style="width: 100%; height: 100%" id="txtPassword" value="" />
  1035. </td>
  1036. </tr>
  1037. <tr>
  1038. <td>
  1039. <label style="height: 100%">Realm<sup>*</sup>:</label>
  1040. </td>
  1041. <td>
  1042. <input type="text" style="width: 100%; height: 100%" id="txtRealm" value="" placeholder="e.g. doubango.org" />
  1043. </td>
  1044. </tr>
  1045. <tr>
  1046. <td colspan="2" align="right">
  1047. <input type="button" class="btn btn-success" id="btnRegister" value="LogIn" disabled onclick='sipRegister();' />
  1048. &nbsp;
  1049. <input type="button" class="btn btn-danger" id="btnUnRegister" value="LogOut" disabled onclick='sipUnRegister();' />
  1050. </td>
  1051. </tr>
  1052. <tr>
  1053. <td colspan="3">
  1054. <p class="small"><sup>*</sup> <i>Mandatory Field</i></p>
  1055. </td>
  1056. </tr>
  1057. <tr>
  1058. <td colspan="3">
  1059. <a class="btn" href="http://code.google.com/p/sipml5/wiki/Public_SIP_Servers" target="_blank">Need SIP account?</a>
  1060. </td>
  1061. </tr>
  1062. <tr>
  1063. <td colspan="3">
  1064. <a class="btn" href="./expert.htm" target="_blank">Expert mode?</a>
  1065. </td>
  1066. </tr>
  1067. </table>
  1068. </div>
  1069. <div id="divCallCtrl" class="span7 well" style='display:table-cell; vertical-align:middle'>
  1070. <label style="width: 100%;" align="center" id="txtCallStatus">
  1071. </label>
  1072. <h2>
  1073. Call control
  1074. </h2>
  1075. <br />
  1076. <table style='width: 100%;'>
  1077. <tr>
  1078. <td style="white-space:nowrap;">
  1079. <input type="text" style="width: 100%; height:100%" id="txtPhoneNumber" value="" placeholder="Enter phone number to call" />
  1080. </td>
  1081. </tr>
  1082. <tr>
  1083. <td colspan="1" align="right">
  1084. <div class="btn-toolbar" style="margin: 0; vertical-align:middle">
  1085. <div id="divBtnCallGroup" class="btn-group">
  1086. <button id="btnCall" disabled class="btn btn-primary" data-toggle="dropdown">Call</button>
  1087. </div>&nbsp;&nbsp;
  1088. <div class="btn-group">
  1089. <input type="button" id="btnHangUp" style="margin: 0; vertical-align:middle; height: 100%;" class="btn btn-primary" value="HangUp" onclick='sipHangUp();' disabled />
  1090. </div>
  1091. </div>
  1092. </td>
  1093. </tr>
  1094. <tr>
  1095. <td id="tdVideo" class='tab-video'>
  1096. <div id="divVideo" class='div-video'>
  1097. <div id="divVideoRemote" style='border:1px solid #000; height:100%; width:100%'>
  1098. <video class="video" width="100%" height="100%" id="video_remote" autoplay="autoplay" style="opacity: 0;
  1099. background-color: #000000; -webkit-transition-property: opacity; -webkit-transition-duration: 2s;">
  1100. </video>
  1101. </div>
  1102. <div id="divVideoLocal" style='border:0px solid #000'>
  1103. <video class="video" width="88px" height="72px" id="video_local" autoplay="autoplay" muted="true" style="opacity: 0;
  1104. margin-top: -80px; margin-left: 5px; background-color: #000000; -webkit-transition-property: opacity;
  1105. -webkit-transition-duration: 2s;">
  1106. </video>
  1107. </div>
  1108. </div>
  1109. </td>
  1110. </tr>
  1111. <tr>
  1112. <td align='center'>
  1113. <div id='divCallOptions' class='call-options' style='opacity: 0; margin-top: 3px'>
  1114. <input type="button" class="btn" style="" id="btnFullScreen" value="FullScreen" disabled onclick='toggleFullScreen();' /> &nbsp;
  1115. <input type="button" class="btn" style="" id="btnHoldResume" value="Hold" onclick='sipToggleHoldResume();' /> &nbsp;
  1116. <input type="button" class="btn" style="" id="btnTransfer" value="Transfer" onclick='sipTransfer();' /> &nbsp;
  1117. <input type="button" class="btn" style="" id="btnKeyPad" value="KeyPad" onclick='openKeyPad();' />
  1118. </div>
  1119. </td>
  1120. </tr>
  1121. </table>
  1122. </div>
  1123. </div>
  1124. <br />
  1125. <footer>
  1126. <p>&copy; Doubango Telecom 2012-2013 <br />
  1127. <i>Inspiring the future</i>
  1128. </p>
  1129. <!-- Creates all ATL/COM objects right now
  1130. Will open confirmation dialogs if not already done
  1131. -->
  1132. <object id="fakeVideoDisplay" classid="clsid:5C2C407B-09D9-449B-BB83-C39B7802A684" style="visibility:hidden;"> </object>
  1133. <object id="fakeLooper" classid="clsid:7082C446-54A8-4280-A18D-54143846211A" style="visibility:visible; width:0px; height:0px"> </object>
  1134. <object id="fakeSessionDescription" classid="clsid:DBA9F8E2-F9FB-47CF-8797-986A69A1CA9C" style="visibility:hidden;"> </object>
  1135. <object id="fakeNetTransport" classid="clsid:5A7D84EC-382C-4844-AB3A-9825DBE30DAE" style="visibility:hidden;"> </object>
  1136. <object id="fakePeerConnection" classid="clsid:56D10AD3-8F52-4AA4-854B-41F4D6F9CEA3" style="visibility:hidden;"> </object>
  1137. <!--
  1138. NPAPI browsers: Safari, Opera and Firefox
  1139. -->
  1140. <!--embed id="WebRtc4npapi" type="application/w4a" width='1' height='1' style='visibility:hidden;' /-->
  1141. </footer>
  1142. </div>
  1143. <!-- /container -->
  1144. <!-- Glass Panel -->
  1145. <div id='divGlassPanel' class='glass-panel' style='visibility:hidden'></div>
  1146. <!-- KeyPad Div -->
  1147. <div id='divKeyPad' class='span2 well div-keypad' style="left:0px; top:0px; width:250; height:240; visibility:hidden">
  1148. <table style="width: 100%; height: 100%">
  1149. <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>
  1150. <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>
  1151. <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>
  1152. <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>
  1153. <tr><td colspan=3><input type="button" style="width: 100%" class="btn btn-medium btn-danger" value="close" onclick="closeKeyPad();" /></td></tr>
  1154. </table>
  1155. </div>
  1156. <!-- Call button options -->
  1157. <ul id="ulCallOptions" class="dropdown-menu" style="visibility:hidden">
  1158. <li><a href="#" onclick='sipCall("call-audio");'>Audio</a></li>
  1159. <li><a href="#" onclick='sipCall("call-audiovideo");'>Video</a></li>
  1160. <li id='liScreenShare' ><a href="#" onclick='sipCall("call-screenshare");'>Screen Share</a></li>
  1161. <li class="divider"></li>
  1162. <li><a href="#" onclick='uiDisableCallOptions();'><b>Disable these options</b></a></li>
  1163. </ul>
  1164. <!-- Le javascript
  1165. ================================================== -->
  1166. <!-- Placed at the end of the document so the pages load faster -->
  1167. <script type="text/javascript" src="./assets/js/jquery.js"></script>
  1168. <script type="text/javascript" src="./assets/js/bootstrap-transition.js"></script>
  1169. <script type="text/javascript" src="./assets/js/bootstrap-alert.js"></script>
  1170. <script type="text/javascript" src="./assets/js/bootstrap-modal.js"></script>
  1171. <script type="text/javascript" src="./assets/js/bootstrap-dropdown.js"></script>
  1172. <script type="text/javascript" src="./assets/js/bootstrap-scrollspy.js"></script>
  1173. <script type="text/javascript" src="./assets/js/bootstrap-tab.js"></script>
  1174. <script type="text/javascript" src="./assets/js/bootstrap-tooltip.js"></script>
  1175. <script type="text/javascript" src="./assets/js/bootstrap-popover.js"></script>
  1176. <script type="text/javascript" src="./assets/js/bootstrap-button.js"></script>
  1177. <script type="text/javascript" src="./assets/js/bootstrap-collapse.js"></script>
  1178. <script type="text/javascript" src="./assets/js/bootstrap-carousel.js"></script>
  1179. <script type="text/javascript" src="./assets/js/bootstrap-typeahead.js"></script>
  1180. <!-- Audios -->
  1181. <audio id="audio_remote" autoplay="autoplay" />
  1182. <audio id="ringtone" loop src="sounds/ringtone.wav" />
  1183. <audio id="ringbacktone" loop src="sounds/ringbacktone.wav" />
  1184. <audio id="dtmfTone" src="sounds/dtmf.wav" />
  1185. <!--
  1186. Microsoft Internet Explorer extension
  1187. For now we use msi installer as we don't have trusted certificate yet :(
  1188. -->
  1189. <!--object id="webrtc4ieLooper" classid="clsid:7082C446-54A8-4280-A18D-54143846211A" CODEBASE="http://sipml5.org/deploy/webrtc4all.CAB"> </object-->
  1190. <!-- GOOGLE ANALYTICS -->
  1191. <script type="text/javascript">
  1192. var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
  1193. document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
  1194. </script>
  1195. <script type="text/javascript">
  1196. try {
  1197. var pageTracker = _gat._getTracker("UA-6868621-19");
  1198. pageTracker._trackPageview();
  1199. } catch (err) { }
  1200. </script>
  1201. <?php
  1202. require_once "resources/footer.php";
  1203. ?>