@signalapp/ringrtc 2.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1462 @@
1
+ "use strict";
2
+ //
3
+ // Copyright 2019-2021 Signal Messenger, LLC
4
+ // SPDX-License-Identifier: AGPL-3.0-only
5
+ //
6
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
7
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
8
+ return new (P || (P = Promise))(function (resolve, reject) {
9
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
10
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
11
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
12
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
13
+ });
14
+ };
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.CallLogLevel = exports.CallEndedReason = exports.CallState = exports.RingCancelReason = exports.BandwidthMode = exports.HangupType = exports.OpaqueMessage = exports.HangupMessage = exports.BusyMessage = exports.IceCandidateMessage = exports.AnswerMessage = exports.OfferType = exports.OfferMessage = exports.CallingMessage = exports.GroupCall = exports.VideoRequest = exports.GroupMemberInfo = exports.RemoteDeviceState = exports.LocalDeviceState = exports.HttpMethod = exports.RingUpdate = exports.CallMessageUrgency = exports.GroupCallEndReason = exports.JoinState = exports.ConnectionState = exports.Call = exports.RingRTCType = exports.ReceivedAudioLevel = exports.NetworkRoute = exports.PeekInfo = exports.PeekDeviceInfo = void 0;
17
+ /* tslint:disable max-classes-per-file */
18
+ const os = require("os");
19
+ const process = require("process");
20
+ // tslint:disable-next-line no-var-requires no-require-imports
21
+ const Native = require('../../build/' +
22
+ os.platform() +
23
+ '/libringrtc-' +
24
+ process.arch +
25
+ '.node');
26
+ class Config {
27
+ constructor() {
28
+ this.use_new_audio_device_module = false;
29
+ }
30
+ }
31
+ // tslint:disable-next-line no-unnecessary-class
32
+ class NativeCallManager {
33
+ constructor(observer) {
34
+ this.observer = observer;
35
+ this.createCallEndpoint(new Config());
36
+ }
37
+ setConfig(config) {
38
+ this.createCallEndpoint(config);
39
+ }
40
+ createCallEndpoint(config) {
41
+ const callEndpoint = Native.createCallEndpoint(this, config.use_new_audio_device_module);
42
+ Object.defineProperty(this, Native.callEndpointPropertyKey, {
43
+ value: callEndpoint,
44
+ configurable: true, // allows it to be changed
45
+ });
46
+ }
47
+ }
48
+ // Mirror methods onto NativeCallManager.
49
+ // This is done through direct assignment rather than wrapper methods to avoid indirection.
50
+ NativeCallManager.prototype.setSelfUuid = Native.cm_setSelfUuid;
51
+ NativeCallManager.prototype.createOutgoingCall =
52
+ Native.cm_createOutgoingCall;
53
+ NativeCallManager.prototype.proceed = Native.cm_proceed;
54
+ NativeCallManager.prototype.accept = Native.cm_accept;
55
+ NativeCallManager.prototype.ignore = Native.cm_ignore;
56
+ NativeCallManager.prototype.hangup = Native.cm_hangup;
57
+ NativeCallManager.prototype.cancelGroupRing =
58
+ Native.cm_cancelGroupRing;
59
+ NativeCallManager.prototype.signalingMessageSent =
60
+ Native.cm_signalingMessageSent;
61
+ NativeCallManager.prototype.signalingMessageSendFailed =
62
+ Native.cm_signalingMessageSendFailed;
63
+ NativeCallManager.prototype.updateBandwidthMode =
64
+ Native.cm_updateBandwidthMode;
65
+ NativeCallManager.prototype.receivedOffer = Native.cm_receivedOffer;
66
+ NativeCallManager.prototype.receivedAnswer = Native.cm_receivedAnswer;
67
+ NativeCallManager.prototype.receivedIceCandidates =
68
+ Native.cm_receivedIceCandidates;
69
+ NativeCallManager.prototype.receivedHangup = Native.cm_receivedHangup;
70
+ NativeCallManager.prototype.receivedBusy = Native.cm_receivedBusy;
71
+ NativeCallManager.prototype.receivedCallMessage =
72
+ Native.cm_receivedCallMessage;
73
+ NativeCallManager.prototype.receivedHttpResponse =
74
+ Native.cm_receivedHttpResponse;
75
+ NativeCallManager.prototype.httpRequestFailed =
76
+ Native.cm_httpRequestFailed;
77
+ NativeCallManager.prototype.setOutgoingAudioEnabled =
78
+ Native.cm_setOutgoingAudioEnabled;
79
+ NativeCallManager.prototype.setOutgoingVideoEnabled =
80
+ Native.cm_setOutgoingVideoEnabled;
81
+ NativeCallManager.prototype.setOutgoingVideoIsScreenShare =
82
+ Native.cm_setOutgoingVideoIsScreenShare;
83
+ NativeCallManager.prototype.sendVideoFrame = Native.cm_sendVideoFrame;
84
+ NativeCallManager.prototype.receiveVideoFrame =
85
+ Native.cm_receiveVideoFrame;
86
+ NativeCallManager.prototype.receiveGroupCallVideoFrame =
87
+ Native.cm_receiveGroupCallVideoFrame;
88
+ NativeCallManager.prototype.createGroupCallClient =
89
+ Native.cm_createGroupCallClient;
90
+ NativeCallManager.prototype.deleteGroupCallClient =
91
+ Native.cm_deleteGroupCallClient;
92
+ NativeCallManager.prototype.connect = Native.cm_connect;
93
+ NativeCallManager.prototype.join = Native.cm_join;
94
+ NativeCallManager.prototype.leave = Native.cm_leave;
95
+ NativeCallManager.prototype.disconnect = Native.cm_disconnect;
96
+ NativeCallManager.prototype.groupRing = Native.cm_groupRing;
97
+ NativeCallManager.prototype.setOutgoingAudioMuted =
98
+ Native.cm_setOutgoingAudioMuted;
99
+ NativeCallManager.prototype.setOutgoingVideoMuted =
100
+ Native.cm_setOutgoingVideoMuted;
101
+ NativeCallManager.prototype.setOutgoingGroupCallVideoIsScreenShare =
102
+ Native.cm_setOutgoingGroupCallVideoIsScreenShare;
103
+ NativeCallManager.prototype.setPresenting = Native.cm_setPresenting;
104
+ NativeCallManager.prototype.resendMediaKeys =
105
+ Native.cm_resendMediaKeys;
106
+ NativeCallManager.prototype.setBandwidthMode =
107
+ Native.cm_setBandwidthMode;
108
+ NativeCallManager.prototype.requestVideo = Native.cm_requestVideo;
109
+ NativeCallManager.prototype.setGroupMembers =
110
+ Native.cm_setGroupMembers;
111
+ NativeCallManager.prototype.setMembershipProof =
112
+ Native.cm_setMembershipProof;
113
+ NativeCallManager.prototype.peekGroupCall = Native.cm_peekGroupCall;
114
+ NativeCallManager.prototype.getAudioInputs = Native.cm_getAudioInputs;
115
+ NativeCallManager.prototype.setAudioInput = Native.cm_setAudioInput;
116
+ NativeCallManager.prototype.getAudioOutputs =
117
+ Native.cm_getAudioOutputs;
118
+ NativeCallManager.prototype.setAudioOutput = Native.cm_setAudioOutput;
119
+ NativeCallManager.prototype.processEvents = Native.cm_processEvents;
120
+ class PeekDeviceInfo {
121
+ constructor(demuxId, userId) {
122
+ this.demuxId = demuxId;
123
+ this.userId = userId;
124
+ }
125
+ }
126
+ exports.PeekDeviceInfo = PeekDeviceInfo;
127
+ class PeekInfo {
128
+ constructor() {
129
+ this.devices = [];
130
+ this.deviceCount = 0;
131
+ }
132
+ }
133
+ exports.PeekInfo = PeekInfo;
134
+ // In sync with WebRTC's PeerConnection.AdapterType.
135
+ // Despite how it looks, this is not an option set.
136
+ // A network adapter type can only be one of the listed values.
137
+ // And there are a few oddities to note:
138
+ // - Cellular means we don't know if it's 2G, 3G, 4G, 5G, ...
139
+ // If we know, it will be one of those corresponding enum values.
140
+ // This means to know if something is cellular or not, you must
141
+ // check all of those values.
142
+ // - Default means we don't know the adapter type (like Unknown)
143
+ // but it's because we bound to the default IP address (0.0.0.0)
144
+ // so it's probably the default adapter (wifi if available, for example)
145
+ // This is unlikely to happen in practice.
146
+ var NetworkAdapterType;
147
+ (function (NetworkAdapterType) {
148
+ NetworkAdapterType[NetworkAdapterType["Unknown"] = 0] = "Unknown";
149
+ NetworkAdapterType[NetworkAdapterType["Ethernet"] = 1] = "Ethernet";
150
+ NetworkAdapterType[NetworkAdapterType["Wifi"] = 2] = "Wifi";
151
+ NetworkAdapterType[NetworkAdapterType["Cellular"] = 4] = "Cellular";
152
+ NetworkAdapterType[NetworkAdapterType["Vpn"] = 8] = "Vpn";
153
+ NetworkAdapterType[NetworkAdapterType["Loopback"] = 16] = "Loopback";
154
+ NetworkAdapterType[NetworkAdapterType["Default"] = 32] = "Default";
155
+ NetworkAdapterType[NetworkAdapterType["Cellular2G"] = 64] = "Cellular2G";
156
+ NetworkAdapterType[NetworkAdapterType["Cellular3G"] = 128] = "Cellular3G";
157
+ NetworkAdapterType[NetworkAdapterType["Cellular4G"] = 256] = "Cellular4G";
158
+ NetworkAdapterType[NetworkAdapterType["Cellular5G"] = 512] = "Cellular5G";
159
+ })(NetworkAdapterType || (NetworkAdapterType = {}));
160
+ // Information about the network route being used for sending audio/video/data
161
+ class NetworkRoute {
162
+ constructor() {
163
+ this.localAdapterType = NetworkAdapterType.Unknown;
164
+ }
165
+ }
166
+ exports.NetworkRoute = NetworkRoute;
167
+ class ReceivedAudioLevel {
168
+ constructor(demuxId, level) {
169
+ this.demuxId = demuxId;
170
+ this.level = level;
171
+ }
172
+ }
173
+ exports.ReceivedAudioLevel = ReceivedAudioLevel;
174
+ function normalizeAudioLevel(raw) {
175
+ return raw / 32767;
176
+ }
177
+ class Requests {
178
+ constructor() {
179
+ this._resolveById = new Map();
180
+ this._nextId = 1;
181
+ }
182
+ add() {
183
+ const id = this._nextId++;
184
+ const promise = new Promise((resolve, _reject) => {
185
+ this._resolveById.set(id, resolve);
186
+ });
187
+ return [id, promise];
188
+ }
189
+ resolve(id, response) {
190
+ const resolve = this._resolveById.get(id);
191
+ if (!resolve) {
192
+ return false;
193
+ }
194
+ resolve(response);
195
+ this._resolveById.delete(id);
196
+ return true;
197
+ }
198
+ }
199
+ class CallInfo {
200
+ constructor(isVideoCall, receivedAtCounter) {
201
+ this.isVideoCall = isVideoCall;
202
+ this.receivedAtCounter = receivedAtCounter;
203
+ }
204
+ }
205
+ class RingRTCType {
206
+ constructor() {
207
+ // Set by UX
208
+ this.handleOutgoingSignaling = null;
209
+ this.handleIncomingCall = null;
210
+ this.handleAutoEndedIncomingCallRequest = null;
211
+ this.handleLogMessage = null;
212
+ this.handleSendHttpRequest = null;
213
+ this.handleSendCallMessage = null;
214
+ this.handleSendCallMessageToGroup = null;
215
+ this.handleGroupCallRingUpdate = null;
216
+ this.callManager = new NativeCallManager(this);
217
+ this._call = null;
218
+ this._groupCallByClientId = new Map();
219
+ this._peekRequests = new Requests();
220
+ this._callInfoByCallId = new Map();
221
+ }
222
+ getCallInfoKey(callId) {
223
+ // CallId is u64 so use a string key instead.
224
+ return callId.high.toString() + callId.low.toString();
225
+ }
226
+ setConfig(config) {
227
+ this.callManager.setConfig(config);
228
+ }
229
+ // Called by UX
230
+ setSelfUuid(uuid) {
231
+ this.callManager.setSelfUuid(uuid);
232
+ }
233
+ // Called by UX
234
+ startOutgoingCall(remoteUserId, isVideoCall, localDeviceId, settings) {
235
+ const callId = this.callManager.createOutgoingCall(remoteUserId, isVideoCall, localDeviceId);
236
+ const isIncoming = false;
237
+ const call = new Call(this.callManager, remoteUserId, callId, isIncoming, isVideoCall, settings, CallState.Prering);
238
+ this._call = call;
239
+ // We won't actually send anything until the remote side accepts.
240
+ call.outgoingAudioEnabled = true;
241
+ call.outgoingVideoEnabled = isVideoCall;
242
+ return call;
243
+ }
244
+ // Called by UX
245
+ cancelGroupRing(groupId, ringId, reason) {
246
+ silly_deadlock_protection(() => {
247
+ this.callManager.cancelGroupRing(groupId, ringId.toString(), reason);
248
+ });
249
+ }
250
+ // Called by Rust
251
+ onStartOutgoingCall(remoteUserId, callId) {
252
+ const call = this._call;
253
+ if (!call || call.remoteUserId !== remoteUserId || !call.settings) {
254
+ return;
255
+ }
256
+ call.callId = callId;
257
+ this.proceed(callId, call.settings);
258
+ }
259
+ // Called by Rust
260
+ onStartIncomingCall(remoteUserId, callId, isVideoCall) {
261
+ // Temporary: Force hangup in all glare scenarios until handled gracefully.
262
+ // In case of a glare loser, an incoming call will be generated right
263
+ // after the outgoing call is ended. In that case, ignore it once.
264
+ if (this._call &&
265
+ (this._call.endedReason === CallEndedReason.Glare ||
266
+ this._call.endedReason === CallEndedReason.ReCall)) {
267
+ this._call.endedReason = undefined;
268
+ // EVIL HACK: We are the "loser" of a glare collision and have ended the outgoing call
269
+ // and are now receiving the incoming call from the remote side (the "winner").
270
+ // However, the Desktop client has a bug where it re-orders the events so that
271
+ // instead of seeing ("outgoing call ended", "incoming call"), it sees
272
+ // ("incoming call", "call ended") and it gets messed up.
273
+ // The solution? Delay processing the incoming call.
274
+ setTimeout(() => {
275
+ this.onStartIncomingCall(remoteUserId, callId, isVideoCall);
276
+ }, 500);
277
+ return;
278
+ }
279
+ const isIncoming = true;
280
+ const call = new Call(this.callManager, remoteUserId, callId, isIncoming, isVideoCall, null, CallState.Prering);
281
+ // Callback to UX not set
282
+ const handleIncomingCall = this.handleIncomingCall;
283
+ if (!handleIncomingCall) {
284
+ call.ignore();
285
+ return;
286
+ }
287
+ this._call = call;
288
+ // tslint:disable no-floating-promises
289
+ (() => __awaiter(this, void 0, void 0, function* () {
290
+ const settings = yield handleIncomingCall(call);
291
+ if (!settings) {
292
+ call.ignore();
293
+ return;
294
+ }
295
+ call.settings = settings;
296
+ this.proceed(callId, settings);
297
+ }))();
298
+ }
299
+ proceed(callId, settings) {
300
+ silly_deadlock_protection(() => {
301
+ this.callManager.proceed(callId, settings.iceServer.username || '', settings.iceServer.password || '', settings.iceServer.urls, settings.hideIp, settings.bandwidthMode, settings.audioLevelsIntervalMillis || 0);
302
+ });
303
+ }
304
+ // Called by Rust
305
+ onCallState(remoteUserId, state) {
306
+ const call = this._call;
307
+ if (!call || call.remoteUserId !== remoteUserId) {
308
+ return;
309
+ }
310
+ call.state = state;
311
+ }
312
+ // Called by Rust
313
+ onCallEnded(remoteUserId, callId, reason, ageSec) {
314
+ let callInfo = this._callInfoByCallId.get(this.getCallInfoKey(callId));
315
+ const { isVideoCall, receivedAtCounter } = callInfo || {
316
+ isVideoCall: false,
317
+ receivedAtCounter: undefined,
318
+ };
319
+ this._callInfoByCallId.delete(this.getCallInfoKey(callId));
320
+ const call = this._call;
321
+ if (call && reason == CallEndedReason.ReceivedOfferWithGlare) {
322
+ // The current call is the outgoing call.
323
+ // The ended call is the incoming call.
324
+ // We're the "winner", so ignore the incoming call and keep going with the outgoing call.
325
+ return;
326
+ }
327
+ if (call &&
328
+ (reason === CallEndedReason.Glare || reason === CallEndedReason.ReCall)) {
329
+ // The current call is the outgoing call.
330
+ // The ended call is the outgoing call.
331
+ // We're the "loser", so end the outgoing/current call and wait for a new incoming call.
332
+ // (proceeded down to the code below)
333
+ }
334
+ // If there is no call or the remoteUserId doesn't match that of the current
335
+ // call, or if one of the "receive offer while already in a call or because
336
+ // it expired" reasons are provided, don't end the current call, because
337
+ // there isn't one for this Ended notification, just update the call history.
338
+ // If the incoming call ends while in the prering state, also immediately
339
+ // update the call history because it is just a replay of messages.
340
+ if (!call ||
341
+ call.remoteUserId !== remoteUserId ||
342
+ reason === CallEndedReason.ReceivedOfferWhileActive ||
343
+ reason === CallEndedReason.ReceivedOfferExpired ||
344
+ (call.state === CallState.Prering && call.isIncoming)) {
345
+ if (this.handleAutoEndedIncomingCallRequest) {
346
+ this.handleAutoEndedIncomingCallRequest(callId, remoteUserId, reason, ageSec, isVideoCall, receivedAtCounter);
347
+ }
348
+ if (call && call.state === CallState.Prering && call.isIncoming) {
349
+ // Set the state to Ended without triggering a state update since we
350
+ // already notified the client.
351
+ call.endedReason = reason;
352
+ call.setCallEnded();
353
+ }
354
+ return;
355
+ }
356
+ // Send the end reason first because setting the state triggers
357
+ // call.handleStateChanged, which may look at call.endedReason.
358
+ call.endedReason = reason;
359
+ call.state = CallState.Ended;
360
+ }
361
+ onRemoteVideoEnabled(remoteUserId, enabled) {
362
+ const call = this._call;
363
+ if (!call || call.remoteUserId !== remoteUserId) {
364
+ return;
365
+ }
366
+ call.remoteVideoEnabled = enabled;
367
+ if (call.handleRemoteVideoEnabled) {
368
+ call.handleRemoteVideoEnabled();
369
+ }
370
+ }
371
+ onRemoteSharingScreen(remoteUserId, enabled) {
372
+ const call = this._call;
373
+ if (!call || call.remoteUserId !== remoteUserId) {
374
+ return;
375
+ }
376
+ call.remoteSharingScreen = enabled;
377
+ if (call.handleRemoteSharingScreen) {
378
+ call.handleRemoteSharingScreen();
379
+ }
380
+ }
381
+ onNetworkRouteChanged(remoteUserId, localNetworkAdapterType) {
382
+ const call = this._call;
383
+ if (!call || call.remoteUserId !== remoteUserId) {
384
+ return;
385
+ }
386
+ call.networkRoute.localAdapterType = localNetworkAdapterType;
387
+ if (call.handleNetworkRouteChanged) {
388
+ call.handleNetworkRouteChanged();
389
+ }
390
+ }
391
+ onAudioLevels(remoteUserId, capturedLevel, receivedLevel) {
392
+ const call = this._call;
393
+ if (!call || call.remoteUserId !== remoteUserId) {
394
+ return;
395
+ }
396
+ call.outgoingAudioLevel = normalizeAudioLevel(capturedLevel);
397
+ call.remoteAudioLevel = normalizeAudioLevel(receivedLevel);
398
+ if (call.handleAudioLevels) {
399
+ call.handleAudioLevels();
400
+ }
401
+ }
402
+ renderVideoFrame(width, height, buffer) {
403
+ var _a, _b;
404
+ const call = this._call;
405
+ if (!call) {
406
+ return;
407
+ }
408
+ if (!!((_a = this._call) === null || _a === void 0 ? void 0 : _a.renderVideoFrame)) {
409
+ (_b = this._call) === null || _b === void 0 ? void 0 : _b.renderVideoFrame(width, height, buffer);
410
+ }
411
+ }
412
+ // Called by Rust
413
+ onSendOffer(remoteUserId, remoteDeviceId, callId, broadcast, offerType, opaque) {
414
+ const message = new CallingMessage();
415
+ message.offer = new OfferMessage();
416
+ message.offer.callId = callId;
417
+ message.offer.type = offerType;
418
+ message.offer.opaque = opaque;
419
+ this.sendSignaling(remoteUserId, remoteDeviceId, callId, broadcast, message);
420
+ }
421
+ // Called by Rust
422
+ onSendAnswer(remoteUserId, remoteDeviceId, callId, broadcast, opaque) {
423
+ const message = new CallingMessage();
424
+ message.answer = new AnswerMessage();
425
+ message.answer.callId = callId;
426
+ message.answer.opaque = opaque;
427
+ this.sendSignaling(remoteUserId, remoteDeviceId, callId, broadcast, message);
428
+ }
429
+ // Called by Rust
430
+ onSendIceCandidates(remoteUserId, remoteDeviceId, callId, broadcast, candidates) {
431
+ const message = new CallingMessage();
432
+ message.iceCandidates = [];
433
+ for (const candidate of candidates) {
434
+ const copy = new IceCandidateMessage();
435
+ copy.callId = callId;
436
+ copy.opaque = candidate;
437
+ message.iceCandidates.push(copy);
438
+ }
439
+ this.sendSignaling(remoteUserId, remoteDeviceId, callId, broadcast, message);
440
+ }
441
+ // Called by Rust
442
+ onSendHangup(remoteUserId, remoteDeviceId, callId, broadcast, hangupType, deviceId) {
443
+ const message = new CallingMessage();
444
+ message.hangup = new HangupMessage();
445
+ message.hangup.callId = callId;
446
+ message.hangup.type = hangupType;
447
+ message.hangup.deviceId = deviceId || 0;
448
+ this.sendSignaling(remoteUserId, remoteDeviceId, callId, broadcast, message);
449
+ }
450
+ // Called by Rust
451
+ onSendBusy(remoteUserId, remoteDeviceId, callId, broadcast) {
452
+ const message = new CallingMessage();
453
+ message.busy = new BusyMessage();
454
+ message.busy.callId = callId;
455
+ this.sendSignaling(remoteUserId, remoteDeviceId, callId, broadcast, message);
456
+ }
457
+ sendSignaling(remoteUserId, remoteDeviceId, callId, broadcast, message) {
458
+ message.supportsMultiRing = true;
459
+ if (!broadcast) {
460
+ message.destinationDeviceId = remoteDeviceId;
461
+ }
462
+ (() => __awaiter(this, void 0, void 0, function* () {
463
+ if (this.handleOutgoingSignaling) {
464
+ const signalingResult = yield this.handleOutgoingSignaling(remoteUserId, message);
465
+ if (signalingResult) {
466
+ this.callManager.signalingMessageSent(callId);
467
+ }
468
+ else {
469
+ this.callManager.signalingMessageSendFailed(callId);
470
+ }
471
+ }
472
+ else {
473
+ this.callManager.signalingMessageSendFailed(callId);
474
+ }
475
+ }))();
476
+ }
477
+ receivedHttpResponse(requestId, status, body) {
478
+ silly_deadlock_protection(() => {
479
+ try {
480
+ this.callManager.receivedHttpResponse(requestId, status, body);
481
+ }
482
+ catch (_a) {
483
+ // We may not have an active connection any more.
484
+ // In which case it doesn't matter
485
+ }
486
+ });
487
+ }
488
+ httpRequestFailed(requestId, debugInfo) {
489
+ silly_deadlock_protection(() => {
490
+ try {
491
+ this.callManager.httpRequestFailed(requestId, debugInfo);
492
+ }
493
+ catch (_a) {
494
+ // We may not have an active connection any more.
495
+ // In which case it doesn't matter
496
+ }
497
+ });
498
+ }
499
+ // Group Calls
500
+ // Called by UX
501
+ getGroupCall(groupId, sfuUrl, hkdfExtraInfo, audioLevelsIntervalMillis, observer) {
502
+ const groupCall = new GroupCall(this.callManager, groupId, sfuUrl, hkdfExtraInfo, audioLevelsIntervalMillis, observer);
503
+ this._groupCallByClientId.set(groupCall.clientId, groupCall);
504
+ return groupCall;
505
+ }
506
+ // Called by UX
507
+ // Returns a list of user IDs
508
+ peekGroupCall(sfuUrl, membershipProof, groupMembers) {
509
+ let [requestId, promise] = this._peekRequests.add();
510
+ // Response comes back via handlePeekResponse
511
+ silly_deadlock_protection(() => {
512
+ this.callManager.peekGroupCall(requestId, sfuUrl, membershipProof, groupMembers);
513
+ });
514
+ return promise;
515
+ }
516
+ // Called by Rust
517
+ requestMembershipProof(clientId) {
518
+ silly_deadlock_protection(() => {
519
+ let groupCall = this._groupCallByClientId.get(clientId);
520
+ if (!groupCall) {
521
+ let error = new Error();
522
+ this.logError('requestMembershipProof(): GroupCall not found in map!');
523
+ return;
524
+ }
525
+ groupCall.requestMembershipProof();
526
+ });
527
+ }
528
+ // Called by Rust
529
+ requestGroupMembers(clientId) {
530
+ silly_deadlock_protection(() => {
531
+ let groupCall = this._groupCallByClientId.get(clientId);
532
+ if (!groupCall) {
533
+ let error = new Error();
534
+ this.logError('requestGroupMembers(): GroupCall not found in map!');
535
+ return;
536
+ }
537
+ groupCall.requestGroupMembers();
538
+ });
539
+ }
540
+ // Called by Rust
541
+ handleConnectionStateChanged(clientId, connectionState) {
542
+ silly_deadlock_protection(() => {
543
+ let groupCall = this._groupCallByClientId.get(clientId);
544
+ if (!groupCall) {
545
+ let error = new Error();
546
+ this.logError('handleConnectionStateChanged(): GroupCall not found in map!');
547
+ return;
548
+ }
549
+ groupCall.handleConnectionStateChanged(connectionState);
550
+ });
551
+ }
552
+ // Called by Rust
553
+ handleJoinStateChanged(clientId, joinState, demuxId) {
554
+ silly_deadlock_protection(() => {
555
+ let groupCall = this._groupCallByClientId.get(clientId);
556
+ if (!groupCall) {
557
+ let error = new Error();
558
+ this.logError('handleJoinStateChanged(): GroupCall not found in map!');
559
+ return;
560
+ }
561
+ groupCall.handleJoinStateChanged(joinState, demuxId);
562
+ });
563
+ }
564
+ // Called by Rust
565
+ handleNetworkRouteChanged(clientId, localNetworkAdapterType) {
566
+ silly_deadlock_protection(() => {
567
+ let groupCall = this._groupCallByClientId.get(clientId);
568
+ if (!groupCall) {
569
+ this.logError('handleNetworkRouteChanged(): GroupCall not found in map!');
570
+ return;
571
+ }
572
+ groupCall.handleNetworkRouteChanged(localNetworkAdapterType);
573
+ });
574
+ }
575
+ // Called by Rust
576
+ handleAudioLevels(clientId, capturedLevel, receivedLevels) {
577
+ silly_deadlock_protection(() => {
578
+ let groupCall = this._groupCallByClientId.get(clientId);
579
+ if (!!groupCall) {
580
+ groupCall.handleAudioLevels(capturedLevel, receivedLevels);
581
+ }
582
+ });
583
+ }
584
+ // Called by Rust
585
+ handleRemoteDevicesChanged(clientId, remoteDeviceStates) {
586
+ silly_deadlock_protection(() => {
587
+ let groupCall = this._groupCallByClientId.get(clientId);
588
+ if (!groupCall) {
589
+ let error = new Error();
590
+ this.logError('handleRemoteDevicesChanged(): GroupCall not found in map!');
591
+ return;
592
+ }
593
+ groupCall.handleRemoteDevicesChanged(remoteDeviceStates);
594
+ });
595
+ }
596
+ // Called by Rust
597
+ handlePeekChanged(clientId, info) {
598
+ silly_deadlock_protection(() => {
599
+ let groupCall = this._groupCallByClientId.get(clientId);
600
+ if (!groupCall) {
601
+ let error = new Error();
602
+ this.logError('handlePeekChanged(): GroupCall not found in map!');
603
+ return;
604
+ }
605
+ groupCall.handlePeekChanged(info);
606
+ });
607
+ }
608
+ // Called by Rust
609
+ handlePeekResponse(request_id, info) {
610
+ silly_deadlock_protection(() => {
611
+ if (!this._peekRequests.resolve(request_id, info)) {
612
+ this.logWarn(`Invalid request ID for handlePeekResponse: ${request_id}`);
613
+ }
614
+ });
615
+ }
616
+ // Called by Rust
617
+ handleEnded(clientId, reason) {
618
+ silly_deadlock_protection(() => {
619
+ let groupCall = this._groupCallByClientId.get(clientId);
620
+ if (!groupCall) {
621
+ let error = new Error();
622
+ this.logError('handleEnded(): GroupCall not found in map!');
623
+ return;
624
+ }
625
+ this._groupCallByClientId.delete(clientId);
626
+ groupCall.handleEnded(reason);
627
+ });
628
+ }
629
+ // Called by Rust
630
+ groupCallRingUpdate(groupId, ringIdString, sender, state) {
631
+ silly_deadlock_protection(() => {
632
+ if (this.handleGroupCallRingUpdate) {
633
+ const ringId = BigInt(ringIdString);
634
+ this.handleGroupCallRingUpdate(groupId, ringId, sender, state);
635
+ }
636
+ else {
637
+ this.logError('RingRTC.handleGroupCallRingUpdate is not set!');
638
+ }
639
+ });
640
+ }
641
+ // Called by Rust
642
+ onLogMessage(level, fileName, line, message) {
643
+ if (this.handleLogMessage) {
644
+ this.handleLogMessage(level, fileName, line, message);
645
+ }
646
+ }
647
+ // Called from here
648
+ logError(message) {
649
+ this.onLogMessage(CallLogLevel.Error, 'Service.ts', 0, message);
650
+ }
651
+ // Called from here
652
+ logWarn(message) {
653
+ this.onLogMessage(CallLogLevel.Warn, 'Service.ts', 0, message);
654
+ }
655
+ // Called from here
656
+ logInfo(message) {
657
+ this.onLogMessage(CallLogLevel.Info, 'Service.ts', 0, message);
658
+ }
659
+ // Called by MessageReceiver
660
+ // tslint:disable-next-line cyclomatic-complexity
661
+ handleCallingMessage(remoteUserId, remoteUuid, remoteDeviceId, localDeviceId, messageAgeSec, messageReceivedAtCounter, message, senderIdentityKey, receiverIdentityKey) {
662
+ if (message.destinationDeviceId &&
663
+ message.destinationDeviceId !== localDeviceId) {
664
+ // Drop the message as it isn't for this device, handleIgnoredCall() is not needed.
665
+ return;
666
+ }
667
+ if (message.offer && message.offer.callId) {
668
+ const callId = message.offer.callId;
669
+ const opaque = to_buffer(message.offer.opaque);
670
+ // opaque is required. sdp is obsolete, but it might still come with opaque.
671
+ if (!opaque) {
672
+ // TODO: Remove once the proto is updated to only support opaque and require it.
673
+ this.logError('handleCallingMessage(): opaque not received for offer, remote should update');
674
+ return;
675
+ }
676
+ const offerType = message.offer.type || OfferType.AudioCall;
677
+ // Save the call details for later when the call is ended.
678
+ let callInfo = new CallInfo(offerType === OfferType.VideoCall, messageReceivedAtCounter);
679
+ this._callInfoByCallId.set(this.getCallInfoKey(callId), callInfo);
680
+ this.callManager.receivedOffer(remoteUserId, remoteDeviceId, localDeviceId, messageAgeSec, callId, offerType, opaque, senderIdentityKey, receiverIdentityKey);
681
+ }
682
+ if (message.answer && message.answer.callId) {
683
+ const callId = message.answer.callId;
684
+ const opaque = to_buffer(message.answer.opaque);
685
+ // opaque is required. sdp is obsolete, but it might still come with opaque.
686
+ if (!opaque) {
687
+ // TODO: Remove once the proto is updated to only support opaque and require it.
688
+ this.logError('handleCallingMessage(): opaque not received for answer, remote should update');
689
+ return;
690
+ }
691
+ this.callManager.receivedAnswer(remoteUserId, remoteDeviceId, callId, opaque, senderIdentityKey, receiverIdentityKey);
692
+ }
693
+ if (message.iceCandidates && message.iceCandidates.length > 0) {
694
+ // We assume they all have the same .callId
695
+ let callId = message.iceCandidates[0].callId;
696
+ // We have to copy them to do the .toArrayBuffer() thing.
697
+ const candidates = [];
698
+ for (const candidate of message.iceCandidates) {
699
+ const copy = to_buffer(candidate.opaque);
700
+ if (copy) {
701
+ candidates.push(copy);
702
+ }
703
+ else {
704
+ // TODO: Remove once the proto is updated to only support opaque and require it.
705
+ this.logError('handleCallingMessage(): opaque not received for ice candidate, remote should update');
706
+ continue;
707
+ }
708
+ }
709
+ if (candidates.length == 0) {
710
+ this.logWarn('handleCallingMessage(): No ice candidates in ice message, remote should update');
711
+ return;
712
+ }
713
+ this.callManager.receivedIceCandidates(remoteUserId, remoteDeviceId, callId, candidates);
714
+ }
715
+ if (message.hangup && message.hangup.callId) {
716
+ const callId = message.hangup.callId;
717
+ const hangupType = message.hangup.type || HangupType.Normal;
718
+ const hangupDeviceId = message.hangup.deviceId || null;
719
+ this.callManager.receivedHangup(remoteUserId, remoteDeviceId, callId, hangupType, hangupDeviceId);
720
+ }
721
+ if (message.legacyHangup && message.legacyHangup.callId) {
722
+ const callId = message.legacyHangup.callId;
723
+ const hangupType = message.legacyHangup.type || HangupType.Normal;
724
+ const hangupDeviceId = message.legacyHangup.deviceId || null;
725
+ this.callManager.receivedHangup(remoteUserId, remoteDeviceId, callId, hangupType, hangupDeviceId);
726
+ }
727
+ if (message.busy && message.busy.callId) {
728
+ const callId = message.busy.callId;
729
+ this.callManager.receivedBusy(remoteUserId, remoteDeviceId, callId);
730
+ }
731
+ if (message.opaque) {
732
+ if (remoteUuid == null) {
733
+ this.logError('handleCallingMessage(): opaque message received without UUID!');
734
+ return;
735
+ }
736
+ const data = to_buffer(message.opaque.data);
737
+ if (data == undefined) {
738
+ this.logError('handleCallingMessage(): opaque message received without data!');
739
+ return;
740
+ }
741
+ this.callManager.receivedCallMessage(remoteUuid, remoteDeviceId, localDeviceId, data, messageAgeSec);
742
+ }
743
+ }
744
+ // Called by Rust
745
+ sendHttpRequest(requestId, url, method, headers, body) {
746
+ if (this.handleSendHttpRequest) {
747
+ this.handleSendHttpRequest(requestId, url, method, headers, body);
748
+ }
749
+ else {
750
+ this.logError('RingRTC.handleSendHttpRequest is not set!');
751
+ }
752
+ }
753
+ // Called by Rust
754
+ sendCallMessage(recipientUuid, message, urgency) {
755
+ if (this.handleSendCallMessage) {
756
+ this.handleSendCallMessage(recipientUuid, message, urgency);
757
+ }
758
+ else {
759
+ this.logError('RingRTC.handleSendCallMessage is not set!');
760
+ }
761
+ }
762
+ // Called by Rust
763
+ sendCallMessageToGroup(groupId, message, urgency) {
764
+ if (this.handleSendCallMessageToGroup) {
765
+ this.handleSendCallMessageToGroup(groupId, message, urgency);
766
+ }
767
+ else {
768
+ this.logError('RingRTC.handleSendCallMessageToGroup is not set!');
769
+ }
770
+ }
771
+ // These are convenience methods. One could use the Call class instead.
772
+ get call() {
773
+ return this._call;
774
+ }
775
+ getCall(callId) {
776
+ const { call } = this;
777
+ if (call &&
778
+ call.callId.high === callId.high &&
779
+ call.callId.low === call.callId.low) {
780
+ return call;
781
+ }
782
+ return null;
783
+ }
784
+ accept(callId, asVideoCall) {
785
+ const call = this.getCall(callId);
786
+ if (!call) {
787
+ return;
788
+ }
789
+ call.accept();
790
+ call.outgoingAudioEnabled = true;
791
+ call.outgoingVideoEnabled = asVideoCall;
792
+ }
793
+ decline(callId) {
794
+ const call = this.getCall(callId);
795
+ if (!call) {
796
+ return;
797
+ }
798
+ call.decline();
799
+ }
800
+ ignore(callId) {
801
+ const call = this.getCall(callId);
802
+ if (!call) {
803
+ return;
804
+ }
805
+ call.ignore();
806
+ }
807
+ hangup(callId) {
808
+ const call = this.getCall(callId);
809
+ if (!call) {
810
+ return;
811
+ }
812
+ call.hangup();
813
+ }
814
+ setOutgoingAudio(callId, enabled) {
815
+ const call = this.getCall(callId);
816
+ if (!call) {
817
+ return;
818
+ }
819
+ call.outgoingAudioEnabled = enabled;
820
+ }
821
+ setOutgoingVideo(callId, enabled) {
822
+ const call = this.getCall(callId);
823
+ if (!call) {
824
+ return;
825
+ }
826
+ call.outgoingVideoEnabled = enabled;
827
+ }
828
+ setOutgoingVideoIsScreenShare(callId, isScreenShare) {
829
+ const call = this.getCall(callId);
830
+ if (!call) {
831
+ return;
832
+ }
833
+ call.outgoingVideoIsScreenShare = isScreenShare;
834
+ }
835
+ setVideoCapturer(callId, capturer) {
836
+ const call = this.getCall(callId);
837
+ if (!call) {
838
+ return;
839
+ }
840
+ call.videoCapturer = capturer;
841
+ }
842
+ setVideoRenderer(callId, renderer) {
843
+ const call = this.getCall(callId);
844
+ if (!call) {
845
+ return;
846
+ }
847
+ call.videoRenderer = renderer;
848
+ }
849
+ getAudioInputs() {
850
+ return this.callManager.getAudioInputs();
851
+ }
852
+ setAudioInput(index) {
853
+ this.callManager.setAudioInput(index);
854
+ }
855
+ getAudioOutputs() {
856
+ return this.callManager.getAudioOutputs();
857
+ }
858
+ setAudioOutput(index) {
859
+ this.callManager.setAudioOutput(index);
860
+ }
861
+ }
862
+ exports.RingRTCType = RingRTCType;
863
+ class Call {
864
+ constructor(callManager, remoteUserId, callId, isIncoming, isVideoCall, settings, state) {
865
+ this._outgoingAudioEnabled = false;
866
+ this._outgoingVideoEnabled = false;
867
+ this._outgoingVideoIsScreenShare = false;
868
+ this._remoteVideoEnabled = false;
869
+ this.outgoingAudioLevel = 0;
870
+ this.remoteAudioLevel = 0;
871
+ this.remoteSharingScreen = false;
872
+ this.networkRoute = new NetworkRoute();
873
+ this._videoCapturer = null;
874
+ this._videoRenderer = null;
875
+ this._callManager = callManager;
876
+ this._remoteUserId = remoteUserId;
877
+ this.callId = callId;
878
+ this._isIncoming = isIncoming;
879
+ this._isVideoCall = isVideoCall;
880
+ this.settings = settings;
881
+ this._state = state;
882
+ }
883
+ get remoteUserId() {
884
+ return this._remoteUserId;
885
+ }
886
+ get isIncoming() {
887
+ return this._isIncoming;
888
+ }
889
+ get isVideoCall() {
890
+ return this._isVideoCall;
891
+ }
892
+ get state() {
893
+ return this._state;
894
+ }
895
+ set state(state) {
896
+ if (state == this._state) {
897
+ return;
898
+ }
899
+ this._state = state;
900
+ this.enableOrDisableCapturer();
901
+ this.enableOrDisableRenderer();
902
+ if (!!this.handleStateChanged) {
903
+ this.handleStateChanged();
904
+ }
905
+ }
906
+ setCallEnded() {
907
+ this._state = CallState.Ended;
908
+ }
909
+ set videoCapturer(capturer) {
910
+ this._videoCapturer = capturer;
911
+ this.enableOrDisableCapturer();
912
+ }
913
+ set videoRenderer(renderer) {
914
+ this._videoRenderer = renderer;
915
+ this.enableOrDisableRenderer();
916
+ }
917
+ accept() {
918
+ this._callManager.accept(this.callId);
919
+ }
920
+ decline() {
921
+ this.hangup();
922
+ }
923
+ ignore() {
924
+ this._callManager.ignore(this.callId);
925
+ }
926
+ hangup() {
927
+ // This is a little faster than waiting for the
928
+ // change in call state to come back.
929
+ if (this._videoCapturer) {
930
+ this._videoCapturer.disable();
931
+ }
932
+ if (this._videoRenderer) {
933
+ this._videoRenderer.disable();
934
+ }
935
+ // This assumes we only have one active call.
936
+ silly_deadlock_protection(() => {
937
+ this._callManager.hangup();
938
+ });
939
+ }
940
+ get outgoingAudioEnabled() {
941
+ return this._outgoingAudioEnabled;
942
+ }
943
+ set outgoingAudioEnabled(enabled) {
944
+ this._outgoingAudioEnabled = enabled;
945
+ // This assumes we only have one active call.
946
+ silly_deadlock_protection(() => {
947
+ this._callManager.setOutgoingAudioEnabled(enabled);
948
+ });
949
+ }
950
+ get outgoingVideoEnabled() {
951
+ return this._outgoingVideoEnabled;
952
+ }
953
+ set outgoingVideoEnabled(enabled) {
954
+ this._outgoingVideoEnabled = enabled;
955
+ this.enableOrDisableCapturer();
956
+ }
957
+ set outgoingVideoIsScreenShare(isScreenShare) {
958
+ // This assumes we only have one active call.
959
+ this._outgoingVideoIsScreenShare = isScreenShare;
960
+ silly_deadlock_protection(() => {
961
+ this._callManager.setOutgoingVideoIsScreenShare(isScreenShare);
962
+ });
963
+ }
964
+ get remoteVideoEnabled() {
965
+ return this._remoteVideoEnabled;
966
+ }
967
+ set remoteVideoEnabled(enabled) {
968
+ this._remoteVideoEnabled = enabled;
969
+ this.enableOrDisableRenderer();
970
+ }
971
+ // With this method, a Call is a VideoFrameSender
972
+ sendVideoFrame(width, height, format, buffer) {
973
+ // This assumes we only have one active all.
974
+ this._callManager.sendVideoFrame(width, height, format, buffer);
975
+ }
976
+ // With this method, a Call is a VideoFrameSource
977
+ receiveVideoFrame(buffer) {
978
+ // This assumes we only have one active all.
979
+ return this._callManager.receiveVideoFrame(buffer);
980
+ }
981
+ enableOrDisableCapturer() {
982
+ if (!this._videoCapturer) {
983
+ return;
984
+ }
985
+ if (!this.outgoingVideoEnabled) {
986
+ this._videoCapturer.disable();
987
+ if (this.state === CallState.Accepted) {
988
+ this.setOutgoingVideoEnabled(false);
989
+ }
990
+ return;
991
+ }
992
+ switch (this.state) {
993
+ case CallState.Prering:
994
+ case CallState.Ringing:
995
+ this._videoCapturer.enableCapture();
996
+ break;
997
+ case CallState.Accepted:
998
+ this._videoCapturer.enableCaptureAndSend(this);
999
+ this.setOutgoingVideoEnabled(true);
1000
+ if (this._outgoingVideoIsScreenShare) {
1001
+ // Make sure the status gets sent.
1002
+ this.outgoingVideoIsScreenShare = true;
1003
+ }
1004
+ break;
1005
+ case CallState.Reconnecting:
1006
+ this._videoCapturer.enableCaptureAndSend(this);
1007
+ // Don't send status until we're reconnected.
1008
+ break;
1009
+ case CallState.Ended:
1010
+ this._videoCapturer.disable();
1011
+ break;
1012
+ default:
1013
+ }
1014
+ }
1015
+ setOutgoingVideoEnabled(enabled) {
1016
+ silly_deadlock_protection(() => {
1017
+ try {
1018
+ this._callManager.setOutgoingVideoEnabled(enabled);
1019
+ }
1020
+ catch (_a) {
1021
+ // We may not have an active connection any more.
1022
+ // In which case it doesn't matter
1023
+ }
1024
+ });
1025
+ }
1026
+ updateBandwidthMode(bandwidthMode) {
1027
+ silly_deadlock_protection(() => {
1028
+ try {
1029
+ this._callManager.updateBandwidthMode(bandwidthMode);
1030
+ }
1031
+ catch (_a) {
1032
+ // We may not have an active connection any more.
1033
+ // In which case it doesn't matter
1034
+ }
1035
+ });
1036
+ }
1037
+ enableOrDisableRenderer() {
1038
+ if (!this._videoRenderer) {
1039
+ return;
1040
+ }
1041
+ if (!this.remoteVideoEnabled) {
1042
+ this._videoRenderer.disable();
1043
+ return;
1044
+ }
1045
+ switch (this.state) {
1046
+ case CallState.Prering:
1047
+ case CallState.Ringing:
1048
+ this._videoRenderer.disable();
1049
+ break;
1050
+ case CallState.Accepted:
1051
+ case CallState.Reconnecting:
1052
+ this._videoRenderer.enable(this);
1053
+ break;
1054
+ case CallState.Ended:
1055
+ this._videoRenderer.disable();
1056
+ break;
1057
+ default:
1058
+ }
1059
+ }
1060
+ }
1061
+ exports.Call = Call;
1062
+ // Represents the connection state to a media server for a group call.
1063
+ var ConnectionState;
1064
+ (function (ConnectionState) {
1065
+ ConnectionState[ConnectionState["NotConnected"] = 0] = "NotConnected";
1066
+ ConnectionState[ConnectionState["Connecting"] = 1] = "Connecting";
1067
+ ConnectionState[ConnectionState["Connected"] = 2] = "Connected";
1068
+ ConnectionState[ConnectionState["Reconnecting"] = 3] = "Reconnecting";
1069
+ })(ConnectionState = exports.ConnectionState || (exports.ConnectionState = {}));
1070
+ // Represents whether or not a user is joined to a group call and can exchange media.
1071
+ var JoinState;
1072
+ (function (JoinState) {
1073
+ JoinState[JoinState["NotJoined"] = 0] = "NotJoined";
1074
+ JoinState[JoinState["Joining"] = 1] = "Joining";
1075
+ JoinState[JoinState["Joined"] = 2] = "Joined";
1076
+ })(JoinState = exports.JoinState || (exports.JoinState = {}));
1077
+ // If not ended purposely by the user, gives the reason why a group call ended.
1078
+ var GroupCallEndReason;
1079
+ (function (GroupCallEndReason) {
1080
+ // Normal events
1081
+ GroupCallEndReason[GroupCallEndReason["DeviceExplicitlyDisconnected"] = 0] = "DeviceExplicitlyDisconnected";
1082
+ GroupCallEndReason[GroupCallEndReason["ServerExplicitlyDisconnected"] = 1] = "ServerExplicitlyDisconnected";
1083
+ // Things that can go wrong
1084
+ GroupCallEndReason[GroupCallEndReason["CallManagerIsBusy"] = 2] = "CallManagerIsBusy";
1085
+ GroupCallEndReason[GroupCallEndReason["SfuClientFailedToJoin"] = 3] = "SfuClientFailedToJoin";
1086
+ GroupCallEndReason[GroupCallEndReason["FailedToCreatePeerConnectionFactory"] = 4] = "FailedToCreatePeerConnectionFactory";
1087
+ GroupCallEndReason[GroupCallEndReason["FailedToNegotiateSrtpKeys"] = 5] = "FailedToNegotiateSrtpKeys";
1088
+ GroupCallEndReason[GroupCallEndReason["FailedToCreatePeerConnection"] = 6] = "FailedToCreatePeerConnection";
1089
+ GroupCallEndReason[GroupCallEndReason["FailedToStartPeerConnection"] = 7] = "FailedToStartPeerConnection";
1090
+ GroupCallEndReason[GroupCallEndReason["FailedToUpdatePeerConnection"] = 8] = "FailedToUpdatePeerConnection";
1091
+ GroupCallEndReason[GroupCallEndReason["FailedToSetMaxSendBitrate"] = 9] = "FailedToSetMaxSendBitrate";
1092
+ GroupCallEndReason[GroupCallEndReason["IceFailedWhileConnecting"] = 10] = "IceFailedWhileConnecting";
1093
+ GroupCallEndReason[GroupCallEndReason["IceFailedAfterConnected"] = 11] = "IceFailedAfterConnected";
1094
+ GroupCallEndReason[GroupCallEndReason["ServerChangedDemuxId"] = 12] = "ServerChangedDemuxId";
1095
+ GroupCallEndReason[GroupCallEndReason["HasMaxDevices"] = 13] = "HasMaxDevices";
1096
+ })(GroupCallEndReason = exports.GroupCallEndReason || (exports.GroupCallEndReason = {}));
1097
+ var CallMessageUrgency;
1098
+ (function (CallMessageUrgency) {
1099
+ CallMessageUrgency[CallMessageUrgency["Droppable"] = 0] = "Droppable";
1100
+ CallMessageUrgency[CallMessageUrgency["HandleImmediately"] = 1] = "HandleImmediately";
1101
+ })(CallMessageUrgency = exports.CallMessageUrgency || (exports.CallMessageUrgency = {}));
1102
+ var RingUpdate;
1103
+ (function (RingUpdate) {
1104
+ /// The sender is trying to ring this user.
1105
+ RingUpdate[RingUpdate["Requested"] = 0] = "Requested";
1106
+ /// The sender tried to ring this user, but it's been too long.
1107
+ RingUpdate[RingUpdate["ExpiredRequest"] = 1] = "ExpiredRequest";
1108
+ /// Call was accepted elsewhere by a different device.
1109
+ RingUpdate[RingUpdate["AcceptedOnAnotherDevice"] = 2] = "AcceptedOnAnotherDevice";
1110
+ /// Call was declined elsewhere by a different device.
1111
+ RingUpdate[RingUpdate["DeclinedOnAnotherDevice"] = 3] = "DeclinedOnAnotherDevice";
1112
+ /// This device is currently on a different call.
1113
+ RingUpdate[RingUpdate["BusyLocally"] = 4] = "BusyLocally";
1114
+ /// A different device is currently on a different call.
1115
+ RingUpdate[RingUpdate["BusyOnAnotherDevice"] = 5] = "BusyOnAnotherDevice";
1116
+ /// The sender cancelled the ring request.
1117
+ RingUpdate[RingUpdate["CancelledByRinger"] = 6] = "CancelledByRinger";
1118
+ })(RingUpdate = exports.RingUpdate || (exports.RingUpdate = {}));
1119
+ // HTTP request methods.
1120
+ var HttpMethod;
1121
+ (function (HttpMethod) {
1122
+ HttpMethod[HttpMethod["Get"] = 0] = "Get";
1123
+ HttpMethod[HttpMethod["Put"] = 1] = "Put";
1124
+ HttpMethod[HttpMethod["Post"] = 2] = "Post";
1125
+ HttpMethod[HttpMethod["Delete"] = 3] = "Delete";
1126
+ })(HttpMethod = exports.HttpMethod || (exports.HttpMethod = {}));
1127
+ // The local device state for a group call.
1128
+ class LocalDeviceState {
1129
+ constructor() {
1130
+ this.connectionState = ConnectionState.NotConnected;
1131
+ this.joinState = JoinState.NotJoined;
1132
+ // By default audio and video are muted.
1133
+ this.audioMuted = true;
1134
+ this.videoMuted = true;
1135
+ this.audioLevel = 0;
1136
+ this.presenting = false;
1137
+ this.sharingScreen = false;
1138
+ this.networkRoute = new NetworkRoute();
1139
+ }
1140
+ }
1141
+ exports.LocalDeviceState = LocalDeviceState;
1142
+ // All remote devices in a group call and their associated state.
1143
+ class RemoteDeviceState {
1144
+ constructor(demuxId, userId, mediaKeysReceived) {
1145
+ this.demuxId = demuxId;
1146
+ this.userId = userId;
1147
+ this.mediaKeysReceived = mediaKeysReceived;
1148
+ this.audioLevel = 0;
1149
+ this.isHigherResolutionPending = false;
1150
+ }
1151
+ }
1152
+ exports.RemoteDeviceState = RemoteDeviceState;
1153
+ // Used to communicate the group membership to RingRTC for a group call.
1154
+ class GroupMemberInfo {
1155
+ constructor(userId, userIdCipherText) {
1156
+ this.userId = userId;
1157
+ this.userIdCipherText = userIdCipherText;
1158
+ }
1159
+ }
1160
+ exports.GroupMemberInfo = GroupMemberInfo;
1161
+ // Used for the application to communicate the actual resolutions of
1162
+ // each device in a group call to RingRTC and the SFU.
1163
+ class VideoRequest {
1164
+ constructor(demuxId, width, height, framerate) {
1165
+ this.demuxId = demuxId;
1166
+ this.width = width;
1167
+ this.height = height;
1168
+ this.framerate = framerate;
1169
+ }
1170
+ }
1171
+ exports.VideoRequest = VideoRequest;
1172
+ class GroupCall {
1173
+ // Called by UI via RingRTC object
1174
+ constructor(callManager, groupId, sfuUrl, hkdfExtraInfo, audioLevelsIntervalMillis, observer) {
1175
+ this._callManager = callManager;
1176
+ this._observer = observer;
1177
+ this._localDeviceState = new LocalDeviceState();
1178
+ this._clientId = this._callManager.createGroupCallClient(groupId, sfuUrl, hkdfExtraInfo, audioLevelsIntervalMillis || 0);
1179
+ }
1180
+ get clientId() {
1181
+ return this._clientId;
1182
+ }
1183
+ // Called by UI
1184
+ connect() {
1185
+ this._callManager.connect(this._clientId);
1186
+ }
1187
+ // Called by UI
1188
+ join() {
1189
+ this._callManager.join(this._clientId);
1190
+ }
1191
+ // Called by UI
1192
+ leave() {
1193
+ this._callManager.leave(this._clientId);
1194
+ }
1195
+ // Called by UI
1196
+ disconnect() {
1197
+ this._callManager.disconnect(this._clientId);
1198
+ }
1199
+ // Called by UI
1200
+ getLocalDeviceState() {
1201
+ return this._localDeviceState;
1202
+ }
1203
+ // Called by UI
1204
+ getRemoteDeviceStates() {
1205
+ return this._remoteDeviceStates;
1206
+ }
1207
+ // Called by UI
1208
+ getPeekInfo() {
1209
+ return this._peekInfo;
1210
+ }
1211
+ // Called by UI
1212
+ setOutgoingAudioMuted(muted) {
1213
+ this._localDeviceState.audioMuted = muted;
1214
+ this._callManager.setOutgoingAudioMuted(this._clientId, muted);
1215
+ this._observer.onLocalDeviceStateChanged(this);
1216
+ }
1217
+ // Called by UI
1218
+ setOutgoingVideoMuted(muted) {
1219
+ this._localDeviceState.videoMuted = muted;
1220
+ this._callManager.setOutgoingVideoMuted(this._clientId, muted);
1221
+ this._observer.onLocalDeviceStateChanged(this);
1222
+ }
1223
+ // Called by UI
1224
+ setPresenting(presenting) {
1225
+ this._localDeviceState.presenting = presenting;
1226
+ this._callManager.setPresenting(this._clientId, presenting);
1227
+ this._observer.onLocalDeviceStateChanged(this);
1228
+ }
1229
+ // Called by UI
1230
+ setOutgoingVideoIsScreenShare(isScreenShare) {
1231
+ this._localDeviceState.sharingScreen = isScreenShare;
1232
+ this._callManager.setOutgoingGroupCallVideoIsScreenShare(this._clientId, isScreenShare);
1233
+ this._observer.onLocalDeviceStateChanged(this);
1234
+ }
1235
+ // Called by UI
1236
+ ringAll() {
1237
+ this._callManager.groupRing(this._clientId, undefined);
1238
+ }
1239
+ // Called by UI
1240
+ resendMediaKeys() {
1241
+ this._callManager.resendMediaKeys(this._clientId);
1242
+ }
1243
+ // Called by UI
1244
+ setBandwidthMode(bandwidthMode) {
1245
+ this._callManager.setBandwidthMode(this._clientId, bandwidthMode);
1246
+ }
1247
+ // Called by UI
1248
+ requestVideo(resolutions, activeSpeakerHeight) {
1249
+ this._callManager.requestVideo(this._clientId, resolutions, activeSpeakerHeight);
1250
+ }
1251
+ // Called by UI
1252
+ setGroupMembers(members) {
1253
+ this._callManager.setGroupMembers(this._clientId, members);
1254
+ }
1255
+ // Called by UI
1256
+ setMembershipProof(proof) {
1257
+ this._callManager.setMembershipProof(this._clientId, proof);
1258
+ }
1259
+ // Called by Rust via RingRTC object
1260
+ requestMembershipProof() {
1261
+ this._observer.requestMembershipProof(this);
1262
+ }
1263
+ // Called by Rust via RingRTC object
1264
+ requestGroupMembers() {
1265
+ this._observer.requestGroupMembers(this);
1266
+ }
1267
+ // Called by Rust via RingRTC object
1268
+ handleConnectionStateChanged(connectionState) {
1269
+ this._localDeviceState.connectionState = connectionState;
1270
+ this._observer.onLocalDeviceStateChanged(this);
1271
+ }
1272
+ // Called by Rust via RingRTC object
1273
+ handleJoinStateChanged(joinState, demuxId) {
1274
+ this._localDeviceState.joinState = joinState;
1275
+ // Don't set to undefined after we leave so we can still know the demuxId after we leave.
1276
+ if (demuxId != undefined) {
1277
+ this._localDeviceState.demuxId = demuxId;
1278
+ }
1279
+ this._observer.onLocalDeviceStateChanged(this);
1280
+ }
1281
+ // Called by Rust via RingRTC object
1282
+ handleNetworkRouteChanged(localNetworkAdapterType) {
1283
+ this._localDeviceState.networkRoute.localAdapterType =
1284
+ localNetworkAdapterType;
1285
+ this._observer.onLocalDeviceStateChanged(this);
1286
+ }
1287
+ handleAudioLevels(capturedLevel, receivedLevels) {
1288
+ this._localDeviceState.audioLevel = normalizeAudioLevel(capturedLevel);
1289
+ if (this._remoteDeviceStates != undefined) {
1290
+ for (const received of receivedLevels) {
1291
+ for (let remoteDeviceState of this._remoteDeviceStates) {
1292
+ if (remoteDeviceState.demuxId == received.demuxId) {
1293
+ remoteDeviceState.audioLevel = normalizeAudioLevel(received.level);
1294
+ }
1295
+ }
1296
+ }
1297
+ }
1298
+ this._observer.onAudioLevels(this);
1299
+ }
1300
+ // Called by Rust via RingRTC object
1301
+ handleRemoteDevicesChanged(remoteDeviceStates) {
1302
+ var _a;
1303
+ // We don't get aspect ratios from RingRTC, so make sure to copy them over.
1304
+ for (const noo of remoteDeviceStates) {
1305
+ const old = (_a = this._remoteDeviceStates) === null || _a === void 0 ? void 0 : _a.find(old => old.demuxId == noo.demuxId);
1306
+ noo.videoAspectRatio = old === null || old === void 0 ? void 0 : old.videoAspectRatio;
1307
+ }
1308
+ this._remoteDeviceStates = remoteDeviceStates;
1309
+ this._observer.onRemoteDeviceStatesChanged(this);
1310
+ }
1311
+ // Called by Rust via RingRTC object
1312
+ handlePeekChanged(info) {
1313
+ this._peekInfo = info;
1314
+ this._observer.onPeekChanged(this);
1315
+ }
1316
+ // Called by Rust via RingRTC object
1317
+ handleEnded(reason) {
1318
+ this._observer.onEnded(this, reason);
1319
+ this._callManager.deleteGroupCallClient(this._clientId);
1320
+ }
1321
+ // With this, a GroupCall is a VideoFrameSender
1322
+ sendVideoFrame(width, height, format, buffer) {
1323
+ // This assumes we only have one active all.
1324
+ this._callManager.sendVideoFrame(width, height, format, buffer);
1325
+ }
1326
+ // With this, a GroupCall can provide a VideoFrameSource for each remote device.
1327
+ getVideoSource(remoteDemuxId) {
1328
+ return new GroupCallVideoFrameSource(this._callManager, this, remoteDemuxId);
1329
+ }
1330
+ // Called by the GroupCallVideoFrameSource when it receives a video frame.
1331
+ setRemoteAspectRatio(remoteDemuxId, aspectRatio) {
1332
+ var _a;
1333
+ const remoteDevice = (_a = this._remoteDeviceStates) === null || _a === void 0 ? void 0 : _a.find(device => device.demuxId == remoteDemuxId);
1334
+ if (!!remoteDevice && remoteDevice.videoAspectRatio != aspectRatio) {
1335
+ remoteDevice.videoAspectRatio = aspectRatio;
1336
+ this._observer.onRemoteDeviceStatesChanged(this);
1337
+ }
1338
+ }
1339
+ }
1340
+ exports.GroupCall = GroupCall;
1341
+ // Implements VideoSource for use in CanvasVideoRenderer
1342
+ class GroupCallVideoFrameSource {
1343
+ constructor(callManager, groupCall, remoteDemuxId // Uint32
1344
+ ) {
1345
+ this._callManager = callManager;
1346
+ this._groupCall = groupCall;
1347
+ this._remoteDemuxId = remoteDemuxId;
1348
+ }
1349
+ receiveVideoFrame(buffer) {
1350
+ // This assumes we only have one active all.
1351
+ const frame = this._callManager.receiveGroupCallVideoFrame(this._groupCall.clientId, this._remoteDemuxId, buffer);
1352
+ if (!!frame) {
1353
+ const [width, height] = frame;
1354
+ this._groupCall.setRemoteAspectRatio(this._remoteDemuxId, width / height);
1355
+ }
1356
+ return frame;
1357
+ }
1358
+ }
1359
+ function to_buffer(pbab) {
1360
+ if (!pbab) {
1361
+ return pbab;
1362
+ }
1363
+ if (pbab instanceof Buffer) {
1364
+ return pbab;
1365
+ }
1366
+ return Buffer.from(pbab.toArrayBuffer());
1367
+ }
1368
+ class CallingMessage {
1369
+ }
1370
+ exports.CallingMessage = CallingMessage;
1371
+ class OfferMessage {
1372
+ }
1373
+ exports.OfferMessage = OfferMessage;
1374
+ var OfferType;
1375
+ (function (OfferType) {
1376
+ OfferType[OfferType["AudioCall"] = 0] = "AudioCall";
1377
+ OfferType[OfferType["VideoCall"] = 1] = "VideoCall";
1378
+ })(OfferType = exports.OfferType || (exports.OfferType = {}));
1379
+ class AnswerMessage {
1380
+ }
1381
+ exports.AnswerMessage = AnswerMessage;
1382
+ class IceCandidateMessage {
1383
+ }
1384
+ exports.IceCandidateMessage = IceCandidateMessage;
1385
+ class BusyMessage {
1386
+ }
1387
+ exports.BusyMessage = BusyMessage;
1388
+ class HangupMessage {
1389
+ }
1390
+ exports.HangupMessage = HangupMessage;
1391
+ class OpaqueMessage {
1392
+ }
1393
+ exports.OpaqueMessage = OpaqueMessage;
1394
+ var HangupType;
1395
+ (function (HangupType) {
1396
+ HangupType[HangupType["Normal"] = 0] = "Normal";
1397
+ HangupType[HangupType["Accepted"] = 1] = "Accepted";
1398
+ HangupType[HangupType["Declined"] = 2] = "Declined";
1399
+ HangupType[HangupType["Busy"] = 3] = "Busy";
1400
+ HangupType[HangupType["NeedPermission"] = 4] = "NeedPermission";
1401
+ })(HangupType = exports.HangupType || (exports.HangupType = {}));
1402
+ var BandwidthMode;
1403
+ (function (BandwidthMode) {
1404
+ BandwidthMode[BandwidthMode["VeryLow"] = 0] = "VeryLow";
1405
+ BandwidthMode[BandwidthMode["Low"] = 1] = "Low";
1406
+ BandwidthMode[BandwidthMode["Normal"] = 2] = "Normal";
1407
+ })(BandwidthMode = exports.BandwidthMode || (exports.BandwidthMode = {}));
1408
+ /// Describes why a ring was cancelled.
1409
+ var RingCancelReason;
1410
+ (function (RingCancelReason) {
1411
+ /// The user explicitly clicked "Decline".
1412
+ RingCancelReason[RingCancelReason["DeclinedByUser"] = 0] = "DeclinedByUser";
1413
+ /// The device is busy with another call.
1414
+ RingCancelReason[RingCancelReason["Busy"] = 1] = "Busy";
1415
+ })(RingCancelReason = exports.RingCancelReason || (exports.RingCancelReason = {}));
1416
+ var CallState;
1417
+ (function (CallState) {
1418
+ CallState["Prering"] = "idle";
1419
+ CallState["Ringing"] = "ringing";
1420
+ CallState["Accepted"] = "connected";
1421
+ CallState["Reconnecting"] = "connecting";
1422
+ CallState["Ended"] = "ended";
1423
+ })(CallState = exports.CallState || (exports.CallState = {}));
1424
+ var CallEndedReason;
1425
+ (function (CallEndedReason) {
1426
+ CallEndedReason["LocalHangup"] = "LocalHangup";
1427
+ CallEndedReason["RemoteHangup"] = "RemoteHangup";
1428
+ CallEndedReason["RemoteHangupNeedPermission"] = "RemoteHangupNeedPermission";
1429
+ CallEndedReason["Declined"] = "Declined";
1430
+ CallEndedReason["Busy"] = "Busy";
1431
+ CallEndedReason["Glare"] = "Glare";
1432
+ CallEndedReason["ReCall"] = "ReCall";
1433
+ CallEndedReason["ReceivedOfferExpired"] = "ReceivedOfferExpired";
1434
+ CallEndedReason["ReceivedOfferWhileActive"] = "ReceivedOfferWhileActive";
1435
+ CallEndedReason["ReceivedOfferWithGlare"] = "ReceivedOfferWithGlare";
1436
+ CallEndedReason["SignalingFailure"] = "SignalingFailure";
1437
+ CallEndedReason["GlareFailure"] = "GlareFailure";
1438
+ CallEndedReason["ConnectionFailure"] = "ConnectionFailure";
1439
+ CallEndedReason["InternalFailure"] = "InternalFailure";
1440
+ CallEndedReason["Timeout"] = "Timeout";
1441
+ CallEndedReason["AcceptedOnAnotherDevice"] = "AcceptedOnAnotherDevice";
1442
+ CallEndedReason["DeclinedOnAnotherDevice"] = "DeclinedOnAnotherDevice";
1443
+ CallEndedReason["BusyOnAnotherDevice"] = "BusyOnAnotherDevice";
1444
+ })(CallEndedReason = exports.CallEndedReason || (exports.CallEndedReason = {}));
1445
+ var CallLogLevel;
1446
+ (function (CallLogLevel) {
1447
+ CallLogLevel[CallLogLevel["Off"] = 0] = "Off";
1448
+ CallLogLevel[CallLogLevel["Error"] = 1] = "Error";
1449
+ CallLogLevel[CallLogLevel["Warn"] = 2] = "Warn";
1450
+ CallLogLevel[CallLogLevel["Info"] = 3] = "Info";
1451
+ CallLogLevel[CallLogLevel["Debug"] = 4] = "Debug";
1452
+ CallLogLevel[CallLogLevel["Trace"] = 5] = "Trace";
1453
+ })(CallLogLevel = exports.CallLogLevel || (exports.CallLogLevel = {}));
1454
+ function silly_deadlock_protection(f) {
1455
+ // tslint:disable no-floating-promises
1456
+ (() => __awaiter(this, void 0, void 0, function* () {
1457
+ // This is a silly way of preventing a deadlock.
1458
+ // tslint:disable-next-line await-promise
1459
+ yield 0;
1460
+ f();
1461
+ }))();
1462
+ }