diff --git a/JitsiMeetJS.ts b/JitsiMeetJS.ts index fea313ce79..e2a05ffd08 100644 --- a/JitsiMeetJS.ts +++ b/JitsiMeetJS.ts @@ -35,6 +35,7 @@ import * as E2ePingEvents from './service/e2eping/E2ePingEvents'; import { createGetUserMediaEvent } from './service/statistics/AnalyticsEvents'; import * as RTCStatsEvents from './modules/RTCStats/RTCStatsEvents'; import { VideoType } from './service/RTC/VideoType'; +import runPreCallTest, { IceServer, PreCallResult } from './modules/statistics/PreCallTest'; const logger = Logger.getLogger(__filename); @@ -477,6 +478,16 @@ export default { NetworkInfo.updateNetworkInfo({ isOnline }); }, + /** + * Run a pre-call test to check the network conditions. + * + * @param {IceServer} iceServers - The ICE servers to use for the test, + * @returns {Promise} - A Promise that resolves with the test results or rejects with an error message. + */ + runPreCallTest(iceServers) { + return runPreCallTest(iceServers); + }, + /** * Represents a hub/namespace for utility functionality which may be of * interest to lib-jitsi-meet clients. diff --git a/modules/statistics/PreCallTest.ts b/modules/statistics/PreCallTest.ts new file mode 100644 index 0000000000..b68310b497 --- /dev/null +++ b/modules/statistics/PreCallTest.ts @@ -0,0 +1,48 @@ +import PreCallTest from 'vo_precalltest/src/main.js'; + + +export interface PreCallResult { + throughput: number; // Maximum bandwidth reached in kbps (kilo bits per second). + fractionalLoss: number; // Packet loss percentage over all the test traffic. + rtt: number; // Round trip time in milliseconds. + jitter: number; + mediaConnectivity: boolean; // Whether the data channel was able to send data or not. +} + +// Same interface as a PeerConnection configuration object. +export interface IceServer { + urls: Array | string; + username?: string; + credential?: string; +} + +let preCallTest: any = null + +/** + * Run a pre-call test to check the network conditions. It uses a TURN server to establish + * a connection between two PeerConnections using the server as a relay. Afterwards it sends + * some test traffic through a data channel to measure the network conditions, these are + * recorded and returned through a Promise. + * + * @param {Array} - The ICE servers to use for the test, these are passes to the PeerConnection constructor. + * @returns {Promise} - A Promise that resolves with the test results or rejects with an error message. + */ +export default async function runPreCallTest(iceServers: Array): Promise { + // On initialization, the PreCallTest object simply does some checks and some browsers verifications, + // these seem to be reusable, so we'll keep the object around. + preCallTest || (preCallTest = new PreCallTest()) + + return new Promise((resolve, reject) => { + // It's not explicitly stated in the code, but if message is not null, something went wrong, + // so we'll treat it as an error. + preCallTest.start(iceServers, (result, message) => { + if (message) { + reject(message); + + return; + } + + resolve(result); + }); + }); +}