@telegenta/webclient 3.1.1 → 3.2.0
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/README.md +61 -53
- package/dist/telegenta.js +204 -65
- package/dist/telegenta.min.js +1 -1
- package/docs/Phone.html +1 -1
- package/docs/Session.html +2 -2
- package/docs/data/search.json +1 -1
- package/docs/event-client.js.html +4 -4
- package/docs/global.html +3 -3
- package/docs/phone-client.js.html +190 -51
- package/docs/requestor.js.html +6 -6
- package/package.json +12 -3
|
@@ -3,10 +3,10 @@
|
|
|
3
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
4
|
import EventEmitter from 'events';
|
|
5
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';
|
|
6
|
+
import { LogHandler, LOGLVL } from './logger.js';
|
|
7
|
+
import * as Exceptions from './exceptions.js';
|
|
8
|
+
import * as Tools from './tools.js';
|
|
9
|
+
import { EventClient } from './event-client.js';
|
|
10
10
|
import camelcaseKeys from 'camelcase-keys';
|
|
11
11
|
|
|
12
12
|
const options = {
|
|
@@ -112,6 +112,9 @@ export class Phone extends EventEmitter {
|
|
|
112
112
|
this._eventClient = null;
|
|
113
113
|
this._options = null;
|
|
114
114
|
|
|
115
|
+
// getUserMedia audio constraint: true (default device) or { deviceId: { exact } }
|
|
116
|
+
this._audioConstraints = true;
|
|
117
|
+
|
|
115
118
|
// List of active sessions
|
|
116
119
|
this._sessionCounter = 0;
|
|
117
120
|
this._activeSessions = {};
|
|
@@ -127,6 +130,7 @@ export class Phone extends EventEmitter {
|
|
|
127
130
|
this._repeatToneActive = false;
|
|
128
131
|
this._repeatToneSequence = [];
|
|
129
132
|
this._repeatToneSequencePos = 0;
|
|
133
|
+
this._toneContext = null;
|
|
130
134
|
this._toneGainProcessor = null;
|
|
131
135
|
this._oscillator1 = null;
|
|
132
136
|
this._oscillator2 = null;
|
|
@@ -146,29 +150,83 @@ export class Phone extends EventEmitter {
|
|
|
146
150
|
* Prepare media and get media permission from browser
|
|
147
151
|
* This must be done prior to using the phone or getting device lists.
|
|
148
152
|
*
|
|
149
|
-
*
|
|
153
|
+
* On failure the previously selected input device (see {@link setInputDevice}) and the
|
|
154
|
+
* current media-permission state are left untouched, unless the browser reports the
|
|
155
|
+
* request was actually denied (NotAllowedError / SecurityError), in which case
|
|
156
|
+
* hasMediaPermission/hasMediaPermissionError are updated to reflect that.
|
|
150
157
|
*
|
|
158
|
+
* @param {object} [mediaOptions]
|
|
159
|
+
* @param {string} [mediaOptions.deviceId] Microphone deviceId (from enumerateDevices); omit or leave
|
|
160
|
+
* out to select the browser default device, which also resets a device previously chosen with
|
|
161
|
+
* {@link setInputDevice}
|
|
162
|
+
* @return {Promise} Resolved when user accepts access to media devices; rejected (never thrown
|
|
163
|
+
* synchronously) otherwise, e.g. when the browser denies permission or has no mediaDevices API
|
|
151
164
|
*/
|
|
152
|
-
prepareMedia() {
|
|
165
|
+
async prepareMedia(mediaOptions = {}) {
|
|
153
166
|
this.log.info('Get media permission');
|
|
154
|
-
const
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
167
|
+
const deviceId = (mediaOptions || {}).deviceId || null;
|
|
168
|
+
const audioConstraints = deviceId ? { deviceId: { exact: deviceId } } : true;
|
|
169
|
+
const constraints = { audio: audioConstraints, video: false };
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
173
|
+
// Only the permission is needed here; release the device again.
|
|
174
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
175
|
+
this.setInputDevice(deviceId);
|
|
176
|
+
this._mediaPermission = true;
|
|
177
|
+
this._mediaPermissionError = false;
|
|
178
|
+
this.log.info('Media permission granted');
|
|
179
|
+
} catch (err) {
|
|
180
|
+
if (err && (err.name === 'NotAllowedError' || err.name === 'SecurityError')) {
|
|
181
|
+
this._mediaPermission = false;
|
|
182
|
+
this._mediaPermissionError = true;
|
|
183
|
+
this.log.error('Denied media permission: ' + err);
|
|
184
|
+
} else {
|
|
185
|
+
this.log.error('Unable to get requested media device: ' + err);
|
|
186
|
+
}
|
|
187
|
+
throw err;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Select the microphone used for subsequent calls and answers.
|
|
193
|
+
* @param {string|null} deviceId Microphone deviceId, or null for the browser default
|
|
194
|
+
*/
|
|
195
|
+
setInputDevice(deviceId) {
|
|
196
|
+
this._audioConstraints = deviceId ? { deviceId: { exact: deviceId } } : true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Current getUserMedia audio constraint (true = default device)
|
|
201
|
+
*/
|
|
202
|
+
get audioConstraints() {
|
|
203
|
+
return this._audioConstraints;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* True when the browser can route audio to a chosen output device (HTMLMediaElement.setSinkId)
|
|
208
|
+
*/
|
|
209
|
+
get outputDeviceSelectionSupported() {
|
|
210
|
+
return typeof this._remoteAudioElement.setSinkId === 'function';
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Route call audio and signal tones to an output device.
|
|
215
|
+
* @param {string|null} deviceId Output deviceId (from enumerateDevices), or null for the default
|
|
216
|
+
* @return {Promise<boolean>} false when the browser does not support output selection
|
|
217
|
+
* @throws Rejects if the browser's HTMLMediaElement.setSinkId() call rejects, e.g. for an
|
|
218
|
+
* unknown deviceId or one the browser is not allowed to use (NotAllowedError)
|
|
219
|
+
*/
|
|
220
|
+
async setOutputDevice(deviceId) {
|
|
221
|
+
if (!this.outputDeviceSelectionSupported) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
const sinkId = deviceId || '';
|
|
225
|
+
await Promise.all([
|
|
226
|
+
this._remoteAudioElement.setSinkId(sinkId),
|
|
227
|
+
this._toneAudioElement.setSinkId(sinkId),
|
|
228
|
+
]);
|
|
229
|
+
return true;
|
|
172
230
|
}
|
|
173
231
|
|
|
174
232
|
/**
|
|
@@ -204,16 +262,16 @@ export class Phone extends EventEmitter {
|
|
|
204
262
|
}
|
|
205
263
|
|
|
206
264
|
// Apply options
|
|
207
|
-
this._options = Object.assign(options, phoneOptions);
|
|
265
|
+
this._options = Object.assign({}, options, phoneOptions);
|
|
208
266
|
|
|
209
267
|
this._initToneGenerator();
|
|
210
268
|
|
|
211
269
|
// Unpack provisioning token if specified
|
|
212
270
|
if (this._options.provisionToken) {
|
|
213
|
-
let pt
|
|
271
|
+
let pt;
|
|
214
272
|
try {
|
|
215
273
|
pt = JSON.parse(atob(this._options.provisionToken));
|
|
216
|
-
} catch
|
|
274
|
+
} catch {
|
|
217
275
|
throw new Exceptions.InvalidOptions('provisionToken', 'Invalid token');
|
|
218
276
|
}
|
|
219
277
|
|
|
@@ -289,7 +347,7 @@ export class Phone extends EventEmitter {
|
|
|
289
347
|
);
|
|
290
348
|
}
|
|
291
349
|
|
|
292
|
-
let wsSocket
|
|
350
|
+
let wsSocket;
|
|
293
351
|
try {
|
|
294
352
|
wsSocket = new JsSIP.WebSocketInterface(this._options.wssServer);
|
|
295
353
|
} catch (err) {
|
|
@@ -367,8 +425,11 @@ export class Phone extends EventEmitter {
|
|
|
367
425
|
self._setConnectionState('UNREGISTERED');
|
|
368
426
|
});
|
|
369
427
|
|
|
370
|
-
this._UA.on('registrationFailed', function (
|
|
371
|
-
self._setConnectionState('REGISTRATION_FAILED'
|
|
428
|
+
this._UA.on('registrationFailed', function (data) {
|
|
429
|
+
self._setConnectionState('REGISTRATION_FAILED', {
|
|
430
|
+
cause: data?.cause,
|
|
431
|
+
statusCode: data?.response?.status_code,
|
|
432
|
+
});
|
|
372
433
|
});
|
|
373
434
|
|
|
374
435
|
this._UA.start();
|
|
@@ -393,6 +454,11 @@ export class Phone extends EventEmitter {
|
|
|
393
454
|
this._UA.stop();
|
|
394
455
|
delete this._UA;
|
|
395
456
|
|
|
457
|
+
// Always mark the phone stopped from here on, even if there is no event client to
|
|
458
|
+
// disconnect below - otherwise isStarted stays true and a later start() would try to
|
|
459
|
+
// stop() this same (already torn down) instance again.
|
|
460
|
+
this._isStarted = false;
|
|
461
|
+
|
|
396
462
|
// Disconnect event client if needed
|
|
397
463
|
if (!this._eventClient) {
|
|
398
464
|
this.log.debug('Event client not running, not stopping');
|
|
@@ -401,14 +467,26 @@ export class Phone extends EventEmitter {
|
|
|
401
467
|
try {
|
|
402
468
|
this._eventClient.disconnect();
|
|
403
469
|
delete this._eventClient;
|
|
404
|
-
} catch
|
|
470
|
+
} catch {
|
|
405
471
|
this.log.warning('Unable to disconnect event client');
|
|
406
472
|
}
|
|
407
|
-
|
|
408
|
-
this._isStarted = false;
|
|
409
473
|
this.log.info('Phone client successfully stopped');
|
|
410
474
|
}
|
|
411
475
|
|
|
476
|
+
/**
|
|
477
|
+
* Re-send REGISTER without tearing down the websocket connection or any active calls.
|
|
478
|
+
* Use this to recover from a REGISTER refresh that failed for a reason other than bad
|
|
479
|
+
* credentials (e.g. a timeout or a 5xx from the registrar) while the transport itself stayed
|
|
480
|
+
* up - JsSIP does not retry those on its own. Safe to call during an active call.
|
|
481
|
+
* @throws NotReady - If phone is not started
|
|
482
|
+
*/
|
|
483
|
+
register() {
|
|
484
|
+
if (!this._isStarted) {
|
|
485
|
+
throw new Exceptions.NotReady('Phone is not started');
|
|
486
|
+
}
|
|
487
|
+
this._UA.register();
|
|
488
|
+
}
|
|
489
|
+
|
|
412
490
|
/**
|
|
413
491
|
* Start a new call
|
|
414
492
|
* If you have other active calls they will be set on hold
|
|
@@ -492,7 +570,7 @@ export class Phone extends EventEmitter {
|
|
|
492
570
|
*/
|
|
493
571
|
getSessionByUUID(uuid) {
|
|
494
572
|
for (let key in this._activeSessions) {
|
|
495
|
-
if (this._activeSessions
|
|
573
|
+
if (Object.hasOwn(this._activeSessions, key)) {
|
|
496
574
|
if (this._activeSessions[key].uuid === uuid) {
|
|
497
575
|
return this._activeSessions[key];
|
|
498
576
|
}
|
|
@@ -510,6 +588,27 @@ export class Phone extends EventEmitter {
|
|
|
510
588
|
return this._options;
|
|
511
589
|
}
|
|
512
590
|
|
|
591
|
+
/**
|
|
592
|
+
* Replace the call token used by subsequent calls and answers.
|
|
593
|
+
* Call tokens expire (30 min); renew via the API and pass the new token here.
|
|
594
|
+
*
|
|
595
|
+
* With useCallDataInfoEvent, the callDataInfo subscription keeps the token from start();
|
|
596
|
+
* call start() again to move it to the new token.
|
|
597
|
+
*
|
|
598
|
+
* @param {string} token New call token
|
|
599
|
+
* @throws NotReady - If phone is not started
|
|
600
|
+
* @throws InvalidOptions - If token is empty
|
|
601
|
+
*/
|
|
602
|
+
setCallToken(token) {
|
|
603
|
+
if (!this._isStarted) {
|
|
604
|
+
throw new Exceptions.NotReady('Phone is not started');
|
|
605
|
+
}
|
|
606
|
+
if (!token) {
|
|
607
|
+
throw new Exceptions.InvalidOptions('callToken', 'Missing call token');
|
|
608
|
+
}
|
|
609
|
+
this._options.callToken = token;
|
|
610
|
+
}
|
|
611
|
+
|
|
513
612
|
/**
|
|
514
613
|
* Return list of current sessions
|
|
515
614
|
* @returns [Session]
|
|
@@ -517,7 +616,7 @@ export class Phone extends EventEmitter {
|
|
|
517
616
|
get sessions() {
|
|
518
617
|
let s = [];
|
|
519
618
|
for (let key in this._activeSessions) {
|
|
520
|
-
if (this._activeSessions
|
|
619
|
+
if (Object.hasOwn(this._activeSessions, key)) {
|
|
521
620
|
s.push(this._activeSessions[key]);
|
|
522
621
|
}
|
|
523
622
|
}
|
|
@@ -575,6 +674,7 @@ export class Phone extends EventEmitter {
|
|
|
575
674
|
*/
|
|
576
675
|
playTone(duration, freq1, freq2 = 0, callback = null) {
|
|
577
676
|
this.log.debug(`Playing tone ${freq1} / ${freq2} for ${duration} ms`);
|
|
677
|
+
this._resumeToneContext();
|
|
578
678
|
|
|
579
679
|
this._oscillator1.frequency.value = freq1;
|
|
580
680
|
this._oscillator2.frequency.value = freq2;
|
|
@@ -641,8 +741,35 @@ export class Phone extends EventEmitter {
|
|
|
641
741
|
}
|
|
642
742
|
}
|
|
643
743
|
|
|
644
|
-
|
|
744
|
+
/**
|
|
745
|
+
* Resume the Web Audio context behind signal tones (ringing, ringback, busy, DTMF feedback).
|
|
746
|
+
* Browsers create an AudioContext "suspended" when it is not created during a user gesture
|
|
747
|
+
* (e.g. a phone started on page load); call this from a user-gesture handler (click, keydown)
|
|
748
|
+
* so tones are audible. Safe to call before {@link start} and any number of times.
|
|
749
|
+
* @return {Promise<boolean>} false when the browser has no Web Audio API or resuming failed
|
|
750
|
+
*/
|
|
751
|
+
async resumeAudio() {
|
|
752
|
+
try {
|
|
753
|
+
this._initToneGenerator();
|
|
754
|
+
} catch {
|
|
755
|
+
return false;
|
|
756
|
+
}
|
|
757
|
+
try {
|
|
758
|
+
await this._toneContext.resume();
|
|
759
|
+
return this._toneContext.state === 'running';
|
|
760
|
+
} catch (err) {
|
|
761
|
+
this.log.warning('Unable to resume audio context: ' + err);
|
|
762
|
+
return false;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// Initialize tone generator. One AudioContext per Phone, reused across start()/stop() -
|
|
767
|
+
// browsers cap the number of live contexts and a new one per start() would leak.
|
|
645
768
|
_initToneGenerator() {
|
|
769
|
+
if (this._toneContext && this._toneContext.state !== 'closed') {
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
|
|
646
773
|
// Create audio context
|
|
647
774
|
const AudioContext = window.AudioContext || window.webkitAudioContext || false;
|
|
648
775
|
if (!AudioContext) {
|
|
@@ -650,6 +777,7 @@ export class Phone extends EventEmitter {
|
|
|
650
777
|
}
|
|
651
778
|
|
|
652
779
|
const ctx = new AudioContext();
|
|
780
|
+
this._toneContext = ctx;
|
|
653
781
|
this._toneStreamNode = ctx.createMediaStreamDestination();
|
|
654
782
|
this._toneAudioElement.srcObject = this._toneStreamNode.stream;
|
|
655
783
|
|
|
@@ -669,6 +797,14 @@ export class Phone extends EventEmitter {
|
|
|
669
797
|
this._oscillator2.start();
|
|
670
798
|
}
|
|
671
799
|
|
|
800
|
+
// Best effort: a context created outside a user gesture is suspended until resumed.
|
|
801
|
+
_resumeToneContext() {
|
|
802
|
+
const ctx = this._toneContext;
|
|
803
|
+
if (ctx && ctx.state === 'suspended' && typeof ctx.resume === 'function') {
|
|
804
|
+
ctx.resume().catch((err) => this.log.debug('Audio context resume refused: ' + err));
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
672
808
|
/**
|
|
673
809
|
* Hold all active calls
|
|
674
810
|
* @throws NotAllowed If there are connection calls
|
|
@@ -682,7 +818,7 @@ export class Phone extends EventEmitter {
|
|
|
682
818
|
|
|
683
819
|
// Iterate through all active calls and hold them
|
|
684
820
|
for (let key in this._activeSessions) {
|
|
685
|
-
if (this._activeSessions
|
|
821
|
+
if (Object.hasOwn(this._activeSessions, key)) {
|
|
686
822
|
let session = this._activeSessions[key];
|
|
687
823
|
if (session.state === 'ACTIVE') {
|
|
688
824
|
session.hold();
|
|
@@ -756,7 +892,7 @@ export class Phone extends EventEmitter {
|
|
|
756
892
|
// Return true if there are calls currently connecting
|
|
757
893
|
_checkForConnectingCalls() {
|
|
758
894
|
for (let key in this._activeSessions) {
|
|
759
|
-
if (this._activeSessions
|
|
895
|
+
if (Object.hasOwn(this._activeSessions, key)) {
|
|
760
896
|
let session = this._activeSessions[key];
|
|
761
897
|
if (
|
|
762
898
|
session.state === 'INITIALIZING' ||
|
|
@@ -781,17 +917,23 @@ export class Phone extends EventEmitter {
|
|
|
781
917
|
* @property {string} REGISTRATION_FAILED Registration failed
|
|
782
918
|
*/
|
|
783
919
|
// Set connection state and emit event
|
|
784
|
-
_setConnectionState(state) {
|
|
920
|
+
_setConnectionState(state, extra = {}) {
|
|
785
921
|
/**
|
|
786
922
|
* @event connectionStateChange
|
|
787
923
|
* @type {object}
|
|
788
924
|
* @param {CONNECTION_STATE} state - The current connection state
|
|
925
|
+
* @param {string} [cause] - For REGISTRATION_FAILED only: JsSIP's registrationFailed
|
|
926
|
+
* cause, e.g. 'Connection Error', 'Request Timeout' (network/transport issues, JsSIP
|
|
927
|
+
* will keep retrying on its own), 'Authentication Error' (401), or 'Rejected' (403 -
|
|
928
|
+
* account disabled or credentials rejected by the registrar)
|
|
929
|
+
* @param {number} [statusCode] - For REGISTRATION_FAILED only: the SIP status code of
|
|
930
|
+
* the failed REGISTER response, when JsSIP received one (e.g. 401, 403)
|
|
789
931
|
*/
|
|
790
932
|
|
|
791
933
|
this.log.info('Connection state: ' + state);
|
|
792
934
|
this._connectionState = state;
|
|
793
935
|
try {
|
|
794
|
-
this.emit('connectionStateChange', { state: state });
|
|
936
|
+
this.emit('connectionStateChange', { state: state, ...extra });
|
|
795
937
|
} catch (e) {
|
|
796
938
|
this.log.error('Exception in connectionStateChange event: ' + e);
|
|
797
939
|
}
|
|
@@ -839,18 +981,15 @@ export class Phone extends EventEmitter {
|
|
|
839
981
|
* @param {string} effectiveCidNameStr - Phone number name used as a-number for call
|
|
840
982
|
* @param {boolean} callPrivacy - Call privacy used for call (number hidden)
|
|
841
983
|
* @param {number} hangupCauseQ850 - Q.850 hangup cause code
|
|
842
|
-
* @param {Object[]} recordings - List of recordings done for this call
|
|
843
|
-
* @param {number} recordings[].startTime - Time recording was started
|
|
844
|
-
* @param {number} recordings[].length - Recording length in milliseconds
|
|
845
|
-
* @param {number} recordings[].size - Recording size (bytes)
|
|
846
|
-
* @param {number} recordings[].urlPlayer - URL for recording with player
|
|
847
|
-
* @param {number} recordings[].url - URL for recording without player
|
|
848
|
-
* @param {number} recordings[].retentionDate - Date recording will be automatically deleted
|
|
849
984
|
*/
|
|
850
985
|
|
|
851
986
|
let e;
|
|
852
987
|
e = camelcaseKeys(eventData);
|
|
853
|
-
|
|
988
|
+
// The call data event no longer carries recordings. Uploads are
|
|
989
|
+
// asynchronous, so the array was almost always empty by the time the CDR
|
|
990
|
+
// was processed, and the event cannot be re-fired once a recording lands
|
|
991
|
+
// because call_token is never persisted on the CDR. A dedicated
|
|
992
|
+
// "recording ready" event will replace it.
|
|
854
993
|
|
|
855
994
|
// Event all duration fields are in seconds, convert to millisecs
|
|
856
995
|
e.duration = e.duration * 1000;
|
|
@@ -943,7 +1082,7 @@ export class Session extends EventEmitter {
|
|
|
943
1082
|
this.destinationNumber = number;
|
|
944
1083
|
|
|
945
1084
|
let options = {
|
|
946
|
-
mediaConstraints: { audio:
|
|
1085
|
+
mediaConstraints: { audio: this._phone.audioConstraints, video: false },
|
|
947
1086
|
pcConfig: {
|
|
948
1087
|
iceServers: [{ urls: ['stun:stun.l.google.com:19302'] }],
|
|
949
1088
|
},
|
|
@@ -1140,7 +1279,7 @@ export class Session extends EventEmitter {
|
|
|
1140
1279
|
self.log.info(`Answer call timeout after ${self._answerCallTimeout} seconds`);
|
|
1141
1280
|
try {
|
|
1142
1281
|
self.hangup();
|
|
1143
|
-
} catch
|
|
1282
|
+
} catch {
|
|
1144
1283
|
self.log.info('No active session, ignoring answer call timeout');
|
|
1145
1284
|
}
|
|
1146
1285
|
}, self._answerCallTimeout * 1000);
|
|
@@ -1297,7 +1436,7 @@ export class Session extends EventEmitter {
|
|
|
1297
1436
|
*/
|
|
1298
1437
|
answer(metaInfo = null) {
|
|
1299
1438
|
let options = {
|
|
1300
|
-
mediaConstraints: { audio:
|
|
1439
|
+
mediaConstraints: { audio: this._phone.audioConstraints, video: false },
|
|
1301
1440
|
pcConfig: {
|
|
1302
1441
|
iceServers: [{ urls: ['stun:stun.l.google.com:19302'] }],
|
|
1303
1442
|
},
|
package/docs/requestor.js.html
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
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: requestor.js</title><!--[if lt IE 9]>
|
|
2
2
|
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
3
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">requestor.js</h1></header><article><pre class="prettyprint source lang-js"><code>import EventEmitter from "events";
|
|
4
|
-
import * as Logger from "./logger";
|
|
5
|
-
import * as Exceptions from "./exceptions";
|
|
6
|
-
import { createUUID } from "./tools";
|
|
7
|
-
import { NotAllowed } from "./exceptions";
|
|
4
|
+
import * as Logger from "./logger.js";
|
|
5
|
+
import * as Exceptions from "./exceptions.js";
|
|
6
|
+
import { createUUID } from "./tools.js";
|
|
7
|
+
import { NotAllowed } from "./exceptions.js";
|
|
8
8
|
|
|
9
9
|
// Request timeout after 10 sec
|
|
10
10
|
const REQUEST_TIMEOUT = 10000;
|
|
@@ -78,13 +78,13 @@ export class Requestor extends EventEmitter {
|
|
|
78
78
|
let msg;
|
|
79
79
|
try {
|
|
80
80
|
msg = JSON.parse(message);
|
|
81
|
-
} catch
|
|
81
|
+
} catch {
|
|
82
82
|
this.log.warning("Unable to parse message: " + message);
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
// Validate msg fields
|
|
87
|
-
if (!
|
|
87
|
+
if (!Object.hasOwn(msg, "type") || !Object.hasOwn(msg, "id")) {
|
|
88
88
|
this.log.warning(`Invalid message received: ${msg} - missing type or id`);
|
|
89
89
|
return;
|
|
90
90
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@telegenta/webclient",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Webphone and event client library",
|
|
6
6
|
"main": "dist/telegenta.js",
|
|
@@ -9,11 +9,18 @@
|
|
|
9
9
|
"watch-docs": "rimraf docs && watch 'npm run build-docs'",
|
|
10
10
|
"build-docs": "rimraf docs && npx jsdoc -c jsdoc.conf.json",
|
|
11
11
|
"deploy-docs": "aws s3 cp docs/ s3://www.telegenta.com/docs/client-lib/$npm_package_version --recursive --profile telegenta && aws cloudfront --profile telegenta create-invalidation --distribution-id E1A9LQ3WGY7RF9 --paths /docs/*",
|
|
12
|
-
"test": "node --test",
|
|
12
|
+
"test": "node --test test/*.test.js",
|
|
13
|
+
"lint": "eslint .",
|
|
14
|
+
"lint:fix": "eslint . --fix",
|
|
13
15
|
"deploy-demos": "aws s3 cp demos/ s3://www.telegenta.com/demos/ --recursive --profile telegenta && aws cloudfront --profile telegenta create-invalidation --distribution-id E1A9LQ3WGY7RF9 --paths /demos/* ",
|
|
14
16
|
"build": "rimraf dist && rollup -c",
|
|
15
17
|
"dev": "rollup -c -w"
|
|
16
18
|
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/akantodevs/telegenta.git",
|
|
22
|
+
"directory": "client-lib"
|
|
23
|
+
},
|
|
17
24
|
"author": "Allan Kristensen",
|
|
18
25
|
"license": "MIT",
|
|
19
26
|
"dependencies": {
|
|
@@ -22,12 +29,14 @@
|
|
|
22
29
|
"jssip": "^3.10.1"
|
|
23
30
|
},
|
|
24
31
|
"devDependencies": {
|
|
32
|
+
"@eslint/js": "^10.0.1",
|
|
25
33
|
"@rollup/plugin-commonjs": "^29.0.0",
|
|
26
34
|
"@rollup/plugin-json": "^6.1.0",
|
|
27
35
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
28
36
|
"@rollup/plugin-terser": "^0.4.4",
|
|
29
37
|
"clean-jsdoc-theme": "^4.3.0",
|
|
30
|
-
"eslint": "^
|
|
38
|
+
"eslint": "^10.9.1",
|
|
39
|
+
"globals": "^17.11.0",
|
|
31
40
|
"jsdoc": "^4.0.5",
|
|
32
41
|
"rimraf": "^6.1.2",
|
|
33
42
|
"rollup": "^2.79.2"
|