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