@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,893 @@
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.WebrtcExtension = void 0;
7
+ const events_1 = require("events");
8
+ const JID_1 = require("stanza/JID");
9
+ const lru_cache_1 = require("lru-cache");
10
+ const Constants_1 = require("stanza/Constants");
11
+ const lodash_throttle_1 = __importDefault(require("lodash.throttle"));
12
+ const browserama_1 = require("browserama");
13
+ const webrtc_signaling_1 = require("./stanza-definitions/webrtc-signaling");
14
+ const utils_1 = require("./utils");
15
+ const client_1 = require("./client");
16
+ const stats_formatter_1 = require("./stats-formatter");
17
+ const interfaces_1 = require("./types/interfaces");
18
+ const stanza_media_session_1 = require("./types/stanza-media-session");
19
+ const genesys_cloud_media_session_1 = require("./types/genesys-cloud-media-session");
20
+ const http_client_1 = require("./http-client");
21
+ const events = {
22
+ REQUEST_WEBRTC_DUMP: 'requestWebrtcDump',
23
+ /* jingle messaging */
24
+ REQUEST_INCOMING_RTCSESSION: 'requestIncomingRtcSession',
25
+ CANCEL_INCOMING_RTCSESSION: 'cancelIncomingRtcSession',
26
+ HANDLED_INCOMING_RTCSESSION: 'handledIncomingRtcSession',
27
+ OUTGOING_RTCSESSION_PROCEED: 'outgoingRtcSessionProceed',
28
+ OUTGOING_RTCSESSION_REJECTED: 'outgoingRtcSessionRejected',
29
+ // /* jingle */
30
+ // RTC_ICESERVERS: 'rtcIceServers', // ice servers have been discovered
31
+ INCOMING_RTCSESSION: 'incomingRtcSession',
32
+ OUTGOING_RTCSESSION: 'outgoingRtcSession',
33
+ RTCSESSION_ERROR: 'rtcSessionError' // jingle error occurred
34
+ // TRACE_RTCSESSION: 'traceRtcSession', // trace messages for logging, etc
35
+ // UPGRADE_MEDIA_ERROR: 'upgradeMediaError', // error occurred joining conference
36
+ // /* other */
37
+ // UPDATE_MEDIA_PRESENCE: 'updateMediaPresence',
38
+ // LASTN_CHANGE: 'lastNChange'
39
+ };
40
+ const desiredMaxStatsSize = 15000;
41
+ const MAX_DISCO_RETRIES = 2;
42
+ const ICE_SERVER_TIMEOUT = 15000; // 15 seconds
43
+ const ICE_SERVER_REFRESH_PERIOD = 1000 * 60 * 60 * 6; // 6 hours
44
+ class WebrtcExtension extends events_1.EventEmitter {
45
+ constructor(client, clientOptions) {
46
+ super();
47
+ // sessionId maps to boolean where `true` means the sessionId is ignored
48
+ this.ignoredSessions = new lru_cache_1.LRUCache({ max: 10, ttl: 10 * 60 * 60 * 6 });
49
+ // sessionId maps to a list of sdp ice candidates
50
+ // hold onto early candidates for 1 minute
51
+ this.earlyIceCandidates = new lru_cache_1.LRUCache({ max: 10, ttl: 1000 * 60, ttlAutopurge: true });
52
+ this.pendingSessions = {};
53
+ this.statsArr = [];
54
+ this.throttleSendStatsInterval = 25000;
55
+ this.currentMaxStatSize = desiredMaxStatsSize;
56
+ this.statsSizeDecreaseAmount = 3000;
57
+ this.statBuffer = 0;
58
+ this.discoRetries = 0;
59
+ this.iceServers = [];
60
+ this.stanzaSessions = [];
61
+ this.webrtcSessions = [];
62
+ // Store a maximum of 5 previous non-duplicate reinvites.
63
+ // These will automatically be purged after three minutes.
64
+ this.reinviteCache = new lru_cache_1.LRUCache({
65
+ max: 5,
66
+ ttl: 1000 * 60 * 3
67
+ });
68
+ this.sessionsMap = {};
69
+ this.client = client;
70
+ this.config = {
71
+ allowIPv6: clientOptions.allowIPv6 === true,
72
+ optOutOfWebrtcStatsTelemetry: clientOptions.optOutOfWebrtcStatsTelemetry
73
+ };
74
+ this.logger = client.logger;
75
+ this.addEventListeners();
76
+ this.throttledSendStats = (0, lodash_throttle_1.default)(this.sendStats.bind(this), this.throttleSendStatsInterval, { leading: false, trailing: true });
77
+ this.client.on('jingle:outgoing', (session) => {
78
+ this.logger.info('Emitting jingle:outgoing media-session (session-init)', session.sid);
79
+ return this.emit(events.OUTGOING_RTCSESSION, session);
80
+ });
81
+ this.client.on('jingle:incoming', (session) => {
82
+ this.logger.info('Emitting jingle:incoming media-session (session-init)', session.sid);
83
+ return this.emit(events.INCOMING_RTCSESSION, session);
84
+ });
85
+ this.client.on('jingle:created', (session) => {
86
+ // if this is not a JingleSession, this is a generic BaseSession from jingle, aka dummy session.
87
+ // in this case, we can just kill this session because we will be using
88
+ if (!(session instanceof stanza_media_session_1.StanzaMediaSession)) {
89
+ session.end('cancel', true);
90
+ }
91
+ });
92
+ if (typeof window !== 'undefined') {
93
+ window.addEventListener('offline', () => this.onOnlineStatusChange(false));
94
+ window.addEventListener('online', () => this.onOnlineStatusChange(true));
95
+ }
96
+ }
97
+ get jid() {
98
+ var _a;
99
+ return (_a = this.stanzaInstance) === null || _a === void 0 ? void 0 : _a.jid;
100
+ }
101
+ onOnlineStatusChange(online) {
102
+ this.addStatToQueue({
103
+ actionName: 'WebrtcStats',
104
+ details: {
105
+ _eventType: 'onlineStatus',
106
+ _eventTimestamp: new Date().getTime(),
107
+ online
108
+ }
109
+ });
110
+ }
111
+ async handleStanzaInstanceChange(stanzaInstance) {
112
+ this.stanzaInstance = stanzaInstance;
113
+ // We create a new Stanza instance every time we connect. If we still have active StanzaMediaSessions,
114
+ // the new instance doesn't know about them and won't properly process actions for those sessions
115
+ // (e.g. it will reply to a `session-terminate`, but the session itself won't receive that action,
116
+ // because Stanza doesn't know about it). Since we track those sessions ourselves, we can tell
117
+ // the new Stanza instance about them so those actions will be processed properly.
118
+ const sessionsMap = this.stanzaSessions.reduce((currentMap, session) => {
119
+ session.parent = stanzaInstance.jingle;
120
+ return { ...currentMap, [session.id]: session };
121
+ }, {});
122
+ this.stanzaInstance.jingle.sessions = sessionsMap;
123
+ if (this.refreshIceServersTimer) {
124
+ clearInterval(this.refreshIceServersTimer);
125
+ this.refreshIceServersTimer = null;
126
+ }
127
+ stanzaInstance.on('iq:set:genesysWebrtc', this.handleGenesysWebrtcStanza.bind(this));
128
+ this.refreshIceServersTimer = setInterval(this.refreshIceServers.bind(this), ICE_SERVER_REFRESH_PERIOD);
129
+ this.client.emit('sessionManagerChange', stanzaInstance);
130
+ }
131
+ async configureNewStanzaInstance(stanzaInstance) {
132
+ Object.assign(stanzaInstance.jingle.config.peerConnectionConfig, {
133
+ sdpSemantics: 'unified-plan'
134
+ });
135
+ await this.configureStanzaIceServers(stanzaInstance);
136
+ stanzaInstance.stanzas.define(webrtc_signaling_1.definitions);
137
+ stanzaInstance.jingle.prepareSession = this.prepareSession.bind(this);
138
+ stanzaInstance.jingle.on('log', (level, message, data) => {
139
+ this.logger[level](message, data);
140
+ });
141
+ const eventsToProxy = [
142
+ 'iceConnectionType',
143
+ 'peerTrackAdded',
144
+ 'peerTrackRemoved',
145
+ 'mute',
146
+ 'unmute',
147
+ 'sessionState',
148
+ 'connectionState',
149
+ 'terminated',
150
+ 'stats',
151
+ 'endOfCandidates'
152
+ ];
153
+ for (const e of eventsToProxy) {
154
+ stanzaInstance.jingle.on(e, (session, ...data) => {
155
+ if (!(session instanceof stanza_media_session_1.StanzaMediaSession)) {
156
+ return;
157
+ }
158
+ session.emit(e, ...data);
159
+ });
160
+ }
161
+ }
162
+ configureStanzaIceServers(stanzaInstance) {
163
+ /* clear out stanzas default use of google's stun server */
164
+ stanzaInstance.jingle.config.iceServers = [];
165
+ /**
166
+ * NOTE: calling this here should not interfere with the `webrtc.ts` extension
167
+ * refreshingIceServers since that is async and this constructor is sync
168
+ */
169
+ this.setIceServers([], stanzaInstance);
170
+ return this._refreshIceServers(stanzaInstance);
171
+ }
172
+ async handleGenesysOffer(iq) {
173
+ const message = iq.genesysWebrtc;
174
+ const params = message.params;
175
+ // XMPP-SIP-Gateway will repeat reinvite offers until the client has responded.
176
+ // We don't want to process the duplicate reinvites and instead will ignore them.
177
+ if (params.reinvite && this.reinviteCache.get(message.id)) {
178
+ this.logger.info('Ignoring duplicate reinvite offer', message.id);
179
+ return;
180
+ }
181
+ // If the reinvite isn't a duplicate, we should cache it so we can check against new offers.
182
+ if (params.reinvite) {
183
+ this.reinviteCache.set(message.id, true);
184
+ }
185
+ const ignoreHostCandidatesForForceTurnFF = this.getIceTransportPolicy() === 'relay' && browserama_1.isFirefox;
186
+ const commonParams = {
187
+ id: params.sessionId,
188
+ logger: this.logger,
189
+ peerID: iq.from,
190
+ fromJid: iq.from,
191
+ sessionType: this.getSessionTypeByJid(iq.from),
192
+ conversationId: params.conversationId,
193
+ ignoreHostCandidatesFromRemote: ignoreHostCandidatesForForceTurnFF,
194
+ optOutOfWebrtcStatsTelemetry: !!this.config.optOutOfWebrtcStatsTelemetry,
195
+ allowIPv6: this.config.allowIPv6,
196
+ iceServers: this.iceServers,
197
+ reinvite: !!params.reinvite,
198
+ iceTransportPolicy: this.getIceTransportPolicy()
199
+ };
200
+ let mediaSessionParams;
201
+ // we should only do something if the pending session tells us to
202
+ const pendingSession = this.pendingSessions[params.sessionId];
203
+ if (pendingSession) {
204
+ mediaSessionParams = {
205
+ ...commonParams,
206
+ meetingId: pendingSession.meetingId,
207
+ fromUserId: pendingSession.fromUserId,
208
+ originalRoomJid: pendingSession.originalRoomJid,
209
+ privAnswerMode: pendingSession.privAnswerMode
210
+ };
211
+ delete this.pendingSessions[pendingSession.sessionId];
212
+ }
213
+ else {
214
+ mediaSessionParams = commonParams;
215
+ }
216
+ // if we receive an offer for an existing session and the ice info has not changed, this is
217
+ // a renogotiate. If the ice has changed, it's a re-invite and we need to create a new session.
218
+ const existingSession = this.webrtcSessions.find(s => s.id === mediaSessionParams.id);
219
+ this.logger.info('offer received', { existingSession: !!existingSession, mediaSessionParams });
220
+ if (existingSession) {
221
+ existingSession.conversationId = params.conversationId;
222
+ // renego
223
+ if (!(0, utils_1.iceIsDifferent)(existingSession.peerConnection.remoteDescription.sdp, params.sdp)) {
224
+ return this.handleGenesysRenegotiate(existingSession, params.sdp);
225
+ }
226
+ }
227
+ // reinvite/new session handled the same way here
228
+ const session = new genesys_cloud_media_session_1.GenesysCloudMediaSession(this, mediaSessionParams);
229
+ await session.setRemoteDescription(params.sdp);
230
+ this.proxyStatsForSession(session);
231
+ session.on('sendIq', (iq) => { var _a; return (_a = this.stanzaInstance) === null || _a === void 0 ? void 0 : _a.sendIQ(iq); });
232
+ session.on('terminated', () => {
233
+ delete this.sessionsMap[session.id];
234
+ this.webrtcSessions = this.webrtcSessions.filter(s => s.id !== session.id);
235
+ });
236
+ this.webrtcSessions.push(session);
237
+ this.logger.info('emitting sdp media-session (offer');
238
+ this.applyEarlyIceCandidates(session);
239
+ return this.emit(events.INCOMING_RTCSESSION, session);
240
+ }
241
+ applyEarlyIceCandidates(session) {
242
+ const earlyCandidates = this.earlyIceCandidates.get(session.id);
243
+ if (earlyCandidates) {
244
+ this.earlyIceCandidates.delete(session.id);
245
+ for (const candidate of earlyCandidates) {
246
+ void session.addRemoteIceCandidate(candidate);
247
+ }
248
+ }
249
+ }
250
+ async handleGenesysRenegotiate(existingSession, newSdp) {
251
+ await existingSession.peerConnection.setRemoteDescription({ sdp: newSdp, type: 'offer' });
252
+ await existingSession.accept();
253
+ }
254
+ async handleGenesysIceCandidate(iq) {
255
+ const message = iq.genesysWebrtc;
256
+ const params = message.params;
257
+ const session = this.getSessionById(params.sessionId, true);
258
+ if (session) {
259
+ await session.addRemoteIceCandidate(params.sdp);
260
+ }
261
+ else {
262
+ const earlyCandidates = this.earlyIceCandidates.get(params.sessionId);
263
+ if (earlyCandidates) {
264
+ this.earlyIceCandidates.set(params.sessionId, [...earlyCandidates, params.sdp]);
265
+ }
266
+ else {
267
+ this.earlyIceCandidates.set(params.sessionId, [params.sdp]);
268
+ }
269
+ }
270
+ }
271
+ async handleGenesysTerminate(iq) {
272
+ const message = iq.genesysWebrtc;
273
+ const params = message.params;
274
+ const session = this.getSessionById(params.sessionId, true);
275
+ if (!session) {
276
+ this.logger.warn('Received terminate for session that does not exist', { sessionId: params.sessionId });
277
+ return;
278
+ }
279
+ session.onSessionTerminate(params.reason);
280
+ }
281
+ getSessionById(id, nullIfNotFound = false) {
282
+ const session = this.getAllSessions().find(session => session.id === id);
283
+ if (!session && !nullIfNotFound) {
284
+ const error = new Error('Failed to find session by id');
285
+ this.logger.error(error, { sessionId: id });
286
+ throw error;
287
+ }
288
+ return session;
289
+ }
290
+ async sendIq(iq) {
291
+ if (!this.stanzaInstance) {
292
+ throw new Error('Failed to send iq because there was no stanza instance');
293
+ }
294
+ return this.stanzaInstance.sendIQ(iq);
295
+ }
296
+ async handleMessage(msg) {
297
+ if (msg.propose) {
298
+ await this.handlePropose(msg);
299
+ }
300
+ else if (msg.retract) {
301
+ this.handleRetract(msg.retract.sessionId);
302
+ }
303
+ else if (msg.accept) {
304
+ this.handledIncomingRtcSession(msg.accept.sessionId, msg);
305
+ }
306
+ else if (msg.reject) {
307
+ this.handledIncomingRtcSession(msg.reject.sessionId, msg);
308
+ }
309
+ }
310
+ async handleGenesysWebrtcStanza(iq) {
311
+ const webrtcInfo = iq.genesysWebrtc;
312
+ if (webrtcInfo.method === 'offer') {
313
+ return this.handleGenesysOffer(iq);
314
+ }
315
+ else if (webrtcInfo.method === 'iceCandidate') {
316
+ return this.handleGenesysIceCandidate(iq);
317
+ }
318
+ else if (webrtcInfo.method === 'terminate') {
319
+ return this.handleGenesysTerminate(iq);
320
+ }
321
+ }
322
+ prepareSession(options) {
323
+ if (options.sid && this.sessionsMap[options.sid]) {
324
+ this.logger.debug('skipping creation of jingle webrtc session due to sdpOverXmpp');
325
+ return;
326
+ }
327
+ const pendingSession = this.pendingSessions[options.sid];
328
+ if (pendingSession) {
329
+ delete this.pendingSessions[pendingSession.sessionId];
330
+ }
331
+ const ignoreHostCandidatesForForceTurnFF = this.getIceTransportPolicy() === 'relay' && browserama_1.isFirefox;
332
+ const gcSessionOpts = {
333
+ options,
334
+ logger: this.logger,
335
+ id: options.sid,
336
+ fromJid: options.peerID,
337
+ peerID: options.peerID,
338
+ optOutOfWebrtcStatsTelemetry: !!this.config.optOutOfWebrtcStatsTelemetry,
339
+ conversationId: pendingSession === null || pendingSession === void 0 ? void 0 : pendingSession.conversationId,
340
+ fromUserId: pendingSession === null || pendingSession === void 0 ? void 0 : pendingSession.fromJid,
341
+ originalRoomJid: pendingSession === null || pendingSession === void 0 ? void 0 : pendingSession.originalRoomJid,
342
+ sessionType: pendingSession === null || pendingSession === void 0 ? void 0 : pendingSession.sessionType,
343
+ allowIPv6: this.config.allowIPv6,
344
+ ignoreHostCandidatesFromRemote: ignoreHostCandidatesForForceTurnFF,
345
+ meetingId: pendingSession === null || pendingSession === void 0 ? void 0 : pendingSession.meetingId
346
+ };
347
+ const session = new stanza_media_session_1.StanzaMediaSession(gcSessionOpts);
348
+ this.proxyStatsForSession(session);
349
+ this.stanzaSessions.push(session);
350
+ session.on('terminated', () => {
351
+ delete this.sessionsMap[session.id];
352
+ this.stanzaSessions = this.stanzaSessions.filter(s => s.id !== session.id);
353
+ });
354
+ return session;
355
+ }
356
+ // This should probably go into the webrtc sdk, but for now I'm putting here so it's in a central location.
357
+ // This should be moved when the sdk is the primary consumer
358
+ proxyStatsForSession(session) {
359
+ session.on('stats', (statsEvent) => {
360
+ const statsCopy = JSON.parse(JSON.stringify(statsEvent));
361
+ const extraDetails = {
362
+ conversationId: session.conversationId,
363
+ sessionId: session.id,
364
+ sessionType: session.sessionType
365
+ };
366
+ // format the event to what the api expects
367
+ const event = (0, stats_formatter_1.formatStatsEvent)(statsCopy, extraDetails);
368
+ this.addStatToQueue(event);
369
+ });
370
+ }
371
+ // this fn checks to see if the new stat fits inside the buffer. If not, send the queue;
372
+ addStatToQueue(stat) {
373
+ if (this.config.optOutOfWebrtcStatsTelemetry) {
374
+ return;
375
+ }
376
+ if (!stat.details._appId) {
377
+ stat.details._appId = this.logger.clientId;
378
+ stat.details._appName = 'streamingclient';
379
+ stat.details._appVersion = client_1.Client.version;
380
+ }
381
+ stat.details._originAppId = this.client.config.appId;
382
+ // nr only accepts single level objects so we must flatten everything just in case
383
+ const flattenedDetails = (0, stats_formatter_1.deepFlatten)(stat.details);
384
+ // new relic doesn't accept booleans so we convert them to strings
385
+ Object.keys(flattenedDetails).forEach((key) => {
386
+ const val = flattenedDetails[key];
387
+ if (typeof val === 'boolean') {
388
+ flattenedDetails[key] = `${val}`;
389
+ }
390
+ });
391
+ const formattedStat = {
392
+ ...stat,
393
+ details: flattenedDetails
394
+ };
395
+ const currentEventSize = (0, utils_1.calculatePayloadSize)(formattedStat);
396
+ // Check if the size of the current event plus the size of the previous stats exceeds max size.
397
+ const exceedsMaxStatSize = this.statBuffer + currentEventSize > this.currentMaxStatSize;
398
+ this.statsArr.push(formattedStat);
399
+ this.statBuffer += currentEventSize;
400
+ // If it exceeds max size, don't append just send current payload.
401
+ if (exceedsMaxStatSize) {
402
+ this.sendStatsImmediately();
403
+ }
404
+ else {
405
+ this.throttledSendStats();
406
+ }
407
+ }
408
+ getLogDetailsForPendingSessionId(sessionId) {
409
+ const logDetails = {
410
+ sessionId
411
+ };
412
+ const pendingSession = this.pendingSessions[sessionId];
413
+ if (pendingSession) {
414
+ logDetails.sessionType = pendingSession.sessionType;
415
+ logDetails.conversationId = pendingSession.conversationId;
416
+ }
417
+ return logDetails;
418
+ }
419
+ sendStatsImmediately() {
420
+ // `throttledSendStats` needs to have a scheduled exeuction for `flush` to invoke the throttled function
421
+ this.throttledSendStats();
422
+ this.throttledSendStats.flush();
423
+ }
424
+ async sendStats() {
425
+ var _a, _b;
426
+ if (!navigator.onLine) {
427
+ return;
428
+ }
429
+ const statsToSend = [];
430
+ let currentSize = 0;
431
+ for (const stats of this.statsArr) {
432
+ const statSize = (0, utils_1.calculatePayloadSize)(stats);
433
+ if (currentSize + statSize < this.currentMaxStatSize) {
434
+ statsToSend.push(stats);
435
+ currentSize += statSize;
436
+ }
437
+ else {
438
+ break;
439
+ }
440
+ }
441
+ this.statsArr.splice(0, statsToSend.length);
442
+ this.statBuffer = this.statsArr.reduce((currentSize, stats) => currentSize + (0, utils_1.calculatePayloadSize)(stats), 0);
443
+ if (!statsToSend.length || this.client.isGuest) {
444
+ return;
445
+ }
446
+ const data = {
447
+ appName: 'streamingclient',
448
+ appVersion: client_1.Client.version,
449
+ originAppName: this.client.config.appName,
450
+ originAppVersion: this.client.config.appVersion,
451
+ actions: statsToSend
452
+ };
453
+ // At least for now, we'll just fire and forget. Since this is non-critical, we'll not retry failures
454
+ try {
455
+ let authToken = this.client.config.authToken;
456
+ let url = 'diagnostics/newrelic/insights';
457
+ if (this.client.backgroundAssistantMode) {
458
+ authToken = this.client.config.jwt;
459
+ url += '/backgroundassistant';
460
+ }
461
+ await this.client.http.requestApi(url, {
462
+ method: 'post',
463
+ responseType: 'text',
464
+ host: this.client.config.apiHost,
465
+ authToken,
466
+ logger: this.client.logger,
467
+ data
468
+ });
469
+ this.currentMaxStatSize = desiredMaxStatsSize;
470
+ }
471
+ catch (err) {
472
+ // re-add the stats to the buffer
473
+ if (http_client_1.HttpClient.retryStatusCodes.has((_a = err.response) === null || _a === void 0 ? void 0 : _a.status) || !navigator.onLine) {
474
+ this.statsArr = [...statsToSend, ...this.statsArr];
475
+ this.statBuffer = this.statsArr.reduce((currentSize, stats) => currentSize + (0, utils_1.calculatePayloadSize)(stats), 0);
476
+ }
477
+ if (((_b = err.response) === null || _b === void 0 ? void 0 : _b.status) === 413) {
478
+ const attemptedPayloadSize = this.currentMaxStatSize;
479
+ this.currentMaxStatSize -= this.statsSizeDecreaseAmount;
480
+ this.logger.info('Failed to send stats due to 413, retrying with smaller set', { attemptedPayloadSize, newPayloadSize: this.currentMaxStatSize });
481
+ await this.sendStats();
482
+ }
483
+ else {
484
+ this.logger.error('Failed to send stats', {
485
+ err,
486
+ numberOfFailedStats: statsToSend.length
487
+ }, { skipServer: !navigator.onLine });
488
+ }
489
+ }
490
+ }
491
+ addEventListeners() {
492
+ this.client.on('connected', () => {
493
+ if (this.refreshIceServersTimer) {
494
+ clearInterval(this.refreshIceServersTimer);
495
+ this.refreshIceServersTimer = null;
496
+ }
497
+ this.refreshIceServersTimer = setInterval(this.refreshIceServers.bind(this), ICE_SERVER_REFRESH_PERIOD);
498
+ return this.refreshIceServers()
499
+ .catch((error) => this.logger.error('Error fetching ice servers after streaming-client connected', {
500
+ error,
501
+ channelId: this.client.config.channelId
502
+ }));
503
+ });
504
+ this.client.on('disconnected', () => {
505
+ clearInterval(this.refreshIceServersTimer);
506
+ this.refreshIceServersTimer = null;
507
+ });
508
+ }
509
+ /**
510
+ * Stanza Handlers
511
+ */
512
+ async handlePropose(msg) {
513
+ if (msg.from === this.jid) {
514
+ return;
515
+ }
516
+ const sessionId = msg.propose.sessionId;
517
+ let sessionInfo = this.pendingSessions[sessionId];
518
+ const isDuplicatePropose = !!sessionInfo;
519
+ const sessionType = this.getSessionTypeByJid(msg.from);
520
+ const loggingParams = { sessionId, conversationId: msg.propose.conversationId, sessionType, isDuplicatePropose };
521
+ this.logger.info('propose received', loggingParams);
522
+ if (!isDuplicatePropose) {
523
+ const { appId } = this.client.config;
524
+ const proposeStat = {
525
+ actionName: 'WebrtcStats',
526
+ details: {
527
+ _eventTimestamp: new Date().getTime(),
528
+ _eventType: 'firstPropose',
529
+ conversationId: loggingParams.conversationId,
530
+ sdpViaXmppRequested: !!msg.propose.sdpOverXmpp,
531
+ sessionId,
532
+ sessionType
533
+ }
534
+ };
535
+ this.addStatToQueue(proposeStat);
536
+ // TODO: is ofrom used?
537
+ // const roomJid = (msg.ofrom && msg.ofrom.full) || msg.from.full || msg.from;
538
+ const fromJid = msg.from;
539
+ const roomJid = fromJid;
540
+ msg.propose.originalRoomJid = msg.propose.originalRoomJid || roomJid;
541
+ sessionInfo = {
542
+ ...msg.propose,
543
+ toJid: msg.to,
544
+ fromJid,
545
+ sessionType,
546
+ roomJid,
547
+ id: sessionId,
548
+ sdpOverXmpp: msg.propose.sdpOverXmpp,
549
+ privAnswerMode: msg.propose.privAnswerMode
550
+ };
551
+ if (!isDuplicatePropose) {
552
+ this.sessionsMap[sessionInfo.id] = !!sessionInfo.sdpOverXmpp;
553
+ this.pendingSessions[sessionId] = sessionInfo;
554
+ }
555
+ }
556
+ if (sessionInfo.accepted) {
557
+ this.logger.info('proceed already sent for this session, but sending another', loggingParams);
558
+ await this.acceptRtcSession(sessionId);
559
+ return;
560
+ }
561
+ this.emit(events.REQUEST_INCOMING_RTCSESSION, Object.assign(sessionInfo));
562
+ }
563
+ handleRetract(sessionId) {
564
+ this.logger.info('retract received', this.getLogDetailsForPendingSessionId(sessionId));
565
+ delete this.sessionsMap[sessionId];
566
+ delete this.pendingSessions[sessionId];
567
+ return this.emit(events.CANCEL_INCOMING_RTCSESSION, sessionId);
568
+ }
569
+ /**
570
+ * Inform the client that another client has already taken care of the pendingSession
571
+ */
572
+ handledIncomingRtcSession(sessionId, msg) {
573
+ const acceptedOrRejected = msg.accept ? 'accept' : 'reject';
574
+ this.logger.info(`${acceptedOrRejected} received`, this.getLogDetailsForPendingSessionId(sessionId));
575
+ return this.emit(events.HANDLED_INCOMING_RTCSESSION, sessionId);
576
+ }
577
+ /**
578
+ * Exposed Api
579
+ */
580
+ async initiateRtcSession(opts) {
581
+ // send media presence to join conference or screen screenRecording
582
+ // or send propose to single client for 1:1 video chat
583
+ const session = {
584
+ to: opts.jid,
585
+ propose: {
586
+ id: globalThis.crypto.randomUUID(),
587
+ descriptions: []
588
+ }
589
+ };
590
+ if (opts.stream) {
591
+ for (const track of Array.from(opts.stream.getTracks())) {
592
+ session.propose.descriptions.push({ media: track.kind });
593
+ }
594
+ }
595
+ if (opts.provideVideo) {
596
+ const videoDescriptionAlreadyExists = session.propose.descriptions.filter((desciption) => desciption.media === 'video').length > 0;
597
+ if (!videoDescriptionAlreadyExists) {
598
+ session.propose.descriptions.push({ media: 'video' });
599
+ }
600
+ }
601
+ if (opts.provideAudio) {
602
+ const audioDescriptionAlreadyExists = session.propose.descriptions.filter((desciption) => desciption.media === 'audio').length > 0;
603
+ if (!audioDescriptionAlreadyExists) {
604
+ session.propose.descriptions.push({ media: 'audio' });
605
+ }
606
+ }
607
+ if (opts.mediaPurpose) {
608
+ session.propose.descriptions.push({ media: opts.mediaPurpose });
609
+ }
610
+ if (opts.jid && opts.jid.match(/@conference/)) {
611
+ let mediaDescriptions = session.propose.descriptions;
612
+ if (mediaDescriptions.length === 0) {
613
+ mediaDescriptions = [{ media: 'listener' }];
614
+ }
615
+ const mediaPresence = {
616
+ type: 'upgradeMedia',
617
+ to: opts.jid,
618
+ id: globalThis.crypto.randomUUID(),
619
+ from: this.jid,
620
+ media: {
621
+ conversationId: opts.conversationId,
622
+ sourceCommunicationId: opts.sourceCommunicationId
623
+ }
624
+ };
625
+ if (opts.mediaPurpose === interfaces_1.SessionTypes.collaborateVideo) {
626
+ Object.assign(mediaPresence.media, {
627
+ video: true,
628
+ audio: true,
629
+ videoGuest: true
630
+ });
631
+ }
632
+ // TODO? can't set last-n on parent element because it invalidates presence root schema
633
+ for (const mediaDescription of mediaDescriptions) {
634
+ mediaPresence.media[mediaDescription.media] = true;
635
+ }
636
+ await this.stanzaInstance.send('presence', mediaPresence);
637
+ }
638
+ else {
639
+ await this.stanzaInstance.send('message', session); // send as Message
640
+ this.pendingSessions[session.propose.id] = session;
641
+ }
642
+ return session.propose.id;
643
+ }
644
+ // jingle proceed
645
+ async acceptRtcSession(sessionId) {
646
+ const session = this.pendingSessions[sessionId];
647
+ if (!session) {
648
+ this.emit(events.RTCSESSION_ERROR, 'Cannot accept session because it is not pending or does not exist');
649
+ return;
650
+ }
651
+ const proceed = {
652
+ to: session.fromJid,
653
+ proceed: {
654
+ sessionId
655
+ }
656
+ };
657
+ session.accepted = true;
658
+ const details = this.getLogDetailsForPendingSessionId(sessionId);
659
+ this.logger.info('sending jingle proceed', details);
660
+ await this.stanzaInstance.send('message', proceed); // send as Message
661
+ this.logger.info('sent jingle proceed', details);
662
+ }
663
+ async rejectRtcSession(sessionId, ignore = false) {
664
+ const logDetails = this.getLogDetailsForPendingSessionId(sessionId);
665
+ const session = this.pendingSessions[sessionId];
666
+ if (!session) {
667
+ this.emit(events.RTCSESSION_ERROR, 'Cannot reject session because it is not pending or does not exist');
668
+ return;
669
+ }
670
+ delete this.sessionsMap[sessionId];
671
+ delete this.pendingSessions[sessionId];
672
+ if (ignore) {
673
+ this.ignoredSessions.set(sessionId, true);
674
+ }
675
+ else {
676
+ const reject1 = {
677
+ to: (0, JID_1.toBare)(this.jid),
678
+ reject: {
679
+ sessionId
680
+ }
681
+ };
682
+ const firstMessage = this.stanzaInstance.send('message', reject1); // send as Message
683
+ const reject2 = {
684
+ to: session.fromJid,
685
+ reject: {
686
+ sessionId
687
+ }
688
+ };
689
+ const secondMessage = this.stanzaInstance.send('message', reject2); // send as Message
690
+ this.logger.info('sending jingle reject', logDetails);
691
+ await Promise.all([firstMessage, secondMessage]);
692
+ this.logger.info('sent jingle reject', logDetails);
693
+ }
694
+ }
695
+ async rtcSessionAccepted(sessionId) {
696
+ const pendingSession = this.pendingSessions[sessionId];
697
+ const logDetails = this.getLogDetailsForPendingSessionId(sessionId);
698
+ const accept = {
699
+ to: (0, JID_1.toBare)(this.jid),
700
+ accept: {
701
+ sessionId
702
+ }
703
+ };
704
+ this.logger.info('sending session-info:accept', logDetails);
705
+ await this.stanzaInstance.send('message', accept); // send as Message
706
+ this.logger.info('sent session-info:accept', logDetails);
707
+ }
708
+ async notifyScreenShareStart(session) {
709
+ return this.stanzaInstance.send('iq', {
710
+ to: `${session.peerID}`,
711
+ from: this.jid,
712
+ type: 'set',
713
+ jingle: {
714
+ action: Constants_1.JingleAction.SessionInfo,
715
+ sid: session.id,
716
+ screenstart: {}
717
+ }
718
+ });
719
+ }
720
+ async notifyScreenShareStop(session) {
721
+ return this.stanzaInstance.send('iq', {
722
+ to: `${session.peerID}`,
723
+ from: this.jid,
724
+ type: 'set',
725
+ jingle: {
726
+ action: Constants_1.JingleAction.SessionInfo,
727
+ sid: session.id,
728
+ screenstop: {}
729
+ }
730
+ });
731
+ }
732
+ async cancelRtcSession(sessionId) {
733
+ const session = this.pendingSessions[sessionId];
734
+ const logDetails = this.getLogDetailsForPendingSessionId(sessionId);
735
+ if (!session) {
736
+ this.emit(events.RTCSESSION_ERROR, 'Cannot cancel session because it is not pending or does not exist');
737
+ return;
738
+ }
739
+ const retract = {
740
+ to: session.toJid,
741
+ retract: {
742
+ sessionId
743
+ }
744
+ };
745
+ delete this.pendingSessions[sessionId];
746
+ delete this.sessionsMap[sessionId];
747
+ this.logger.info('sending jingle retract', logDetails);
748
+ await this.stanzaInstance.send('message', retract); // send as Message
749
+ this.logger.info('sent jingle retract', logDetails);
750
+ }
751
+ async refreshIceServers() {
752
+ if (!this.refreshIceServersRetryPromise) {
753
+ this.refreshIceServersRetryPromise = (0, utils_1.retryPromise)(this._refreshIceServers.bind(this, this.stanzaInstance), (error) => {
754
+ if (++this.discoRetries > MAX_DISCO_RETRIES) {
755
+ this.logger.warn('fetching ice servers failed. max retries reached.', {
756
+ retryAttempt: this.discoRetries,
757
+ MAX_DISCO_RETRIES,
758
+ error,
759
+ channelId: this.client.config.channelId
760
+ });
761
+ return false;
762
+ }
763
+ this.logger.warn('fetching ice servers failed. retrying', {
764
+ retryAttempt: this.discoRetries,
765
+ error,
766
+ channelId: this.client.config.channelId
767
+ });
768
+ return true;
769
+ }, 0, this.client.logger);
770
+ }
771
+ return this.refreshIceServersRetryPromise.promise
772
+ .finally(() => {
773
+ this.discoRetries = 0;
774
+ this.refreshIceServersRetryPromise = undefined;
775
+ });
776
+ }
777
+ async _refreshIceServers(stanzaInstance) {
778
+ if (!stanzaInstance) {
779
+ throw new Error('No stanza instance to refresh ice servers');
780
+ }
781
+ const server = stanzaInstance.config.server;
782
+ const turnServersPromise = stanzaInstance.getServices(server, 'turn', '1');
783
+ const stunServersPromise = stanzaInstance.getServices(server, 'stun', '1');
784
+ const servicesPromise = new Promise((resolve, reject) => {
785
+ setTimeout(() => {
786
+ reject(new Error('Timeout waiting for refresh ice servers to finish'));
787
+ }, ICE_SERVER_TIMEOUT);
788
+ Promise.all([
789
+ turnServersPromise,
790
+ stunServersPromise
791
+ ])
792
+ .then(([turn, stun]) => {
793
+ resolve([turn, stun]);
794
+ })
795
+ .catch(reject);
796
+ });
797
+ const [turnServers, stunServers] = await servicesPromise;
798
+ const iceServers = [
799
+ ...turnServers.services,
800
+ ...stunServers.services
801
+ ].map((service) => {
802
+ const port = service.port ? `:${service.port}` : '';
803
+ const ice = {
804
+ type: service.type,
805
+ urls: `${service.type}:${service.host}${port}`
806
+ };
807
+ if (['turn', 'turns'].includes(service.type)) {
808
+ if (service.transport && service.transport !== 'udp') {
809
+ ice.urls += `?transport=${service.transport}`;
810
+ }
811
+ if (service.username) {
812
+ ice.username = service.username;
813
+ }
814
+ if (service.password) {
815
+ ice.credential = service.password;
816
+ }
817
+ }
818
+ return ice;
819
+ });
820
+ this.setIceServers(iceServers, stanzaInstance);
821
+ if (!stunServers.services.length) {
822
+ this.logger.info('No stun servers received, setting iceTransportPolicy to "relay"');
823
+ this.setIceTransportPolicy('relay', stanzaInstance);
824
+ }
825
+ else {
826
+ this.setIceTransportPolicy('all', stanzaInstance);
827
+ }
828
+ return iceServers;
829
+ }
830
+ setIceServers(iceServers, stanzaInstance) {
831
+ stanzaInstance.jingle.iceServers = iceServers;
832
+ this.iceServers = iceServers;
833
+ }
834
+ getIceTransportPolicy() {
835
+ var _a;
836
+ return (_a = this.stanzaInstance) === null || _a === void 0 ? void 0 : _a.jingle.config.peerConnectionConfig.iceTransportPolicy;
837
+ }
838
+ setIceTransportPolicy(policy, stanzaInstance) {
839
+ stanzaInstance.jingle.config.peerConnectionConfig.iceTransportPolicy = policy;
840
+ }
841
+ getSessionTypeByJid(jid) {
842
+ if ((0, utils_1.isAcdJid)(jid)) {
843
+ return interfaces_1.SessionTypes.acdScreenShare;
844
+ }
845
+ else if ((0, utils_1.isScreenRecordingJid)(jid)) {
846
+ return interfaces_1.SessionTypes.screenRecording;
847
+ }
848
+ else if ((0, utils_1.isLiveScreenMonitoringJid)(jid)) {
849
+ return interfaces_1.SessionTypes.liveScreenMonitoring;
850
+ }
851
+ else if ((0, utils_1.isSoftphoneJid)(jid)) {
852
+ return interfaces_1.SessionTypes.softphone;
853
+ }
854
+ else if ((0, utils_1.isVideoJid)(jid)) {
855
+ return interfaces_1.SessionTypes.collaborateVideo;
856
+ }
857
+ else {
858
+ return interfaces_1.SessionTypes.unknown;
859
+ }
860
+ }
861
+ getSessionManager() {
862
+ var _a;
863
+ return (_a = this.stanzaInstance) === null || _a === void 0 ? void 0 : _a.jingle;
864
+ }
865
+ getAllSessions() {
866
+ return [...this.stanzaSessions, ...this.webrtcSessions];
867
+ }
868
+ proxyNRStat(stat) {
869
+ this.addStatToQueue(stat);
870
+ }
871
+ get expose() {
872
+ return {
873
+ on: this.on.bind(this),
874
+ once: this.once.bind(this),
875
+ off: this.off.bind(this),
876
+ removeAllListeners: this.removeAllListeners.bind(this),
877
+ removeListener: this.removeListener.bind(this),
878
+ refreshIceServers: this.refreshIceServers.bind(this),
879
+ acceptRtcSession: this.acceptRtcSession.bind(this),
880
+ rejectRtcSession: this.rejectRtcSession.bind(this),
881
+ cancelRtcSession: this.cancelRtcSession.bind(this),
882
+ notifyScreenShareStart: this.notifyScreenShareStart.bind(this),
883
+ notifyScreenShareStop: this.notifyScreenShareStop.bind(this),
884
+ rtcSessionAccepted: this.rtcSessionAccepted.bind(this),
885
+ initiateRtcSession: this.initiateRtcSession.bind(this),
886
+ getSessionTypeByJid: this.getSessionTypeByJid.bind(this),
887
+ getSessionManager: this.getSessionManager.bind(this),
888
+ getAllSessions: this.getAllSessions.bind(this),
889
+ proxyNRStat: this.proxyNRStat.bind(this)
890
+ };
891
+ }
892
+ }
893
+ exports.WebrtcExtension = WebrtcExtension;