@signalapp/ringrtc 2.23.1 → 2.25.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.
- package/dist/ringrtc/Service.d.ts +11 -12
- package/dist/ringrtc/Service.js +86 -33
- package/dist/ringrtc/VideoSupport.d.ts +11 -1
- package/dist/ringrtc/VideoSupport.js +2 -1
- package/dist/test/CallingClass.d.ts +25 -0
- package/dist/test/CallingClass.js +197 -0
- package/dist/test/RingRTC-test.js +145 -5
- package/dist/test/Utils.d.ts +7 -0
- package/dist/test/Utils.js +51 -0
- package/package.json +8 -3
|
@@ -51,7 +51,8 @@ export declare class RingRTCType {
|
|
|
51
51
|
private _callInfoByCallId;
|
|
52
52
|
private getCallInfoKey;
|
|
53
53
|
handleOutgoingSignaling: ((remoteUserId: UserId, message: CallingMessage) => Promise<boolean>) | null;
|
|
54
|
-
handleIncomingCall: ((call: Call) => Promise<
|
|
54
|
+
handleIncomingCall: ((call: Call) => Promise<boolean>) | null;
|
|
55
|
+
handleStartCall: ((call: Call) => Promise<boolean>) | null;
|
|
55
56
|
handleAutoEndedIncomingCallRequest: ((callId: CallId, remoteUserId: UserId, reason: CallEndedReason, ageSec: number, wasVideoCall: boolean, receivedAtCounter: number | undefined) => void) | null;
|
|
56
57
|
handleLogMessage: ((level: CallLogLevel, fileName: string, line: number, message: string) => void) | null;
|
|
57
58
|
handleSendHttpRequest: ((requestId: number, url: string, method: HttpMethod, headers: {
|
|
@@ -63,11 +64,11 @@ export declare class RingRTCType {
|
|
|
63
64
|
constructor();
|
|
64
65
|
setConfig(config: Config): void;
|
|
65
66
|
setSelfUuid(uuid: Buffer): void;
|
|
66
|
-
startOutgoingCall(remoteUserId: UserId, isVideoCall: boolean, localDeviceId: DeviceId
|
|
67
|
+
startOutgoingCall(remoteUserId: UserId, isVideoCall: boolean, localDeviceId: DeviceId): Call;
|
|
67
68
|
cancelGroupRing(groupId: GroupId, ringId: bigint, reason: RingCancelReason | null): void;
|
|
68
69
|
onStartOutgoingCall(remoteUserId: UserId, callId: CallId): void;
|
|
69
70
|
onStartIncomingCall(remoteUserId: UserId, callId: CallId, isVideoCall: boolean): void;
|
|
70
|
-
|
|
71
|
+
proceed(callId: CallId, settings: CallSettings): void;
|
|
71
72
|
onCallState(remoteUserId: UserId, state: CallState): void;
|
|
72
73
|
onCallEnded(remoteUserId: UserId, callId: CallId, reason: CallEndedReason, ageSec: number): void;
|
|
73
74
|
onRemoteVideoEnabled(remoteUserId: UserId, enabled: boolean): void;
|
|
@@ -154,7 +155,6 @@ export declare class Call {
|
|
|
154
155
|
callId: CallId;
|
|
155
156
|
private readonly _isIncoming;
|
|
156
157
|
private readonly _isVideoCall;
|
|
157
|
-
settings: CallSettings | null;
|
|
158
158
|
private _state;
|
|
159
159
|
private _outgoingAudioEnabled;
|
|
160
160
|
private _outgoingVideoEnabled;
|
|
@@ -173,7 +173,7 @@ export declare class Call {
|
|
|
173
173
|
handleNetworkRouteChanged?: () => void;
|
|
174
174
|
handleAudioLevels?: () => void;
|
|
175
175
|
renderVideoFrame?: (width: number, height: number, buffer: Buffer) => void;
|
|
176
|
-
constructor(callManager: CallManager, remoteUserId: UserId, callId: CallId, isIncoming: boolean, isVideoCall: boolean,
|
|
176
|
+
constructor(callManager: CallManager, remoteUserId: UserId, callId: CallId, isIncoming: boolean, isVideoCall: boolean, state: CallState);
|
|
177
177
|
get remoteUserId(): UserId;
|
|
178
178
|
get isIncoming(): boolean;
|
|
179
179
|
get isVideoCall(): boolean;
|
|
@@ -194,7 +194,7 @@ export declare class Call {
|
|
|
194
194
|
get remoteVideoEnabled(): boolean;
|
|
195
195
|
set remoteVideoEnabled(enabled: boolean);
|
|
196
196
|
sendVideoFrame(width: number, height: number, format: VideoPixelFormatEnum, buffer: Buffer): void;
|
|
197
|
-
receiveVideoFrame(buffer: Buffer): [number, number] | undefined;
|
|
197
|
+
receiveVideoFrame(buffer: Buffer, maxWidth: number, maxHeight: number): [number, number] | undefined;
|
|
198
198
|
private enableOrDisableCapturer;
|
|
199
199
|
private setOutgoingVideoEnabled;
|
|
200
200
|
updateBandwidthMode(bandwidthMode: BandwidthMode): void;
|
|
@@ -340,7 +340,7 @@ declare class GroupCallVideoFrameSource {
|
|
|
340
340
|
private readonly _groupCall;
|
|
341
341
|
private readonly _remoteDemuxId;
|
|
342
342
|
constructor(callManager: CallManager, groupCall: GroupCall, remoteDemuxId: number);
|
|
343
|
-
receiveVideoFrame(buffer: Buffer): [number, number] | undefined;
|
|
343
|
+
receiveVideoFrame(buffer: Buffer, maxWidth: number, maxHeight: number): [number, number] | undefined;
|
|
344
344
|
}
|
|
345
345
|
declare type ProtobufBuffer = Buffer | {
|
|
346
346
|
toArrayBuffer: () => ArrayBuffer;
|
|
@@ -400,9 +400,8 @@ export declare enum HangupType {
|
|
|
400
400
|
NeedPermission = 4
|
|
401
401
|
}
|
|
402
402
|
export declare enum BandwidthMode {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
Normal = 2
|
|
403
|
+
Low = 0,
|
|
404
|
+
Normal = 1
|
|
406
405
|
}
|
|
407
406
|
export declare enum RingCancelReason {
|
|
408
407
|
DeclinedByUser = 0,
|
|
@@ -424,7 +423,7 @@ export interface CallManager {
|
|
|
424
423
|
setOutgoingVideoIsScreenShare(enabled: boolean): void;
|
|
425
424
|
updateBandwidthMode(bandwidthMode: BandwidthMode): void;
|
|
426
425
|
sendVideoFrame(width: number, height: number, format: VideoPixelFormatEnum, buffer: Buffer): void;
|
|
427
|
-
receiveVideoFrame(buffer: Buffer): [number, number] | undefined;
|
|
426
|
+
receiveVideoFrame(buffer: Buffer, maxWidth: number, maxHeight: number): [number, number] | undefined;
|
|
428
427
|
receivedOffer(remoteUserId: UserId, remoteDeviceId: DeviceId, messageAgeSec: number, callId: CallId, offerType: OfferType, localDeviceId: DeviceId, opaque: Buffer, senderIdentityKey: Buffer, receiverIdentityKey: Buffer): void;
|
|
429
428
|
receivedAnswer(remoteUserId: UserId, remoteDeviceId: DeviceId, callId: CallId, opaque: Buffer, senderIdentityKey: Buffer, receiverIdentityKey: Buffer): void;
|
|
430
429
|
receivedIceCandidates(remoteUserId: UserId, remoteDeviceId: DeviceId, callId: CallId, candidates: Array<Buffer>): void;
|
|
@@ -449,7 +448,7 @@ export interface CallManager {
|
|
|
449
448
|
requestVideo(clientId: GroupCallClientId, resolutions: Array<VideoRequest>, activeSpeakerHeight: number): void;
|
|
450
449
|
setGroupMembers(clientId: GroupCallClientId, members: Array<GroupMemberInfo>): void;
|
|
451
450
|
setMembershipProof(clientId: GroupCallClientId, proof: Buffer): void;
|
|
452
|
-
receiveGroupCallVideoFrame(clientId: GroupCallClientId, remoteDemuxId: number, buffer: Buffer): [number, number] | undefined;
|
|
451
|
+
receiveGroupCallVideoFrame(clientId: GroupCallClientId, remoteDemuxId: number, buffer: Buffer, maxWidth: number, maxHeight: number): [number, number] | undefined;
|
|
453
452
|
peekGroupCall(requestId: number, sfu_url: string, membership_proof: Buffer, group_members: Array<GroupMemberInfo>): Promise<PeekInfo>;
|
|
454
453
|
getAudioInputs(): AudioDevice[];
|
|
455
454
|
setAudioInput(index: number): void;
|
package/dist/ringrtc/Service.js
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
3
3
|
// Copyright 2019-2021 Signal Messenger, LLC
|
|
4
4
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
5
5
|
//
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
6
25
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
7
26
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
8
27
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -15,8 +34,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
15
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
35
|
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
36
|
/* tslint:disable max-classes-per-file */
|
|
18
|
-
const os = require("os");
|
|
19
|
-
const process = require("process");
|
|
37
|
+
const os = __importStar(require("os"));
|
|
38
|
+
const process = __importStar(require("process"));
|
|
20
39
|
// tslint:disable-next-line no-var-requires no-require-imports
|
|
21
40
|
const Native = require('../../build/' +
|
|
22
41
|
os.platform() +
|
|
@@ -41,10 +60,16 @@ class NativeCallManager {
|
|
|
41
60
|
const fieldTrialsString = Object.entries(config.field_trials || {})
|
|
42
61
|
.map(([k, v]) => `${k}/${v}`)
|
|
43
62
|
.join('/') + '/';
|
|
44
|
-
const callEndpoint = Native.createCallEndpoint(this, config.use_new_audio_device_module, fieldTrialsString);
|
|
45
63
|
Object.defineProperty(this, Native.callEndpointPropertyKey, {
|
|
46
|
-
|
|
47
|
-
|
|
64
|
+
configurable: true,
|
|
65
|
+
get() {
|
|
66
|
+
const callEndpoint = Native.createCallEndpoint(this, config.use_new_audio_device_module, fieldTrialsString);
|
|
67
|
+
Object.defineProperty(this, Native.callEndpointPropertyKey, {
|
|
68
|
+
configurable: true,
|
|
69
|
+
value: callEndpoint,
|
|
70
|
+
});
|
|
71
|
+
return callEndpoint;
|
|
72
|
+
},
|
|
48
73
|
});
|
|
49
74
|
}
|
|
50
75
|
}
|
|
@@ -210,6 +235,7 @@ class RingRTCType {
|
|
|
210
235
|
// Set by UX
|
|
211
236
|
this.handleOutgoingSignaling = null;
|
|
212
237
|
this.handleIncomingCall = null;
|
|
238
|
+
this.handleStartCall = null;
|
|
213
239
|
this.handleAutoEndedIncomingCallRequest = null;
|
|
214
240
|
this.handleLogMessage = null;
|
|
215
241
|
this.handleSendHttpRequest = null;
|
|
@@ -234,10 +260,10 @@ class RingRTCType {
|
|
|
234
260
|
this.callManager.setSelfUuid(uuid);
|
|
235
261
|
}
|
|
236
262
|
// Called by UX
|
|
237
|
-
startOutgoingCall(remoteUserId, isVideoCall, localDeviceId
|
|
263
|
+
startOutgoingCall(remoteUserId, isVideoCall, localDeviceId) {
|
|
238
264
|
const callId = this.callManager.createOutgoingCall(remoteUserId, isVideoCall, localDeviceId);
|
|
239
265
|
const isIncoming = false;
|
|
240
|
-
const call = new Call(this.callManager, remoteUserId, callId, isIncoming, isVideoCall,
|
|
266
|
+
const call = new Call(this.callManager, remoteUserId, callId, isIncoming, isVideoCall, CallState.Prering);
|
|
241
267
|
this._call = call;
|
|
242
268
|
// We won't actually send anything until the remote side accepts.
|
|
243
269
|
call.outgoingAudioEnabled = true;
|
|
@@ -253,11 +279,26 @@ class RingRTCType {
|
|
|
253
279
|
// Called by Rust
|
|
254
280
|
onStartOutgoingCall(remoteUserId, callId) {
|
|
255
281
|
const call = this._call;
|
|
256
|
-
if (!call || call.remoteUserId !== remoteUserId
|
|
282
|
+
if (!call || call.remoteUserId !== remoteUserId) {
|
|
257
283
|
return;
|
|
258
284
|
}
|
|
259
285
|
call.callId = callId;
|
|
260
|
-
this.
|
|
286
|
+
const handleStartCall = this.handleStartCall;
|
|
287
|
+
if (!handleStartCall) {
|
|
288
|
+
call.ignore();
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
handleStartCall(call)
|
|
292
|
+
.then(result => {
|
|
293
|
+
if (!result) {
|
|
294
|
+
this.logWarn('RingRTC.handleStartCall failed for outgoing call. Call ignored.');
|
|
295
|
+
call.ignore();
|
|
296
|
+
}
|
|
297
|
+
})
|
|
298
|
+
.catch(e => {
|
|
299
|
+
this.logError('RingRTC.handleStartCall exception: ' + e.toString());
|
|
300
|
+
call.ignore();
|
|
301
|
+
});
|
|
261
302
|
}
|
|
262
303
|
// Called by Rust
|
|
263
304
|
onStartIncomingCall(remoteUserId, callId, isVideoCall) {
|
|
@@ -280,24 +321,38 @@ class RingRTCType {
|
|
|
280
321
|
return;
|
|
281
322
|
}
|
|
282
323
|
const isIncoming = true;
|
|
283
|
-
const call = new Call(this.callManager, remoteUserId, callId, isIncoming, isVideoCall,
|
|
284
|
-
// Callback to UX not set
|
|
324
|
+
const call = new Call(this.callManager, remoteUserId, callId, isIncoming, isVideoCall, CallState.Prering);
|
|
285
325
|
const handleIncomingCall = this.handleIncomingCall;
|
|
286
|
-
|
|
326
|
+
const handleStartCall = this.handleStartCall;
|
|
327
|
+
if (!handleIncomingCall || !handleStartCall) {
|
|
287
328
|
call.ignore();
|
|
288
329
|
return;
|
|
289
330
|
}
|
|
290
331
|
this._call = call;
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
332
|
+
handleIncomingCall(call)
|
|
333
|
+
.then(success => {
|
|
334
|
+
if (!success) {
|
|
335
|
+
this.logWarn('RingRTC.handleIncomingCall failed for incoming call. Call ignored.');
|
|
295
336
|
call.ignore();
|
|
296
|
-
return;
|
|
297
337
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
338
|
+
else {
|
|
339
|
+
handleStartCall(call)
|
|
340
|
+
.then(success => {
|
|
341
|
+
if (!success) {
|
|
342
|
+
this.logWarn('RingRTC.handleStartCall failed for incoming call. Call ignored.');
|
|
343
|
+
call.ignore();
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
.catch(e => {
|
|
347
|
+
this.logError('RingRTC.handleStartCall exception: ' + e.toString());
|
|
348
|
+
call.ignore();
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
})
|
|
352
|
+
.catch(e => {
|
|
353
|
+
this.logError('RingRTC.handleIncomingCall exception: ' + e.toString());
|
|
354
|
+
call.ignore();
|
|
355
|
+
});
|
|
301
356
|
}
|
|
302
357
|
proceed(callId, settings) {
|
|
303
358
|
silly_deadlock_protection(() => {
|
|
@@ -864,7 +919,7 @@ class RingRTCType {
|
|
|
864
919
|
}
|
|
865
920
|
exports.RingRTCType = RingRTCType;
|
|
866
921
|
class Call {
|
|
867
|
-
constructor(callManager, remoteUserId, callId, isIncoming, isVideoCall,
|
|
922
|
+
constructor(callManager, remoteUserId, callId, isIncoming, isVideoCall, state) {
|
|
868
923
|
this._outgoingAudioEnabled = false;
|
|
869
924
|
this._outgoingVideoEnabled = false;
|
|
870
925
|
this._outgoingVideoIsScreenShare = false;
|
|
@@ -880,7 +935,6 @@ class Call {
|
|
|
880
935
|
this.callId = callId;
|
|
881
936
|
this._isIncoming = isIncoming;
|
|
882
937
|
this._isVideoCall = isVideoCall;
|
|
883
|
-
this.settings = settings;
|
|
884
938
|
this._state = state;
|
|
885
939
|
}
|
|
886
940
|
get remoteUserId() {
|
|
@@ -973,13 +1027,13 @@ class Call {
|
|
|
973
1027
|
}
|
|
974
1028
|
// With this method, a Call is a VideoFrameSender
|
|
975
1029
|
sendVideoFrame(width, height, format, buffer) {
|
|
976
|
-
// This assumes we only have one active
|
|
1030
|
+
// This assumes we only have one active call.
|
|
977
1031
|
this._callManager.sendVideoFrame(width, height, format, buffer);
|
|
978
1032
|
}
|
|
979
1033
|
// With this method, a Call is a VideoFrameSource
|
|
980
|
-
receiveVideoFrame(buffer) {
|
|
981
|
-
// This assumes we only have one active
|
|
982
|
-
return this._callManager.receiveVideoFrame(buffer);
|
|
1034
|
+
receiveVideoFrame(buffer, maxWidth, maxHeight) {
|
|
1035
|
+
// This assumes we only have one active call.
|
|
1036
|
+
return this._callManager.receiveVideoFrame(buffer, maxWidth, maxHeight);
|
|
983
1037
|
}
|
|
984
1038
|
enableOrDisableCapturer() {
|
|
985
1039
|
if (!this._videoCapturer) {
|
|
@@ -1323,7 +1377,7 @@ class GroupCall {
|
|
|
1323
1377
|
}
|
|
1324
1378
|
// With this, a GroupCall is a VideoFrameSender
|
|
1325
1379
|
sendVideoFrame(width, height, format, buffer) {
|
|
1326
|
-
// This assumes we only have one active
|
|
1380
|
+
// This assumes we only have one active call.
|
|
1327
1381
|
this._callManager.sendVideoFrame(width, height, format, buffer);
|
|
1328
1382
|
}
|
|
1329
1383
|
// With this, a GroupCall can provide a VideoFrameSource for each remote device.
|
|
@@ -1349,9 +1403,9 @@ class GroupCallVideoFrameSource {
|
|
|
1349
1403
|
this._groupCall = groupCall;
|
|
1350
1404
|
this._remoteDemuxId = remoteDemuxId;
|
|
1351
1405
|
}
|
|
1352
|
-
receiveVideoFrame(buffer) {
|
|
1353
|
-
// This assumes we only have one active
|
|
1354
|
-
const frame = this._callManager.receiveGroupCallVideoFrame(this._groupCall.clientId, this._remoteDemuxId, buffer);
|
|
1406
|
+
receiveVideoFrame(buffer, maxWidth, maxHeight) {
|
|
1407
|
+
// This assumes we only have one active call.
|
|
1408
|
+
const frame = this._callManager.receiveGroupCallVideoFrame(this._groupCall.clientId, this._remoteDemuxId, buffer, maxWidth, maxHeight);
|
|
1355
1409
|
if (!!frame) {
|
|
1356
1410
|
const [width, height] = frame;
|
|
1357
1411
|
this._groupCall.setRemoteAspectRatio(this._remoteDemuxId, width / height);
|
|
@@ -1404,9 +1458,8 @@ var HangupType;
|
|
|
1404
1458
|
})(HangupType = exports.HangupType || (exports.HangupType = {}));
|
|
1405
1459
|
var BandwidthMode;
|
|
1406
1460
|
(function (BandwidthMode) {
|
|
1407
|
-
BandwidthMode[BandwidthMode["
|
|
1408
|
-
BandwidthMode[BandwidthMode["
|
|
1409
|
-
BandwidthMode[BandwidthMode["Normal"] = 2] = "Normal";
|
|
1461
|
+
BandwidthMode[BandwidthMode["Low"] = 0] = "Low";
|
|
1462
|
+
BandwidthMode[BandwidthMode["Normal"] = 1] = "Normal";
|
|
1410
1463
|
})(BandwidthMode = exports.BandwidthMode || (exports.BandwidthMode = {}));
|
|
1411
1464
|
/// Describes why a ring was cancelled.
|
|
1412
1465
|
var RingCancelReason;
|
|
@@ -8,7 +8,17 @@ export declare enum VideoPixelFormatEnum {
|
|
|
8
8
|
Rgba = 2
|
|
9
9
|
}
|
|
10
10
|
export interface VideoFrameSource {
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Copies the latest frame into `buffer`.
|
|
13
|
+
*
|
|
14
|
+
* Note that `maxWidth` and `maxHeight` specify maximum dimensions,
|
|
15
|
+
* but allow for rotation, i.e. a maximum of 1920x1080 will also allow
|
|
16
|
+
* portrait-mode 1080x1920.
|
|
17
|
+
*
|
|
18
|
+
* Returns a `[width, height]` pair for the resulting frame,
|
|
19
|
+
* or `undefined` if there's no new frame ready to be displayed.
|
|
20
|
+
*/
|
|
21
|
+
receiveVideoFrame(buffer: Buffer, maxWidth: number, maxHeight: number): [number, number] | undefined;
|
|
12
22
|
}
|
|
13
23
|
interface VideoFrameSender {
|
|
14
24
|
sendVideoFrame(width: number, height: number, format: VideoPixelFormatEnum, buffer: Buffer): void;
|
|
@@ -144,6 +144,7 @@ class GumVideoCapturer {
|
|
|
144
144
|
chromeMediaSourceId: options.screenShareSourceId,
|
|
145
145
|
maxWidth: options.maxWidth,
|
|
146
146
|
maxHeight: options.maxHeight,
|
|
147
|
+
minFrameRate: 1,
|
|
147
148
|
maxFrameRate: options.maxFramerate,
|
|
148
149
|
},
|
|
149
150
|
};
|
|
@@ -375,7 +376,7 @@ class CanvasVideoRenderer {
|
|
|
375
376
|
if (!context) {
|
|
376
377
|
return;
|
|
377
378
|
}
|
|
378
|
-
const frame = this.source.receiveVideoFrame(this.buffer);
|
|
379
|
+
const frame = this.source.receiveVideoFrame(this.buffer, exports.MAX_VIDEO_CAPTURE_WIDTH, exports.MAX_VIDEO_CAPTURE_HEIGHT);
|
|
379
380
|
if (!frame) {
|
|
380
381
|
return;
|
|
381
382
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare class CallingClass {
|
|
2
|
+
private _name;
|
|
3
|
+
private _id;
|
|
4
|
+
private _localDeviceId;
|
|
5
|
+
private _call;
|
|
6
|
+
private _delayIncomingCallSettingsRequest;
|
|
7
|
+
private _delayOutgoingCallSettingsRequest;
|
|
8
|
+
set delayIncomingCallSettingsRequest(value: number);
|
|
9
|
+
set delayOutgoingCallSettingsRequest(value: number);
|
|
10
|
+
constructor(name: string, id: string);
|
|
11
|
+
private setupCallCallbacks;
|
|
12
|
+
private handleOutgoingSignaling;
|
|
13
|
+
private handleIncomingCall;
|
|
14
|
+
private handleStartCall;
|
|
15
|
+
private handleAutoEndedIncomingCallRequest;
|
|
16
|
+
private handleLogMessage;
|
|
17
|
+
private handleSendHttpRequest;
|
|
18
|
+
private handleSendCallMessage;
|
|
19
|
+
private handleSendCallMessageToGroup;
|
|
20
|
+
private handleGroupCallRingUpdate;
|
|
21
|
+
private getCallSettings;
|
|
22
|
+
initialize(): void;
|
|
23
|
+
startOutgoingDirectCall(remoteUserId: string): Promise<void>;
|
|
24
|
+
hangup(): boolean;
|
|
25
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//
|
|
3
|
+
// Copyright 2023 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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
16
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.CallingClass = void 0;
|
|
20
|
+
const Service_1 = require("../ringrtc/Service");
|
|
21
|
+
const index_1 = require("../index");
|
|
22
|
+
const long_1 = __importDefault(require("long"));
|
|
23
|
+
const Utils_1 = require("./Utils");
|
|
24
|
+
// This class mimics the Desktop Client CallingClass in ts/services/calling.ts to facilitate testing
|
|
25
|
+
class CallingClass {
|
|
26
|
+
constructor(name, id) {
|
|
27
|
+
this._name = name;
|
|
28
|
+
this._id = id;
|
|
29
|
+
this._localDeviceId = 1;
|
|
30
|
+
this._delayIncomingCallSettingsRequest = 0;
|
|
31
|
+
this._delayOutgoingCallSettingsRequest = 0;
|
|
32
|
+
}
|
|
33
|
+
set delayIncomingCallSettingsRequest(value) {
|
|
34
|
+
this._delayIncomingCallSettingsRequest = value;
|
|
35
|
+
}
|
|
36
|
+
set delayOutgoingCallSettingsRequest(value) {
|
|
37
|
+
this._delayIncomingCallSettingsRequest = value;
|
|
38
|
+
}
|
|
39
|
+
setupCallCallbacks(call) {
|
|
40
|
+
// eslint-disable-next-line no-param-reassign
|
|
41
|
+
call.handleStateChanged = () => __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
(0, Utils_1.log)('handleCallStateChanged');
|
|
43
|
+
(0, Utils_1.log)(`call.state === ${call.state}`);
|
|
44
|
+
if (call.state === Service_1.CallState.Ended) {
|
|
45
|
+
(0, Utils_1.log)(`call.endedReason === ${call.endedReason}`);
|
|
46
|
+
this._call = undefined;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
// eslint-disable-next-line no-param-reassign
|
|
50
|
+
call.handleRemoteVideoEnabled = () => {
|
|
51
|
+
(0, Utils_1.log)('handleRemoteVideoEnabled');
|
|
52
|
+
};
|
|
53
|
+
// eslint-disable-next-line no-param-reassign
|
|
54
|
+
call.handleRemoteSharingScreen = () => {
|
|
55
|
+
(0, Utils_1.log)('handleRemoteSharingScreen');
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
59
|
+
// Callbacks
|
|
60
|
+
handleOutgoingSignaling(remoteUserId, message, urgency) {
|
|
61
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
(0, Utils_1.log)('handleOutgoingSignaling remoteUserId: ' + remoteUserId);
|
|
63
|
+
return true;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
handleIncomingCall(call) {
|
|
67
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
+
(0, Utils_1.log)('handleIncomingCall');
|
|
69
|
+
this._call = call;
|
|
70
|
+
this.setupCallCallbacks(call);
|
|
71
|
+
return true;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
handleStartCall(call) {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
const callSettings = yield this.getCallSettings(call.isIncoming);
|
|
77
|
+
index_1.RingRTC.proceed(call.callId, callSettings);
|
|
78
|
+
return true;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
handleAutoEndedIncomingCallRequest(callId, remoteUserId, reason, ageInSeconds, wasVideoCall, receivedAtCounter) {
|
|
82
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
83
|
+
(0, Utils_1.log)('handleAutoEndedIncomingCallRequest');
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
handleLogMessage(level, fileName, line, message) {
|
|
87
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
88
|
+
switch (level) {
|
|
89
|
+
case Service_1.CallLogLevel.Info:
|
|
90
|
+
// FgGray
|
|
91
|
+
console.log(`\x1b[90m${fileName}:${line} ${message}\x1b[0m`);
|
|
92
|
+
break;
|
|
93
|
+
case Service_1.CallLogLevel.Warn:
|
|
94
|
+
// FgYellow
|
|
95
|
+
console.warn(`\x1b[33m${fileName}:${line} ${message}\x1b[0m`);
|
|
96
|
+
break;
|
|
97
|
+
case Service_1.CallLogLevel.Error:
|
|
98
|
+
// FgRed
|
|
99
|
+
console.error(`\x1b[31m${fileName}:${line} ${message}\x1b[0m`);
|
|
100
|
+
break;
|
|
101
|
+
default:
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
handleSendHttpRequest(requestId, url, method, headers, body) {
|
|
107
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
108
|
+
(0, Utils_1.log)('handleSendHttpRequest');
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
handleSendCallMessage(recipient, data, urgency) {
|
|
112
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
113
|
+
(0, Utils_1.log)('handleSendCallMessage');
|
|
114
|
+
return true;
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
handleSendCallMessageToGroup(groupIdBytes, data, urgency) {
|
|
118
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
119
|
+
(0, Utils_1.log)('handleSendCallMessageToGroup');
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
handleGroupCallRingUpdate(groupIdBytes, ringId, ringerBytes, update) {
|
|
123
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
124
|
+
(0, Utils_1.log)('handleGroupCallRingUpdate');
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
128
|
+
// Support
|
|
129
|
+
getCallSettings(isIncoming) {
|
|
130
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
131
|
+
if (isIncoming) {
|
|
132
|
+
(0, Utils_1.log)('getCallSettings delayed by ' +
|
|
133
|
+
this._delayIncomingCallSettingsRequest.toString() +
|
|
134
|
+
'ms');
|
|
135
|
+
yield (0, Utils_1.sleep)(this._delayIncomingCallSettingsRequest);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
(0, Utils_1.log)('getCallSettings delayed by ' +
|
|
139
|
+
this._delayOutgoingCallSettingsRequest.toString() +
|
|
140
|
+
'ms');
|
|
141
|
+
yield (0, Utils_1.sleep)(this._delayOutgoingCallSettingsRequest);
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
iceServer: {
|
|
145
|
+
urls: ['stun:turn3.voip.signal.org'],
|
|
146
|
+
},
|
|
147
|
+
hideIp: false,
|
|
148
|
+
bandwidthMode: Service_1.BandwidthMode.Normal,
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
153
|
+
// Actions
|
|
154
|
+
initialize() {
|
|
155
|
+
(0, Utils_1.log)('initialize');
|
|
156
|
+
index_1.RingRTC.setConfig({
|
|
157
|
+
use_new_audio_device_module: true,
|
|
158
|
+
field_trials: undefined,
|
|
159
|
+
});
|
|
160
|
+
index_1.RingRTC.handleOutgoingSignaling = this.handleOutgoingSignaling.bind(this);
|
|
161
|
+
index_1.RingRTC.handleIncomingCall = this.handleIncomingCall.bind(this);
|
|
162
|
+
index_1.RingRTC.handleStartCall = this.handleStartCall.bind(this);
|
|
163
|
+
index_1.RingRTC.handleAutoEndedIncomingCallRequest =
|
|
164
|
+
this.handleAutoEndedIncomingCallRequest.bind(this);
|
|
165
|
+
index_1.RingRTC.handleLogMessage = this.handleLogMessage.bind(this);
|
|
166
|
+
index_1.RingRTC.handleSendHttpRequest = this.handleSendHttpRequest.bind(this);
|
|
167
|
+
index_1.RingRTC.handleSendCallMessage = this.handleSendCallMessage.bind(this);
|
|
168
|
+
index_1.RingRTC.handleSendCallMessageToGroup =
|
|
169
|
+
this.handleSendCallMessageToGroup.bind(this);
|
|
170
|
+
index_1.RingRTC.handleGroupCallRingUpdate =
|
|
171
|
+
this.handleGroupCallRingUpdate.bind(this);
|
|
172
|
+
index_1.RingRTC.setSelfUuid(Buffer.from((0, Utils_1.uuidToBytes)(this._id)));
|
|
173
|
+
}
|
|
174
|
+
startOutgoingDirectCall(remoteUserId) {
|
|
175
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
176
|
+
(0, Utils_1.log)('startOutgoingDirectCall');
|
|
177
|
+
if (index_1.RingRTC.call && index_1.RingRTC.call.state !== Service_1.CallState.Ended) {
|
|
178
|
+
(0, Utils_1.log)('Call already in progress, new call not allowed.');
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const call = index_1.RingRTC.startOutgoingCall(remoteUserId, false, this._localDeviceId);
|
|
182
|
+
(0, Utils_1.log)('Outgoing callId ' + long_1.default.fromValue(call.callId).toString());
|
|
183
|
+
index_1.RingRTC.setOutgoingAudio(call.callId, true);
|
|
184
|
+
this._call = call;
|
|
185
|
+
this.setupCallCallbacks(call);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
hangup() {
|
|
189
|
+
(0, Utils_1.log)('hangup');
|
|
190
|
+
if (this._call) {
|
|
191
|
+
index_1.RingRTC.hangup(this._call.callId);
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
exports.CallingClass = CallingClass;
|
|
@@ -12,15 +12,46 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
12
12
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13
13
|
});
|
|
14
14
|
};
|
|
15
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
16
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
17
|
+
};
|
|
15
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
19
|
const chai_1 = require("chai");
|
|
17
|
-
const
|
|
20
|
+
const chai_as_promised_1 = __importDefault(require("chai-as-promised"));
|
|
21
|
+
const crypto_1 = require("crypto");
|
|
18
22
|
const index_1 = require("../index");
|
|
19
|
-
|
|
23
|
+
const long_1 = __importDefault(require("long"));
|
|
24
|
+
const chai_2 = require("chai");
|
|
25
|
+
const sinon_1 = __importDefault(require("sinon"));
|
|
26
|
+
const sinon_chai_1 = __importDefault(require("sinon-chai"));
|
|
27
|
+
const CallingClass_1 = require("./CallingClass");
|
|
28
|
+
const Utils_1 = require("./Utils");
|
|
29
|
+
(0, chai_1.use)(chai_as_promised_1.default);
|
|
30
|
+
(0, chai_2.should)();
|
|
31
|
+
(0, chai_1.use)(sinon_chai_1.default);
|
|
32
|
+
function generateOfferCallingMessage(callId) {
|
|
33
|
+
// Audio-only hex based SDP generated from a direct client call
|
|
34
|
+
const audioOnlySdp = Buffer.from('22560a204b18bc751315cb718c643db7b3a65aaabe826c7094932afaf5aebc86d36bb6491204484b6b481a18524b3041496f63334245514e5670424b57786f38787051712204082e1034220408281034220208082880897a', 'hex');
|
|
35
|
+
return {
|
|
36
|
+
offer: {
|
|
37
|
+
callId: callId,
|
|
38
|
+
opaque: audioOnlySdp,
|
|
39
|
+
type: index_1.OfferType.AudioCall,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
20
43
|
describe('RingRTC', () => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
44
|
+
const identity_key_length = 31;
|
|
45
|
+
const user1_name = 'user1';
|
|
46
|
+
const user1_id = '11';
|
|
47
|
+
const user1_device_id = 11;
|
|
48
|
+
const user1_identity_key = (0, crypto_1.randomBytes)(identity_key_length);
|
|
49
|
+
const user2_id = '22';
|
|
50
|
+
const user2_device_id = 22;
|
|
51
|
+
const user2_identity_key = (0, crypto_1.randomBytes)(identity_key_length);
|
|
52
|
+
let handleOutgoingSignalingSpy;
|
|
53
|
+
let handleIncomingCallSpy;
|
|
54
|
+
let handleAutoEndedIncomingCallRequestSpy;
|
|
24
55
|
it('reports an age for expired offers', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
56
|
const offer = {
|
|
26
57
|
offer: {
|
|
@@ -68,4 +99,113 @@ describe('RingRTC', () => {
|
|
|
68
99
|
index_1.RingRTC.handleAutoEndedIncomingCallRequest = null;
|
|
69
100
|
}
|
|
70
101
|
}));
|
|
102
|
+
function initializeSpies() {
|
|
103
|
+
handleAutoEndedIncomingCallRequestSpy = sinon_1.default.spy(index_1.RingRTC, 'handleAutoEndedIncomingCallRequest');
|
|
104
|
+
handleIncomingCallSpy = sinon_1.default.spy(index_1.RingRTC, 'handleIncomingCall');
|
|
105
|
+
handleOutgoingSignalingSpy = sinon_1.default.spy(index_1.RingRTC, 'handleOutgoingSignaling');
|
|
106
|
+
}
|
|
107
|
+
it('can initialize RingRTC', () => {
|
|
108
|
+
chai_1.assert.isNotNull(index_1.RingRTC, "RingRTC didn't initialize!");
|
|
109
|
+
});
|
|
110
|
+
it('can establish outgoing call', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
111
|
+
let calling = new CallingClass_1.CallingClass(user1_name, user1_id);
|
|
112
|
+
calling.initialize();
|
|
113
|
+
initializeSpies();
|
|
114
|
+
yield calling.startOutgoingDirectCall(user2_id);
|
|
115
|
+
yield (0, Utils_1.sleep)(1000);
|
|
116
|
+
// An offer and at least one ICE message should have been sent.
|
|
117
|
+
(0, chai_1.expect)(handleOutgoingSignalingSpy.callCount).to.be.gt(1);
|
|
118
|
+
yield (0, Utils_1.sleep)(2000);
|
|
119
|
+
// Cleanup.
|
|
120
|
+
const handleStateChangedSpy = sinon_1.default.spy(index_1.RingRTC.call, 'handleStateChanged');
|
|
121
|
+
(0, chai_1.expect)(calling.hangup()).to.be.true;
|
|
122
|
+
yield (0, Utils_1.sleep)(500);
|
|
123
|
+
handleStateChangedSpy.should.have.been.calledOnce;
|
|
124
|
+
(0, chai_1.expect)(calling.hangup()).to.be.false;
|
|
125
|
+
yield (0, Utils_1.sleep)(100);
|
|
126
|
+
}));
|
|
127
|
+
it('can establish incoming call', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
128
|
+
let calling = new CallingClass_1.CallingClass(user1_name, user1_id);
|
|
129
|
+
calling.initialize();
|
|
130
|
+
initializeSpies();
|
|
131
|
+
// Generate incoming calling message
|
|
132
|
+
const message_age_sec = 1;
|
|
133
|
+
const message_received_at_counter = 10;
|
|
134
|
+
const callId = new long_1.default(1, 1, true);
|
|
135
|
+
const offerCallingMessage = generateOfferCallingMessage(callId);
|
|
136
|
+
index_1.RingRTC.handleCallingMessage(user2_id, Buffer.from((0, Utils_1.uuidToBytes)(user2_id)), user2_device_id, user1_device_id, message_age_sec, message_received_at_counter, offerCallingMessage, user2_identity_key, user1_identity_key);
|
|
137
|
+
yield (0, Utils_1.sleep)(1000);
|
|
138
|
+
handleIncomingCallSpy.should.have.been.calledOnce;
|
|
139
|
+
chai_1.assert.equal(index_1.CallState.Prering, index_1.RingRTC.call.state);
|
|
140
|
+
// Hangup call
|
|
141
|
+
(0, chai_1.expect)(calling.hangup()).to.be.true;
|
|
142
|
+
yield (0, Utils_1.sleep)(500);
|
|
143
|
+
// Validate hangup related callbacks and call state
|
|
144
|
+
handleAutoEndedIncomingCallRequestSpy.should.have.been.calledOnce;
|
|
145
|
+
(0, chai_1.expect)(handleOutgoingSignalingSpy.callCount).to.be.gt(1);
|
|
146
|
+
chai_1.assert.equal(index_1.CallState.Ended, index_1.RingRTC.call.state);
|
|
147
|
+
}));
|
|
148
|
+
it('outgoing call wins glare when incoming call id is lower', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
149
|
+
let calling = new CallingClass_1.CallingClass(user1_name, user1_id);
|
|
150
|
+
calling.initialize();
|
|
151
|
+
initializeSpies();
|
|
152
|
+
yield runGlareScenario(calling, true, 0, 0);
|
|
153
|
+
}));
|
|
154
|
+
it('outgoing call wins glare when incoming call id is lower even when outgoing call settings are delayed', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
155
|
+
let calling = new CallingClass_1.CallingClass(user1_name, user1_id);
|
|
156
|
+
calling.initialize();
|
|
157
|
+
initializeSpies();
|
|
158
|
+
yield runGlareScenario(calling, true, 0, 1000);
|
|
159
|
+
}));
|
|
160
|
+
it('outgoing call loses glare when incoming call id is higher even when outgoing call settings are delayed', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
161
|
+
let calling = new CallingClass_1.CallingClass(user1_name, user1_id);
|
|
162
|
+
calling.initialize();
|
|
163
|
+
initializeSpies();
|
|
164
|
+
yield runGlareScenario(calling, false, 0, 1000);
|
|
165
|
+
}));
|
|
166
|
+
it('outgoing call loses glare when incoming call id is higher', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
167
|
+
let calling = new CallingClass_1.CallingClass(user1_name, user1_id);
|
|
168
|
+
calling.initialize();
|
|
169
|
+
initializeSpies();
|
|
170
|
+
yield runGlareScenario(calling, false, 0, 0);
|
|
171
|
+
}));
|
|
172
|
+
function runGlareScenario(calling, outgoingWinner, delayIncomingCallSetings, delayOutgoingCallSetings) {
|
|
173
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
+
calling.delayOutgoingCallSettingsRequest = delayOutgoingCallSetings;
|
|
175
|
+
calling.delayIncomingCallSettingsRequest = delayIncomingCallSetings;
|
|
176
|
+
const outgoingCallLatch = (0, Utils_1.countDownLatch)(1);
|
|
177
|
+
calling
|
|
178
|
+
.startOutgoingDirectCall(user2_id)
|
|
179
|
+
.then(result => {
|
|
180
|
+
(0, Utils_1.log)('Outgoing call succeeded as expected');
|
|
181
|
+
outgoingCallLatch.countDown();
|
|
182
|
+
})
|
|
183
|
+
.catch(e => {
|
|
184
|
+
chai_1.assert.fail('Outgoing call should not have failed');
|
|
185
|
+
});
|
|
186
|
+
yield outgoingCallLatch.finished;
|
|
187
|
+
const outgoingCallId = long_1.default.fromValue(index_1.RingRTC.call.callId);
|
|
188
|
+
// Generate a call id based on the desired glare winner
|
|
189
|
+
const incomingCallId = outgoingCallId.unsigned
|
|
190
|
+
? new long_1.default(outgoingWinner ? outgoingCallId.low - 1 : outgoingCallId.low + 1, outgoingCallId.high, outgoingCallId.unsigned)
|
|
191
|
+
: new long_1.default(outgoingWinner ? outgoingCallId.low + 1 : outgoingCallId.low - 1, outgoingCallId.high, outgoingCallId.unsigned);
|
|
192
|
+
// Generate incoming calling message
|
|
193
|
+
const message_age_sec = 1;
|
|
194
|
+
const message_received_at_counter = 10;
|
|
195
|
+
const offerCallingMessage = generateOfferCallingMessage(incomingCallId);
|
|
196
|
+
// Initiate an incoming call
|
|
197
|
+
index_1.RingRTC.handleCallingMessage(user2_id, Buffer.from((0, Utils_1.uuidToBytes)(user2_id)), user2_device_id, user1_device_id, message_age_sec, message_received_at_counter, offerCallingMessage, user2_identity_key, user1_identity_key);
|
|
198
|
+
yield (0, Utils_1.sleep)(1000);
|
|
199
|
+
if (outgoingWinner) {
|
|
200
|
+
chai_1.assert.isTrue(outgoingCallId.eq(long_1.default.fromValue(index_1.RingRTC.call.callId)));
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
chai_1.assert.isTrue(incomingCallId.eq(long_1.default.fromValue(index_1.RingRTC.call.callId)));
|
|
204
|
+
}
|
|
205
|
+
// Cleanup.
|
|
206
|
+
(0, chai_1.expect)(calling.hangup()).to.be.true;
|
|
207
|
+
yield (0, Utils_1.sleep)(500);
|
|
208
|
+
chai_1.assert.equal(index_1.CallState.Ended, index_1.RingRTC.call.state);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
71
211
|
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function countDownLatch(count: number): {
|
|
2
|
+
countDown: () => void;
|
|
3
|
+
finished: Promise<unknown>;
|
|
4
|
+
};
|
|
5
|
+
export declare function log(line: string): void;
|
|
6
|
+
export declare let sleep: (timeout: number) => Promise<void>;
|
|
7
|
+
export declare function uuidToBytes(uuid: string): Uint8Array;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//
|
|
3
|
+
// Copyright 2023 Signal Messenger, LLC
|
|
4
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
5
|
+
//
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.uuidToBytes = exports.sleep = exports.log = exports.countDownLatch = void 0;
|
|
8
|
+
const lodash_1 = require("lodash");
|
|
9
|
+
const chai_1 = require("chai");
|
|
10
|
+
function countDownLatch(count) {
|
|
11
|
+
(0, chai_1.assert)(count > 0, 'count must be a positive number');
|
|
12
|
+
let resolve;
|
|
13
|
+
const finished = new Promise(resolveInternal => {
|
|
14
|
+
resolve = resolveInternal;
|
|
15
|
+
});
|
|
16
|
+
const countDown = () => {
|
|
17
|
+
count--;
|
|
18
|
+
if (count == 0) {
|
|
19
|
+
resolve();
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
countDown: countDown,
|
|
24
|
+
finished,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
exports.countDownLatch = countDownLatch;
|
|
28
|
+
function log(line) {
|
|
29
|
+
// Standard logging used for checkpoints.
|
|
30
|
+
// Use --renderer to see the log output. (edit: Maybe always shown now?)
|
|
31
|
+
// BgYellow
|
|
32
|
+
console.log(`\x1b[43m${line}\x1b[0m`);
|
|
33
|
+
}
|
|
34
|
+
exports.log = log;
|
|
35
|
+
let sleep = (timeout) => {
|
|
36
|
+
return new Promise(resolve => {
|
|
37
|
+
setTimeout(() => {
|
|
38
|
+
// BgBlue
|
|
39
|
+
console.log(`\x1b[44msleeping ${timeout} ms\x1b[0m`);
|
|
40
|
+
resolve();
|
|
41
|
+
}, timeout);
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
exports.sleep = sleep;
|
|
45
|
+
function uuidToBytes(uuid) {
|
|
46
|
+
if (uuid.length !== 36) {
|
|
47
|
+
return new Uint8Array(0);
|
|
48
|
+
}
|
|
49
|
+
return Uint8Array.from((0, lodash_1.chunk)(uuid.replace(/-/g, ''), 2).map(pair => parseInt(pair.join(''), 16)));
|
|
50
|
+
}
|
|
51
|
+
exports.uuidToBytes = uuidToBytes;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signalapp/ringrtc",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.25.0",
|
|
4
4
|
"description": "Signal Messenger voice and video calling library.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "tsc",
|
|
13
13
|
"clean": "rimraf dist",
|
|
14
|
-
"test": "electron-mocha --recursive dist/test",
|
|
14
|
+
"test": "electron-mocha --recursive dist/test --timeout 10000",
|
|
15
15
|
"eslint": "eslint --cache .",
|
|
16
16
|
"lint": "yarn format --list-different && yarn eslint",
|
|
17
17
|
"format": "prettier --write \"*.{css,js,json,md,scss,ts,tsx}\" \"./**/*.{css,js,json,md,scss,ts,tsx}\"",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"config": {
|
|
22
22
|
"prebuildUrl": "https://build-artifacts.signal.org/libraries/ringrtc-desktop-build-v${npm_package_version}.tar.gz",
|
|
23
|
-
"prebuildChecksum": "
|
|
23
|
+
"prebuildChecksum": "99767cde606a663ef881deaa1d3dec8976e2c52981d808c5c95397e773810f22"
|
|
24
24
|
},
|
|
25
25
|
"author": "",
|
|
26
26
|
"license": "AGPL-3.0-only",
|
|
@@ -31,10 +31,12 @@
|
|
|
31
31
|
"@types/chai": "4.2.18",
|
|
32
32
|
"@types/chai-as-promised": "^7.1.3",
|
|
33
33
|
"@types/dom-mediacapture-transform": "0.1.2",
|
|
34
|
+
"@types/long": "4.0.1",
|
|
34
35
|
"@types/mocha": "5.2.7",
|
|
35
36
|
"@types/node": "14.14.37",
|
|
36
37
|
"@types/offscreencanvas": "^2019.6.4",
|
|
37
38
|
"@types/react": "16.8.5",
|
|
39
|
+
"@types/sinon-chai": "^3.2.9",
|
|
38
40
|
"chai": "4.3.5",
|
|
39
41
|
"chai-as-promised": "^7.1.1",
|
|
40
42
|
"electron": "15.3.2",
|
|
@@ -46,9 +48,12 @@
|
|
|
46
48
|
"eslint-plugin-mocha": "9.0.0",
|
|
47
49
|
"eslint-plugin-more": "1.0.5",
|
|
48
50
|
"eslint-plugin-react": "7.28.0",
|
|
51
|
+
"long": "4.0.0",
|
|
49
52
|
"mocha": "9.2.0",
|
|
50
53
|
"prettier": "^2.5.1",
|
|
51
54
|
"rimraf": "3.0.2",
|
|
55
|
+
"sinon": "^15.0.1",
|
|
56
|
+
"sinon-chai": "^3.7.0",
|
|
52
57
|
"typescript": "4.5.2",
|
|
53
58
|
"yarn-audit-fix": "^9.2.2"
|
|
54
59
|
}
|