@telegenta/webclient 3.0.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/demos/calldata_available.html +1 -1
- package/demos/event_client.html +225 -210
- package/demos/phone_client.html +539 -519
- package/dist/telegenta.js +410 -292
- package/dist/telegenta.min.js +1 -1
- package/docs/EventClient.html +1 -1
- package/docs/EventServiceNotConnected.html +3 -0
- package/docs/InvalidMediaDevice.html +1 -1
- package/docs/InvalidOptions.html +1 -1
- package/docs/InvalidParameter.html +1 -1
- package/docs/LogHandler.html +2 -2
- package/docs/MediaNotPrepared.html +1 -1
- package/docs/NoActiveSession.html +1 -1
- package/docs/NotAllowed.html +1 -1
- package/docs/NotReady.html +1 -1
- package/docs/Phone.html +2 -2
- package/docs/Request.html +1 -1
- package/docs/Requestor.html +1 -1
- package/docs/Session.html +4 -1
- package/docs/UnableToConnect.html +1 -1
- package/docs/data/search.json +1 -1
- package/docs/event-client.js.html +44 -38
- package/docs/exceptions.js.html +15 -4
- package/docs/global.html +3 -3
- package/docs/index.html +1 -1
- package/docs/logger.js.html +2 -2
- package/docs/phone-client.js.html +328 -264
- package/docs/requestor.js.html +3 -3
- package/package.json +45 -45
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
<!DOCTYPE html><html lang="en" style="font-size:16px"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Source: phone-client.js</title><!--[if lt IE 9]>
|
|
2
2
|
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
3
|
-
<![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(locationPathname=document.location.pathname).substr(0,locationPathname.lastIndexOf("/")+1)</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="dark"><div class="sidebar-container"><div class="sidebar" id="sidebar"><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="EventClient.html">EventClient</a></div><div class="sidebar-section-children"><a href="InvalidMediaDevice.html">InvalidMediaDevice</a></div><div class="sidebar-section-children"><a href="InvalidOptions.html">InvalidOptions</a></div><div class="sidebar-section-children"><a href="InvalidParameter.html">InvalidParameter</a></div><div class="sidebar-section-children"><a href="LogHandler.html">LogHandler</a></div><div class="sidebar-section-children"><a href="MediaNotPrepared.html">MediaNotPrepared</a></div><div class="sidebar-section-children"><a href="NoActiveSession.html">NoActiveSession</a></div><div class="sidebar-section-children"><a href="NotAllowed.html">NotAllowed</a></div><div class="sidebar-section-children"><a href="NotReady.html">NotReady</a></div><div class="sidebar-section-children"><a href="Phone.html">Phone</a></div><div class="sidebar-section-children"><a href="Request.html">Request</a></div><div class="sidebar-section-children"><a href="Requestor.html">Requestor</a></div><div class="sidebar-section-children"><a href="Session.html">Session</a></div><div class="sidebar-section-children"><a href="UnableToConnect.html">UnableToConnect</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-events"><div>Events</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#event:callDataInfo">callDataInfo</a></div><div class="sidebar-section-children"><a href="global.html#event:callDurationUpdate">callDurationUpdate</a></div><div class="sidebar-section-children"><a href="global.html#event:callEnded">callEnded</a></div><div class="sidebar-section-children"><a href="global.html#event:callQualityReportUpdate">callQualityReportUpdate</a></div><div class="sidebar-section-children"><a href="global.html#event:connectionStateChange">connectionStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:holdStateChange">holdStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:incomingCall">incomingCall</a></div><div class="sidebar-section-children"><a href="global.html#event:muteStateChange">muteStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:recordingStateChange">recordingStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:sessionCreated">sessionCreated</a></div><div class="sidebar-section-children"><a href="global.html#event:sessionRemoved">sessionRemoved</a></div><div class="sidebar-section-children"><a href="global.html#event:sessionStateChange">sessionStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:whisperModeChange">whisperModeChange</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-global"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#CALL_DIRECTION">CALL_DIRECTION</a></div><div class="sidebar-section-children"><a href="global.html#CALL_DISPOSITION">CALL_DISPOSITION</a></div><div class="sidebar-section-children"><a href="global.html#CONNECTION_STATE">CONNECTION_STATE</a></div><div class="sidebar-section-children"><a href="global.html#LOGLVL">LOGLVL</a></div><div class="sidebar-section-children"><a href="global.html#SESSION_STATE">SESSION_STATE</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section id="source-page" class="source-page"><header><h1 id="title" class="has-anchor">phone-client.js</h1></header><article><pre class="prettyprint source lang-js"><code>// 'use strict';
|
|
4
|
-
import EventEmitter from
|
|
5
|
-
import JsSIP from
|
|
6
|
-
import { LogHandler, LOGLVL } from
|
|
7
|
-
import * as Exceptions from
|
|
8
|
-
import * as Tools from
|
|
9
|
-
import { EventClient } from
|
|
10
|
-
import camelcaseKeys from
|
|
3
|
+
<![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(locationPathname=document.location.pathname).substr(0,locationPathname.lastIndexOf("/")+1)</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="dark"><div class="sidebar-container"><div class="sidebar" id="sidebar"><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="EventClient.html">EventClient</a></div><div class="sidebar-section-children"><a href="EventServiceNotConnected.html">EventServiceNotConnected</a></div><div class="sidebar-section-children"><a href="InvalidMediaDevice.html">InvalidMediaDevice</a></div><div class="sidebar-section-children"><a href="InvalidOptions.html">InvalidOptions</a></div><div class="sidebar-section-children"><a href="InvalidParameter.html">InvalidParameter</a></div><div class="sidebar-section-children"><a href="LogHandler.html">LogHandler</a></div><div class="sidebar-section-children"><a href="MediaNotPrepared.html">MediaNotPrepared</a></div><div class="sidebar-section-children"><a href="NoActiveSession.html">NoActiveSession</a></div><div class="sidebar-section-children"><a href="NotAllowed.html">NotAllowed</a></div><div class="sidebar-section-children"><a href="NotReady.html">NotReady</a></div><div class="sidebar-section-children"><a href="Phone.html">Phone</a></div><div class="sidebar-section-children"><a href="Request.html">Request</a></div><div class="sidebar-section-children"><a href="Requestor.html">Requestor</a></div><div class="sidebar-section-children"><a href="Session.html">Session</a></div><div class="sidebar-section-children"><a href="UnableToConnect.html">UnableToConnect</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-events"><div>Events</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#event:callDataInfo">callDataInfo</a></div><div class="sidebar-section-children"><a href="global.html#event:callDurationUpdate">callDurationUpdate</a></div><div class="sidebar-section-children"><a href="global.html#event:callEnded">callEnded</a></div><div class="sidebar-section-children"><a href="global.html#event:callQualityReportUpdate">callQualityReportUpdate</a></div><div class="sidebar-section-children"><a href="global.html#event:connectionStateChange">connectionStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:holdStateChange">holdStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:incomingCall">incomingCall</a></div><div class="sidebar-section-children"><a href="global.html#event:muteStateChange">muteStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:recordingStateChange">recordingStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:sessionCreated">sessionCreated</a></div><div class="sidebar-section-children"><a href="global.html#event:sessionRemoved">sessionRemoved</a></div><div class="sidebar-section-children"><a href="global.html#event:sessionStateChange">sessionStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:whisperModeChange">whisperModeChange</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-global"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#CALL_DIRECTION">CALL_DIRECTION</a></div><div class="sidebar-section-children"><a href="global.html#CALL_DISPOSITION">CALL_DISPOSITION</a></div><div class="sidebar-section-children"><a href="global.html#CONNECTION_STATE">CONNECTION_STATE</a></div><div class="sidebar-section-children"><a href="global.html#LOGLVL">LOGLVL</a></div><div class="sidebar-section-children"><a href="global.html#SESSION_STATE">SESSION_STATE</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section id="source-page" class="source-page"><header><h1 id="title" class="has-anchor">phone-client.js</h1></header><article><pre class="prettyprint source lang-js"><code>// 'use strict';
|
|
4
|
+
import EventEmitter from 'events';
|
|
5
|
+
import JsSIP from 'jssip';
|
|
6
|
+
import { LogHandler, LOGLVL } from './logger';
|
|
7
|
+
import * as Exceptions from './exceptions';
|
|
8
|
+
import * as Tools from './tools';
|
|
9
|
+
import { EventClient } from './event-client';
|
|
10
|
+
import camelcaseKeys from 'camelcase-keys';
|
|
11
11
|
|
|
12
12
|
const options = {
|
|
13
|
-
wssServer:
|
|
14
|
-
eventServer:
|
|
13
|
+
wssServer: 'wss://api.telegenta.com/sip/',
|
|
14
|
+
eventServer: 'wss://esvc.telegenta.com/',
|
|
15
15
|
provisionToken: null,
|
|
16
16
|
authorizationUsername: null,
|
|
17
17
|
password: null,
|
|
@@ -44,9 +44,9 @@ const DTMF_FREQUENCY_TABLE = {
|
|
|
44
44
|
8: [1336, 852],
|
|
45
45
|
9: [1477, 852],
|
|
46
46
|
c: [1633, 852],
|
|
47
|
-
|
|
47
|
+
'*': [1209, 941],
|
|
48
48
|
0: [1336, 941],
|
|
49
|
-
|
|
49
|
+
'#': [1477, 941],
|
|
50
50
|
d: [1633, 941],
|
|
51
51
|
};
|
|
52
52
|
|
|
@@ -117,11 +117,11 @@ export class Phone extends EventEmitter {
|
|
|
117
117
|
this._activeSessions = {};
|
|
118
118
|
|
|
119
119
|
// Create remote audio element
|
|
120
|
-
this._remoteAudioElement = document.createElement(
|
|
120
|
+
this._remoteAudioElement = document.createElement('AUDIO');
|
|
121
121
|
this._remoteAudioElement.autoplay = true;
|
|
122
122
|
|
|
123
123
|
// Tone generator
|
|
124
|
-
this._toneAudioElement = document.createElement(
|
|
124
|
+
this._toneAudioElement = document.createElement('AUDIO');
|
|
125
125
|
this._toneAudioElement.autoplay = true;
|
|
126
126
|
this._toneTimer = null;
|
|
127
127
|
this._repeatToneActive = false;
|
|
@@ -136,9 +136,9 @@ export class Phone extends EventEmitter {
|
|
|
136
136
|
|
|
137
137
|
// Handle jssip debug logs
|
|
138
138
|
if (this.log.level === LOGLVL.DEBUG) {
|
|
139
|
-
JsSIP.debug.disable(
|
|
139
|
+
JsSIP.debug.disable('JsSIP:*');
|
|
140
140
|
} else {
|
|
141
|
-
JsSIP.debug.disable(
|
|
141
|
+
JsSIP.debug.disable('JsSIP:*');
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
|
|
@@ -150,7 +150,7 @@ export class Phone extends EventEmitter {
|
|
|
150
150
|
*
|
|
151
151
|
*/
|
|
152
152
|
prepareMedia() {
|
|
153
|
-
this.log.info(
|
|
153
|
+
this.log.info('Get media permission');
|
|
154
154
|
const self = this;
|
|
155
155
|
const constraints = { audio: true, video: false };
|
|
156
156
|
return new Promise(function (resolve, reject) {
|
|
@@ -158,13 +158,13 @@ export class Phone extends EventEmitter {
|
|
|
158
158
|
() => {
|
|
159
159
|
self._mediaPermission = true;
|
|
160
160
|
self._mediaPermissionError = false;
|
|
161
|
-
self.log.info(
|
|
161
|
+
self.log.info('Media permission granted');
|
|
162
162
|
resolve();
|
|
163
163
|
},
|
|
164
164
|
(err) => {
|
|
165
165
|
self._mediaPermission = false;
|
|
166
166
|
self._mediaPermissionError = true;
|
|
167
|
-
self.log.error(
|
|
167
|
+
self.log.error('Denied media permission: ' + err);
|
|
168
168
|
reject(err);
|
|
169
169
|
},
|
|
170
170
|
);
|
|
@@ -199,7 +199,7 @@ export class Phone extends EventEmitter {
|
|
|
199
199
|
this._checkMediaPermission();
|
|
200
200
|
// Check phone is not running already, if so stop it first
|
|
201
201
|
if (this._isStarted) {
|
|
202
|
-
this.log.warning(
|
|
202
|
+
this.log.warning('Phone already started, stopping first');
|
|
203
203
|
this.stop();
|
|
204
204
|
}
|
|
205
205
|
|
|
@@ -214,29 +214,29 @@ export class Phone extends EventEmitter {
|
|
|
214
214
|
try {
|
|
215
215
|
pt = JSON.parse(atob(this._options.provisionToken));
|
|
216
216
|
} catch (err) {
|
|
217
|
-
throw new Exceptions.InvalidOptions(
|
|
217
|
+
throw new Exceptions.InvalidOptions('provisionToken', 'Invalid token');
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
this.log.info(
|
|
220
|
+
this.log.info('Using provisioning token authorization');
|
|
221
221
|
this._options.wssServer = pt.wss_server;
|
|
222
222
|
this._options.eventServer = pt.event_server;
|
|
223
223
|
this._options.authorizationUsername = pt.wss_username;
|
|
224
224
|
this._options.password = pt.wss_password;
|
|
225
225
|
this._options.callToken = pt.wss_token;
|
|
226
226
|
} else {
|
|
227
|
-
this.log.info(
|
|
227
|
+
this.log.info('Using manual specified credentials');
|
|
228
228
|
|
|
229
229
|
// Check auth info is provided
|
|
230
230
|
if (!this._options.authorizationUsername) {
|
|
231
|
-
throw new Exceptions.InvalidOptions(
|
|
231
|
+
throw new Exceptions.InvalidOptions('authorizationUsername', 'Missing username');
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
if (!this._options.password) {
|
|
235
|
-
throw new Exceptions.InvalidOptions(
|
|
235
|
+
throw new Exceptions.InvalidOptions('password', 'Missing password');
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
if (!this._options.callToken) {
|
|
239
|
-
throw new Exceptions.InvalidOptions(
|
|
239
|
+
throw new Exceptions.InvalidOptions('callToken', 'Missing call token');
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
|
|
@@ -259,18 +259,18 @@ export class Phone extends EventEmitter {
|
|
|
259
259
|
if (this._options.useCallDataInfoEvent) {
|
|
260
260
|
// Subscribe to calldata_available events
|
|
261
261
|
let eventSpec = {
|
|
262
|
-
event_name:
|
|
262
|
+
event_name: 'calldata_available',
|
|
263
263
|
call_token: this._options.callToken,
|
|
264
264
|
};
|
|
265
265
|
|
|
266
266
|
this._eventClient
|
|
267
267
|
.subscribe(eventSpec, (data) => {
|
|
268
268
|
try {
|
|
269
|
-
this.log.debug(
|
|
269
|
+
this.log.debug('Received remote call data info');
|
|
270
270
|
this.log.debug(data);
|
|
271
271
|
this._fireCallDataInfoEvent(data);
|
|
272
272
|
} catch (e) {
|
|
273
|
-
this.log.error(
|
|
273
|
+
this.log.error('Event callback failed: ' + e);
|
|
274
274
|
}
|
|
275
275
|
})
|
|
276
276
|
.then(
|
|
@@ -293,10 +293,10 @@ export class Phone extends EventEmitter {
|
|
|
293
293
|
try {
|
|
294
294
|
wsSocket = new JsSIP.WebSocketInterface(this._options.wssServer);
|
|
295
295
|
} catch (err) {
|
|
296
|
-
throw new Exceptions.UnableToConnect(
|
|
296
|
+
throw new Exceptions.UnableToConnect('Unable to connect phone websocket: ' + err);
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
-
this.log.info(
|
|
299
|
+
this.log.info('Starting phone');
|
|
300
300
|
this.log.debug(this._options);
|
|
301
301
|
|
|
302
302
|
this._UA = new JsSIP.UA({
|
|
@@ -305,15 +305,15 @@ export class Phone extends EventEmitter {
|
|
|
305
305
|
password: this._options.password,
|
|
306
306
|
register: this._options.register,
|
|
307
307
|
display_name: this._options.authorizationUsername,
|
|
308
|
-
uri: this._options.authorizationUsername +
|
|
308
|
+
uri: this._options.authorizationUsername + '@telegenta.com',
|
|
309
309
|
session_timers: false,
|
|
310
310
|
});
|
|
311
311
|
|
|
312
312
|
// Setup remote media handler
|
|
313
313
|
const self = this;
|
|
314
|
-
this._UA.on(
|
|
315
|
-
self.log.debug(
|
|
316
|
-
if (data.originator ===
|
|
314
|
+
this._UA.on('newRTCSession', function (data) {
|
|
315
|
+
self.log.debug('New RTCSession');
|
|
316
|
+
if (data.originator === 'remote') {
|
|
317
317
|
// Create new session
|
|
318
318
|
const session = new Session(self);
|
|
319
319
|
|
|
@@ -326,18 +326,20 @@ export class Phone extends EventEmitter {
|
|
|
326
326
|
// Check if we have other sessions and reject call if autoBusyIncoming is true
|
|
327
327
|
if (self._options.autoBusyIncoming) {
|
|
328
328
|
if (Object.keys(self._activeSessions).length > 0) {
|
|
329
|
-
self.log.info(
|
|
330
|
-
|
|
329
|
+
self.log.info(
|
|
330
|
+
`Autorejecting incoming call ${session.uuid} because there is already active calls`,
|
|
331
|
+
);
|
|
332
|
+
session.reject(486, 'Busy');
|
|
331
333
|
return;
|
|
332
334
|
} else {
|
|
333
|
-
self.log.debug(
|
|
335
|
+
self.log.debug('There are no other sessions, adding incoming call');
|
|
334
336
|
}
|
|
335
337
|
}
|
|
336
338
|
|
|
337
339
|
self._addSession(session);
|
|
338
340
|
|
|
339
341
|
// Set new session state
|
|
340
|
-
session._setSessionState(
|
|
342
|
+
session._setSessionState('INCOMING');
|
|
341
343
|
|
|
342
344
|
// Now fire incomingCall event
|
|
343
345
|
self._fireIncomingCallEvent(session);
|
|
@@ -345,33 +347,33 @@ export class Phone extends EventEmitter {
|
|
|
345
347
|
});
|
|
346
348
|
|
|
347
349
|
// Setup connection state event subscriptions
|
|
348
|
-
this._UA.on(
|
|
349
|
-
self._setConnectionState(
|
|
350
|
+
this._UA.on('connecting', function (/* data */) {
|
|
351
|
+
self._setConnectionState('CONNECTING');
|
|
350
352
|
});
|
|
351
353
|
|
|
352
|
-
this._UA.on(
|
|
353
|
-
self._setConnectionState(
|
|
354
|
+
this._UA.on('connected', function (/* data */) {
|
|
355
|
+
self._setConnectionState('CONNECTED');
|
|
354
356
|
});
|
|
355
357
|
|
|
356
|
-
this._UA.on(
|
|
357
|
-
self._setConnectionState(
|
|
358
|
+
this._UA.on('disconnected', function (/* data */) {
|
|
359
|
+
self._setConnectionState('DISCONNECTED');
|
|
358
360
|
});
|
|
359
361
|
|
|
360
|
-
this._UA.on(
|
|
361
|
-
self._setConnectionState(
|
|
362
|
+
this._UA.on('registered', function (/* data */) {
|
|
363
|
+
self._setConnectionState('REGISTERED');
|
|
362
364
|
});
|
|
363
365
|
|
|
364
|
-
this._UA.on(
|
|
365
|
-
self._setConnectionState(
|
|
366
|
+
this._UA.on('unregistered', function (/* data */) {
|
|
367
|
+
self._setConnectionState('UNREGISTERED');
|
|
366
368
|
});
|
|
367
369
|
|
|
368
|
-
this._UA.on(
|
|
369
|
-
self._setConnectionState(
|
|
370
|
+
this._UA.on('registrationFailed', function (/* data */) {
|
|
371
|
+
self._setConnectionState('REGISTRATION_FAILED');
|
|
370
372
|
});
|
|
371
373
|
|
|
372
374
|
this._UA.start();
|
|
373
375
|
this._isStarted = true;
|
|
374
|
-
this.log.info(
|
|
376
|
+
this.log.info('Successfully started phone');
|
|
375
377
|
}
|
|
376
378
|
|
|
377
379
|
/**
|
|
@@ -381,7 +383,7 @@ export class Phone extends EventEmitter {
|
|
|
381
383
|
stop() {
|
|
382
384
|
// Check phone is started first
|
|
383
385
|
if (!this._isStarted) {
|
|
384
|
-
throw new Exceptions.NotReady(
|
|
386
|
+
throw new Exceptions.NotReady('Phone is not started');
|
|
385
387
|
}
|
|
386
388
|
|
|
387
389
|
// Make sure events are not firing anymore, we can't rely on GC.
|
|
@@ -393,18 +395,18 @@ export class Phone extends EventEmitter {
|
|
|
393
395
|
|
|
394
396
|
// Disconnect event client if needed
|
|
395
397
|
if (!this._eventClient) {
|
|
396
|
-
this.log.debug(
|
|
398
|
+
this.log.debug('Event client not running, not stopping');
|
|
397
399
|
return;
|
|
398
400
|
}
|
|
399
401
|
try {
|
|
400
402
|
this._eventClient.disconnect();
|
|
401
403
|
delete this._eventClient;
|
|
402
404
|
} catch (e) {
|
|
403
|
-
this.log.warning(
|
|
405
|
+
this.log.warning('Unable to disconnect event client');
|
|
404
406
|
}
|
|
405
407
|
|
|
406
408
|
this._isStarted = false;
|
|
407
|
-
this.log.info(
|
|
409
|
+
this.log.info('Phone client successfully stopped');
|
|
408
410
|
}
|
|
409
411
|
|
|
410
412
|
/**
|
|
@@ -418,20 +420,22 @@ export class Phone extends EventEmitter {
|
|
|
418
420
|
* @param {number} [params.answerCallTimeout=0] Hangup call with NO ANSWER if call is not picked up before specified interval (seconds). If 0, timeout is disabled.
|
|
419
421
|
* @param {number} [params.maximumCallCost] Maximum call cost (in customer currency) allowed for call. The call will automatically be stopped when the specified cost has been reached. Setting this to 0 disables checking for maximum cost.
|
|
420
422
|
* @param {string} [params.metaInfo] Add meta info to call, which will be available in server events and inside call complete webhook (max 256 chars)
|
|
423
|
+
* @param {object} [params.setHeader] Custom SIP headers to add to the INVITE, as {name: value}.
|
|
421
424
|
* @return {Session} object for call
|
|
422
425
|
* @throws NotReady - If phone is not ready to call
|
|
423
426
|
* @throws NotAllowed - If there are calls currently connecting
|
|
427
|
+
* @throws InvalidParameter - If setHeader contains an invalid header name or container
|
|
424
428
|
*
|
|
425
429
|
*/
|
|
426
430
|
call(number, params = {}) {
|
|
427
431
|
// Check phone is started first
|
|
428
432
|
if (!this._isStarted) {
|
|
429
|
-
throw new Exceptions.NotReady(
|
|
433
|
+
throw new Exceptions.NotReady('Phone is not started');
|
|
430
434
|
}
|
|
431
435
|
|
|
432
436
|
// Check we dont have any other connecting calls
|
|
433
437
|
if (this._checkForConnectingCalls()) {
|
|
434
|
-
throw Exceptions.NotAllowed(
|
|
438
|
+
throw new Exceptions.NotAllowed('Unable to make new calls while others are connecting');
|
|
435
439
|
}
|
|
436
440
|
|
|
437
441
|
// Hold other calls if needed
|
|
@@ -445,15 +449,16 @@ export class Phone extends EventEmitter {
|
|
|
445
449
|
explicitCallerId: null,
|
|
446
450
|
explicitShortCallerId: null,
|
|
447
451
|
metaInfo: null,
|
|
452
|
+
setHeader: null,
|
|
448
453
|
_isListenCall: false,
|
|
449
454
|
},
|
|
450
455
|
params,
|
|
451
456
|
);
|
|
452
457
|
|
|
453
458
|
// Trim phone number to remove spaces and '()'
|
|
454
|
-
number = number.trim().replace(/ |\(|\)/g,
|
|
459
|
+
number = number.trim().replace(/ |\(|\)/g, '');
|
|
455
460
|
|
|
456
|
-
this.log.info(
|
|
461
|
+
this.log.info('Calling number: ' + number);
|
|
457
462
|
|
|
458
463
|
let session = new Session(this);
|
|
459
464
|
session.newOutboundSession(number, callParams);
|
|
@@ -469,12 +474,12 @@ export class Phone extends EventEmitter {
|
|
|
469
474
|
* @throws NotAllowed - If there are calls currently connecting
|
|
470
475
|
*/
|
|
471
476
|
listen(listenKey) {
|
|
472
|
-
const s = listenKey.split(
|
|
477
|
+
const s = listenKey.split('@');
|
|
473
478
|
let callUUID = s[0];
|
|
474
|
-
let mediaSwitch =
|
|
479
|
+
let mediaSwitch = 'sip:' + s[1];
|
|
475
480
|
|
|
476
|
-
this.log.debug(
|
|
477
|
-
return this.call(
|
|
481
|
+
this.log.debug('Initiating listen to call with uuid ' + callUUID + ' on media switch ' + mediaSwitch);
|
|
482
|
+
return this.call('listen-' + callUUID, {
|
|
478
483
|
mediaSwitchURI: mediaSwitch,
|
|
479
484
|
_isListenCall: true,
|
|
480
485
|
});
|
|
@@ -600,7 +605,7 @@ export class Phone extends EventEmitter {
|
|
|
600
605
|
|
|
601
606
|
// Begin repeating tones
|
|
602
607
|
_startRepeatTone(sequences) {
|
|
603
|
-
this.log.info(
|
|
608
|
+
this.log.info('Repeating tone sequence started');
|
|
604
609
|
this.log.debug(sequences);
|
|
605
610
|
this._repeatToneSequence = sequences;
|
|
606
611
|
this._repeatToneSequencePos = 0;
|
|
@@ -630,7 +635,7 @@ export class Phone extends EventEmitter {
|
|
|
630
635
|
// End repeating tones
|
|
631
636
|
_endRepeatTone() {
|
|
632
637
|
if (this._repeatToneActive) {
|
|
633
|
-
this.log.info(
|
|
638
|
+
this.log.info('Repeating tone stopped');
|
|
634
639
|
this._repeatToneActive = false;
|
|
635
640
|
this.stopTone();
|
|
636
641
|
}
|
|
@@ -641,7 +646,7 @@ export class Phone extends EventEmitter {
|
|
|
641
646
|
// Create audio context
|
|
642
647
|
const AudioContext = window.AudioContext || window.webkitAudioContext || false;
|
|
643
648
|
if (!AudioContext) {
|
|
644
|
-
throw new Exceptions.NotAllowed(
|
|
649
|
+
throw new Exceptions.NotAllowed('Audio API not supported by this browser');
|
|
645
650
|
}
|
|
646
651
|
|
|
647
652
|
const ctx = new AudioContext();
|
|
@@ -669,17 +674,17 @@ export class Phone extends EventEmitter {
|
|
|
669
674
|
* @throws NotAllowed If there are connection calls
|
|
670
675
|
*/
|
|
671
676
|
holdAllCalls() {
|
|
672
|
-
this.log.info(
|
|
677
|
+
this.log.info('Holding all active sessions');
|
|
673
678
|
// Check all session can be set on hold
|
|
674
679
|
if (this._checkForConnectingCalls()) {
|
|
675
|
-
throw Exceptions.NotAllowed(
|
|
680
|
+
throw new Exceptions.NotAllowed('A session is currently connecting');
|
|
676
681
|
}
|
|
677
682
|
|
|
678
683
|
// Iterate through all active calls and hold them
|
|
679
684
|
for (let key in this._activeSessions) {
|
|
680
685
|
if (this._activeSessions.hasOwnProperty(key)) {
|
|
681
686
|
let session = this._activeSessions[key];
|
|
682
|
-
if (session.state ===
|
|
687
|
+
if (session.state === 'ACTIVE') {
|
|
683
688
|
session.hold();
|
|
684
689
|
}
|
|
685
690
|
}
|
|
@@ -708,9 +713,9 @@ export class Phone extends EventEmitter {
|
|
|
708
713
|
|
|
709
714
|
// Fire event
|
|
710
715
|
try {
|
|
711
|
-
this.emit(
|
|
716
|
+
this.emit('sessionCreated', { session: session });
|
|
712
717
|
} catch (e) {
|
|
713
|
-
this.log.error(
|
|
718
|
+
this.log.error('Exception in sessionCreated event: ' + e);
|
|
714
719
|
}
|
|
715
720
|
}
|
|
716
721
|
|
|
@@ -726,9 +731,9 @@ export class Phone extends EventEmitter {
|
|
|
726
731
|
|
|
727
732
|
// Fire event
|
|
728
733
|
try {
|
|
729
|
-
this.emit(
|
|
734
|
+
this.emit('sessionRemoved', { session: session });
|
|
730
735
|
} catch (e) {
|
|
731
|
-
this.log.error(
|
|
736
|
+
this.log.error('Exception in sessionRemoved event: ' + e);
|
|
732
737
|
}
|
|
733
738
|
|
|
734
739
|
delete this._activeSessions[session.__containerId];
|
|
@@ -753,7 +758,12 @@ export class Phone extends EventEmitter {
|
|
|
753
758
|
for (let key in this._activeSessions) {
|
|
754
759
|
if (this._activeSessions.hasOwnProperty(key)) {
|
|
755
760
|
let session = this._activeSessions[key];
|
|
756
|
-
if (
|
|
761
|
+
if (
|
|
762
|
+
session.state === 'INITIALIZING' ||
|
|
763
|
+
session.state === 'CALLING' ||
|
|
764
|
+
session.state === 'PROGRESS' ||
|
|
765
|
+
session.state === 'INCOMING'
|
|
766
|
+
) {
|
|
757
767
|
return true;
|
|
758
768
|
}
|
|
759
769
|
}
|
|
@@ -778,12 +788,12 @@ export class Phone extends EventEmitter {
|
|
|
778
788
|
* @param {CONNECTION_STATE} state - The current connection state
|
|
779
789
|
*/
|
|
780
790
|
|
|
781
|
-
this.log.info(
|
|
791
|
+
this.log.info('Connection state: ' + state);
|
|
782
792
|
this._connectionState = state;
|
|
783
793
|
try {
|
|
784
|
-
this.emit(
|
|
794
|
+
this.emit('connectionStateChange', { state: state });
|
|
785
795
|
} catch (e) {
|
|
786
|
-
this.log.error(
|
|
796
|
+
this.log.error('Exception in connectionStateChange event: ' + e);
|
|
787
797
|
}
|
|
788
798
|
}
|
|
789
799
|
|
|
@@ -794,9 +804,9 @@ export class Phone extends EventEmitter {
|
|
|
794
804
|
*/
|
|
795
805
|
_fireIncomingCallEvent(session) {
|
|
796
806
|
try {
|
|
797
|
-
this.emit(
|
|
807
|
+
this.emit('incomingCall', session);
|
|
798
808
|
} catch (e) {
|
|
799
|
-
this.log.error(
|
|
809
|
+
this.log.error('Exception in incomingCall event: ' + e);
|
|
800
810
|
}
|
|
801
811
|
}
|
|
802
812
|
|
|
@@ -849,12 +859,12 @@ export class Phone extends EventEmitter {
|
|
|
849
859
|
|
|
850
860
|
// Add some extra convenience fields
|
|
851
861
|
e.durationStr = Tools.createDurationString(e.duration);
|
|
852
|
-
e.answerDurationStr = e.answerDuration ? Tools.createDurationString(e.answerDuration) :
|
|
853
|
-
e.activeDurationStr = e.activeDuration ? Tools.createDurationString(e.activeDuration) :
|
|
862
|
+
e.answerDurationStr = e.answerDuration ? Tools.createDurationString(e.answerDuration) : '';
|
|
863
|
+
e.activeDurationStr = e.activeDuration ? Tools.createDurationString(e.activeDuration) : '';
|
|
854
864
|
try {
|
|
855
|
-
this.emit(
|
|
865
|
+
this.emit('callDataInfo', e);
|
|
856
866
|
} catch (e) {
|
|
857
|
-
this.log.error(
|
|
867
|
+
this.log.error('Exception in callDataInfo event: ' + e);
|
|
858
868
|
}
|
|
859
869
|
}
|
|
860
870
|
|
|
@@ -935,33 +945,37 @@ export class Session extends EventEmitter {
|
|
|
935
945
|
let options = {
|
|
936
946
|
mediaConstraints: { audio: true, video: false },
|
|
937
947
|
pcConfig: {
|
|
938
|
-
iceServers: [{ urls: [
|
|
948
|
+
iceServers: [{ urls: ['stun:stun.l.google.com:19302'] }],
|
|
939
949
|
},
|
|
940
|
-
extraHeaders: [
|
|
950
|
+
extraHeaders: [
|
|
951
|
+
'X-Call-token: ' + this._phone.options.callToken,
|
|
952
|
+
'X-P-UUID: ' + this._callUUID,
|
|
953
|
+
'X-Max-cost: ' + callParams.maximumCallCost,
|
|
954
|
+
],
|
|
941
955
|
};
|
|
942
956
|
|
|
943
957
|
// Append explicit caller id if needed
|
|
944
958
|
if (callParams.explicitCallerId) {
|
|
945
|
-
options.extraHeaders.push(
|
|
959
|
+
options.extraHeaders.push('X-CID-Number-Id: ' + callParams.explicitCallerId);
|
|
946
960
|
}
|
|
947
961
|
|
|
948
962
|
// Append explicit short cid if needed
|
|
949
963
|
if (callParams.explicitShortCallerId) {
|
|
950
|
-
options.extraHeaders.push(
|
|
964
|
+
options.extraHeaders.push('X-Short-CID-Id: ' + callParams.explicitShortCallerId);
|
|
951
965
|
}
|
|
952
966
|
|
|
953
967
|
// Append meta info
|
|
954
968
|
if (callParams.metaInfo) {
|
|
955
|
-
options.extraHeaders.push(
|
|
969
|
+
options.extraHeaders.push('X-Meta-Info: ' + encodeURI(callParams.metaInfo.toString().substr(0, 255)));
|
|
956
970
|
}
|
|
957
971
|
|
|
958
972
|
// Enable recording?
|
|
959
973
|
if (callParams.record) {
|
|
960
974
|
if (isNaN(callParams.record)) {
|
|
961
|
-
throw new Exceptions.InvalidParameter(
|
|
975
|
+
throw new Exceptions.InvalidParameter('Record parameter must be a number');
|
|
962
976
|
}
|
|
963
977
|
this.log.debug(`Recording enabled and kept for ${callParams.record} days`);
|
|
964
|
-
options.extraHeaders.push(
|
|
978
|
+
options.extraHeaders.push('X-Record: ' + callParams.record);
|
|
965
979
|
this._isRecording = true;
|
|
966
980
|
} else {
|
|
967
981
|
this._isRecording = false;
|
|
@@ -972,8 +986,8 @@ export class Session extends EventEmitter {
|
|
|
972
986
|
|
|
973
987
|
// Manually specified media switch
|
|
974
988
|
if (callParams.mediaSwitchURI) {
|
|
975
|
-
this.log.debug(
|
|
976
|
-
options.extraHeaders.push(
|
|
989
|
+
this.log.debug('Requesting specific media switch ' + callParams.mediaSwitchURI);
|
|
990
|
+
options.extraHeaders.push('X-RMS: ' + callParams.mediaSwitchURI);
|
|
977
991
|
} else {
|
|
978
992
|
// Request specific media switch to group calls on same server
|
|
979
993
|
const otherSessions = this.getOtherSessions();
|
|
@@ -981,24 +995,41 @@ export class Session extends EventEmitter {
|
|
|
981
995
|
if (otherSessions.length > 0) {
|
|
982
996
|
if (otherSessions[0]._mediaSwitch) {
|
|
983
997
|
// There are existing active calls, append first media switch address found and request call grouping to this
|
|
984
|
-
this.log.debug(
|
|
985
|
-
options.extraHeaders.push(
|
|
998
|
+
this.log.debug('Requesting call grouping on media switch ' + otherSessions[0]._mediaSwitch);
|
|
999
|
+
options.extraHeaders.push('X-RMS: sip:' + otherSessions[0]._mediaSwitch);
|
|
986
1000
|
} else {
|
|
987
|
-
this.log.warning(
|
|
1001
|
+
this.log.warning('Other sessions exist but media switch address is invalid');
|
|
988
1002
|
}
|
|
989
1003
|
} else {
|
|
990
|
-
this.log.debug(
|
|
1004
|
+
this.log.debug('No other active calls, no media switch grouping requested');
|
|
991
1005
|
}
|
|
992
1006
|
}
|
|
993
1007
|
|
|
1008
|
+
// Custom headers last, so they cannot displace the built-in ones.
|
|
1009
|
+
// Must be before _UA.call() below: jssip clones extraHeaders synchronously
|
|
1010
|
+
// inside connect(), so anything pushed after that call never reaches the INVITE.
|
|
1011
|
+
let customHeaders;
|
|
1012
|
+
try {
|
|
1013
|
+
customHeaders = Tools.buildCustomHeaders(callParams.setHeader);
|
|
1014
|
+
} catch (error) {
|
|
1015
|
+
if (error instanceof TypeError) {
|
|
1016
|
+
throw new Exceptions.InvalidParameter(error.message);
|
|
1017
|
+
}
|
|
1018
|
+
throw error;
|
|
1019
|
+
}
|
|
1020
|
+
for (const header of customHeaders) {
|
|
1021
|
+
this.log.debug('Adding custom header: ' + header);
|
|
1022
|
+
options.extraHeaders.push(header);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
994
1025
|
// Prepare invite uri
|
|
995
|
-
const uri =
|
|
1026
|
+
const uri = 'sip:' + number + '@telegenta.com';
|
|
996
1027
|
|
|
997
1028
|
// Not start call and create sip session
|
|
998
1029
|
try {
|
|
999
1030
|
this._initWebRTCSession(this._phone._UA.call(uri, options));
|
|
1000
1031
|
} catch (error) {
|
|
1001
|
-
this.log.error(
|
|
1032
|
+
this.log.error('Error starting call:', error);
|
|
1002
1033
|
return null;
|
|
1003
1034
|
}
|
|
1004
1035
|
|
|
@@ -1009,16 +1040,16 @@ export class Session extends EventEmitter {
|
|
|
1009
1040
|
|
|
1010
1041
|
// Create new inbound session
|
|
1011
1042
|
newInboundSession(newSessionRequest) {
|
|
1012
|
-
this._callUUID = newSessionRequest.request.getHeader(
|
|
1013
|
-
this._destinationNumber = newSessionRequest.request.getHeader(
|
|
1014
|
-
this._localNumberName = unescape(newSessionRequest.request.getHeader(
|
|
1043
|
+
this._callUUID = newSessionRequest.request.getHeader('X-P-UUID', 0);
|
|
1044
|
+
this._destinationNumber = newSessionRequest.request.getHeader('X-DID', 0);
|
|
1045
|
+
this._localNumberName = unescape(newSessionRequest.request.getHeader('X-DID-NAME', 0));
|
|
1015
1046
|
this._originName = newSessionRequest.request.from.display_name;
|
|
1016
1047
|
this._originatingNumber = newSessionRequest.request.from.uri.user;
|
|
1017
1048
|
this.log.info(`Incoming call from ${this._originatingNumber} [${this._callUUID}]`);
|
|
1018
1049
|
this.log.debug(newSessionRequest);
|
|
1019
1050
|
|
|
1020
1051
|
// Get media switch info
|
|
1021
|
-
this._mediaSwitch = newSessionRequest.request.getHeader(
|
|
1052
|
+
this._mediaSwitch = newSessionRequest.request.getHeader('X-MS');
|
|
1022
1053
|
this.log.debug(`Media switch handling call: ${this._mediaSwitch}`);
|
|
1023
1054
|
|
|
1024
1055
|
this._initWebRTCSession(newSessionRequest.session);
|
|
@@ -1052,10 +1083,10 @@ export class Session extends EventEmitter {
|
|
|
1052
1083
|
const self = this;
|
|
1053
1084
|
|
|
1054
1085
|
// ICE CANDIDATES
|
|
1055
|
-
this._webRTCSession.on(
|
|
1086
|
+
this._webRTCSession.on('icecandidate', function (event) {
|
|
1056
1087
|
const c = event.candidate;
|
|
1057
1088
|
self.log.debug(`Got ICE candidate: ${c.candidate}`);
|
|
1058
|
-
if (c.type ===
|
|
1089
|
+
if (c.type === 'srflx' && c.relatedAddress !== null && c.relatedPort !== null) {
|
|
1059
1090
|
self.log.info(`Accepting ICE candidate: ${c.candidate}`);
|
|
1060
1091
|
|
|
1061
1092
|
// Clear timer first
|
|
@@ -1078,24 +1109,24 @@ export class Session extends EventEmitter {
|
|
|
1078
1109
|
}
|
|
1079
1110
|
});
|
|
1080
1111
|
|
|
1081
|
-
this._webRTCSession.on(
|
|
1112
|
+
this._webRTCSession.on('connecting', function (/* data */) {
|
|
1082
1113
|
self._startDurationUpdateTimer();
|
|
1083
1114
|
self._startRTCPStatsUpdateTimer();
|
|
1084
|
-
self._setSessionState(
|
|
1115
|
+
self._setSessionState('INITIALIZING');
|
|
1085
1116
|
});
|
|
1086
1117
|
|
|
1087
|
-
this._webRTCSession.on(
|
|
1118
|
+
this._webRTCSession.on('sending', function (/* data */) {
|
|
1088
1119
|
// Play call initialized tone if needed
|
|
1089
1120
|
if (self._phone.options.playCallInitializedTone) {
|
|
1090
1121
|
self._phone._startRepeatTone(ST_CALLINIT);
|
|
1091
1122
|
}
|
|
1092
1123
|
|
|
1093
|
-
self._setSessionState(
|
|
1124
|
+
self._setSessionState('CALLING');
|
|
1094
1125
|
});
|
|
1095
1126
|
|
|
1096
|
-
this._webRTCSession.on(
|
|
1097
|
-
if (data.originator ===
|
|
1098
|
-
self._setSessionState(
|
|
1127
|
+
this._webRTCSession.on('progress', function (data) {
|
|
1128
|
+
if (data.originator === 'remote') {
|
|
1129
|
+
self._setSessionState('PROGRESS', { code: data.response.status_code });
|
|
1099
1130
|
self._phone._endRepeatTone();
|
|
1100
1131
|
|
|
1101
1132
|
// Ringback handling on 180 RINGING
|
|
@@ -1110,14 +1141,14 @@ export class Session extends EventEmitter {
|
|
|
1110
1141
|
try {
|
|
1111
1142
|
self.hangup();
|
|
1112
1143
|
} catch (e) {
|
|
1113
|
-
self.log.info(
|
|
1144
|
+
self.log.info('No active session, ignoring answer call timeout');
|
|
1114
1145
|
}
|
|
1115
1146
|
}, self._answerCallTimeout * 1000);
|
|
1116
1147
|
}
|
|
1117
1148
|
}
|
|
1118
1149
|
});
|
|
1119
1150
|
|
|
1120
|
-
this._webRTCSession.on(
|
|
1151
|
+
this._webRTCSession.on('accepted', function (data) {
|
|
1121
1152
|
// Always end ringsback
|
|
1122
1153
|
self._phone._endRepeatTone();
|
|
1123
1154
|
|
|
@@ -1130,27 +1161,27 @@ export class Session extends EventEmitter {
|
|
|
1130
1161
|
}
|
|
1131
1162
|
|
|
1132
1163
|
// Get initial recording state
|
|
1133
|
-
if (data.originator ===
|
|
1134
|
-
const recState = data.response.getHeader(
|
|
1135
|
-
if (recState ===
|
|
1136
|
-
self.log.debug(
|
|
1164
|
+
if (data.originator === 'remote') {
|
|
1165
|
+
const recState = data.response.getHeader('X-Recording');
|
|
1166
|
+
if (recState === 'true') {
|
|
1167
|
+
self.log.debug('Call is being prerecorded');
|
|
1137
1168
|
// self._isRecording = true;
|
|
1138
1169
|
// self.emit('recordingStateChange', {state: true, error: null});
|
|
1139
1170
|
} else {
|
|
1140
|
-
self.log.debug(
|
|
1171
|
+
self.log.debug('No call recording started yet');
|
|
1141
1172
|
}
|
|
1142
1173
|
|
|
1143
1174
|
// Get media switch info
|
|
1144
|
-
self._mediaSwitch = data.response.getHeader(
|
|
1175
|
+
self._mediaSwitch = data.response.getHeader('X-MS');
|
|
1145
1176
|
self.log.debug(`Media switch handling call: ${self._mediaSwitch}`);
|
|
1146
1177
|
}
|
|
1147
1178
|
});
|
|
1148
1179
|
|
|
1149
|
-
this._webRTCSession.on(
|
|
1150
|
-
self._setSessionState(
|
|
1180
|
+
this._webRTCSession.on('confirmed', function (/* data */) {
|
|
1181
|
+
self._setSessionState('ACTIVE');
|
|
1151
1182
|
});
|
|
1152
1183
|
|
|
1153
|
-
this._webRTCSession.on(
|
|
1184
|
+
this._webRTCSession.on('ended', function (/* data */) {
|
|
1154
1185
|
// End any ringsbacks if needed
|
|
1155
1186
|
self._phone._endRepeatTone();
|
|
1156
1187
|
|
|
@@ -1161,10 +1192,10 @@ export class Session extends EventEmitter {
|
|
|
1161
1192
|
clearTimeout(self._answerCallTimer);
|
|
1162
1193
|
}
|
|
1163
1194
|
|
|
1164
|
-
self._setSessionState(
|
|
1195
|
+
self._setSessionState('TERMINATED');
|
|
1165
1196
|
});
|
|
1166
1197
|
|
|
1167
|
-
this._webRTCSession.on(
|
|
1198
|
+
this._webRTCSession.on('failed', function (data) {
|
|
1168
1199
|
// End any ringsbacks if needed
|
|
1169
1200
|
self._phone._endRepeatTone();
|
|
1170
1201
|
|
|
@@ -1182,54 +1213,54 @@ export class Session extends EventEmitter {
|
|
|
1182
1213
|
if (data.message) {
|
|
1183
1214
|
m = `${data.message.status_code} ${data.message.reason_phrase}`;
|
|
1184
1215
|
} else {
|
|
1185
|
-
m =
|
|
1216
|
+
m = '';
|
|
1186
1217
|
}
|
|
1187
1218
|
|
|
1188
|
-
self._setSessionState(
|
|
1219
|
+
self._setSessionState('FAILED', { cause: data.cause, message: m });
|
|
1189
1220
|
});
|
|
1190
1221
|
|
|
1191
|
-
this._webRTCSession.on(
|
|
1192
|
-
self.log.debug(
|
|
1222
|
+
this._webRTCSession.on('dtmf', function (data) {
|
|
1223
|
+
self.log.debug('Session DTMF', data);
|
|
1193
1224
|
});
|
|
1194
1225
|
|
|
1195
|
-
this._webRTCSession.on(
|
|
1196
|
-
self.log.debug(
|
|
1226
|
+
this._webRTCSession.on('newInfo', function (data) {
|
|
1227
|
+
self.log.debug('New session info', data);
|
|
1197
1228
|
});
|
|
1198
1229
|
|
|
1199
|
-
this._webRTCSession.on(
|
|
1230
|
+
this._webRTCSession.on('hold', function (/* data */) {
|
|
1200
1231
|
self._isOnHold = true;
|
|
1201
1232
|
self._fireHoldStateEvent();
|
|
1202
|
-
self._setSessionState(
|
|
1233
|
+
self._setSessionState('ON_HOLD');
|
|
1203
1234
|
});
|
|
1204
1235
|
|
|
1205
|
-
this._webRTCSession.on(
|
|
1236
|
+
this._webRTCSession.on('unhold', function (/* data */) {
|
|
1206
1237
|
self._isOnHold = false;
|
|
1207
1238
|
self._fireHoldStateEvent();
|
|
1208
|
-
self._setSessionState(
|
|
1239
|
+
self._setSessionState('ACTIVE');
|
|
1209
1240
|
});
|
|
1210
1241
|
|
|
1211
|
-
this._webRTCSession.on(
|
|
1212
|
-
self.log.debug(
|
|
1242
|
+
this._webRTCSession.on('muted', function (data) {
|
|
1243
|
+
self.log.debug('Microphone muted', data);
|
|
1213
1244
|
self._isMuted = true;
|
|
1214
1245
|
self._fireMuteStateEvent();
|
|
1215
1246
|
});
|
|
1216
1247
|
|
|
1217
|
-
this._webRTCSession.on(
|
|
1218
|
-
self.log.debug(
|
|
1248
|
+
this._webRTCSession.on('unmuted', function (data) {
|
|
1249
|
+
self.log.debug('Microphone unmuted', data);
|
|
1219
1250
|
self._isMuted = false;
|
|
1220
1251
|
self._fireMuteStateEvent();
|
|
1221
1252
|
});
|
|
1222
1253
|
|
|
1223
|
-
this._webRTCSession.on(
|
|
1224
|
-
self.log.debug(
|
|
1254
|
+
this._webRTCSession.on('reinvite', function (data) {
|
|
1255
|
+
self.log.debug('Session reinvite', data);
|
|
1225
1256
|
});
|
|
1226
1257
|
|
|
1227
|
-
this._webRTCSession.on(
|
|
1228
|
-
self.log.debug(
|
|
1258
|
+
this._webRTCSession.on('update', function (data) {
|
|
1259
|
+
self.log.debug('Session update', data);
|
|
1229
1260
|
});
|
|
1230
1261
|
|
|
1231
|
-
this._webRTCSession.on(
|
|
1232
|
-
self.log.error(
|
|
1262
|
+
this._webRTCSession.on('getusermediafailed', function (data) {
|
|
1263
|
+
self.log.error('Getusermedia failed', data);
|
|
1233
1264
|
});
|
|
1234
1265
|
|
|
1235
1266
|
// If connection connect audio stream
|
|
@@ -1238,7 +1269,7 @@ export class Session extends EventEmitter {
|
|
|
1238
1269
|
}
|
|
1239
1270
|
|
|
1240
1271
|
// DEBUG STUFF
|
|
1241
|
-
this.log.debug(
|
|
1272
|
+
this.log.debug('WebRTCSession object:');
|
|
1242
1273
|
this.log.debug(this);
|
|
1243
1274
|
}
|
|
1244
1275
|
|
|
@@ -1249,13 +1280,13 @@ export class Session extends EventEmitter {
|
|
|
1249
1280
|
*/
|
|
1250
1281
|
hangup(disposition = null) {
|
|
1251
1282
|
if (!disposition) {
|
|
1252
|
-
this.log.info(
|
|
1283
|
+
this.log.info('Hanging up call');
|
|
1253
1284
|
this._webRTCSession.terminate();
|
|
1254
1285
|
} else {
|
|
1255
1286
|
this.log.info(`Hanging up call with disposition ${disposition}`);
|
|
1256
1287
|
this._manualDisposition = disposition;
|
|
1257
1288
|
this._webRTCSession.terminate({
|
|
1258
|
-
extraHeaders: [
|
|
1289
|
+
extraHeaders: ['X-HDISP: ' + disposition],
|
|
1259
1290
|
});
|
|
1260
1291
|
}
|
|
1261
1292
|
}
|
|
@@ -1268,14 +1299,14 @@ export class Session extends EventEmitter {
|
|
|
1268
1299
|
let options = {
|
|
1269
1300
|
mediaConstraints: { audio: true, video: false },
|
|
1270
1301
|
pcConfig: {
|
|
1271
|
-
iceServers: [{ urls: [
|
|
1302
|
+
iceServers: [{ urls: ['stun:stun.l.google.com:19302'] }],
|
|
1272
1303
|
},
|
|
1273
|
-
extraHeaders: [
|
|
1304
|
+
extraHeaders: ['X-Call-token: ' + this._phone.options.callToken],
|
|
1274
1305
|
};
|
|
1275
1306
|
|
|
1276
1307
|
// Append meta info if needed
|
|
1277
1308
|
if (metaInfo) {
|
|
1278
|
-
options.extraHeaders.push(
|
|
1309
|
+
options.extraHeaders.push('X-Meta-Info: ' + encodeURI(metaInfo.toString().substr(0, 255)));
|
|
1279
1310
|
}
|
|
1280
1311
|
|
|
1281
1312
|
this._webRTCSession.answer(options);
|
|
@@ -1289,8 +1320,8 @@ export class Session extends EventEmitter {
|
|
|
1289
1320
|
* @param statusCode - SIP Status code
|
|
1290
1321
|
* @param reasonPhrase - Reason phrase
|
|
1291
1322
|
*/
|
|
1292
|
-
reject(statusCode = 603, reasonPhrase =
|
|
1293
|
-
this.log.info(
|
|
1323
|
+
reject(statusCode = 603, reasonPhrase = 'Rejected call') {
|
|
1324
|
+
this.log.info('Rejecting call');
|
|
1294
1325
|
this._webRTCSession.terminate({
|
|
1295
1326
|
status_code: statusCode,
|
|
1296
1327
|
reason_phrase: reasonPhrase,
|
|
@@ -1331,7 +1362,7 @@ export class Session extends EventEmitter {
|
|
|
1331
1362
|
|
|
1332
1363
|
// Set destination number
|
|
1333
1364
|
set destinationNumber(number) {
|
|
1334
|
-
this.log.debug(
|
|
1365
|
+
this.log.debug('Setting destination number to: ' + number);
|
|
1335
1366
|
this._destinationNumber = number;
|
|
1336
1367
|
}
|
|
1337
1368
|
|
|
@@ -1349,53 +1380,77 @@ export class Session extends EventEmitter {
|
|
|
1349
1380
|
*/
|
|
1350
1381
|
get direction() {
|
|
1351
1382
|
if (this._isListenCall) {
|
|
1352
|
-
this.log.debug(
|
|
1353
|
-
return
|
|
1354
|
-
} else if (this._webRTCSession.direction ===
|
|
1355
|
-
this.log.debug(
|
|
1356
|
-
return
|
|
1357
|
-
} else if (this._webRTCSession.direction ===
|
|
1358
|
-
this.log.debug(
|
|
1359
|
-
return
|
|
1383
|
+
this.log.debug('Call direction is LISTEN');
|
|
1384
|
+
return 'LISTEN';
|
|
1385
|
+
} else if (this._webRTCSession.direction === 'incoming') {
|
|
1386
|
+
this.log.debug('Call direction is INBOUND');
|
|
1387
|
+
return 'INBOUND';
|
|
1388
|
+
} else if (this._webRTCSession.direction === 'outgoing') {
|
|
1389
|
+
this.log.debug('Call direction is OUTBOUND');
|
|
1390
|
+
return 'OUTBOUND';
|
|
1360
1391
|
} else {
|
|
1361
|
-
this.log.error(
|
|
1362
|
-
return
|
|
1392
|
+
this.log.error('Unknown call direction: ' + this._webRTCSession.direction);
|
|
1393
|
+
return 'UNKNOWN';
|
|
1363
1394
|
}
|
|
1364
1395
|
}
|
|
1365
1396
|
|
|
1397
|
+
/**
|
|
1398
|
+
* Raw WebRTC statistics for this session's peer connection.
|
|
1399
|
+
*
|
|
1400
|
+
* Returns the browser's own `RTCStatsReport` untouched, so callers can read
|
|
1401
|
+
* any statistic the browser exposes - RTP packet and byte counters, the
|
|
1402
|
+
* DTLS/ICE transport state, codec and candidate-pair details.
|
|
1403
|
+
*
|
|
1404
|
+
* @returns {Promise<RTCStatsReport>} The peer connection's statistics
|
|
1405
|
+
* @throws NoActiveSession - If the session has no established peer connection
|
|
1406
|
+
* (thrown synchronously, before the promise is created)
|
|
1407
|
+
*
|
|
1408
|
+
* @example
|
|
1409
|
+
* const report = await session.getRTCStats();
|
|
1410
|
+
* for (const stat of report.values()) {
|
|
1411
|
+
* if (stat.type === 'inbound-rtp') console.log(stat.packetsReceived);
|
|
1412
|
+
* }
|
|
1413
|
+
*/
|
|
1414
|
+
getRTCStats() {
|
|
1415
|
+
if (!this._webRTCSession || !this._webRTCSession.connection) {
|
|
1416
|
+
throw new Exceptions.NoActiveSession('no peer connection for this session');
|
|
1417
|
+
}
|
|
1418
|
+
return this._webRTCSession.connection.getStats();
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1366
1421
|
// RECORDING
|
|
1367
1422
|
/**
|
|
1368
1423
|
* Start recording
|
|
1369
1424
|
*/
|
|
1370
1425
|
startRecording() {
|
|
1371
1426
|
const opt = {
|
|
1372
|
-
extraHeaders: [
|
|
1427
|
+
extraHeaders: ['Record: on'],
|
|
1373
1428
|
};
|
|
1374
1429
|
|
|
1375
|
-
this.log.debug(
|
|
1430
|
+
this.log.debug('Request start recording');
|
|
1376
1431
|
|
|
1377
1432
|
const self = this;
|
|
1378
|
-
this._webRTCSession.once(
|
|
1379
|
-
if (data.originator ===
|
|
1380
|
-
data.info.on(
|
|
1381
|
-
self.log.info(
|
|
1433
|
+
this._webRTCSession.once('newInfo', (data) => {
|
|
1434
|
+
if (data.originator === 'local') {
|
|
1435
|
+
data.info.on('succeeded', function (/* data */) {
|
|
1436
|
+
self.log.info('Recording started successfully');
|
|
1382
1437
|
self._isRecording = true;
|
|
1383
1438
|
try {
|
|
1384
|
-
self.emit(
|
|
1439
|
+
self.emit('recordingStateChange', { state: true, error: null });
|
|
1385
1440
|
} catch (e) {
|
|
1386
|
-
self.log.error(
|
|
1441
|
+
self.log.error('Exception in recordingStateChange event: ' + e);
|
|
1387
1442
|
}
|
|
1388
1443
|
});
|
|
1389
1444
|
|
|
1390
|
-
data.info.on(
|
|
1445
|
+
data.info.on('failed', function (data) {
|
|
1391
1446
|
self._recordingError = data.response.reason_phrase;
|
|
1392
|
-
self.log.error(
|
|
1447
|
+
self.log.error('Recording start failed: ' + self._recordingError);
|
|
1393
1448
|
self._fireRecordingStateEvent();
|
|
1394
1449
|
});
|
|
1395
1450
|
}
|
|
1396
1451
|
});
|
|
1397
1452
|
|
|
1398
|
-
this._webRTCSession.sendInfo(
|
|
1453
|
+
this._webRTCSession.sendInfo('application/info', null, opt);
|
|
1399
1454
|
}
|
|
1400
1455
|
|
|
1401
1456
|
/**
|
|
@@ -1403,35 +1458,35 @@ export class Session extends EventEmitter {
|
|
|
1403
1458
|
*/
|
|
1404
1459
|
stopRecording() {
|
|
1405
1460
|
const opt = {
|
|
1406
|
-
extraHeaders: [
|
|
1461
|
+
extraHeaders: ['Record: off'],
|
|
1407
1462
|
};
|
|
1408
1463
|
|
|
1409
|
-
this.log.debug(
|
|
1464
|
+
this.log.debug('Request stop recording');
|
|
1410
1465
|
|
|
1411
1466
|
const self = this;
|
|
1412
1467
|
|
|
1413
|
-
this._webRTCSession.once(
|
|
1414
|
-
data.info.on(
|
|
1415
|
-
self.log.info(
|
|
1468
|
+
this._webRTCSession.once('newInfo', (data) => {
|
|
1469
|
+
data.info.on('succeeded', function (/* data */) {
|
|
1470
|
+
self.log.info('Recording stopped successfully');
|
|
1416
1471
|
self._isRecording = false;
|
|
1417
1472
|
try {
|
|
1418
|
-
self.emit(
|
|
1473
|
+
self.emit('recordingStateChange', { state: false, error: null });
|
|
1419
1474
|
} catch (e) {
|
|
1420
|
-
self.log.error(
|
|
1475
|
+
self.log.error('Exception in recordingStateChange event: ' + e);
|
|
1421
1476
|
}
|
|
1422
1477
|
});
|
|
1423
1478
|
|
|
1424
|
-
data.info.on(
|
|
1425
|
-
self.log.error(
|
|
1479
|
+
data.info.on('failed', function (data) {
|
|
1480
|
+
self.log.error('Recording stopped failed: ' + data.response.reason_phrase);
|
|
1426
1481
|
try {
|
|
1427
|
-
self.emit(
|
|
1482
|
+
self.emit('recordingStateChange', { state: self._isRecording, error: data.response.reason_phrase });
|
|
1428
1483
|
} catch (e) {
|
|
1429
|
-
self.log.error(
|
|
1484
|
+
self.log.error('Exception in recordingStateChange event: ' + e);
|
|
1430
1485
|
}
|
|
1431
1486
|
});
|
|
1432
1487
|
});
|
|
1433
1488
|
|
|
1434
|
-
this._webRTCSession.sendInfo(
|
|
1489
|
+
this._webRTCSession.sendInfo('application/info', null, opt);
|
|
1435
1490
|
}
|
|
1436
1491
|
|
|
1437
1492
|
/**
|
|
@@ -1460,7 +1515,7 @@ export class Session extends EventEmitter {
|
|
|
1460
1515
|
* Mute microphone
|
|
1461
1516
|
*/
|
|
1462
1517
|
muteMic() {
|
|
1463
|
-
this.log.info(
|
|
1518
|
+
this.log.info('Mute microphone');
|
|
1464
1519
|
this._webRTCSession.mute();
|
|
1465
1520
|
}
|
|
1466
1521
|
|
|
@@ -1468,7 +1523,7 @@ export class Session extends EventEmitter {
|
|
|
1468
1523
|
* Unmute microphone
|
|
1469
1524
|
*/
|
|
1470
1525
|
unmuteMic() {
|
|
1471
|
-
this.log.info(
|
|
1526
|
+
this.log.info('Unmute microphone');
|
|
1472
1527
|
this._webRTCSession.unmute();
|
|
1473
1528
|
}
|
|
1474
1529
|
|
|
@@ -1496,7 +1551,7 @@ export class Session extends EventEmitter {
|
|
|
1496
1551
|
* Hold call
|
|
1497
1552
|
*/
|
|
1498
1553
|
hold() {
|
|
1499
|
-
this.log.info(
|
|
1554
|
+
this.log.info('Hold call');
|
|
1500
1555
|
this._webRTCSession.hold();
|
|
1501
1556
|
}
|
|
1502
1557
|
|
|
@@ -1504,7 +1559,7 @@ export class Session extends EventEmitter {
|
|
|
1504
1559
|
* Unhold call
|
|
1505
1560
|
*/
|
|
1506
1561
|
unhold() {
|
|
1507
|
-
this.log.info(
|
|
1562
|
+
this.log.info('Uncall call');
|
|
1508
1563
|
this._phone.holdAllCalls();
|
|
1509
1564
|
this._webRTCSession.unhold();
|
|
1510
1565
|
}
|
|
@@ -1537,10 +1592,10 @@ export class Session extends EventEmitter {
|
|
|
1537
1592
|
sendDTMF(code, playLocal = true) {
|
|
1538
1593
|
// Check for correct DTMF and get frequencies
|
|
1539
1594
|
if (!(code in DTMF_FREQUENCY_TABLE)) {
|
|
1540
|
-
throw new Exceptions.InvalidParameter(
|
|
1595
|
+
throw new Exceptions.InvalidParameter('Invalid DTMF code');
|
|
1541
1596
|
}
|
|
1542
1597
|
|
|
1543
|
-
this.log.info(
|
|
1598
|
+
this.log.info('Sending DTMF: ' + code);
|
|
1544
1599
|
this._webRTCSession.sendDTMF(code);
|
|
1545
1600
|
|
|
1546
1601
|
if (playLocal) {
|
|
@@ -1548,15 +1603,15 @@ export class Session extends EventEmitter {
|
|
|
1548
1603
|
|
|
1549
1604
|
// First mute microphone before playing DTMF
|
|
1550
1605
|
if (this._isMuted) {
|
|
1551
|
-
this.log.debug(
|
|
1606
|
+
this.log.debug('Mic already muted, just sending DTMF');
|
|
1552
1607
|
this._phone.playTone(500, f[0], f[1]);
|
|
1553
1608
|
} else {
|
|
1554
|
-
this.log.debug(
|
|
1609
|
+
this.log.debug('Mute mic while sending DTMF');
|
|
1555
1610
|
this._webRTCSession.mute();
|
|
1556
1611
|
|
|
1557
1612
|
const self = this;
|
|
1558
1613
|
this._phone.playTone(500, f[0], f[1], function () {
|
|
1559
|
-
self.log.debug(
|
|
1614
|
+
self.log.debug('Unmute mic after DTMF');
|
|
1560
1615
|
self._webRTCSession.unmute();
|
|
1561
1616
|
});
|
|
1562
1617
|
}
|
|
@@ -1572,20 +1627,22 @@ export class Session extends EventEmitter {
|
|
|
1572
1627
|
this.log.info(`Transferring ${this.uuid} => ${dstSession.uuid}`);
|
|
1573
1628
|
|
|
1574
1629
|
// Create ReferSubscriber event class
|
|
1575
|
-
const referSubscriber = this._webRTCSession.refer(this._webRTCSession._request.ruri, {
|
|
1630
|
+
const referSubscriber = this._webRTCSession.refer(this._webRTCSession._request.ruri, {
|
|
1631
|
+
replaces: dstSession._webRTCSession,
|
|
1632
|
+
});
|
|
1576
1633
|
|
|
1577
1634
|
const self = this;
|
|
1578
1635
|
|
|
1579
1636
|
// Setup some logging
|
|
1580
|
-
referSubscriber.on(
|
|
1581
|
-
self.log.info(
|
|
1637
|
+
referSubscriber.on('requestSucceeded', function () {
|
|
1638
|
+
self.log.info('Transfer completed successfully');
|
|
1582
1639
|
});
|
|
1583
1640
|
|
|
1584
|
-
referSubscriber.on(
|
|
1641
|
+
referSubscriber.on('requestFailed', function (cause) {
|
|
1585
1642
|
self.log.error(`Transfer rejected: ${cause}`);
|
|
1586
1643
|
});
|
|
1587
1644
|
|
|
1588
|
-
referSubscriber.on(
|
|
1645
|
+
referSubscriber.on('failed', function (cause) {
|
|
1589
1646
|
self.log.error(`Transfer failed: ${cause}`);
|
|
1590
1647
|
});
|
|
1591
1648
|
}
|
|
@@ -1603,14 +1660,14 @@ export class Session extends EventEmitter {
|
|
|
1603
1660
|
playback(media_file_id, hangup_after = false) {
|
|
1604
1661
|
// Check event service is enabled first
|
|
1605
1662
|
if (!this._phone._options.connectEventService) {
|
|
1606
|
-
throw new Exceptions.NotAllowed(
|
|
1663
|
+
throw new Exceptions.NotAllowed('Event service not enabled');
|
|
1607
1664
|
}
|
|
1608
1665
|
|
|
1609
1666
|
this.log.info(`Playback media file ${media_file_id} hangup after ${hangup_after}`);
|
|
1610
1667
|
|
|
1611
|
-
const p = this._phone._eventClient.fireEvent(
|
|
1668
|
+
const p = this._phone._eventClient.fireEvent('call_command', {
|
|
1612
1669
|
call_uuid: this.uuid,
|
|
1613
|
-
call_command:
|
|
1670
|
+
call_command: 'playback',
|
|
1614
1671
|
media_file_id: media_file_id,
|
|
1615
1672
|
hangup_after: hangup_after,
|
|
1616
1673
|
});
|
|
@@ -1626,7 +1683,7 @@ export class Session extends EventEmitter {
|
|
|
1626
1683
|
// When playback starts set state to playback
|
|
1627
1684
|
p.then(() => {
|
|
1628
1685
|
// Set session state
|
|
1629
|
-
this._setSessionState(
|
|
1686
|
+
this._setSessionState('PLAYBACK');
|
|
1630
1687
|
});
|
|
1631
1688
|
}
|
|
1632
1689
|
|
|
@@ -1642,12 +1699,12 @@ export class Session extends EventEmitter {
|
|
|
1642
1699
|
* @throws InvalidOptions - If invalid mode given
|
|
1643
1700
|
*/
|
|
1644
1701
|
setWhisperMode(mode = 0) {
|
|
1645
|
-
if (!this.direction ===
|
|
1646
|
-
throw new Exceptions.NotAllowed(
|
|
1702
|
+
if (!this.direction === 'LISTEN') {
|
|
1703
|
+
throw new Exceptions.NotAllowed('Call is not correct type (listen)');
|
|
1647
1704
|
}
|
|
1648
1705
|
|
|
1649
1706
|
if (mode < 0 || mode > 2) {
|
|
1650
|
-
throw new Exceptions.InvalidOptions(
|
|
1707
|
+
throw new Exceptions.InvalidOptions('Invalid mode');
|
|
1651
1708
|
}
|
|
1652
1709
|
|
|
1653
1710
|
let t_dtmf_mode;
|
|
@@ -1705,13 +1762,13 @@ export class Session extends EventEmitter {
|
|
|
1705
1762
|
duration: Date.now() - self._callBeginTime,
|
|
1706
1763
|
durationStr: Tools.createDurationString(Date.now() - self._callBeginTime),
|
|
1707
1764
|
activeDuration: activeDuration,
|
|
1708
|
-
activeDurationStr: activeDuration ? Tools.createDurationString(activeDuration) :
|
|
1765
|
+
activeDurationStr: activeDuration ? Tools.createDurationString(activeDuration) : '',
|
|
1709
1766
|
};
|
|
1710
1767
|
|
|
1711
1768
|
try {
|
|
1712
|
-
self.emit(
|
|
1769
|
+
self.emit('callDurationUpdate', e);
|
|
1713
1770
|
} catch (e) {
|
|
1714
|
-
self.log.error(
|
|
1771
|
+
self.log.error('Exception in call duration update event: ' + e);
|
|
1715
1772
|
}
|
|
1716
1773
|
}, 1000);
|
|
1717
1774
|
}
|
|
@@ -1775,40 +1832,46 @@ export class Session extends EventEmitter {
|
|
|
1775
1832
|
for (let report of data.values()) {
|
|
1776
1833
|
// this.log.debug(report);
|
|
1777
1834
|
switch (report.type) {
|
|
1778
|
-
case
|
|
1835
|
+
case 'outbound-rtp':
|
|
1779
1836
|
// this.log.debug('Got: outbound-rtp');
|
|
1780
1837
|
// this.log.debug(report);
|
|
1781
1838
|
// Packets
|
|
1782
1839
|
totalReport.outboundPacketsSent = report.packetsSent;
|
|
1783
|
-
deltaReport.outboundPacketsSent =
|
|
1840
|
+
deltaReport.outboundPacketsSent =
|
|
1841
|
+
report.packetsSent - this._currentReport.outboundPacketsSent;
|
|
1784
1842
|
// Bytes
|
|
1785
1843
|
totalReport.outboundBytesSent = report.bytesSent;
|
|
1786
|
-
deltaReport.outboundBytesSent =
|
|
1844
|
+
deltaReport.outboundBytesSent =
|
|
1845
|
+
report.bytesSent - this._currentReport.outboundBytesSent;
|
|
1787
1846
|
break;
|
|
1788
1847
|
|
|
1789
|
-
case
|
|
1848
|
+
case 'inbound-rtp':
|
|
1790
1849
|
// this.log.debug('Got: inbound-rtp');
|
|
1791
1850
|
// this.log.debug(report);
|
|
1792
1851
|
// Packets
|
|
1793
1852
|
totalReport.inboundPacketsReceived = report.packetsReceived;
|
|
1794
|
-
deltaReport.inboundPacketsReceived =
|
|
1853
|
+
deltaReport.inboundPacketsReceived =
|
|
1854
|
+
report.packetsReceived - this._currentReport.inboundPacketsReceived;
|
|
1795
1855
|
// Bytes
|
|
1796
1856
|
totalReport.inboundBytesReceived = report.bytesReceived;
|
|
1797
|
-
deltaReport.inboundBytesReceived =
|
|
1857
|
+
deltaReport.inboundBytesReceived =
|
|
1858
|
+
report.bytesReceived - this._currentReport.inboundBytesReceived;
|
|
1798
1859
|
// Loss
|
|
1799
1860
|
totalReport.inboundPacketsLost = report.packetsLost;
|
|
1800
|
-
deltaReport.inboundPacketsLost =
|
|
1861
|
+
deltaReport.inboundPacketsLost =
|
|
1862
|
+
report.packetsLost - this._currentReport.inboundPacketsLost;
|
|
1801
1863
|
// Jitter
|
|
1802
1864
|
totalReport.inboundJitter = report.jitter * 1000;
|
|
1803
1865
|
deltaReport.inboundJitter = report.jitter * 1000;
|
|
1804
1866
|
break;
|
|
1805
1867
|
|
|
1806
|
-
case
|
|
1868
|
+
case 'remote-inbound-rtp':
|
|
1807
1869
|
// this.log.debug('Got: remote-inbound-rtp');
|
|
1808
1870
|
// this.log.debug(report);
|
|
1809
1871
|
// Loss
|
|
1810
1872
|
totalReport.outboundPacketsLost = report.packetsLost;
|
|
1811
|
-
deltaReport.outboundPacketsLost =
|
|
1873
|
+
deltaReport.outboundPacketsLost =
|
|
1874
|
+
report.packetsLost - this._currentReport.outboundPacketsLost;
|
|
1812
1875
|
// Jitter
|
|
1813
1876
|
totalReport.outboundJitter = report.jitter * 1000;
|
|
1814
1877
|
deltaReport.outboundJitter = report.jitter * 1000;
|
|
@@ -1834,9 +1897,9 @@ export class Session extends EventEmitter {
|
|
|
1834
1897
|
};
|
|
1835
1898
|
|
|
1836
1899
|
try {
|
|
1837
|
-
this.emit(
|
|
1900
|
+
this.emit('callQualityReportUpdate', finalReport);
|
|
1838
1901
|
} catch (e) {
|
|
1839
|
-
this.log.error(
|
|
1902
|
+
this.log.error('Exception in call quality report update event: ' + e);
|
|
1840
1903
|
}
|
|
1841
1904
|
}
|
|
1842
1905
|
});
|
|
@@ -1860,27 +1923,28 @@ export class Session extends EventEmitter {
|
|
|
1860
1923
|
// this.log.debug(`R factor loss effect ${lossEffect} / latency effect ${latencyEffect}`);
|
|
1861
1924
|
|
|
1862
1925
|
report.rFactor = Math.max(0, 100 - lossEffect - latencyEffect);
|
|
1863
|
-
report.mos =
|
|
1926
|
+
report.mos =
|
|
1927
|
+
1 + 0.035 * report.rFactor + 0.000007 * report.rFactor * (report.rFactor - 60) * (100 - report.rFactor);
|
|
1864
1928
|
|
|
1865
1929
|
// Quality string
|
|
1866
1930
|
switch (true) {
|
|
1867
1931
|
case report.rFactor < 50:
|
|
1868
|
-
report.qualityString =
|
|
1932
|
+
report.qualityString = 'Bad';
|
|
1869
1933
|
break;
|
|
1870
1934
|
case report.rFactor < 70:
|
|
1871
|
-
report.qualityString =
|
|
1935
|
+
report.qualityString = 'Poor';
|
|
1872
1936
|
break;
|
|
1873
1937
|
case report.rFactor < 80:
|
|
1874
|
-
report.qualityString =
|
|
1938
|
+
report.qualityString = 'Fair';
|
|
1875
1939
|
break;
|
|
1876
1940
|
case report.rFactor < 90:
|
|
1877
|
-
report.qualityString =
|
|
1941
|
+
report.qualityString = 'Good';
|
|
1878
1942
|
break;
|
|
1879
1943
|
case report.rFactor <= 100:
|
|
1880
|
-
report.qualityString =
|
|
1944
|
+
report.qualityString = 'Excellent';
|
|
1881
1945
|
break;
|
|
1882
1946
|
default:
|
|
1883
|
-
report.qualityString =
|
|
1947
|
+
report.qualityString = 'Error';
|
|
1884
1948
|
}
|
|
1885
1949
|
|
|
1886
1950
|
return report;
|
|
@@ -1914,7 +1978,7 @@ export class Session extends EventEmitter {
|
|
|
1914
1978
|
*
|
|
1915
1979
|
*/
|
|
1916
1980
|
|
|
1917
|
-
this.log.debug(
|
|
1981
|
+
this.log.debug('Session state: ' + state);
|
|
1918
1982
|
if (info) {
|
|
1919
1983
|
this.log.debug(info);
|
|
1920
1984
|
}
|
|
@@ -1922,7 +1986,7 @@ export class Session extends EventEmitter {
|
|
|
1922
1986
|
this._sessionState = state;
|
|
1923
1987
|
try {
|
|
1924
1988
|
this.emit(
|
|
1925
|
-
|
|
1989
|
+
'sessionStateChange',
|
|
1926
1990
|
Object.assign(
|
|
1927
1991
|
{
|
|
1928
1992
|
state: state,
|
|
@@ -1932,51 +1996,51 @@ export class Session extends EventEmitter {
|
|
|
1932
1996
|
),
|
|
1933
1997
|
);
|
|
1934
1998
|
} catch (e) {
|
|
1935
|
-
this.log.error(
|
|
1999
|
+
this.log.error('Exception in sessionStateChange event:' + e);
|
|
1936
2000
|
}
|
|
1937
2001
|
|
|
1938
2002
|
// Trigger callDataAvailable dummy event
|
|
1939
|
-
if (state ===
|
|
1940
|
-
this._callDisposition = this._manualDisposition ||
|
|
2003
|
+
if (state === 'TERMINATED') {
|
|
2004
|
+
this._callDisposition = this._manualDisposition || 'NORMAL';
|
|
1941
2005
|
this._callFinished();
|
|
1942
2006
|
}
|
|
1943
2007
|
|
|
1944
|
-
if (state ===
|
|
1945
|
-
if (info.cause ===
|
|
1946
|
-
this._callDisposition =
|
|
2008
|
+
if (state === 'FAILED') {
|
|
2009
|
+
if (info.cause === 'Unavailable') {
|
|
2010
|
+
this._callDisposition = 'TEMP_UNAVAIL';
|
|
1947
2011
|
if (this._phone.options.playSignalTones) {
|
|
1948
2012
|
this._phone._startRepeatTone(ST_TEMP_UNAVAIL);
|
|
1949
2013
|
}
|
|
1950
2014
|
}
|
|
1951
2015
|
|
|
1952
|
-
if (info.cause ===
|
|
1953
|
-
this._callDisposition =
|
|
2016
|
+
if (info.cause === 'Not Found') {
|
|
2017
|
+
this._callDisposition = 'INVALID_NUMBER';
|
|
1954
2018
|
if (this._phone.options.playSignalTones) {
|
|
1955
2019
|
this._phone._startRepeatTone(ST_INVALID_NUMBER);
|
|
1956
2020
|
}
|
|
1957
2021
|
}
|
|
1958
2022
|
|
|
1959
|
-
if (info.cause ===
|
|
1960
|
-
this._callDisposition = this._manualDisposition ||
|
|
2023
|
+
if (info.cause === 'Canceled') {
|
|
2024
|
+
this._callDisposition = this._manualDisposition || 'NO_ANSWER';
|
|
1961
2025
|
}
|
|
1962
2026
|
|
|
1963
|
-
if (info.cause ===
|
|
1964
|
-
if (this.direction ===
|
|
1965
|
-
this._callDisposition =
|
|
2027
|
+
if (info.cause === 'Rejected') {
|
|
2028
|
+
if (this.direction === 'INBOUND') {
|
|
2029
|
+
this._callDisposition = 'REJECTED';
|
|
1966
2030
|
} else {
|
|
1967
|
-
this._callDisposition =
|
|
2031
|
+
this._callDisposition = 'BARRED';
|
|
1968
2032
|
}
|
|
1969
2033
|
}
|
|
1970
2034
|
|
|
1971
|
-
if (info.cause ===
|
|
1972
|
-
this._callDisposition =
|
|
2035
|
+
if (info.cause === 'Busy') {
|
|
2036
|
+
this._callDisposition = 'BUSY';
|
|
1973
2037
|
if (this._phone.options.playSignalTones) {
|
|
1974
2038
|
this._phone._startRepeatTone(ST_BUSY);
|
|
1975
2039
|
}
|
|
1976
2040
|
}
|
|
1977
2041
|
|
|
1978
2042
|
// If session is incoming and failed, we don't fire calldataAvailable event
|
|
1979
|
-
if (this._webRTCSession.direction ===
|
|
2043
|
+
if (this._webRTCSession.direction === 'incoming') {
|
|
1980
2044
|
// return;
|
|
1981
2045
|
}
|
|
1982
2046
|
|
|
@@ -2006,7 +2070,7 @@ export class Session extends EventEmitter {
|
|
|
2006
2070
|
* @property {string} REJECTED Incoming call was rejected
|
|
2007
2071
|
*/
|
|
2008
2072
|
_callFinished() {
|
|
2009
|
-
this.log.info(
|
|
2073
|
+
this.log.info('Call finished');
|
|
2010
2074
|
|
|
2011
2075
|
// Fire callEnded event
|
|
2012
2076
|
this._fireCallEndedEvent();
|
|
@@ -2023,7 +2087,7 @@ export class Session extends EventEmitter {
|
|
|
2023
2087
|
|
|
2024
2088
|
// Set answer call timeout
|
|
2025
2089
|
_setAnswerCallTimeout(timeout) {
|
|
2026
|
-
this.log.debug(
|
|
2090
|
+
this.log.debug('Setting answer call timeout to: ' + timeout);
|
|
2027
2091
|
this._answerCallTimeout = timeout;
|
|
2028
2092
|
}
|
|
2029
2093
|
|
|
@@ -2035,9 +2099,9 @@ export class Session extends EventEmitter {
|
|
|
2035
2099
|
* @property {boolean} state - New recording state
|
|
2036
2100
|
*/
|
|
2037
2101
|
try {
|
|
2038
|
-
this.emit(
|
|
2102
|
+
this.emit('recordingStateChange', { state: this._isRecording, error: this._recordingError });
|
|
2039
2103
|
} catch (e) {
|
|
2040
|
-
this.log.error(
|
|
2104
|
+
this.log.error('Exception in recording state change event: ' + e);
|
|
2041
2105
|
}
|
|
2042
2106
|
}
|
|
2043
2107
|
|
|
@@ -2049,9 +2113,9 @@ export class Session extends EventEmitter {
|
|
|
2049
2113
|
* @property {boolean} state - Mute state (true = muted / false = unmuted)
|
|
2050
2114
|
*/
|
|
2051
2115
|
try {
|
|
2052
|
-
this.emit(
|
|
2116
|
+
this.emit('muteStateChange', { state: this._isMuted });
|
|
2053
2117
|
} catch (e) {
|
|
2054
|
-
this.log.error(
|
|
2118
|
+
this.log.error('Exception in mute state change event: ' + e);
|
|
2055
2119
|
}
|
|
2056
2120
|
}
|
|
2057
2121
|
|
|
@@ -2063,9 +2127,9 @@ export class Session extends EventEmitter {
|
|
|
2063
2127
|
* @property {boolean} state - New hold state
|
|
2064
2128
|
*/
|
|
2065
2129
|
try {
|
|
2066
|
-
this.emit(
|
|
2130
|
+
this.emit('holdStateChange', { state: this._isOnHold });
|
|
2067
2131
|
} catch (e) {
|
|
2068
|
-
this.log.error(
|
|
2132
|
+
this.log.error('Exception in hold state change event: ' + e);
|
|
2069
2133
|
}
|
|
2070
2134
|
}
|
|
2071
2135
|
|
|
@@ -2077,9 +2141,9 @@ export class Session extends EventEmitter {
|
|
|
2077
2141
|
* @property {boolean} mode - New whisper mode (0 = No whisper / 1 = Local only / 2 = Three way)
|
|
2078
2142
|
*/
|
|
2079
2143
|
try {
|
|
2080
|
-
this.emit(
|
|
2144
|
+
this.emit('whisperModeChange', { mode: this._whisperMode });
|
|
2081
2145
|
} catch (e) {
|
|
2082
|
-
this.log.error(
|
|
2146
|
+
this.log.error('Exception in whisper mode change event: ' + e);
|
|
2083
2147
|
}
|
|
2084
2148
|
}
|
|
2085
2149
|
|
|
@@ -2128,14 +2192,14 @@ export class Session extends EventEmitter {
|
|
|
2128
2192
|
|
|
2129
2193
|
// Add some extra convenience fields
|
|
2130
2194
|
e.durationStr = Tools.createDurationString(e.duration);
|
|
2131
|
-
e.answerDurationStr = e.answerDuration ? Tools.createDurationString(e.answerDuration) :
|
|
2132
|
-
e.activeDurationStr = e.activeDuration ? Tools.createDurationString(e.activeDuration) :
|
|
2195
|
+
e.answerDurationStr = e.answerDuration ? Tools.createDurationString(e.answerDuration) : '';
|
|
2196
|
+
e.activeDurationStr = e.activeDuration ? Tools.createDurationString(e.activeDuration) : '';
|
|
2133
2197
|
e.callQualityReport = this._currentReport;
|
|
2134
2198
|
|
|
2135
2199
|
try {
|
|
2136
|
-
this.emit(
|
|
2200
|
+
this.emit('callEnded', e);
|
|
2137
2201
|
} catch (e) {
|
|
2138
|
-
this.log.error(
|
|
2202
|
+
this.log.error('Exception in callEnded event: ' + e);
|
|
2139
2203
|
}
|
|
2140
2204
|
}
|
|
2141
2205
|
|
|
@@ -2146,10 +2210,10 @@ export class Session extends EventEmitter {
|
|
|
2146
2210
|
|
|
2147
2211
|
const self = this;
|
|
2148
2212
|
session.connection.ontrack = function (event) {
|
|
2149
|
-
self.log.debug(
|
|
2213
|
+
self.log.debug('Start media output (track):');
|
|
2150
2214
|
self.log.debug(event);
|
|
2151
2215
|
self._phone._remoteAudioElement.srcObject = event.streams[0];
|
|
2152
2216
|
};
|
|
2153
2217
|
}
|
|
2154
2218
|
}
|
|
2155
|
-
</code></pre></article></section></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"><div class="mobile-sidebar-wrapper"><div class="mobile-nav-links"></div><div class="mobile-sidebar-items-c"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="EventClient.html">EventClient</a></div><div class="sidebar-section-children"><a href="InvalidMediaDevice.html">InvalidMediaDevice</a></div><div class="sidebar-section-children"><a href="InvalidOptions.html">InvalidOptions</a></div><div class="sidebar-section-children"><a href="InvalidParameter.html">InvalidParameter</a></div><div class="sidebar-section-children"><a href="LogHandler.html">LogHandler</a></div><div class="sidebar-section-children"><a href="MediaNotPrepared.html">MediaNotPrepared</a></div><div class="sidebar-section-children"><a href="NoActiveSession.html">NoActiveSession</a></div><div class="sidebar-section-children"><a href="NotAllowed.html">NotAllowed</a></div><div class="sidebar-section-children"><a href="NotReady.html">NotReady</a></div><div class="sidebar-section-children"><a href="Phone.html">Phone</a></div><div class="sidebar-section-children"><a href="Request.html">Request</a></div><div class="sidebar-section-children"><a href="Requestor.html">Requestor</a></div><div class="sidebar-section-children"><a href="Session.html">Session</a></div><div class="sidebar-section-children"><a href="UnableToConnect.html">UnableToConnect</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-events"><div>Events</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#event:callDataInfo">callDataInfo</a></div><div class="sidebar-section-children"><a href="global.html#event:callDurationUpdate">callDurationUpdate</a></div><div class="sidebar-section-children"><a href="global.html#event:callEnded">callEnded</a></div><div class="sidebar-section-children"><a href="global.html#event:callQualityReportUpdate">callQualityReportUpdate</a></div><div class="sidebar-section-children"><a href="global.html#event:connectionStateChange">connectionStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:holdStateChange">holdStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:incomingCall">incomingCall</a></div><div class="sidebar-section-children"><a href="global.html#event:muteStateChange">muteStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:recordingStateChange">recordingStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:sessionCreated">sessionCreated</a></div><div class="sidebar-section-children"><a href="global.html#event:sessionRemoved">sessionRemoved</a></div><div class="sidebar-section-children"><a href="global.html#event:sessionStateChange">sessionStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:whisperModeChange">whisperModeChange</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-global"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#CALL_DIRECTION">CALL_DIRECTION</a></div><div class="sidebar-section-children"><a href="global.html#CALL_DISPOSITION">CALL_DISPOSITION</a></div><div class="sidebar-section-children"><a href="global.html#CONNECTION_STATE">CONNECTION_STATE</a></div><div class="sidebar-section-children"><a href="global.html#LOGLVL">LOGLVL</a></div><div class="sidebar-section-children"><a href="global.html#SESSION_STATE">SESSION_STATE</a></div></div></div><div class="mobile-navbar-actions"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div></div></div><script type="text/javascript" src="scripts/core.min.js"></script><script src="scripts/search.min.js" defer="defer"></script><script src="scripts/third-party/fuse.js" defer="defer"></script><script type="text/javascript">var tocbotInstance=tocbot.init({tocSelector:"#eed4d2a0bfd64539bb9df78095dec881",contentSelector:".main-content",headingSelector:"h1, h2, h3",hasInnerContainers:!0,scrollContainer:".main-content",headingsOffset:130,onClick:bringLinkToView})</script></body></html>
|
|
2219
|
+
</code></pre></article></section></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"><div class="mobile-sidebar-wrapper"><div class="mobile-nav-links"></div><div class="mobile-sidebar-items-c"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="EventClient.html">EventClient</a></div><div class="sidebar-section-children"><a href="EventServiceNotConnected.html">EventServiceNotConnected</a></div><div class="sidebar-section-children"><a href="InvalidMediaDevice.html">InvalidMediaDevice</a></div><div class="sidebar-section-children"><a href="InvalidOptions.html">InvalidOptions</a></div><div class="sidebar-section-children"><a href="InvalidParameter.html">InvalidParameter</a></div><div class="sidebar-section-children"><a href="LogHandler.html">LogHandler</a></div><div class="sidebar-section-children"><a href="MediaNotPrepared.html">MediaNotPrepared</a></div><div class="sidebar-section-children"><a href="NoActiveSession.html">NoActiveSession</a></div><div class="sidebar-section-children"><a href="NotAllowed.html">NotAllowed</a></div><div class="sidebar-section-children"><a href="NotReady.html">NotReady</a></div><div class="sidebar-section-children"><a href="Phone.html">Phone</a></div><div class="sidebar-section-children"><a href="Request.html">Request</a></div><div class="sidebar-section-children"><a href="Requestor.html">Requestor</a></div><div class="sidebar-section-children"><a href="Session.html">Session</a></div><div class="sidebar-section-children"><a href="UnableToConnect.html">UnableToConnect</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-events"><div>Events</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#event:callDataInfo">callDataInfo</a></div><div class="sidebar-section-children"><a href="global.html#event:callDurationUpdate">callDurationUpdate</a></div><div class="sidebar-section-children"><a href="global.html#event:callEnded">callEnded</a></div><div class="sidebar-section-children"><a href="global.html#event:callQualityReportUpdate">callQualityReportUpdate</a></div><div class="sidebar-section-children"><a href="global.html#event:connectionStateChange">connectionStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:holdStateChange">holdStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:incomingCall">incomingCall</a></div><div class="sidebar-section-children"><a href="global.html#event:muteStateChange">muteStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:recordingStateChange">recordingStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:sessionCreated">sessionCreated</a></div><div class="sidebar-section-children"><a href="global.html#event:sessionRemoved">sessionRemoved</a></div><div class="sidebar-section-children"><a href="global.html#event:sessionStateChange">sessionStateChange</a></div><div class="sidebar-section-children"><a href="global.html#event:whisperModeChange">whisperModeChange</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-global"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#CALL_DIRECTION">CALL_DIRECTION</a></div><div class="sidebar-section-children"><a href="global.html#CALL_DISPOSITION">CALL_DISPOSITION</a></div><div class="sidebar-section-children"><a href="global.html#CONNECTION_STATE">CONNECTION_STATE</a></div><div class="sidebar-section-children"><a href="global.html#LOGLVL">LOGLVL</a></div><div class="sidebar-section-children"><a href="global.html#SESSION_STATE">SESSION_STATE</a></div></div></div><div class="mobile-navbar-actions"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div></div></div><script type="text/javascript" src="scripts/core.min.js"></script><script src="scripts/search.min.js" defer="defer"></script><script src="scripts/third-party/fuse.js" defer="defer"></script><script type="text/javascript">var tocbotInstance=tocbot.init({tocSelector:"#eed4d2a0bfd64539bb9df78095dec881",contentSelector:".main-content",headingSelector:"h1, h2, h3",hasInnerContainers:!0,scrollContainer:".main-content",headingsOffset:130,onClick:bringLinkToView})</script></body></html>
|