@ohos-ports/genesys-cloud-streaming-client 20.1.0-beta.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.
Files changed (176) hide show
  1. package/README.md +47 -0
  2. package/dist/cjs/alerting-leader.d.ts +29 -0
  3. package/dist/cjs/alerting-leader.js +163 -0
  4. package/dist/cjs/client.d.ts +84 -0
  5. package/dist/cjs/client.js +680 -0
  6. package/dist/cjs/connection-manager.d.ts +18 -0
  7. package/dist/cjs/connection-manager.js +120 -0
  8. package/dist/cjs/connection-transfer.d.ts +7 -0
  9. package/dist/cjs/connection-transfer.js +20 -0
  10. package/dist/cjs/http-client.d.ts +18 -0
  11. package/dist/cjs/http-client.js +230 -0
  12. package/dist/cjs/index.d.ts +10 -0
  13. package/dist/cjs/index.js +31 -0
  14. package/dist/cjs/messenger.d.ts +37 -0
  15. package/dist/cjs/messenger.js +54 -0
  16. package/dist/cjs/notifications.d.ts +94 -0
  17. package/dist/cjs/notifications.js +495 -0
  18. package/dist/cjs/ping.d.ts +21 -0
  19. package/dist/cjs/ping.js +60 -0
  20. package/dist/cjs/polyfills.d.ts +0 -0
  21. package/dist/cjs/polyfills.js +6 -0
  22. package/dist/cjs/server-monitor.d.ts +16 -0
  23. package/dist/cjs/server-monitor.js +44 -0
  24. package/dist/cjs/stanza-definitions/webrtc-signaling.d.ts +29 -0
  25. package/dist/cjs/stanza-definitions/webrtc-signaling.js +113 -0
  26. package/dist/cjs/stanza-definitions/xep0051.d.ts +19 -0
  27. package/dist/cjs/stanza-definitions/xep0051.js +28 -0
  28. package/dist/cjs/stats-formatter.d.ts +6 -0
  29. package/dist/cjs/stats-formatter.js +63 -0
  30. package/dist/cjs/types/genesys-cloud-media-session.d.ts +64 -0
  31. package/dist/cjs/types/genesys-cloud-media-session.js +353 -0
  32. package/dist/cjs/types/interfaces.d.ts +310 -0
  33. package/dist/cjs/types/interfaces.js +22 -0
  34. package/dist/cjs/types/libs.d.ts +32 -0
  35. package/dist/cjs/types/libs.js +1 -0
  36. package/dist/cjs/types/media-session.d.ts +76 -0
  37. package/dist/cjs/types/media-session.js +2 -0
  38. package/dist/cjs/types/named-agent.d.ts +13 -0
  39. package/dist/cjs/types/named-agent.js +2 -0
  40. package/dist/cjs/types/offline-error.d.ts +2 -0
  41. package/dist/cjs/types/offline-error.js +5 -0
  42. package/dist/cjs/types/sasl-error.d.ts +8 -0
  43. package/dist/cjs/types/sasl-error.js +12 -0
  44. package/dist/cjs/types/stanza-media-session.d.ts +56 -0
  45. package/dist/cjs/types/stanza-media-session.js +255 -0
  46. package/dist/cjs/types/streaming-client-extension.d.ts +14 -0
  47. package/dist/cjs/types/streaming-client-extension.js +2 -0
  48. package/dist/cjs/types/timeout-error.d.ts +3 -0
  49. package/dist/cjs/types/timeout-error.js +9 -0
  50. package/dist/cjs/types/user-cancelled-error.d.ts +2 -0
  51. package/dist/cjs/types/user-cancelled-error.js +5 -0
  52. package/dist/cjs/utils.d.ts +34 -0
  53. package/dist/cjs/utils.js +202 -0
  54. package/dist/cjs/webrtc.d.ts +126 -0
  55. package/dist/cjs/webrtc.js +891 -0
  56. package/dist/deploy-info.json +21 -0
  57. package/dist/es/alerting-leader.d.ts +29 -0
  58. package/dist/es/alerting-leader.js +177 -0
  59. package/dist/es/client.d.ts +84 -0
  60. package/dist/es/client.js +699 -0
  61. package/dist/es/connection-manager.d.ts +18 -0
  62. package/dist/es/connection-manager.js +124 -0
  63. package/dist/es/connection-transfer.d.ts +7 -0
  64. package/dist/es/connection-transfer.js +16 -0
  65. package/dist/es/http-client.d.ts +18 -0
  66. package/dist/es/http-client.js +194 -0
  67. package/dist/es/index.bundle.js +39629 -0
  68. package/dist/es/index.d.ts +10 -0
  69. package/dist/es/index.js +10 -0
  70. package/dist/es/messenger.d.ts +37 -0
  71. package/dist/es/messenger.js +62 -0
  72. package/dist/es/notifications.d.ts +94 -0
  73. package/dist/es/notifications.js +507 -0
  74. package/dist/es/ping.d.ts +21 -0
  75. package/dist/es/ping.js +68 -0
  76. package/dist/es/polyfills.d.ts +0 -0
  77. package/dist/es/polyfills.js +6 -0
  78. package/dist/es/server-monitor.d.ts +16 -0
  79. package/dist/es/server-monitor.js +41 -0
  80. package/dist/es/stanza-definitions/webrtc-signaling.d.ts +29 -0
  81. package/dist/es/stanza-definitions/webrtc-signaling.js +110 -0
  82. package/dist/es/stanza-definitions/xep0051.d.ts +19 -0
  83. package/dist/es/stanza-definitions/xep0051.js +25 -0
  84. package/dist/es/stats-formatter.d.ts +6 -0
  85. package/dist/es/stats-formatter.js +54 -0
  86. package/dist/es/types/genesys-cloud-media-session.d.ts +64 -0
  87. package/dist/es/types/genesys-cloud-media-session.js +379 -0
  88. package/dist/es/types/interfaces.d.ts +310 -0
  89. package/dist/es/types/interfaces.js +19 -0
  90. package/dist/es/types/libs.d.ts +32 -0
  91. package/dist/es/types/libs.js +1 -0
  92. package/dist/es/types/media-session.d.ts +76 -0
  93. package/dist/es/types/media-session.js +1 -0
  94. package/dist/es/types/named-agent.d.ts +13 -0
  95. package/dist/es/types/named-agent.js +1 -0
  96. package/dist/es/types/offline-error.d.ts +2 -0
  97. package/dist/es/types/offline-error.js +2 -0
  98. package/dist/es/types/sasl-error.d.ts +8 -0
  99. package/dist/es/types/sasl-error.js +9 -0
  100. package/dist/es/types/stanza-media-session.d.ts +56 -0
  101. package/dist/es/types/stanza-media-session.js +264 -0
  102. package/dist/es/types/streaming-client-extension.d.ts +14 -0
  103. package/dist/es/types/streaming-client-extension.js +1 -0
  104. package/dist/es/types/timeout-error.d.ts +3 -0
  105. package/dist/es/types/timeout-error.js +5 -0
  106. package/dist/es/types/user-cancelled-error.d.ts +2 -0
  107. package/dist/es/types/user-cancelled-error.js +2 -0
  108. package/dist/es/utils.d.ts +34 -0
  109. package/dist/es/utils.js +192 -0
  110. package/dist/es/webrtc.d.ts +126 -0
  111. package/dist/es/webrtc.js +917 -0
  112. package/dist/manifest.json +19 -0
  113. package/dist/npm/CHANGELOG.md +637 -0
  114. package/dist/npm/README.md +47 -0
  115. package/dist/npm/alerting-leader.d.ts +29 -0
  116. package/dist/npm/alerting-leader.js +163 -0
  117. package/dist/npm/client.d.ts +84 -0
  118. package/dist/npm/client.js +680 -0
  119. package/dist/npm/connection-manager.d.ts +18 -0
  120. package/dist/npm/connection-manager.js +120 -0
  121. package/dist/npm/connection-transfer.d.ts +7 -0
  122. package/dist/npm/connection-transfer.js +20 -0
  123. package/dist/npm/http-client.d.ts +18 -0
  124. package/dist/npm/http-client.js +230 -0
  125. package/dist/npm/index.d.ts +10 -0
  126. package/dist/npm/index.js +31 -0
  127. package/dist/npm/messenger.d.ts +37 -0
  128. package/dist/npm/messenger.js +54 -0
  129. package/dist/npm/module.js +10 -0
  130. package/dist/npm/notifications.d.ts +94 -0
  131. package/dist/npm/notifications.js +495 -0
  132. package/dist/npm/ping.d.ts +21 -0
  133. package/dist/npm/ping.js +60 -0
  134. package/dist/npm/polyfills.d.ts +0 -0
  135. package/dist/npm/polyfills.js +6 -0
  136. package/dist/npm/server-monitor.d.ts +16 -0
  137. package/dist/npm/server-monitor.js +44 -0
  138. package/dist/npm/stanza-definitions/webrtc-signaling.d.ts +29 -0
  139. package/dist/npm/stanza-definitions/webrtc-signaling.js +113 -0
  140. package/dist/npm/stanza-definitions/xep0051.d.ts +19 -0
  141. package/dist/npm/stanza-definitions/xep0051.js +28 -0
  142. package/dist/npm/stats-formatter.d.ts +6 -0
  143. package/dist/npm/stats-formatter.js +63 -0
  144. package/dist/npm/types/genesys-cloud-media-session.d.ts +64 -0
  145. package/dist/npm/types/genesys-cloud-media-session.js +353 -0
  146. package/dist/npm/types/interfaces.d.ts +310 -0
  147. package/dist/npm/types/interfaces.js +22 -0
  148. package/dist/npm/types/libs.d.ts +32 -0
  149. package/dist/npm/types/libs.js +1 -0
  150. package/dist/npm/types/media-session.d.ts +76 -0
  151. package/dist/npm/types/media-session.js +2 -0
  152. package/dist/npm/types/named-agent.d.ts +13 -0
  153. package/dist/npm/types/named-agent.js +2 -0
  154. package/dist/npm/types/offline-error.d.ts +2 -0
  155. package/dist/npm/types/offline-error.js +5 -0
  156. package/dist/npm/types/sasl-error.d.ts +8 -0
  157. package/dist/npm/types/sasl-error.js +12 -0
  158. package/dist/npm/types/stanza-media-session.d.ts +56 -0
  159. package/dist/npm/types/stanza-media-session.js +255 -0
  160. package/dist/npm/types/streaming-client-extension.d.ts +14 -0
  161. package/dist/npm/types/streaming-client-extension.js +2 -0
  162. package/dist/npm/types/timeout-error.d.ts +3 -0
  163. package/dist/npm/types/timeout-error.js +9 -0
  164. package/dist/npm/types/user-cancelled-error.d.ts +2 -0
  165. package/dist/npm/types/user-cancelled-error.js +5 -0
  166. package/dist/npm/utils.d.ts +34 -0
  167. package/dist/npm/utils.js +207 -0
  168. package/dist/npm/webrtc.d.ts +126 -0
  169. package/dist/npm/webrtc.js +893 -0
  170. package/dist/streaming-client.browser.js +2 -0
  171. package/dist/streaming-client.browser.js.LICENSE.txt +12 -0
  172. package/dist/v20/streaming-client.browser.js +2 -0
  173. package/dist/v20/streaming-client.browser.js.LICENSE.txt +12 -0
  174. package/dist/v20.1.0/streaming-client.browser.js +2 -0
  175. package/dist/v20.1.0/streaming-client.browser.js.LICENSE.txt +12 -0
  176. package/package.json +132 -0
@@ -0,0 +1,255 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.StanzaMediaSession = void 0;
7
+ /* istanbul ignore file */
8
+ const events_1 = __importDefault(require("events"));
9
+ const jingle_1 = require("stanza/jingle");
10
+ const Constants_1 = require("stanza/Constants");
11
+ const webrtc_stats_gatherer_1 = __importDefault(require("webrtc-stats-gatherer"));
12
+ const interfaces_1 = require("./interfaces");
13
+ const loggingOverrides = {
14
+ 'Discovered new ICE candidate': { skipMessage: true }
15
+ };
16
+ // because we are trying to unify the interfaces between stanza and genesys media session
17
+ // we kind of have to hack the stanza one so it works with typescript
18
+ class StanzaMediaSession extends jingle_1.MediaSession {
19
+ constructor(params) {
20
+ super(params.options);
21
+ this.iceCandidatesDiscovered = 0;
22
+ this.iceCandidatesReceivedFromPeer = 0;
23
+ this.reinvite = false;
24
+ this.logger = params.logger;
25
+ this.conversationId = params.conversationId;
26
+ this.peerConnection = this.pc;
27
+ this.fromUserId = params.fromUserId;
28
+ this.meetingId = params.meetingId;
29
+ this.id = this.sid;
30
+ this.originalRoomJid = params.originalRoomJid;
31
+ this.sessionType = interfaces_1.SessionTypes[params.sessionType];
32
+ this.ignoreHostCandidatesFromRemote = !!params.ignoreHostCandidatesFromRemote;
33
+ this.allowIPv6 = !!params.allowIPv6;
34
+ this.allowTCP = !!params.allowTCP;
35
+ this.privAnswerMode = params.privAnswerMode;
36
+ // babel does not like the typescript recipe for multiple extends so we are hacking this one
37
+ // referencing https://github.com/babel/babel/issues/798
38
+ const eventEmitter = new events_1.default();
39
+ Object.keys(eventEmitter.__proto__).forEach((name) => {
40
+ this[name] = eventEmitter[name];
41
+ });
42
+ if (!params.optOutOfWebrtcStatsTelemetry) {
43
+ this.setupStatsGatherer();
44
+ }
45
+ this.pc.addEventListener('connectionstatechange', this.onConnectionStateChange.bind(this));
46
+ this.pc.addEventListener('icecandidateerror', this.onIceCandidateError.bind(this));
47
+ }
48
+ getLogDetails() {
49
+ return {
50
+ conversationId: this.conversationId,
51
+ sessionId: this.id,
52
+ sessionType: this.sessionType
53
+ };
54
+ }
55
+ async onTransportInfo(changes, cb) {
56
+ var _a, _b;
57
+ const transport = (_a = changes.contents) === null || _a === void 0 ? void 0 : _a[0].transport;
58
+ const candidates = transport === null || transport === void 0 ? void 0 : transport.candidates;
59
+ if (this.ignoreHostCandidatesFromRemote) {
60
+ const nonHostCandidates = candidates === null || candidates === void 0 ? void 0 : candidates.filter(candidate => candidate.type !== 'host');
61
+ if ((nonHostCandidates === null || nonHostCandidates === void 0 ? void 0 : nonHostCandidates.length) !== ((_b = transport === null || transport === void 0 ? void 0 : transport.candidates) === null || _b === void 0 ? void 0 : _b.length)) {
62
+ this._log('info', 'Ignoring remote host ice candidates');
63
+ transport.candidates = nonHostCandidates;
64
+ }
65
+ }
66
+ if (candidates) {
67
+ for (const candidate of candidates) {
68
+ this._log('info', 'Received candidate from peer', { candidateType: candidate.type });
69
+ this.iceCandidatesReceivedFromPeer++;
70
+ }
71
+ }
72
+ return super.onTransportInfo(changes, cb);
73
+ }
74
+ _log(level, message, ...data) {
75
+ const redactionInfo = loggingOverrides[message];
76
+ if (redactionInfo === null || redactionInfo === void 0 ? void 0 : redactionInfo.skipMessage) {
77
+ return;
78
+ }
79
+ let details;
80
+ if (data.length) {
81
+ const firstItem = data[0];
82
+ // if first item is an object, merge the details, else wrap them
83
+ if (typeof firstItem === 'object' &&
84
+ !Array.isArray(firstItem) &&
85
+ firstItem !== null) {
86
+ Object.assign(data[0], this.getLogDetails());
87
+ details = data;
88
+ }
89
+ else {
90
+ details = { ...this.getLogDetails(), data: firstItem };
91
+ }
92
+ }
93
+ else {
94
+ details = [...data, this.getLogDetails()];
95
+ }
96
+ this.logger[level](message, details);
97
+ }
98
+ async end(reason = 'success', silent = false) {
99
+ this.state = 'ended';
100
+ this.processingQueue.kill();
101
+ if (typeof reason === 'string') {
102
+ reason = { condition: reason };
103
+ }
104
+ if (!silent) {
105
+ this._log('info', 'sending jingle session-terminate');
106
+ this.send('session-terminate', { reason });
107
+ }
108
+ // After sending session-terminate, wait for the peer connection to die -> if it doesn't, we will manually close it.
109
+ setTimeout(() => {
110
+ if (this.pc.connectionState === 'connected' || this.pc.connectionState === 'connecting') {
111
+ this.pc.close();
112
+ }
113
+ }, 2000);
114
+ this.parent.emit('terminated', this, reason);
115
+ this.parent.forgetSession(this);
116
+ }
117
+ setupStatsGatherer() {
118
+ this.statsGatherer = new webrtc_stats_gatherer_1.default(this.pc);
119
+ this.statsGatherer.on('stats', this.emit.bind(this, 'stats'));
120
+ }
121
+ onIceStateChange() {
122
+ const iceState = this.pc.iceConnectionState;
123
+ const sessionId = this.id;
124
+ const conversationId = this.conversationId;
125
+ const sessionType = this.sessionType;
126
+ this._log('info', 'ICE state changed: ', { iceState, sessionId, conversationId });
127
+ if (iceState === 'disconnected') {
128
+ // this means we actually connected at one point
129
+ if (this.pc.signalingState === 'stable') {
130
+ this.interruptionStart = new Date();
131
+ this._log('info', 'Connection state is interrupted', { sessionId, conversationId, sessionType });
132
+ }
133
+ }
134
+ else if (iceState === 'connected') {
135
+ this._log('info', 'sending session-info: active');
136
+ this.send(Constants_1.JingleAction.SessionInfo, {
137
+ info: {
138
+ infoType: Constants_1.JINGLE_INFO_ACTIVE
139
+ }
140
+ });
141
+ this._setupDataChannel();
142
+ }
143
+ else if (iceState === 'failed') {
144
+ this._log('info', 'ICE connection failed', {
145
+ candidatesDiscovered: this.iceCandidatesDiscovered,
146
+ candidatesReceivedFromPeer: this.iceCandidatesReceivedFromPeer
147
+ });
148
+ }
149
+ super.onIceStateChange();
150
+ }
151
+ onConnectionStateChange() {
152
+ const connectionState = this.pc.connectionState;
153
+ const sessionId = this.id;
154
+ const conversationId = this.conversationId;
155
+ const sessionType = this.sessionType;
156
+ this._log('info', 'Connection state changed: ', { connectionState, sessionId, conversationId, sessionType });
157
+ if (this.interruptionStart) {
158
+ if (connectionState === 'connected') {
159
+ const diff = new Date().getTime() - this.interruptionStart.getTime();
160
+ this._log('info', 'Connection was interrupted but was successfully recovered/connected', { sessionId, conversationId, sessionType, timeToRecover: diff });
161
+ this.interruptionStart = undefined;
162
+ }
163
+ else if (connectionState === 'failed') {
164
+ this._log('info', 'Connection was interrupted and failed to recover', { sessionId, conversationId, sessionType });
165
+ }
166
+ }
167
+ }
168
+ onIceCandidateError(ev) {
169
+ const event = ev;
170
+ this._log('error', 'IceCandidateError', {
171
+ errorCode: event.errorCode,
172
+ errorText: event.errorText,
173
+ url: event.url
174
+ });
175
+ console.error('IceCandidateError', event);
176
+ }
177
+ onIceCandidate(e) {
178
+ if (e.candidate) {
179
+ if (!this.allowTCP && e.candidate.protocol === 'tcp') {
180
+ return;
181
+ }
182
+ if (!this.allowIPv6) {
183
+ const addressRegex = /.+udp [^ ]+ ([^ ]+).*typ host/;
184
+ const matches = addressRegex.exec(e.candidate.candidate);
185
+ const ipv4Regex = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/;
186
+ if (matches && !matches[1].match(ipv4Regex)) {
187
+ this._log('debug', 'Filtering out IPv6 candidate', e.candidate.candidate);
188
+ return;
189
+ }
190
+ }
191
+ // this has too much information and can only be logged locally (debug)
192
+ this._log('debug', 'Processing ice candidate', e.candidate.candidate);
193
+ // this one is info level so it can go to the server
194
+ this._log('info', 'Discovered ice candidate to send to peer', { type: e.candidate.type });
195
+ this.iceCandidatesDiscovered++;
196
+ }
197
+ return super.onIceCandidate(e);
198
+ }
199
+ onIceEndOfCandidates() {
200
+ super.onIceEndOfCandidates();
201
+ this.emit('endOfCandidates');
202
+ }
203
+ addTrack(track, stream) {
204
+ if (track.kind === 'audio') {
205
+ this.includesAudio = true;
206
+ }
207
+ if (track.kind === 'video') {
208
+ this.includesVideo = true;
209
+ }
210
+ return this.processLocal('addtrack', async () => {
211
+ // find an available sender with the correct type
212
+ const availableTransceiver = this.pc.getTransceivers().find((transceiver) => {
213
+ var _a;
214
+ return !transceiver.sender.track && ((_a = transceiver.receiver.track) === null || _a === void 0 ? void 0 : _a.kind) === track.kind;
215
+ });
216
+ if (availableTransceiver) {
217
+ return availableTransceiver.sender.replaceTrack(track);
218
+ }
219
+ this.pc.addTrack(track, stream);
220
+ return;
221
+ });
222
+ }
223
+ _setupDataChannel() {
224
+ var _a;
225
+ // this shouldn't happen, but we shouldn't set the datachannel up more than once
226
+ if (this.dataChannel) {
227
+ return;
228
+ }
229
+ // do nothing if a datachannel wasn't offered
230
+ if ((_a = this.pc.localDescription) === null || _a === void 0 ? void 0 : _a.sdp.includes('webrtc-datachannel')) {
231
+ this._log('info', 'creating data channel');
232
+ this.dataChannel = this.pc.createDataChannel('videoConferenceControl');
233
+ this.dataChannel.addEventListener('open', () => {
234
+ this._log('info', 'data channel opened');
235
+ });
236
+ this.dataChannel.addEventListener('message', this._handleDataChannelMessage.bind(this));
237
+ this.dataChannel.addEventListener('close', () => {
238
+ this._log('info', 'closing data channel');
239
+ });
240
+ this.dataChannel.addEventListener('error', (error) => {
241
+ this._log('error', 'Error occurred with the data channel', error);
242
+ });
243
+ }
244
+ }
245
+ _handleDataChannelMessage(event) {
246
+ try {
247
+ const message = JSON.parse(event.data);
248
+ this.emit('dataChannelMessage', message);
249
+ }
250
+ catch (e) {
251
+ this._log('error', 'Failed to parse data channel message', { error: e });
252
+ }
253
+ }
254
+ }
255
+ exports.StanzaMediaSession = StanzaMediaSession;
@@ -0,0 +1,14 @@
1
+ import { TokenBucket } from 'limiter';
2
+ import { IQ, Message } from 'stanza/protocol';
3
+ import { NamedAgent } from './named-agent';
4
+ export interface StreamingClientExtension {
5
+ handleIq?: (iq: IQ) => void;
6
+ handleMessage?: (message: Message) => void;
7
+ tokenBucket?: TokenBucket;
8
+ on?: (eventName: string, ...args: any[]) => void;
9
+ expose?: {
10
+ [fnName: string]: any;
11
+ };
12
+ configureNewStanzaInstance?: (stanzaInstance: NamedAgent) => Promise<any>;
13
+ handleStanzaInstanceChange: (stanzaInstance: NamedAgent) => void;
14
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ export declare class TimeoutError extends Error {
2
+ constructor(message: string);
3
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TimeoutError = void 0;
4
+ class TimeoutError extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ }
8
+ }
9
+ exports.TimeoutError = TimeoutError;
@@ -0,0 +1,2 @@
1
+ export default class UserCancelledError extends Error {
2
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class UserCancelledError extends Error {
4
+ }
5
+ exports.default = UserCancelledError;
@@ -0,0 +1,34 @@
1
+ import { StreamingClientErrorTypes, StreamingSubscriptionErrorDetails } from './types/interfaces';
2
+ export declare class StreamingClientError extends Error {
3
+ type: StreamingClientErrorTypes;
4
+ details?: unknown;
5
+ constructor(type: StreamingClientErrorTypes | null, messageOrError: string | Error, details?: unknown);
6
+ }
7
+ export declare class StreamingSubscriptionError extends Error {
8
+ readonly topic?: string | undefined;
9
+ readonly operation?: "subscribe" | "unsubscribe" | undefined;
10
+ name: string;
11
+ missingPermissions?: string[];
12
+ constructor(message: string, topic?: string | undefined, operation?: "subscribe" | "unsubscribe" | undefined, details?: StreamingSubscriptionErrorDetails);
13
+ }
14
+ export declare function timeoutPromise(fn: Function, timeoutMs: number, msg: string, details?: any): Promise<any>;
15
+ export declare function delay(ms: number): Promise<void>;
16
+ export declare function splitIntoIndividualTopics(topicString: string): string[];
17
+ export declare const isAcdJid: (jid: string) => boolean;
18
+ export declare const isScreenRecordingJid: (jid: string) => boolean;
19
+ export declare const isLiveScreenMonitoringJid: (jid: string) => boolean;
20
+ export declare const isSoftphoneJid: (jid: string) => boolean;
21
+ export declare const isVideoJid: (jid: string) => boolean;
22
+ export declare type RetryPromise<T = any> = {
23
+ promise: Promise<T>;
24
+ cancel: (reason?: string | Error) => void;
25
+ complete: (value?: T) => void;
26
+ hasCompleted: () => boolean;
27
+ _id: string;
28
+ };
29
+ export declare function retryPromise<T = any>(promiseFn: () => Promise<T>, retryFn: (error?: Error | any) => boolean | number, retryInterval?: number, logger?: any): RetryPromise<T>;
30
+ export declare const parseJwt: (token: string) => any;
31
+ export declare function calculatePayloadSize(trace: any): number;
32
+ export declare function getUfragFromSdp(sdp: string | undefined): string | null;
33
+ export declare function getIcePwdFromSdp(sdp: string | undefined): string | null;
34
+ export declare function iceIsDifferent(sdp1: string | undefined, sdp2: string | undefined): boolean;
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.iceIsDifferent = exports.getIcePwdFromSdp = exports.getUfragFromSdp = exports.calculatePayloadSize = exports.parseJwt = exports.retryPromise = exports.isVideoJid = exports.isSoftphoneJid = exports.isLiveScreenMonitoringJid = exports.isScreenRecordingJid = exports.isAcdJid = exports.splitIntoIndividualTopics = exports.delay = exports.timeoutPromise = exports.StreamingSubscriptionError = exports.StreamingClientError = void 0;
4
+ const timeout_error_1 = require("./types/timeout-error");
5
+ const interfaces_1 = require("./types/interfaces");
6
+ class StreamingClientError extends Error {
7
+ constructor(type, messageOrError, details) {
8
+ let message;
9
+ if (messageOrError instanceof Error) {
10
+ message = messageOrError.message;
11
+ }
12
+ else {
13
+ message = messageOrError;
14
+ }
15
+ super(message);
16
+ if (messageOrError instanceof Error) {
17
+ this.name = messageOrError.name;
18
+ }
19
+ this.type = type !== null && type !== void 0 ? type : interfaces_1.StreamingClientErrorTypes.generic;
20
+ this.details = details;
21
+ }
22
+ }
23
+ exports.StreamingClientError = StreamingClientError;
24
+ class StreamingSubscriptionError extends Error {
25
+ constructor(message, topic, operation, details) {
26
+ super(message);
27
+ this.topic = topic;
28
+ this.operation = operation;
29
+ this.name = 'StreamingSubscriptionError';
30
+ this.missingPermissions = details === null || details === void 0 ? void 0 : details.missingPermissions;
31
+ }
32
+ }
33
+ exports.StreamingSubscriptionError = StreamingSubscriptionError;
34
+ /* istanbul ignore next */
35
+ function timeoutPromise(fn, timeoutMs, msg, details) {
36
+ return new Promise(function (resolve, reject) {
37
+ const timeout = setTimeout(function () {
38
+ const err = new timeout_error_1.TimeoutError(`Timeout: ${msg}`);
39
+ err.details = details;
40
+ reject(err);
41
+ }, timeoutMs);
42
+ const done = function (resolvedValue) {
43
+ clearTimeout(timeout);
44
+ resolve(resolvedValue);
45
+ };
46
+ fn(done, reject);
47
+ });
48
+ }
49
+ exports.timeoutPromise = timeoutPromise;
50
+ function delay(ms) {
51
+ return new Promise((resolve) => {
52
+ setTimeout(resolve, ms);
53
+ });
54
+ }
55
+ exports.delay = delay;
56
+ function splitIntoIndividualTopics(topicString) {
57
+ const topics = [];
58
+ if (topicString.includes('?')) {
59
+ const split = topicString.split('?');
60
+ const prefix = split[0];
61
+ const postfixes = split[1] && split[1].split('&');
62
+ if (postfixes && postfixes.length) {
63
+ postfixes.forEach(postfix => {
64
+ topics.push(`${prefix}.${postfix}`);
65
+ });
66
+ }
67
+ }
68
+ else {
69
+ topics.push(topicString);
70
+ }
71
+ return topics;
72
+ }
73
+ exports.splitIntoIndividualTopics = splitIntoIndividualTopics;
74
+ const isAcdJid = function (jid) {
75
+ return jid.startsWith('acd-') && !(0, exports.isSoftphoneJid)(jid);
76
+ };
77
+ exports.isAcdJid = isAcdJid;
78
+ const isScreenRecordingJid = function (jid) {
79
+ return jid.startsWith('screenrecording-') && !(0, exports.isSoftphoneJid)(jid);
80
+ };
81
+ exports.isScreenRecordingJid = isScreenRecordingJid;
82
+ const isLiveScreenMonitoringJid = function (jid) {
83
+ return jid.startsWith('livemonitor-') && !(0, exports.isSoftphoneJid)(jid);
84
+ };
85
+ exports.isLiveScreenMonitoringJid = isLiveScreenMonitoringJid;
86
+ const isSoftphoneJid = function (jid) {
87
+ if (!jid) {
88
+ return false;
89
+ }
90
+ return !!jid.match(/.*@.*gjoll.*/i);
91
+ };
92
+ exports.isSoftphoneJid = isSoftphoneJid;
93
+ const isVideoJid = function (jid) {
94
+ return !!(jid && jid.match(/@conference/) && !(0, exports.isAcdJid)(jid));
95
+ };
96
+ exports.isVideoJid = isVideoJid;
97
+ function retryPromise(promiseFn,
98
+ // if a number is returned, that's how long we will wait before retrying (in milliseconds)
99
+ retryFn, retryInterval = 15000, logger = console) {
100
+ let timeout;
101
+ let cancel;
102
+ let complete;
103
+ let tryPromiseFn;
104
+ let _hasCompleted = false;
105
+ const promise = new Promise((resolve, reject) => {
106
+ tryPromiseFn = async () => {
107
+ try {
108
+ const val = await promiseFn();
109
+ complete(val);
110
+ }
111
+ catch (error) {
112
+ let timeToWait = retryInterval;
113
+ const retryValue = retryFn(error);
114
+ if (Number.isInteger(retryValue)) {
115
+ timeToWait = retryValue;
116
+ }
117
+ if (retryValue !== false) {
118
+ logger.debug('Retrying promise', error);
119
+ timeout = setTimeout(tryPromiseFn, timeToWait);
120
+ }
121
+ else {
122
+ cancel(error);
123
+ }
124
+ }
125
+ };
126
+ complete = (value) => {
127
+ clearTimeout(timeout);
128
+ _hasCompleted = true;
129
+ resolve(value);
130
+ };
131
+ cancel = (reason) => {
132
+ clearTimeout(timeout);
133
+ _hasCompleted = true;
134
+ reject(reason);
135
+ };
136
+ tryPromiseFn();
137
+ });
138
+ return {
139
+ promise,
140
+ cancel,
141
+ complete,
142
+ _id: globalThis.crypto.randomUUID(),
143
+ hasCompleted: () => _hasCompleted
144
+ };
145
+ }
146
+ exports.retryPromise = retryPromise;
147
+ // from https://stackoverflow.com/questions/38552003/how-to-decode-jwt-token-in-javascript
148
+ const parseJwt = (token) => {
149
+ const base64Url = token.split('.')[1];
150
+ const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
151
+ const jsonPayload = decodeURIComponent(window.atob(base64).split('').map(function (c) {
152
+ return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
153
+ }).join(''));
154
+ return JSON.parse(jsonPayload);
155
+ };
156
+ exports.parseJwt = parseJwt;
157
+ function calculatePayloadSize(trace) {
158
+ const str = JSON.stringify(trace);
159
+ // http://stackoverflow.com/questions/5515869/string-length-in-bytes-in-javascript
160
+ // Matches only the 10.. bytes that are non-initial characters in a multi-byte sequence.
161
+ const m = encodeURIComponent(str).match(/%[89ABab]/g);
162
+ return str.length + (m ? m.length : 0);
163
+ }
164
+ exports.calculatePayloadSize = calculatePayloadSize;
165
+ function getUfragFromSdp(sdp) {
166
+ if (!sdp) {
167
+ return null;
168
+ }
169
+ const regex = /a=ice-ufrag:(\S+)/;
170
+ const match = sdp.match(regex);
171
+ return match ? match[1] : null;
172
+ }
173
+ exports.getUfragFromSdp = getUfragFromSdp;
174
+ function getIcePwdFromSdp(sdp) {
175
+ if (!sdp) {
176
+ return null;
177
+ }
178
+ const regex = /a=ice-pwd:(\S+)/;
179
+ const match = sdp.match(regex);
180
+ return match ? match[1] : null;
181
+ }
182
+ exports.getIcePwdFromSdp = getIcePwdFromSdp;
183
+ function iceIsDifferent(sdp1, sdp2) {
184
+ return getUfragFromSdp(sdp1) !== getUfragFromSdp(sdp2) || getIcePwdFromSdp(sdp1) !== getIcePwdFromSdp(sdp2);
185
+ }
186
+ exports.iceIsDifferent = iceIsDifferent;
187
+ // unsed, but handy. no test coverage until used
188
+ // function mergeOptions (destination, provided) {
189
+ // for (var key in provided) {
190
+ // let value = provided[key];
191
+ // if (value instanceof Object) {
192
+ // if (!destination[key]) {
193
+ // destination[key] = {};
194
+ // }
195
+ // mergeOptions(destination[key], value);
196
+ // } else {
197
+ // destination[key] = provided[key];
198
+ // }
199
+ // }
200
+ //
201
+ // return destination;
202
+ // }
@@ -0,0 +1,126 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'events';
3
+ import { IQ } from 'stanza/protocol';
4
+ import { LRUCache } from 'lru-cache';
5
+ import { SessionManager } from 'stanza/jingle';
6
+ import { SessionOpts } from 'stanza/jingle/Session';
7
+ import { Client } from './client';
8
+ import { ExtendedRTCIceServer, IClientOptions, SessionTypes, IPendingSession, StreamingClientExtension, NRProxyStat, InsightAction } from './types/interfaces';
9
+ import { NamedAgent } from './types/named-agent';
10
+ import { StanzaMediaSession } from './types/stanza-media-session';
11
+ import { IMediaSession } from './types/media-session';
12
+ import Logger from 'genesys-cloud-client-logger';
13
+ export interface InitRtcSessionOptions {
14
+ stream?: MediaStream;
15
+ provideVideo?: boolean;
16
+ provideAudio?: boolean;
17
+ mediaPurpose?: string;
18
+ jid?: string;
19
+ conversationId?: string;
20
+ sourceCommunicationId?: string;
21
+ videoGuest?: boolean;
22
+ }
23
+ export declare class WebrtcExtension extends EventEmitter implements StreamingClientExtension {
24
+ client: Client;
25
+ ignoredSessions: LRUCache<string, boolean, unknown>;
26
+ private earlyIceCandidates;
27
+ logger: Logger;
28
+ pendingSessions: {
29
+ [sessionId: string]: IPendingSession;
30
+ };
31
+ config: {
32
+ allowIPv6: boolean;
33
+ optOutOfWebrtcStatsTelemetry?: boolean;
34
+ };
35
+ private statsArr;
36
+ private throttleSendStatsInterval;
37
+ private currentMaxStatSize;
38
+ private statsSizeDecreaseAmount;
39
+ private statBuffer;
40
+ private throttledSendStats;
41
+ private discoRetries;
42
+ private refreshIceServersRetryPromise;
43
+ private refreshIceServersTimer;
44
+ private iceServers;
45
+ private stanzaInstance?;
46
+ private stanzaSessions;
47
+ private webrtcSessions;
48
+ private reinviteCache;
49
+ private sessionsMap;
50
+ get jid(): string | undefined;
51
+ constructor(client: Client, clientOptions: IClientOptions);
52
+ private onOnlineStatusChange;
53
+ handleStanzaInstanceChange(stanzaInstance: NamedAgent): Promise<void>;
54
+ configureNewStanzaInstance(stanzaInstance: NamedAgent): Promise<void>;
55
+ private configureStanzaIceServers;
56
+ private handleGenesysOffer;
57
+ private applyEarlyIceCandidates;
58
+ private handleGenesysRenegotiate;
59
+ private handleGenesysIceCandidate;
60
+ private handleGenesysTerminate;
61
+ private getSessionById;
62
+ sendIq(iq: IQ): Promise<any>;
63
+ handleMessage(msg: any): Promise<void>;
64
+ handleGenesysWebrtcStanza(iq: IQ): Promise<boolean | void>;
65
+ prepareSession(options: SessionOpts): StanzaMediaSession | undefined;
66
+ proxyStatsForSession(session: IMediaSession): void;
67
+ addStatToQueue<T extends {
68
+ _eventType: string;
69
+ }>(stat: InsightAction<T>): void;
70
+ getLogDetailsForPendingSessionId(sessionId: string): {
71
+ conversationId?: string;
72
+ sessionId: string;
73
+ sessionType?: SessionTypes;
74
+ };
75
+ sendStatsImmediately(): void;
76
+ sendStats(): Promise<void>;
77
+ addEventListeners(): void;
78
+ /**
79
+ * Stanza Handlers
80
+ */
81
+ private handlePropose;
82
+ private handleRetract;
83
+ /**
84
+ * Inform the client that another client has already taken care of the pendingSession
85
+ */
86
+ private handledIncomingRtcSession;
87
+ /**
88
+ * Exposed Api
89
+ */
90
+ initiateRtcSession(opts: InitRtcSessionOptions): Promise<any>;
91
+ acceptRtcSession(sessionId: string): Promise<void>;
92
+ rejectRtcSession(sessionId: string, ignore?: boolean): Promise<void>;
93
+ rtcSessionAccepted(sessionId: string): Promise<void>;
94
+ notifyScreenShareStart(session: IMediaSession): Promise<void>;
95
+ notifyScreenShareStop(session: IMediaSession): Promise<void>;
96
+ cancelRtcSession(sessionId: string): Promise<void>;
97
+ refreshIceServers(): Promise<ExtendedRTCIceServer[]>;
98
+ _refreshIceServers(stanzaInstance?: NamedAgent): Promise<ExtendedRTCIceServer[]>;
99
+ setIceServers(iceServers: any[], stanzaInstance: NamedAgent): void;
100
+ getIceTransportPolicy(): RTCIceTransportPolicy | undefined;
101
+ setIceTransportPolicy(policy: 'relay' | 'all', stanzaInstance: NamedAgent): void;
102
+ getSessionTypeByJid(jid: string): SessionTypes;
103
+ getSessionManager(): SessionManager | undefined;
104
+ getAllSessions(): IMediaSession[];
105
+ proxyNRStat(stat: NRProxyStat): void;
106
+ get expose(): WebrtcExtensionAPI;
107
+ }
108
+ export interface WebrtcExtensionAPI {
109
+ on: (event: string, handler: (...args: any) => void) => void;
110
+ once: (event: string, handler: (...args: any) => void) => void;
111
+ off: (event: string, handler: (...args: any) => void) => void;
112
+ removeAllListeners(event?: string | symbol): void;
113
+ removeListener(event: string | symbol, listener: (...args: any[]) => void): void;
114
+ refreshIceServers(): Promise<any[]>;
115
+ acceptRtcSession(sessionId: string): void;
116
+ rejectRtcSession(sessionId: string, ignore?: boolean): void;
117
+ cancelRtcSession(sessionId: string): void;
118
+ rtcSessionAccepted(sessionId: string): void;
119
+ initiateRtcSession(opts: InitRtcSessionOptions): Promise<void>;
120
+ notifyScreenShareStart(session: IMediaSession): void;
121
+ notifyScreenShareStop(session: IMediaSession): void;
122
+ getSessionTypeByJid(jid: string): SessionTypes;
123
+ getSessionManager: () => SessionManager | undefined;
124
+ getAllSessions: () => IMediaSession[];
125
+ proxyNRStat: (stat: NRProxyStat) => void;
126
+ }