@telegenta/webclient 3.1.1 → 3.1.2
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 +34 -53
- package/dist/telegenta.js +26 -26
- package/dist/telegenta.min.js +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -39,63 +39,49 @@ and you are ready to go. The client has no external requirements (like jQuery an
|
|
|
39
39
|
|
|
40
40
|
Before starting, you will need an account on telegenta.com, to create sip accounts and api tokens.
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
Runnable examples live in `demos/`. They load the browser bundle from `../dist/telegenta.min.js`, so
|
|
43
|
+
run `npm run build` first, then serve the directory over https. WebRTC requires a secure context;
|
|
44
|
+
`localhost` counts as secure, but opening a demo as `file://...` does not - media permissions are not
|
|
45
|
+
remembered there, so you will be prompted for the microphone every time.
|
|
43
46
|
|
|
44
|
-
|
|
47
|
+
#### Example: phone with a provisioning token
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
library /embedded_client/index.html and modify the credentials:
|
|
49
|
+
`demos/phone_client.html` is a complete softphone - start/stop, outbound calls, transfer, listen-in,
|
|
50
|
+
incoming calls and the event client.
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
var USERNAME='your username';
|
|
53
|
-
var PASSWORD='your password';
|
|
54
|
-
|
|
55
|
-
window.onload = function () {
|
|
56
|
-
...
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Now open the file (index.html) in your browser. After you have been prompted for permission to use the audio devices,
|
|
60
|
-
you should have a working phone.
|
|
61
|
-
Note: If you are viewing a file using "file://index.html", it is not considered a secure connection by the browser
|
|
62
|
-
and media permissions are not remembered, so you will be prompted every time you open the file.
|
|
63
|
-
However, once you move the file to a secure webserver (https), this will no longer be an issue.
|
|
64
|
-
|
|
65
|
-
#### Example 2: Using SIP Flex accounts
|
|
52
|
+
First create a static API token in the admin interface
|
|
53
|
+
(https://admin.telegenta.com/integration/access-tokens). Open the demo and paste the token in; it then
|
|
66
54
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
For this example we need a backend service and we provide a simple example in PHP using the built in Webserver.
|
|
55
|
+
1. requests a short-lived provisioning token with `GET /api/get-call-session/?id=<account id>`, and
|
|
56
|
+
2. starts the phone with that token:
|
|
70
57
|
|
|
71
|
-
|
|
58
|
+
```
|
|
59
|
+
const opts = {
|
|
60
|
+
// Enable event client
|
|
61
|
+
connectEventService: true,
|
|
72
62
|
|
|
73
|
-
|
|
74
|
-
|
|
63
|
+
// Subscribe to detailed information about call after processing
|
|
64
|
+
useCallDataInfoEvent: true,
|
|
75
65
|
|
|
76
|
-
|
|
66
|
+
// Enable incoming calls (you must set a phone number to call the account also)
|
|
67
|
+
register: true,
|
|
77
68
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
69
|
+
// Configure client with provision token
|
|
70
|
+
provisionToken: data.provision_token,
|
|
71
|
+
};
|
|
81
72
|
|
|
82
|
-
|
|
83
|
-
// It possible to have multiple sip flex accounts with different configurations
|
|
84
|
-
$flex_identification = 'test';
|
|
85
|
-
...
|
|
73
|
+
phoneClient.start(opts);
|
|
86
74
|
```
|
|
87
75
|
|
|
88
|
-
|
|
76
|
+
Issuing the provisioning token from your own backend is the recommended integration: the short-lived
|
|
77
|
+
token is all that reaches the browser, and your API token stays on the server.
|
|
89
78
|
|
|
90
|
-
|
|
91
|
-
cd embedded_client
|
|
92
|
-
php -S localhost:9000
|
|
93
|
-
```
|
|
79
|
+
The remaining demos cover narrower cases:
|
|
94
80
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
81
|
+
- `demos/event_client.html` - the event client on its own, without a phone
|
|
82
|
+
- `demos/calldata_available.html` - subscribing to call data after a call completes
|
|
83
|
+
- `demos/add_phone_number.html` - adding a phone number through the API
|
|
84
|
+
- `demos/embedded_config.html` - embedding the admin config pages with a config token
|
|
99
85
|
|
|
100
86
|
## Approaching the integration
|
|
101
87
|
|
|
@@ -106,15 +92,10 @@ Depending on how much flexibility you need, you can choose between the following
|
|
|
106
92
|
We believe in using standard protocols as much as possible and it will work nicely, but you need to address most
|
|
107
93
|
of the issues we listed above in the previous section yourself.
|
|
108
94
|
|
|
109
|
-
2. Use our free library
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
We have made a simple phone with frontend, which can be easily included in your own project. Just grab the
|
|
114
|
-
index.html, style.css and embedded_phone.js and insert it into your own project.
|
|
115
|
-
We named the JS and CSS to try and avoid any potential conflicts.
|
|
116
|
-
You only need to provide it with credentials or provisioning token (as in the example above) from you backend and
|
|
117
|
-
you are set to start calling.
|
|
95
|
+
2. Use our free library and provide your own frontend.
|
|
96
|
+
Load `dist/telegenta.min.js` in the browser (global `Telegenta`) or import the package in your
|
|
97
|
+
bundler, then handle events and use javascript methods like call, hangup, startRecord, etc..
|
|
98
|
+
`demos/phone_client.html` shows the whole flow end to end.
|
|
118
99
|
|
|
119
100
|
## Migrating from 2.x
|
|
120
101
|
|
package/dist/telegenta.js
CHANGED
|
@@ -25,23 +25,23 @@ class LogHandler {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
debug(...args) {
|
|
28
|
-
this._doLog(LOGLVL
|
|
28
|
+
this._doLog(LOGLVL.DEBUG, args);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
info(...args) {
|
|
32
|
-
this._doLog(LOGLVL
|
|
32
|
+
this._doLog(LOGLVL.INFO, args);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
warn(...args) {
|
|
36
|
-
this._doLog(LOGLVL
|
|
36
|
+
this._doLog(LOGLVL.WARN, args);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
warning(...args) {
|
|
40
|
-
this._doLog(LOGLVL
|
|
40
|
+
this._doLog(LOGLVL.WARN, args);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
error(...args) {
|
|
44
|
-
this._doLog(LOGLVL
|
|
44
|
+
this._doLog(LOGLVL.ERROR, args);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
_doLog(level, args) {
|
|
@@ -60,19 +60,19 @@ class LogHandler {
|
|
|
60
60
|
this.extHandler(LOGLVLSTR[level], args);
|
|
61
61
|
} else {
|
|
62
62
|
switch (level) {
|
|
63
|
-
case LOGLVL
|
|
63
|
+
case LOGLVL.DEBUG:
|
|
64
64
|
console.debug(args);
|
|
65
65
|
break;
|
|
66
66
|
|
|
67
|
-
case LOGLVL
|
|
67
|
+
case LOGLVL.INFO:
|
|
68
68
|
console.info(args);
|
|
69
69
|
break;
|
|
70
70
|
|
|
71
|
-
case LOGLVL
|
|
71
|
+
case LOGLVL.WARN:
|
|
72
72
|
console.warn(args);
|
|
73
73
|
break;
|
|
74
74
|
|
|
75
|
-
case LOGLVL
|
|
75
|
+
case LOGLVL.ERROR:
|
|
76
76
|
console.error(args);
|
|
77
77
|
break;
|
|
78
78
|
|
|
@@ -91,7 +91,7 @@ class LogHandler {
|
|
|
91
91
|
* @property {number} INFO 2 Informational messages (default)
|
|
92
92
|
* @property {number} DEBUG 3 Debug messages
|
|
93
93
|
*/
|
|
94
|
-
const LOGLVL
|
|
94
|
+
const LOGLVL = {
|
|
95
95
|
DEBUG: 3,
|
|
96
96
|
INFO: 2,
|
|
97
97
|
WARN: 1,
|
|
@@ -386,7 +386,7 @@ class Request {
|
|
|
386
386
|
class Requestor extends EventEmitter {
|
|
387
387
|
constructor(logger = null) {
|
|
388
388
|
super();
|
|
389
|
-
this.log = logger ? logger : new LogHandler(LOGLVL
|
|
389
|
+
this.log = logger ? logger : new LogHandler(LOGLVL.INFO);
|
|
390
390
|
this._pendingRequests = [];
|
|
391
391
|
}
|
|
392
392
|
|
|
@@ -401,13 +401,13 @@ class Requestor extends EventEmitter {
|
|
|
401
401
|
let msg;
|
|
402
402
|
try {
|
|
403
403
|
msg = JSON.parse(message);
|
|
404
|
-
} catch
|
|
404
|
+
} catch {
|
|
405
405
|
this.log.warning("Unable to parse message: " + message);
|
|
406
406
|
return;
|
|
407
407
|
}
|
|
408
408
|
|
|
409
409
|
// Validate msg fields
|
|
410
|
-
if (!
|
|
410
|
+
if (!Object.hasOwn(msg, "type") || !Object.hasOwn(msg, "id")) {
|
|
411
411
|
this.log.warning(`Invalid message received: ${msg} - missing type or id`);
|
|
412
412
|
return;
|
|
413
413
|
}
|
|
@@ -658,7 +658,7 @@ class EventClient {
|
|
|
658
658
|
throw new InvalidParameter('You must specify both event spec and callback function');
|
|
659
659
|
}
|
|
660
660
|
|
|
661
|
-
if (!
|
|
661
|
+
if (!Object.hasOwn(eventSpecification, 'event_name')) {
|
|
662
662
|
throw new InvalidParameter('Your event specification must contain event name');
|
|
663
663
|
}
|
|
664
664
|
|
|
@@ -1663,10 +1663,10 @@ class Phone extends EventEmitter {
|
|
|
1663
1663
|
this._oscillator2 = null;
|
|
1664
1664
|
|
|
1665
1665
|
// Set default logger
|
|
1666
|
-
this.log = logger ? logger : new LogHandler(LOGLVL
|
|
1666
|
+
this.log = logger ? logger : new LogHandler(LOGLVL.INFO);
|
|
1667
1667
|
|
|
1668
1668
|
// Handle jssip debug logs
|
|
1669
|
-
if (this.log.level === LOGLVL
|
|
1669
|
+
if (this.log.level === LOGLVL.DEBUG) {
|
|
1670
1670
|
JsSIP.debug.disable('JsSIP:*');
|
|
1671
1671
|
} else {
|
|
1672
1672
|
JsSIP.debug.disable('JsSIP:*');
|
|
@@ -1741,10 +1741,10 @@ class Phone extends EventEmitter {
|
|
|
1741
1741
|
|
|
1742
1742
|
// Unpack provisioning token if specified
|
|
1743
1743
|
if (this._options.provisionToken) {
|
|
1744
|
-
let pt
|
|
1744
|
+
let pt;
|
|
1745
1745
|
try {
|
|
1746
1746
|
pt = JSON.parse(atob(this._options.provisionToken));
|
|
1747
|
-
} catch
|
|
1747
|
+
} catch {
|
|
1748
1748
|
throw new InvalidOptions('provisionToken', 'Invalid token');
|
|
1749
1749
|
}
|
|
1750
1750
|
|
|
@@ -1820,7 +1820,7 @@ class Phone extends EventEmitter {
|
|
|
1820
1820
|
);
|
|
1821
1821
|
}
|
|
1822
1822
|
|
|
1823
|
-
let wsSocket
|
|
1823
|
+
let wsSocket;
|
|
1824
1824
|
try {
|
|
1825
1825
|
wsSocket = new JsSIP.WebSocketInterface(this._options.wssServer);
|
|
1826
1826
|
} catch (err) {
|
|
@@ -1932,7 +1932,7 @@ class Phone extends EventEmitter {
|
|
|
1932
1932
|
try {
|
|
1933
1933
|
this._eventClient.disconnect();
|
|
1934
1934
|
delete this._eventClient;
|
|
1935
|
-
} catch
|
|
1935
|
+
} catch {
|
|
1936
1936
|
this.log.warning('Unable to disconnect event client');
|
|
1937
1937
|
}
|
|
1938
1938
|
|
|
@@ -2023,7 +2023,7 @@ class Phone extends EventEmitter {
|
|
|
2023
2023
|
*/
|
|
2024
2024
|
getSessionByUUID(uuid) {
|
|
2025
2025
|
for (let key in this._activeSessions) {
|
|
2026
|
-
if (this._activeSessions
|
|
2026
|
+
if (Object.hasOwn(this._activeSessions, key)) {
|
|
2027
2027
|
if (this._activeSessions[key].uuid === uuid) {
|
|
2028
2028
|
return this._activeSessions[key];
|
|
2029
2029
|
}
|
|
@@ -2048,7 +2048,7 @@ class Phone extends EventEmitter {
|
|
|
2048
2048
|
get sessions() {
|
|
2049
2049
|
let s = [];
|
|
2050
2050
|
for (let key in this._activeSessions) {
|
|
2051
|
-
if (this._activeSessions
|
|
2051
|
+
if (Object.hasOwn(this._activeSessions, key)) {
|
|
2052
2052
|
s.push(this._activeSessions[key]);
|
|
2053
2053
|
}
|
|
2054
2054
|
}
|
|
@@ -2213,7 +2213,7 @@ class Phone extends EventEmitter {
|
|
|
2213
2213
|
|
|
2214
2214
|
// Iterate through all active calls and hold them
|
|
2215
2215
|
for (let key in this._activeSessions) {
|
|
2216
|
-
if (this._activeSessions
|
|
2216
|
+
if (Object.hasOwn(this._activeSessions, key)) {
|
|
2217
2217
|
let session = this._activeSessions[key];
|
|
2218
2218
|
if (session.state === 'ACTIVE') {
|
|
2219
2219
|
session.hold();
|
|
@@ -2287,7 +2287,7 @@ class Phone extends EventEmitter {
|
|
|
2287
2287
|
// Return true if there are calls currently connecting
|
|
2288
2288
|
_checkForConnectingCalls() {
|
|
2289
2289
|
for (let key in this._activeSessions) {
|
|
2290
|
-
if (this._activeSessions
|
|
2290
|
+
if (Object.hasOwn(this._activeSessions, key)) {
|
|
2291
2291
|
let session = this._activeSessions[key];
|
|
2292
2292
|
if (
|
|
2293
2293
|
session.state === 'INITIALIZING' ||
|
|
@@ -2671,7 +2671,7 @@ class Session extends EventEmitter {
|
|
|
2671
2671
|
self.log.info(`Answer call timeout after ${self._answerCallTimeout} seconds`);
|
|
2672
2672
|
try {
|
|
2673
2673
|
self.hangup();
|
|
2674
|
-
} catch
|
|
2674
|
+
} catch {
|
|
2675
2675
|
self.log.info('No active session, ignoring answer call timeout');
|
|
2676
2676
|
}
|
|
2677
2677
|
}, self._answerCallTimeout * 1000);
|
|
@@ -3742,4 +3742,4 @@ class Session extends EventEmitter {
|
|
|
3742
3742
|
}
|
|
3743
3743
|
}
|
|
3744
3744
|
|
|
3745
|
-
export { EventClient, EventServiceNotConnected, InvalidMediaDevice, InvalidOptions, InvalidParameter, LOGLVL
|
|
3745
|
+
export { EventClient, EventServiceNotConnected, InvalidMediaDevice, InvalidOptions, InvalidParameter, LOGLVL, LogHandler, MediaNotPrepared, NoActiveSession, NotAllowed, NotReady, Phone, Request, Requestor, Session, UnableToConnect, browserIsChrome, browserIsEdge, browserIsFirefox, browserIsOpera, browserIsSafari, buildCustomHeaders, compareObjects, createDurationString, createUUID };
|