@stream-io/video-client 0.0.1-alpha.137 → 0.0.1-alpha.139
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/CHANGELOG.md +13 -0
- package/dist/index.browser.es.js +53 -149
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +53 -149
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +53 -149
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +3 -9
- package/dist/src/StreamSfuClient.d.ts +2 -1
- package/dist/src/gen/coordinator/index.d.ts +280 -85
- package/dist/src/rtc/flows/join.d.ts +11 -3
- package/dist/src/types.d.ts +5 -1
- package/package.json +2 -2
- package/src/Call.ts +10 -22
- package/src/StreamSfuClient.ts +7 -37
- package/src/gen/coordinator/index.ts +280 -80
- package/src/rtc/__tests__/publisher.test.ts +1 -0
- package/src/rtc/flows/join.ts +61 -64
- package/src/types.ts +6 -0
- package/dist/src/rtc/flows/__tests__/latency.test.d.ts +0 -1
- package/dist/src/rtc/flows/latency.d.ts +0 -26
- package/src/rtc/flows/__tests__/latency.test.ts +0 -46
- package/src/rtc/flows/latency.ts +0 -91
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
## [0.0.1-alpha.139](https://github.com/GetStream/stream-video-js/compare/client0.0.1-alpha.138...client0.0.1-alpha.139) (2023-05-15)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* faster join flow ([#499](https://github.com/GetStream/stream-video-js/issues/499)) ([898341b](https://github.com/GetStream/stream-video-js/commit/898341b26495412acea7d9e08c0c8f9b0b54e3b3))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [0.0.1-alpha.138](https://github.com/GetStream/stream-video-js/compare/client0.0.1-alpha.137...client0.0.1-alpha.138) (2023-05-15)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
5
18
|
## [0.0.1-alpha.137](https://github.com/GetStream/stream-video-js/compare/client0.0.1-alpha.136...client0.0.1-alpha.137) (2023-05-12)
|
|
6
19
|
|
|
7
20
|
|
package/dist/index.browser.es.js
CHANGED
|
@@ -6003,30 +6003,6 @@ function removeConnectionEventListeners(cb) {
|
|
|
6003
6003
|
}
|
|
6004
6004
|
}
|
|
6005
6005
|
|
|
6006
|
-
const hostnameFromUrl = (url) => {
|
|
6007
|
-
try {
|
|
6008
|
-
const u = new URL(url);
|
|
6009
|
-
return {
|
|
6010
|
-
hostname: u.hostname,
|
|
6011
|
-
port: u.port,
|
|
6012
|
-
};
|
|
6013
|
-
}
|
|
6014
|
-
catch (e) {
|
|
6015
|
-
console.warn(`Invalid URL. Can't extract hostname from it.`, e);
|
|
6016
|
-
return {
|
|
6017
|
-
hostname: url,
|
|
6018
|
-
port: 3031,
|
|
6019
|
-
};
|
|
6020
|
-
}
|
|
6021
|
-
};
|
|
6022
|
-
const toURL = (url) => {
|
|
6023
|
-
try {
|
|
6024
|
-
return new URL(url);
|
|
6025
|
-
}
|
|
6026
|
-
catch (e) {
|
|
6027
|
-
return null;
|
|
6028
|
-
}
|
|
6029
|
-
};
|
|
6030
6006
|
/**
|
|
6031
6007
|
* The client used for exchanging information with the SFU.
|
|
6032
6008
|
*/
|
|
@@ -6036,9 +6012,10 @@ class StreamSfuClient {
|
|
|
6036
6012
|
*
|
|
6037
6013
|
* @param dispatcher the event dispatcher to use.
|
|
6038
6014
|
* @param url the URL of the SFU.
|
|
6015
|
+
* @param wsEndpoint the WebSocket endpoint of the SFU.
|
|
6039
6016
|
* @param token the JWT token to use for authentication.
|
|
6040
6017
|
*/
|
|
6041
|
-
constructor(dispatcher, url, token) {
|
|
6018
|
+
constructor(dispatcher, url, wsEndpoint, token) {
|
|
6042
6019
|
/**
|
|
6043
6020
|
* A buffer for ICE Candidates that are received before
|
|
6044
6021
|
* the PeerConnections are ready to handle them.
|
|
@@ -6133,17 +6110,6 @@ class StreamSfuClient {
|
|
|
6133
6110
|
}),
|
|
6134
6111
|
],
|
|
6135
6112
|
});
|
|
6136
|
-
// FIXME: OL: this should come from the coordinator API
|
|
6137
|
-
const { hostname, port } = hostnameFromUrl(url);
|
|
6138
|
-
let wsEndpoint = `ws://${hostname}:${port}/ws`;
|
|
6139
|
-
if (!['localhost', '127.0.0.1'].includes(hostname)) {
|
|
6140
|
-
const sfuUrl = toURL(url);
|
|
6141
|
-
if (sfuUrl) {
|
|
6142
|
-
sfuUrl.protocol = 'wss:';
|
|
6143
|
-
sfuUrl.pathname = '/ws';
|
|
6144
|
-
wsEndpoint = sfuUrl.toString();
|
|
6145
|
-
}
|
|
6146
|
-
}
|
|
6147
6113
|
// Special handling for the ICETrickle kind of events.
|
|
6148
6114
|
// These events might be triggered by the SFU before the initial RTC
|
|
6149
6115
|
// connection is established. In that case, those events (ICE candidates)
|
|
@@ -7373,99 +7339,19 @@ const registerRingingCallEventHandlers = (call) => {
|
|
|
7373
7339
|
};
|
|
7374
7340
|
};
|
|
7375
7341
|
|
|
7376
|
-
const toSeconds = (ms) => ms / 1000;
|
|
7377
7342
|
/**
|
|
7378
|
-
*
|
|
7343
|
+
* Collects all necessary information to join a call, talks to the coordinator
|
|
7344
|
+
* and returns the necessary information to join the call.
|
|
7379
7345
|
*
|
|
7380
|
-
* @param
|
|
7381
|
-
* @param
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
const controller = new AbortController();
|
|
7386
|
-
const abortTimeout = setTimeout(() => {
|
|
7387
|
-
controller.abort();
|
|
7388
|
-
}, timeoutAfterMs);
|
|
7389
|
-
try {
|
|
7390
|
-
const src = new URL(endpoint);
|
|
7391
|
-
src.searchParams.set('r', `js_${Math.random() * 10000000}`);
|
|
7392
|
-
yield fetch(src.toString(), {
|
|
7393
|
-
signal: controller.signal,
|
|
7394
|
-
});
|
|
7395
|
-
const latency = Date.now() - start;
|
|
7396
|
-
return toSeconds(latency);
|
|
7397
|
-
}
|
|
7398
|
-
catch (e) {
|
|
7399
|
-
console.debug(`failed to measure latency to ${endpoint}`, e);
|
|
7400
|
-
return -1; // indicate error in measurement
|
|
7401
|
-
}
|
|
7402
|
-
finally {
|
|
7403
|
-
// clear timeout in case fetch completes before timeout
|
|
7404
|
-
clearTimeout(abortTimeout);
|
|
7405
|
-
}
|
|
7406
|
-
});
|
|
7407
|
-
/**
|
|
7408
|
-
* Measures the latency of the current client to the given edges.
|
|
7409
|
-
*
|
|
7410
|
-
* All measurements run in parallel,
|
|
7411
|
-
* and the whole process is limited by the given timeout.
|
|
7412
|
-
*
|
|
7413
|
-
* @param edges the edges to measure latency to.
|
|
7414
|
-
* @param attempts the number of attempts to measure latency.
|
|
7415
|
-
* @param attemptTimeoutAfterMs the request cancellation period per measurement.
|
|
7416
|
-
* @param measureTimeoutAfterMs the hard-limit for the whole measure process.
|
|
7417
|
-
*/
|
|
7418
|
-
const measureLatencyToEdges = (edges, { attempts = 3, attemptTimeoutAfterMs = 1000, measureTimeoutAfterMs = 1200, } = {}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
7419
|
-
const latencyByEdge = {};
|
|
7420
|
-
const measurements = [];
|
|
7421
|
-
const start = Date.now();
|
|
7422
|
-
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
7423
|
-
for (const edge of edges) {
|
|
7424
|
-
measurements.push(measureResourceLoadLatencyTo(edge.latency_url, attemptTimeoutAfterMs).then((latency) => {
|
|
7425
|
-
var _a;
|
|
7426
|
-
var _b;
|
|
7427
|
-
((_a = latencyByEdge[_b = edge.name]) !== null && _a !== void 0 ? _a : (latencyByEdge[_b] = [])).push(latency);
|
|
7428
|
-
}));
|
|
7429
|
-
}
|
|
7430
|
-
}
|
|
7431
|
-
yield Promise.race([
|
|
7432
|
-
Promise.all(measurements),
|
|
7433
|
-
new Promise((resolve) => setTimeout(resolve, measureTimeoutAfterMs)),
|
|
7434
|
-
]);
|
|
7435
|
-
console.log(`finished measuring latency to ${edges.length} edges in ${Date.now() - start}ms.`);
|
|
7436
|
-
return latencyByEdge;
|
|
7437
|
-
});
|
|
7438
|
-
|
|
7439
|
-
const getCascadingModeParams = () => {
|
|
7440
|
-
var _a;
|
|
7441
|
-
if (typeof window === 'undefined')
|
|
7442
|
-
return null;
|
|
7443
|
-
const params = new URLSearchParams((_a = window.location) === null || _a === void 0 ? void 0 : _a.search);
|
|
7444
|
-
const cascadingEnabled = params.get('cascading') !== null;
|
|
7445
|
-
if (cascadingEnabled) {
|
|
7446
|
-
const rawParams = {};
|
|
7447
|
-
params.forEach((value, key) => {
|
|
7448
|
-
rawParams[key] = value;
|
|
7449
|
-
});
|
|
7450
|
-
return rawParams;
|
|
7451
|
-
}
|
|
7452
|
-
return null;
|
|
7453
|
-
};
|
|
7454
|
-
const watch = (httpClient, type, id, data) => __awaiter(void 0, void 0, void 0, function* () {
|
|
7455
|
-
yield httpClient.connectionIdPromise;
|
|
7456
|
-
// FIXME OL: remove this once cascading is enabled by default
|
|
7457
|
-
const cascadingModeParams = getCascadingModeParams();
|
|
7458
|
-
if (cascadingModeParams) {
|
|
7459
|
-
return httpClient.doAxiosRequest('post', `/call/${type}/${id}/join`, data, {
|
|
7460
|
-
params: Object.assign({}, cascadingModeParams),
|
|
7461
|
-
});
|
|
7462
|
-
}
|
|
7463
|
-
return httpClient.post(`/call/${type}/${id}/join`, data);
|
|
7464
|
-
});
|
|
7346
|
+
* @param httpClient the http client to use.
|
|
7347
|
+
* @param type the type of the call.
|
|
7348
|
+
* @param id the id of the call.
|
|
7349
|
+
* @param data the data for the call.
|
|
7350
|
+
*/
|
|
7465
7351
|
const join = (httpClient, type, id, data) => __awaiter(void 0, void 0, void 0, function* () {
|
|
7466
|
-
|
|
7467
|
-
const
|
|
7468
|
-
const { credentials } =
|
|
7352
|
+
yield httpClient.connectionIdPromise;
|
|
7353
|
+
const joinCallResponse = yield doJoin(httpClient, type, id, data);
|
|
7354
|
+
const { call, credentials, members } = joinCallResponse;
|
|
7469
7355
|
return {
|
|
7470
7356
|
connectionConfig: toRtcConfiguration(credentials.ice_servers),
|
|
7471
7357
|
sfuServer: credentials.server,
|
|
@@ -7474,18 +7360,31 @@ const join = (httpClient, type, id, data) => __awaiter(void 0, void 0, void 0, f
|
|
|
7474
7360
|
members,
|
|
7475
7361
|
};
|
|
7476
7362
|
});
|
|
7477
|
-
const
|
|
7478
|
-
const
|
|
7479
|
-
|
|
7480
|
-
};
|
|
7363
|
+
const doJoin = (httpClient, type, id, data) => __awaiter(void 0, void 0, void 0, function* () {
|
|
7364
|
+
const location = yield getLocationHint();
|
|
7365
|
+
const request = Object.assign(Object.assign({}, data), { location });
|
|
7481
7366
|
// FIXME OL: remove this once cascading is enabled by default
|
|
7482
7367
|
const cascadingModeParams = getCascadingModeParams();
|
|
7483
7368
|
if (cascadingModeParams) {
|
|
7484
|
-
return httpClient.doAxiosRequest('post', `/call/${type}/${id}/
|
|
7369
|
+
return httpClient.doAxiosRequest('post', `/call/${type}/${id}/join`, request, {
|
|
7485
7370
|
params: Object.assign({}, cascadingModeParams),
|
|
7486
7371
|
});
|
|
7487
7372
|
}
|
|
7488
|
-
return httpClient.post(`/call/${type}/${id}/
|
|
7373
|
+
return httpClient.post(`/call/${type}/${id}/join`, request);
|
|
7374
|
+
});
|
|
7375
|
+
const getLocationHint = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
7376
|
+
const hintURL = `https://hint.stream-io-video.com/`;
|
|
7377
|
+
try {
|
|
7378
|
+
const response = yield fetch(hintURL, {
|
|
7379
|
+
method: 'HEAD',
|
|
7380
|
+
});
|
|
7381
|
+
const awsPop = response.headers.get('x-amz-cf-pop') || 'ERR';
|
|
7382
|
+
return awsPop.substring(0, 3); // AMS1-P2 -> AMS
|
|
7383
|
+
}
|
|
7384
|
+
catch (e) {
|
|
7385
|
+
console.error(`Failed to get location hint from ${hintURL}`, e);
|
|
7386
|
+
return 'ERR';
|
|
7387
|
+
}
|
|
7489
7388
|
});
|
|
7490
7389
|
const toRtcConfiguration = (config) => {
|
|
7491
7390
|
if (!config || config.length === 0)
|
|
@@ -7499,6 +7398,21 @@ const toRtcConfiguration = (config) => {
|
|
|
7499
7398
|
};
|
|
7500
7399
|
return rtcConfig;
|
|
7501
7400
|
};
|
|
7401
|
+
const getCascadingModeParams = () => {
|
|
7402
|
+
var _a;
|
|
7403
|
+
if (typeof window === 'undefined')
|
|
7404
|
+
return null;
|
|
7405
|
+
const params = new URLSearchParams((_a = window.location) === null || _a === void 0 ? void 0 : _a.search);
|
|
7406
|
+
const cascadingEnabled = params.get('cascading') !== null;
|
|
7407
|
+
if (cascadingEnabled) {
|
|
7408
|
+
const rawParams = {};
|
|
7409
|
+
params.forEach((value, key) => {
|
|
7410
|
+
rawParams[key] = value;
|
|
7411
|
+
});
|
|
7412
|
+
return rawParams;
|
|
7413
|
+
}
|
|
7414
|
+
return null;
|
|
7415
|
+
};
|
|
7502
7416
|
|
|
7503
7417
|
/**
|
|
7504
7418
|
* Creates a new StatsReporter instance that collects metrics about the ongoing call and reports them to the state store
|
|
@@ -8058,6 +7972,8 @@ class Call {
|
|
|
8058
7972
|
const response = yield this.streamClient.get(this.streamClientBasePath);
|
|
8059
7973
|
this.state.setMetadata(response.call);
|
|
8060
7974
|
this.state.setMembers(response.members);
|
|
7975
|
+
this.watching = true;
|
|
7976
|
+
this.clientStore.registerCall(this);
|
|
8061
7977
|
return response;
|
|
8062
7978
|
});
|
|
8063
7979
|
/**
|
|
@@ -8072,21 +7988,6 @@ class Call {
|
|
|
8072
7988
|
}
|
|
8073
7989
|
this.state.setMetadata(response.call);
|
|
8074
7990
|
this.state.setMembers(response.members);
|
|
8075
|
-
this.clientStore.registerCall(this);
|
|
8076
|
-
return response;
|
|
8077
|
-
});
|
|
8078
|
-
/**
|
|
8079
|
-
* Will start to watch for call related WebSocket events, but it won't join the call. If you watch a call you'll be notified about WebSocket events, but you won't be able to publish your audio and video, and you won't be able to see and hear others. You won't show up in the list of joined participants.
|
|
8080
|
-
*
|
|
8081
|
-
* @param data
|
|
8082
|
-
*/
|
|
8083
|
-
this.watch = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
8084
|
-
const response = yield watch(this.streamClient, this.type, this.id, data);
|
|
8085
|
-
this.state.setMetadata(response.call);
|
|
8086
|
-
this.state.setMembers(response.members);
|
|
8087
|
-
if ((data === null || data === void 0 ? void 0 : data.ring) && !this.ringing) {
|
|
8088
|
-
this.ringingSubject.next(true);
|
|
8089
|
-
}
|
|
8090
7991
|
this.watching = true;
|
|
8091
7992
|
this.clientStore.registerCall(this);
|
|
8092
7993
|
return response;
|
|
@@ -8117,14 +8018,17 @@ class Call {
|
|
|
8117
8018
|
this.clientStore.registerCall(this);
|
|
8118
8019
|
// FIXME OL: remove once cascading is implemented
|
|
8119
8020
|
let sfuUrl = call.sfuServer.url;
|
|
8021
|
+
let sfuWsUrl = call.sfuServer.ws_endpoint;
|
|
8120
8022
|
if (typeof window !== 'undefined' &&
|
|
8121
8023
|
window.location &&
|
|
8122
8024
|
window.location.search) {
|
|
8123
8025
|
const params = new URLSearchParams(window.location.search);
|
|
8124
8026
|
const sfuUrlParam = params.get('sfuUrl');
|
|
8125
8027
|
sfuUrl = sfuUrlParam || call.sfuServer.url;
|
|
8028
|
+
const sfuWsUrlParam = params.get('sfuWsUrl');
|
|
8029
|
+
sfuWsUrl = sfuWsUrlParam || call.sfuServer.ws_endpoint;
|
|
8126
8030
|
}
|
|
8127
|
-
const sfuClient = (this.sfuClient = new StreamSfuClient(this.dispatcher, sfuUrl, call.token));
|
|
8031
|
+
const sfuClient = (this.sfuClient = new StreamSfuClient(this.dispatcher, sfuUrl, sfuWsUrl, call.token));
|
|
8128
8032
|
/**
|
|
8129
8033
|
* A closure which hides away the re-connection logic.
|
|
8130
8034
|
*/
|
|
@@ -10567,7 +10471,7 @@ class StreamClient {
|
|
|
10567
10471
|
}
|
|
10568
10472
|
getUserAgent() {
|
|
10569
10473
|
return (this.userAgent ||
|
|
10570
|
-
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.1-alpha.
|
|
10474
|
+
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.1-alpha.138"}`);
|
|
10571
10475
|
}
|
|
10572
10476
|
setUserAgent(userAgent) {
|
|
10573
10477
|
this.userAgent = userAgent;
|