@twilio/voice-sdk
Version:
Twilio's JavaScript Voice SDK
168 lines (136 loc) • 5.39 kB
text/typescript
import * as assert from 'assert';
import Call from '../../lib/twilio/call';
import Device from '../../lib/twilio/device';
import { generateAccessToken } from '../../tests/lib/token';
import { expectEvent, isFirefox } from '../../tests/lib/util';
const CONNECTION_DELAY_THRESHOLD = 1000;
const SUITE_TIMEOUT = 20000;
const MAX_TIMEOUT = 300000;
const maybeSkip = isFirefox() ? describe.skip : describe;
maybeSkip('ICE Nomination', function() {
Cypress.config('defaultCommandTimeout', MAX_TIMEOUT);
this.timeout(MAX_TIMEOUT);
let device1: Device;
let device2: Device;
let identity1: string;
let identity2: string;
let device1Options: Device.Options = {};
let device2Options: Device.Options = {};
let highDelayEdge: string;
let lowDelayEdge: string;
const setupDevices = () => {
identity1 = 'id1-' + Date.now();
identity2 = 'id2-' + Date.now();
const token1 = generateAccessToken(identity1);
const token2 = generateAccessToken(identity2);
device1 = new Device(token1, device1Options);
device2 = new Device(token2, device2Options);
const devicePromises = Promise.all([
expectEvent(Device.EventName.Registered, device1),
expectEvent(Device.EventName.Registered, device2),
]);
device1.register();
device2.register();
return devicePromises;
};
const destroyDevices = () => {
if (device1) {
device1.disconnectAll();
device1.destroy();
}
if (device2) {
device2.disconnectAll();
device2.destroy();
}
};
const getCallDuration = (direction: Call.CallDirection): Promise<number> => new Promise(async (resolve) => {
let start: number;
let device = device1;
if (direction === Call.CallDirection.Incoming) {
device = device2;
}
// We don't currently expose ice connection state changes.
// Let's hook to makeCall and subscribe to events
const makeCall = device['_makeCall'].bind(device);
(device['_makeCall'] as any) = async (...params: any) => {
const call = await makeCall(...params);
call['_mediaHandler'].oniceconnectionstatechange = (state: string) => {
if (state === 'checking') {
start = Date.now();
}
};
call['_mediaHandler'].onpcconnectionstatechange = (state: string) => {
if (state === 'connected') {
const duration = Date.now() - start;
resolve(duration);
}
};
return call;
};
await device1.connect({ params: { To: identity2 } });
const call2 = await expectEvent('incoming', device2);
call2.accept();
});
before(async () => {
console.log('Measuring delays for each region...');
const durations: number[] = [];
const edges = ['sydney', 'sao-paulo', 'dublin', 'tokyo', 'singapore', 'ashburn'];
for (let i = 0; i < edges.length; i++) {
const edge = edges[i];
device2Options.edge = edge;
await setupDevices();
const duration = await getCallDuration(Call.CallDirection.Incoming);
durations.push(duration);
destroyDevices();
console.log(`${edge}: ${duration}`);
}
delete device2Options.edge;
lowDelayEdge = edges[durations.indexOf(Math.min(...durations))];
highDelayEdge = edges[durations.indexOf(Math.max(...durations))];
console.log(JSON.stringify({ lowDelayEdge, highDelayEdge }, null, 2));
});
[Call.CallDirection.Incoming, Call.CallDirection.Outgoing].forEach(direction => {
describe(`for ${direction} calls`, function() {
this.timeout(SUITE_TIMEOUT);
let deviceOptions: Device.Options;
beforeEach(() => {
deviceOptions = direction === Call.CallDirection.Outgoing ? device1Options : device2Options;
});
afterEach(() => {
device1Options = {};
device2Options = {};
destroyDevices();
});
it('should not have a significant dtls handshake delay when using low-delay region and aggressive nomination is false', async () => {
deviceOptions.edge = lowDelayEdge;
await setupDevices();
await getCallDuration(direction).then(duration => {
assert(duration < CONNECTION_DELAY_THRESHOLD);
});
});
it('should not have a significant dtls handshake delay when using low-delay region and aggressive nomination is true', async () => {
deviceOptions.edge = lowDelayEdge;
deviceOptions.forceAggressiveIceNomination = true;
await setupDevices();
await getCallDuration(direction).then(duration => {
assert(duration < CONNECTION_DELAY_THRESHOLD);
});
});
it('should have a significant dtls handshake delay when using high-delay region and aggressive nomination is false', async () => {
deviceOptions.edge = highDelayEdge;
await setupDevices();
await getCallDuration(direction).then(duration => {
assert(duration > CONNECTION_DELAY_THRESHOLD);
});
});
it('should not have a significant dtls handshake delay when using high-delay region and aggressive nomination is true', async () => {
deviceOptions.edge = highDelayEdge;
deviceOptions.forceAggressiveIceNomination = true;
await setupDevices();
await getCallDuration(direction).then(duration => {
assert(duration < CONNECTION_DELAY_THRESHOLD);
});
});
});
});
});