@stream-io/video-client 0.0.14 → 0.0.16
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 +14 -0
- package/dist/index.browser.es.js +227 -125
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +229 -124
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +227 -125
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +2 -1
- package/dist/src/StreamSfuClient.d.ts +1 -0
- package/dist/src/StreamVideoClient.d.ts +5 -1
- package/dist/src/coordinator/connection/types.d.ts +3 -2
- package/dist/src/coordinator/connection/utils.d.ts +2 -1
- package/dist/src/logger.d.ts +4 -0
- package/dist/src/rtc/Dispatcher.d.ts +2 -0
- package/dist/src/rtc/IceTrickleBuffer.d.ts +2 -0
- package/dist/src/rtc/publisher.d.ts +1 -0
- package/dist/src/store/CallState.d.ts +2 -0
- package/index.ts +1 -0
- package/package.json +1 -1
- package/src/Call.ts +61 -40
- package/src/StreamSfuClient.ts +70 -29
- package/src/StreamVideoClient.ts +46 -3
- package/src/coordinator/connection/client.ts +22 -29
- package/src/coordinator/connection/connection.ts +2 -3
- package/src/coordinator/connection/connection_fallback.ts +0 -1
- package/src/coordinator/connection/types.ts +4 -2
- package/src/coordinator/connection/utils.ts +5 -2
- package/src/devices/devices.ts +10 -3
- package/src/events/call.ts +11 -4
- package/src/events/sessions.ts +7 -2
- package/src/logger.ts +45 -0
- package/src/rtc/Dispatcher.ts +14 -4
- package/src/rtc/IceTrickleBuffer.ts +8 -1
- package/src/rtc/codecs.ts +7 -5
- package/src/rtc/flows/join.ts +4 -1
- package/src/rtc/publisher.ts +31 -12
- package/src/rtc/signal.ts +8 -7
- package/src/rtc/subscriber.ts +16 -10
- package/src/stats/state-store-stats-reporter.ts +9 -3
- package/src/store/CallState.ts +6 -1
- package/src/types.ts +1 -0
package/dist/index.browser.es.js
CHANGED
|
@@ -5273,13 +5273,41 @@ const toggleDtx = (sdp, enable) => {
|
|
|
5273
5273
|
return sdp;
|
|
5274
5274
|
};
|
|
5275
5275
|
|
|
5276
|
+
let logger;
|
|
5277
|
+
const logToConsole = (logLevel, message, extraData, tags) => {
|
|
5278
|
+
let logMethod;
|
|
5279
|
+
if (logLevel === 'error') {
|
|
5280
|
+
logMethod = console.error;
|
|
5281
|
+
}
|
|
5282
|
+
else if (logLevel === 'warn') {
|
|
5283
|
+
logMethod = console.warn;
|
|
5284
|
+
}
|
|
5285
|
+
else {
|
|
5286
|
+
logMethod = console.log;
|
|
5287
|
+
}
|
|
5288
|
+
logMethod(logLevel, `${tags === null || tags === void 0 ? void 0 : tags.join(':')} - ${message}`, extraData ? extraData : '');
|
|
5289
|
+
};
|
|
5290
|
+
const setLogger = (l) => {
|
|
5291
|
+
logger = l;
|
|
5292
|
+
};
|
|
5293
|
+
const getLogger = (withTags) => {
|
|
5294
|
+
const loggerMethod = logger || (() => { });
|
|
5295
|
+
const result = (logLevel, messeage, extraData, tags) => {
|
|
5296
|
+
loggerMethod(logLevel, messeage, extraData, [
|
|
5297
|
+
...(tags || []),
|
|
5298
|
+
...(withTags || []),
|
|
5299
|
+
]);
|
|
5300
|
+
};
|
|
5301
|
+
return result;
|
|
5302
|
+
};
|
|
5303
|
+
|
|
5276
5304
|
const getPreferredCodecs = (kind, preferredCodec, codecToRemove) => {
|
|
5305
|
+
const logger = getLogger(['codecs']);
|
|
5277
5306
|
if (!('getCapabilities' in RTCRtpSender)) {
|
|
5278
|
-
|
|
5307
|
+
logger === null || logger === void 0 ? void 0 : logger('warn', 'RTCRtpSender.getCapabilities is not supported');
|
|
5279
5308
|
return;
|
|
5280
5309
|
}
|
|
5281
5310
|
const cap = RTCRtpSender.getCapabilities(kind);
|
|
5282
|
-
console.log('s4e');
|
|
5283
5311
|
if (!cap)
|
|
5284
5312
|
return;
|
|
5285
5313
|
const matched = [];
|
|
@@ -5287,7 +5315,7 @@ const getPreferredCodecs = (kind, preferredCodec, codecToRemove) => {
|
|
|
5287
5315
|
const unmatched = [];
|
|
5288
5316
|
cap.codecs.forEach((c) => {
|
|
5289
5317
|
const codec = c.mimeType.toLowerCase();
|
|
5290
|
-
|
|
5318
|
+
logger === null || logger === void 0 ? void 0 : logger('debug', `Found supported codec: ${codec}`);
|
|
5291
5319
|
const shouldRemoveCodec = codecToRemove && codec === `${kind}/${codecToRemove}`;
|
|
5292
5320
|
if (shouldRemoveCodec)
|
|
5293
5321
|
return;
|
|
@@ -5307,10 +5335,11 @@ const getPreferredCodecs = (kind, preferredCodec, codecToRemove) => {
|
|
|
5307
5335
|
}
|
|
5308
5336
|
return;
|
|
5309
5337
|
}
|
|
5310
|
-
console.log('matched', matched);
|
|
5311
5338
|
matched.push(c);
|
|
5312
5339
|
});
|
|
5313
|
-
|
|
5340
|
+
const result = [...matched, ...partialMatched, ...unmatched];
|
|
5341
|
+
logger === null || logger === void 0 ? void 0 : logger('info', `Preffered codecs: `, result);
|
|
5342
|
+
return result;
|
|
5314
5343
|
};
|
|
5315
5344
|
const getGenericSdp = (direction, isRedEnabled, preferredVideoCodec) => __awaiter(void 0, void 0, void 0, function* () {
|
|
5316
5345
|
var _a;
|
|
@@ -5376,17 +5405,19 @@ class Dispatcher {
|
|
|
5376
5405
|
constructor() {
|
|
5377
5406
|
this.subscribers = {};
|
|
5378
5407
|
this.dispatch = (message) => {
|
|
5408
|
+
var _a, _b;
|
|
5379
5409
|
const eventKind = message.eventPayload.oneofKind;
|
|
5380
5410
|
if (eventKind) {
|
|
5381
|
-
|
|
5382
|
-
|
|
5411
|
+
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'info', `Dispatching ${eventKind}`);
|
|
5412
|
+
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.call(this, 'debug', `Event payload`, message.eventPayload[eventKind]);
|
|
5383
5413
|
const listeners = this.subscribers[eventKind];
|
|
5384
5414
|
listeners === null || listeners === void 0 ? void 0 : listeners.forEach((fn) => {
|
|
5415
|
+
var _a;
|
|
5385
5416
|
try {
|
|
5386
5417
|
fn(message);
|
|
5387
5418
|
}
|
|
5388
5419
|
catch (e) {
|
|
5389
|
-
|
|
5420
|
+
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'warn', 'Listener failed with error', e);
|
|
5390
5421
|
}
|
|
5391
5422
|
});
|
|
5392
5423
|
}
|
|
@@ -5410,6 +5441,7 @@ class Dispatcher {
|
|
|
5410
5441
|
this.subscribers = {};
|
|
5411
5442
|
}
|
|
5412
5443
|
};
|
|
5444
|
+
this.logger = getLogger(['sfu-client']);
|
|
5413
5445
|
}
|
|
5414
5446
|
}
|
|
5415
5447
|
|
|
@@ -5422,6 +5454,7 @@ class IceTrickleBuffer {
|
|
|
5422
5454
|
this.subscriberCandidates = new ReplaySubject();
|
|
5423
5455
|
this.publisherCandidates = new ReplaySubject();
|
|
5424
5456
|
this.push = (iceTrickle) => {
|
|
5457
|
+
var _a;
|
|
5425
5458
|
if (iceTrickle.peerType === PeerType.SUBSCRIBER) {
|
|
5426
5459
|
this.subscriberCandidates.next(iceTrickle);
|
|
5427
5460
|
}
|
|
@@ -5429,9 +5462,10 @@ class IceTrickleBuffer {
|
|
|
5429
5462
|
this.publisherCandidates.next(iceTrickle);
|
|
5430
5463
|
}
|
|
5431
5464
|
else {
|
|
5432
|
-
|
|
5465
|
+
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'warn', `ICETrickle, Unknown peer type`, iceTrickle);
|
|
5433
5466
|
}
|
|
5434
5467
|
};
|
|
5468
|
+
this.logger = getLogger(['sfu-client']);
|
|
5435
5469
|
}
|
|
5436
5470
|
}
|
|
5437
5471
|
|
|
@@ -5622,6 +5656,7 @@ class Publisher {
|
|
|
5622
5656
|
* @param opts
|
|
5623
5657
|
*/
|
|
5624
5658
|
this.publishStream = (mediaStream, track, trackType, opts = {}) => __awaiter(this, void 0, void 0, function* () {
|
|
5659
|
+
var _a;
|
|
5625
5660
|
let transceiver = this.publisher
|
|
5626
5661
|
.getTransceivers()
|
|
5627
5662
|
.find((t) => {
|
|
@@ -5635,7 +5670,8 @@ class Publisher {
|
|
|
5635
5670
|
* Once the track has ended, it will notify the SFU and update the state.
|
|
5636
5671
|
*/
|
|
5637
5672
|
const handleTrackEnded = () => __awaiter(this, void 0, void 0, function* () {
|
|
5638
|
-
|
|
5673
|
+
var _b;
|
|
5674
|
+
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.call(this, 'info', `Track ${TrackType[trackType]} has ended, notifying the SFU`);
|
|
5639
5675
|
yield this.notifyTrackMuteStateChanged(mediaStream, track, trackType, true);
|
|
5640
5676
|
// clean-up, this event listener needs to run only once.
|
|
5641
5677
|
track.removeEventListener('ended', handleTrackEnded);
|
|
@@ -5660,7 +5696,7 @@ class Publisher {
|
|
|
5660
5696
|
});
|
|
5661
5697
|
this.transceiverRegistry[trackType] = transceiver;
|
|
5662
5698
|
if ('setCodecPreferences' in transceiver && codecPreferences) {
|
|
5663
|
-
|
|
5699
|
+
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'info', `Setting ${TrackType[trackType]} codec preferences`, codecPreferences);
|
|
5664
5700
|
transceiver.setCodecPreferences(codecPreferences);
|
|
5665
5701
|
}
|
|
5666
5702
|
}
|
|
@@ -5744,9 +5780,9 @@ class Publisher {
|
|
|
5744
5780
|
this.publisher.close();
|
|
5745
5781
|
};
|
|
5746
5782
|
this.updateVideoPublishQuality = (enabledRids) => __awaiter(this, void 0, void 0, function* () {
|
|
5747
|
-
var
|
|
5748
|
-
|
|
5749
|
-
const videoSender = (
|
|
5783
|
+
var _c, _d, _e, _f;
|
|
5784
|
+
(_c = this.logger) === null || _c === void 0 ? void 0 : _c.call(this, 'info', 'Update publish quality, requested rids by SFU:', enabledRids);
|
|
5785
|
+
const videoSender = (_d = this.transceiverRegistry[TrackType.VIDEO]) === null || _d === void 0 ? void 0 : _d.sender;
|
|
5750
5786
|
if (!videoSender)
|
|
5751
5787
|
return;
|
|
5752
5788
|
const params = videoSender.getParameters();
|
|
@@ -5761,10 +5797,10 @@ class Publisher {
|
|
|
5761
5797
|
});
|
|
5762
5798
|
if (changed) {
|
|
5763
5799
|
if (params.encodings.length === 0) {
|
|
5764
|
-
|
|
5800
|
+
(_e = this.logger) === null || _e === void 0 ? void 0 : _e.call(this, 'warn', 'No suitable video encoding quality found');
|
|
5765
5801
|
}
|
|
5766
5802
|
yield videoSender.setParameters(params);
|
|
5767
|
-
|
|
5803
|
+
(_f = this.logger) === null || _f === void 0 ? void 0 : _f.call(this, 'info', `Update publish quality, enabled rids: ${params.encodings
|
|
5768
5804
|
.filter((e) => e.active)
|
|
5769
5805
|
.map((e) => e.rid)
|
|
5770
5806
|
.join(', ')}`);
|
|
@@ -5781,9 +5817,10 @@ class Publisher {
|
|
|
5781
5817
|
}
|
|
5782
5818
|
};
|
|
5783
5819
|
this.onIceCandidate = (e) => __awaiter(this, void 0, void 0, function* () {
|
|
5820
|
+
var _g;
|
|
5784
5821
|
const { candidate } = e;
|
|
5785
5822
|
if (!candidate) {
|
|
5786
|
-
|
|
5823
|
+
(_g = this.logger) === null || _g === void 0 ? void 0 : _g.call(this, 'warn', 'null ice candidate');
|
|
5787
5824
|
return;
|
|
5788
5825
|
}
|
|
5789
5826
|
yield this.sfuClient.iceTrickle({
|
|
@@ -5792,7 +5829,8 @@ class Publisher {
|
|
|
5792
5829
|
});
|
|
5793
5830
|
});
|
|
5794
5831
|
this.onNegotiationNeeded = () => __awaiter(this, void 0, void 0, function* () {
|
|
5795
|
-
|
|
5832
|
+
var _h, _j;
|
|
5833
|
+
(_h = this.logger) === null || _h === void 0 ? void 0 : _h.call(this, 'info', 'AAA onNegotiationNeeded');
|
|
5796
5834
|
const offer = yield this.publisher.createOffer();
|
|
5797
5835
|
let sdp = offer.sdp;
|
|
5798
5836
|
if (sdp) {
|
|
@@ -5855,28 +5893,38 @@ class Publisher {
|
|
|
5855
5893
|
});
|
|
5856
5894
|
}
|
|
5857
5895
|
catch (e) {
|
|
5858
|
-
|
|
5896
|
+
(_j = this.logger) === null || _j === void 0 ? void 0 : _j.call(this, 'error', `Publisher: setRemoteDescription error`, {
|
|
5897
|
+
sdp: response.sdp,
|
|
5898
|
+
error: e,
|
|
5899
|
+
});
|
|
5859
5900
|
}
|
|
5860
5901
|
this.sfuClient.iceTrickleBuffer.publisherCandidates.subscribe((candidate) => __awaiter(this, void 0, void 0, function* () {
|
|
5902
|
+
var _k;
|
|
5861
5903
|
try {
|
|
5862
5904
|
const iceCandidate = JSON.parse(candidate.iceCandidate);
|
|
5863
5905
|
yield this.publisher.addIceCandidate(iceCandidate);
|
|
5864
5906
|
}
|
|
5865
5907
|
catch (e) {
|
|
5866
|
-
|
|
5908
|
+
(_k = this.logger) === null || _k === void 0 ? void 0 : _k.call(this, 'error', `Publisher: ICE candidate error`, {
|
|
5909
|
+
error: e,
|
|
5910
|
+
candidate,
|
|
5911
|
+
});
|
|
5867
5912
|
}
|
|
5868
5913
|
}));
|
|
5869
5914
|
});
|
|
5870
5915
|
this.onIceCandidateError = (e) => {
|
|
5916
|
+
var _a;
|
|
5871
5917
|
const errorMessage = e instanceof RTCPeerConnectionIceErrorEvent &&
|
|
5872
5918
|
`${e.errorCode}: ${e.errorText}`;
|
|
5873
|
-
|
|
5919
|
+
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'error', `Publisher: ICE Candidate error`, errorMessage);
|
|
5874
5920
|
};
|
|
5875
5921
|
this.onIceConnectionStateChange = () => {
|
|
5876
|
-
|
|
5922
|
+
var _a;
|
|
5923
|
+
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'error', `Publisher: ICE Connection state changed`, this.publisher.iceConnectionState);
|
|
5877
5924
|
};
|
|
5878
5925
|
this.onIceGatheringStateChange = () => {
|
|
5879
|
-
|
|
5926
|
+
var _a;
|
|
5927
|
+
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'error', `Publisher: ICE Gathering State`, this.publisher.iceGatheringState);
|
|
5880
5928
|
};
|
|
5881
5929
|
this.ridToVideoQuality = (rid) => {
|
|
5882
5930
|
return rid === 'q'
|
|
@@ -5909,12 +5957,13 @@ class Publisher {
|
|
|
5909
5957
|
}
|
|
5910
5958
|
|
|
5911
5959
|
const createSubscriber = ({ sfuClient, dispatcher, connectionConfig, onTrack, }) => {
|
|
5960
|
+
const logger = getLogger(['sfu-client']);
|
|
5912
5961
|
const subscriber = new RTCPeerConnection(connectionConfig);
|
|
5913
5962
|
attachDebugEventListeners(subscriber);
|
|
5914
5963
|
subscriber.addEventListener('icecandidate', (e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
5915
5964
|
const { candidate } = e;
|
|
5916
5965
|
if (!candidate) {
|
|
5917
|
-
|
|
5966
|
+
logger === null || logger === void 0 ? void 0 : logger('warn', 'null ice candidate');
|
|
5918
5967
|
return;
|
|
5919
5968
|
}
|
|
5920
5969
|
yield sfuClient.iceTrickle({
|
|
@@ -5930,7 +5979,7 @@ const createSubscriber = ({ sfuClient, dispatcher, connectionConfig, onTrack, })
|
|
|
5930
5979
|
if (message.eventPayload.oneofKind !== 'subscriberOffer')
|
|
5931
5980
|
return;
|
|
5932
5981
|
const { subscriberOffer } = message.eventPayload;
|
|
5933
|
-
|
|
5982
|
+
logger === null || logger === void 0 ? void 0 : logger('info', 'Received subscriberOffer', subscriberOffer);
|
|
5934
5983
|
yield subscriber.setRemoteDescription({
|
|
5935
5984
|
type: 'offer',
|
|
5936
5985
|
sdp: subscriberOffer.sdp,
|
|
@@ -5941,7 +5990,10 @@ const createSubscriber = ({ sfuClient, dispatcher, connectionConfig, onTrack, })
|
|
|
5941
5990
|
yield subscriber.addIceCandidate(iceCandidate);
|
|
5942
5991
|
}
|
|
5943
5992
|
catch (e) {
|
|
5944
|
-
|
|
5993
|
+
logger === null || logger === void 0 ? void 0 : logger('error', `Subscriber: ICE candidate error`, {
|
|
5994
|
+
error: e,
|
|
5995
|
+
candidate,
|
|
5996
|
+
});
|
|
5945
5997
|
}
|
|
5946
5998
|
}));
|
|
5947
5999
|
// apply ice candidates
|
|
@@ -5964,31 +6016,33 @@ const createSubscriber = ({ sfuClient, dispatcher, connectionConfig, onTrack, })
|
|
|
5964
6016
|
return subscriber;
|
|
5965
6017
|
};
|
|
5966
6018
|
const attachDebugEventListeners = (subscriber) => {
|
|
6019
|
+
const logger = getLogger(['sfu-client']);
|
|
5967
6020
|
subscriber.addEventListener('icecandidateerror', (e) => {
|
|
5968
6021
|
const errorMessage = e instanceof RTCPeerConnectionIceErrorEvent &&
|
|
5969
6022
|
`${e.errorCode}: ${e.errorText}`;
|
|
5970
|
-
|
|
6023
|
+
logger === null || logger === void 0 ? void 0 : logger('error', `Subscriber: ICE Candidate error: ${errorMessage}`);
|
|
5971
6024
|
});
|
|
5972
6025
|
subscriber.addEventListener('iceconnectionstatechange', () => {
|
|
5973
|
-
|
|
6026
|
+
logger === null || logger === void 0 ? void 0 : logger('info', `Subscriber: ICE Connection state changed: ${subscriber.iceConnectionState}`);
|
|
5974
6027
|
});
|
|
5975
6028
|
subscriber.addEventListener('icegatheringstatechange', () => {
|
|
5976
|
-
|
|
6029
|
+
logger === null || logger === void 0 ? void 0 : logger('info', `Subscriber: ICE Gathering State: ${subscriber.iceGatheringState}`);
|
|
5977
6030
|
});
|
|
5978
6031
|
};
|
|
5979
6032
|
|
|
5980
6033
|
const createWebSocketSignalChannel = (opts) => {
|
|
6034
|
+
const logger = getLogger(['sfu-client']);
|
|
5981
6035
|
const { endpoint, onMessage } = opts;
|
|
5982
6036
|
const ws = new WebSocket(endpoint);
|
|
5983
6037
|
ws.binaryType = 'arraybuffer'; // do we need this?
|
|
5984
6038
|
ws.addEventListener('error', (e) => {
|
|
5985
|
-
|
|
6039
|
+
logger === null || logger === void 0 ? void 0 : logger('error', 'Signaling WS channel error', e);
|
|
5986
6040
|
});
|
|
5987
6041
|
ws.addEventListener('close', (e) => {
|
|
5988
|
-
|
|
6042
|
+
logger === null || logger === void 0 ? void 0 : logger('info', 'Signaling WS channel is closed', e);
|
|
5989
6043
|
});
|
|
5990
6044
|
ws.addEventListener('open', (e) => {
|
|
5991
|
-
|
|
6045
|
+
logger === null || logger === void 0 ? void 0 : logger('info', 'Signaling WS channel is open', e);
|
|
5992
6046
|
});
|
|
5993
6047
|
if (onMessage) {
|
|
5994
6048
|
ws.addEventListener('message', (e) => {
|
|
@@ -5999,7 +6053,7 @@ const createWebSocketSignalChannel = (opts) => {
|
|
|
5999
6053
|
onMessage(message);
|
|
6000
6054
|
}
|
|
6001
6055
|
catch (err) {
|
|
6002
|
-
|
|
6056
|
+
logger === null || logger === void 0 ? void 0 : logger('error', 'Failed to decode a message. Check whether the Proto models match.', { event: e, error: err });
|
|
6003
6057
|
}
|
|
6004
6058
|
});
|
|
6005
6059
|
}
|
|
@@ -6100,14 +6154,14 @@ function convertErrorToJson(err) {
|
|
|
6100
6154
|
* isOnline safely return the navigator.online value for browser env
|
|
6101
6155
|
* if navigator is not in global object, it always return true
|
|
6102
6156
|
*/
|
|
6103
|
-
function isOnline() {
|
|
6157
|
+
function isOnline(logger) {
|
|
6104
6158
|
const nav = typeof navigator !== 'undefined'
|
|
6105
6159
|
? navigator
|
|
6106
6160
|
: typeof window !== 'undefined' && window.navigator
|
|
6107
6161
|
? window.navigator
|
|
6108
6162
|
: undefined;
|
|
6109
6163
|
if (!nav) {
|
|
6110
|
-
|
|
6164
|
+
logger('warn', 'isOnline failed to access window.navigator and assume browser is online');
|
|
6111
6165
|
return true;
|
|
6112
6166
|
}
|
|
6113
6167
|
// RN navigator has undefined for onLine
|
|
@@ -6163,16 +6217,16 @@ class StreamSfuClient {
|
|
|
6163
6217
|
return retryable(() => this.rpc.updateSubscriptions({
|
|
6164
6218
|
sessionId: this.sessionId,
|
|
6165
6219
|
tracks: subscriptions,
|
|
6166
|
-
}));
|
|
6220
|
+
}), this.logger);
|
|
6167
6221
|
});
|
|
6168
6222
|
this.setPublisher = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
6169
|
-
return retryable(() => this.rpc.setPublisher(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })));
|
|
6223
|
+
return retryable(() => this.rpc.setPublisher(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })), this.logger);
|
|
6170
6224
|
});
|
|
6171
6225
|
this.sendAnswer = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
6172
|
-
return retryable(() => this.rpc.sendAnswer(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })));
|
|
6226
|
+
return retryable(() => this.rpc.sendAnswer(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })), this.logger);
|
|
6173
6227
|
});
|
|
6174
6228
|
this.iceTrickle = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
6175
|
-
return retryable(() => this.rpc.iceTrickle(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })));
|
|
6229
|
+
return retryable(() => this.rpc.iceTrickle(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })), this.logger);
|
|
6176
6230
|
});
|
|
6177
6231
|
this.updateMuteState = (trackType, muted) => __awaiter(this, void 0, void 0, function* () {
|
|
6178
6232
|
return this.updateMuteStates({
|
|
@@ -6185,7 +6239,7 @@ class StreamSfuClient {
|
|
|
6185
6239
|
});
|
|
6186
6240
|
});
|
|
6187
6241
|
this.updateMuteStates = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
6188
|
-
return retryable(() => this.rpc.updateMuteStates(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })));
|
|
6242
|
+
return retryable(() => this.rpc.updateMuteStates(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })), this.logger);
|
|
6189
6243
|
});
|
|
6190
6244
|
this.join = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
6191
6245
|
const joinRequest = JoinRequest.create(Object.assign(Object.assign({}, data), { sessionId: this.sessionId, token: this.token }));
|
|
@@ -6206,7 +6260,7 @@ class StreamSfuClient {
|
|
|
6206
6260
|
clearInterval(this.keepAliveInterval);
|
|
6207
6261
|
}
|
|
6208
6262
|
this.keepAliveInterval = setInterval(() => {
|
|
6209
|
-
|
|
6263
|
+
this.logger('info', 'Sending healthCheckRequest to SFU');
|
|
6210
6264
|
const message = SfuRequest.create({
|
|
6211
6265
|
requestPayload: {
|
|
6212
6266
|
oneofKind: 'healthCheckRequest',
|
|
@@ -6224,7 +6278,7 @@ class StreamSfuClient {
|
|
|
6224
6278
|
if (this.lastMessageTimestamp) {
|
|
6225
6279
|
const timeSinceLastMessage = new Date().getTime() - this.lastMessageTimestamp.getTime();
|
|
6226
6280
|
if (timeSinceLastMessage > this.unhealthyTimeoutInMs) {
|
|
6227
|
-
|
|
6281
|
+
this.logger('error', 'SFU connection unhealthy, closing');
|
|
6228
6282
|
this.close(4001, `SFU connection unhealthy. Didn't receive any healthcheck messages for ${this.unhealthyTimeoutInMs}ms`);
|
|
6229
6283
|
}
|
|
6230
6284
|
}
|
|
@@ -6232,12 +6286,22 @@ class StreamSfuClient {
|
|
|
6232
6286
|
};
|
|
6233
6287
|
this.sessionId = sessionId || generateUUIDv4();
|
|
6234
6288
|
this.token = token;
|
|
6289
|
+
this.logger = getLogger(['sfu-client']);
|
|
6290
|
+
const logger = this.logger;
|
|
6291
|
+
const logInterceptor = {
|
|
6292
|
+
interceptUnary(next, method, input, options) {
|
|
6293
|
+
logger('info', `Calling SFU RPC method ${method.name}`);
|
|
6294
|
+
logger('debug', `Method call payload`, { input, options });
|
|
6295
|
+
return next(method, input, options);
|
|
6296
|
+
},
|
|
6297
|
+
};
|
|
6235
6298
|
this.rpc = createSignalClient({
|
|
6236
6299
|
baseUrl: url,
|
|
6237
6300
|
interceptors: [
|
|
6238
6301
|
withHeaders({
|
|
6239
6302
|
Authorization: `Bearer ${token}`,
|
|
6240
6303
|
}),
|
|
6304
|
+
logInterceptor,
|
|
6241
6305
|
],
|
|
6242
6306
|
});
|
|
6243
6307
|
// Special handling for the ICETrickle kind of events.
|
|
@@ -6279,7 +6343,7 @@ const MAX_RETRIES = 5;
|
|
|
6279
6343
|
* @param <I> the type of the request object.
|
|
6280
6344
|
* @param <O> the type of the response object.
|
|
6281
6345
|
*/
|
|
6282
|
-
const retryable = (rpc) => __awaiter(void 0, void 0, void 0, function* () {
|
|
6346
|
+
const retryable = (rpc, logger) => __awaiter(void 0, void 0, void 0, function* () {
|
|
6283
6347
|
var _a;
|
|
6284
6348
|
let retryAttempt = 0;
|
|
6285
6349
|
let rpcCallResult;
|
|
@@ -6289,9 +6353,11 @@ const retryable = (rpc) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
6289
6353
|
yield sleep(retryInterval(retryAttempt));
|
|
6290
6354
|
}
|
|
6291
6355
|
rpcCallResult = yield rpc();
|
|
6356
|
+
logger('info', `SFU RPC response received for ${rpcCallResult.method.name}`);
|
|
6357
|
+
logger('debug', `Response payload`, rpcCallResult);
|
|
6292
6358
|
// if the RPC call failed, log the error and retry
|
|
6293
6359
|
if (rpcCallResult.response.error) {
|
|
6294
|
-
|
|
6360
|
+
logger('error', 'SFU RPC Error:', rpcCallResult.response.error);
|
|
6295
6361
|
}
|
|
6296
6362
|
retryAttempt++;
|
|
6297
6363
|
} while (((_a = rpcCallResult.response.error) === null || _a === void 0 ? void 0 : _a.shouldRetry) &&
|
|
@@ -6974,7 +7040,7 @@ class CallState {
|
|
|
6974
7040
|
this.updateParticipant = (sessionId, patch) => {
|
|
6975
7041
|
const participant = this.findParticipantBySessionId(sessionId);
|
|
6976
7042
|
if (!participant) {
|
|
6977
|
-
|
|
7043
|
+
this.logger('warn', `Participant with sessionId ${sessionId} not found`);
|
|
6978
7044
|
return;
|
|
6979
7045
|
}
|
|
6980
7046
|
const thePatch = typeof patch === 'function' ? patch(participant) : patch;
|
|
@@ -7023,6 +7089,7 @@ class CallState {
|
|
|
7023
7089
|
return p;
|
|
7024
7090
|
}));
|
|
7025
7091
|
};
|
|
7092
|
+
this.logger = getLogger(['call-state']);
|
|
7026
7093
|
this.participants$ = this.participantsSubject.pipe(map$1((ps) => ps.sort(this.sortParticipantsBy)));
|
|
7027
7094
|
this.localParticipant$ = this.participants$.pipe(map$1((participants) => participants.find(isStreamVideoLocalParticipant)));
|
|
7028
7095
|
this.remoteParticipants$ = this.participants$.pipe(map$1((participants) => participants.filter((p) => !p.isLocalParticipant)));
|
|
@@ -7179,13 +7246,13 @@ const watchCallRejected = (call) => {
|
|
|
7179
7246
|
const { call: eventCall } = event;
|
|
7180
7247
|
const { session: callSession } = eventCall;
|
|
7181
7248
|
if (!callSession) {
|
|
7182
|
-
|
|
7249
|
+
call.logger('warn', 'No call session provided. Ignoring call.rejected event.', event);
|
|
7183
7250
|
return;
|
|
7184
7251
|
}
|
|
7185
7252
|
const rejectedBy = callSession.rejected_by;
|
|
7186
7253
|
const { members, callingState } = call.state;
|
|
7187
7254
|
if (callingState !== CallingState.RINGING) {
|
|
7188
|
-
|
|
7255
|
+
call.logger('warn', 'Call is not in ringing mode (it is either accepted or rejected already). Ignoring call.rejected event.', event);
|
|
7189
7256
|
return;
|
|
7190
7257
|
}
|
|
7191
7258
|
if (call.isCreatedByMe) {
|
|
@@ -7193,13 +7260,13 @@ const watchCallRejected = (call) => {
|
|
|
7193
7260
|
.filter((m) => m.user_id !== call.currentUserId)
|
|
7194
7261
|
.every((m) => rejectedBy[m.user_id]);
|
|
7195
7262
|
if (everyoneElseRejected) {
|
|
7196
|
-
|
|
7263
|
+
call.logger('info', 'everyone rejected, leaving the call');
|
|
7197
7264
|
yield call.leave();
|
|
7198
7265
|
}
|
|
7199
7266
|
}
|
|
7200
7267
|
else {
|
|
7201
7268
|
if (rejectedBy[eventCall.created_by.id]) {
|
|
7202
|
-
|
|
7269
|
+
call.logger('info', 'call creator rejected, leaving call');
|
|
7203
7270
|
yield call.leave();
|
|
7204
7271
|
}
|
|
7205
7272
|
}
|
|
@@ -7607,7 +7674,7 @@ const watchCallSessionParticipantJoined = (state) => {
|
|
|
7607
7674
|
const { user } = event;
|
|
7608
7675
|
state.setMetadata((metadata) => {
|
|
7609
7676
|
if (!metadata || !metadata.session) {
|
|
7610
|
-
|
|
7677
|
+
state.logger('warn', `Received call.session_participant_joined event but the metadata structure is invalid.`, event);
|
|
7611
7678
|
return metadata;
|
|
7612
7679
|
}
|
|
7613
7680
|
const { session } = metadata;
|
|
@@ -7635,7 +7702,7 @@ const watchCallSessionParticipantLeft = (state) => {
|
|
|
7635
7702
|
const { user } = event;
|
|
7636
7703
|
state.setMetadata((metadata) => {
|
|
7637
7704
|
if (!metadata || !metadata.session) {
|
|
7638
|
-
|
|
7705
|
+
state.logger('warn', `Received call.session_participant_left event but the metadata structure is invalid.`, event);
|
|
7639
7706
|
return metadata;
|
|
7640
7707
|
}
|
|
7641
7708
|
const { session } = metadata;
|
|
@@ -7780,16 +7847,18 @@ const getLocationHint = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
7780
7847
|
const hintURL = `https://hint.stream-io-video.com/`;
|
|
7781
7848
|
const abortController = new AbortController();
|
|
7782
7849
|
const timeoutId = setTimeout(() => abortController.abort(), 1000);
|
|
7850
|
+
const logger = getLogger(['call']);
|
|
7783
7851
|
try {
|
|
7784
7852
|
const response = yield fetch(hintURL, {
|
|
7785
7853
|
method: 'HEAD',
|
|
7786
7854
|
signal: abortController.signal,
|
|
7787
7855
|
});
|
|
7788
7856
|
const awsPop = response.headers.get('x-amz-cf-pop') || 'ERR';
|
|
7857
|
+
logger === null || logger === void 0 ? void 0 : logger('info', `Location header: ${awsPop}`);
|
|
7789
7858
|
return awsPop.substring(0, 3); // AMS1-P2 -> AMS
|
|
7790
7859
|
}
|
|
7791
7860
|
catch (e) {
|
|
7792
|
-
|
|
7861
|
+
logger === null || logger === void 0 ? void 0 : logger('error', `Failed to get location hint from ${hintURL}`, e);
|
|
7793
7862
|
return 'ERR';
|
|
7794
7863
|
}
|
|
7795
7864
|
finally {
|
|
@@ -7828,6 +7897,7 @@ const getCascadingModeParams = () => {
|
|
|
7828
7897
|
* Creates a new StatsReporter instance that collects metrics about the ongoing call and reports them to the state store
|
|
7829
7898
|
*/
|
|
7830
7899
|
const createStatsReporter = ({ subscriber, publisher, state, edgeName, pollingIntervalInMs = 2000, }) => {
|
|
7900
|
+
const logger = getLogger(['stats']);
|
|
7831
7901
|
const getRawStatsForTrack = (kind, selector) => __awaiter(void 0, void 0, void 0, function* () {
|
|
7832
7902
|
if (kind === 'subscriber' && subscriber) {
|
|
7833
7903
|
return subscriber.getStats(selector);
|
|
@@ -7836,7 +7906,7 @@ const createStatsReporter = ({ subscriber, publisher, state, edgeName, pollingIn
|
|
|
7836
7906
|
return publisher.getStats(selector);
|
|
7837
7907
|
}
|
|
7838
7908
|
else {
|
|
7839
|
-
|
|
7909
|
+
logger('warn', `Can't retrieve RTC stats for ${kind}`);
|
|
7840
7910
|
return undefined;
|
|
7841
7911
|
}
|
|
7842
7912
|
});
|
|
@@ -7888,7 +7958,7 @@ const createStatsReporter = ({ subscriber, publisher, state, edgeName, pollingIn
|
|
|
7888
7958
|
});
|
|
7889
7959
|
}
|
|
7890
7960
|
catch (e) {
|
|
7891
|
-
|
|
7961
|
+
logger('error', `Failed to collect stats for ${kind} if ${participant.userId}`, e);
|
|
7892
7962
|
}
|
|
7893
7963
|
}
|
|
7894
7964
|
}
|
|
@@ -7926,7 +7996,7 @@ const createStatsReporter = ({ subscriber, publisher, state, edgeName, pollingIn
|
|
|
7926
7996
|
if (pollingIntervalInMs > 0) {
|
|
7927
7997
|
const loop = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
7928
7998
|
yield run().catch((e) => {
|
|
7929
|
-
|
|
7999
|
+
logger('warn', 'Failed to collect stats', e);
|
|
7930
8000
|
});
|
|
7931
8001
|
timeoutId = setTimeout(loop, pollingIntervalInMs);
|
|
7932
8002
|
});
|
|
@@ -8527,7 +8597,7 @@ class Call {
|
|
|
8527
8597
|
*/
|
|
8528
8598
|
const rejoin = () => __awaiter(this, void 0, void 0, function* () {
|
|
8529
8599
|
var _g, _h, _j;
|
|
8530
|
-
|
|
8600
|
+
this.logger('debug', `Rejoining call ${this.cid} (${this.reconnectAttempts})...`);
|
|
8531
8601
|
this.reconnectAttempts++;
|
|
8532
8602
|
this.state.setCallingState(CallingState.RECONNECTING);
|
|
8533
8603
|
// take a snapshot of the current "local participant" state
|
|
@@ -8539,7 +8609,7 @@ class Call {
|
|
|
8539
8609
|
sfuClient.close(); // clean up previous connection
|
|
8540
8610
|
yield sleep(retryInterval(this.reconnectAttempts));
|
|
8541
8611
|
yield this.join(data);
|
|
8542
|
-
|
|
8612
|
+
this.logger('info', `Rejoin: ${this.reconnectAttempts} successful!`);
|
|
8543
8613
|
if (localParticipant && !isReactNative()) {
|
|
8544
8614
|
const { audioStream, videoStream, screenShareStream: screenShare, } = localParticipant;
|
|
8545
8615
|
// restore previous publishing state
|
|
@@ -8550,7 +8620,7 @@ class Call {
|
|
|
8550
8620
|
if (screenShare)
|
|
8551
8621
|
yield this.publishScreenShareStream(screenShare);
|
|
8552
8622
|
}
|
|
8553
|
-
|
|
8623
|
+
this.logger('info', `Rejoin: state restored ${this.reconnectAttempts}`);
|
|
8554
8624
|
});
|
|
8555
8625
|
this.rejoinPromise = rejoin;
|
|
8556
8626
|
// reconnect if the connection was closed unexpectedly. example:
|
|
@@ -8570,12 +8640,12 @@ class Call {
|
|
|
8570
8640
|
return;
|
|
8571
8641
|
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
|
8572
8642
|
rejoin().catch(() => {
|
|
8573
|
-
|
|
8643
|
+
this.logger('error', `Rejoin failed for ${this.reconnectAttempts} times. Giving up.`);
|
|
8574
8644
|
this.state.setCallingState(CallingState.RECONNECTING_FAILED);
|
|
8575
8645
|
});
|
|
8576
8646
|
}
|
|
8577
8647
|
else {
|
|
8578
|
-
|
|
8648
|
+
this.logger('error', 'Reconnect attempts exceeded. Giving up...');
|
|
8579
8649
|
this.state.setCallingState(CallingState.RECONNECTING_FAILED);
|
|
8580
8650
|
}
|
|
8581
8651
|
});
|
|
@@ -8585,15 +8655,15 @@ class Call {
|
|
|
8585
8655
|
if (typeof window !== 'undefined' && window.addEventListener) {
|
|
8586
8656
|
const handleOnOffline = () => {
|
|
8587
8657
|
window.removeEventListener('offline', handleOnOffline);
|
|
8588
|
-
|
|
8658
|
+
this.logger('warn', 'Join: Going offline...');
|
|
8589
8659
|
this.state.setCallingState(CallingState.OFFLINE);
|
|
8590
8660
|
};
|
|
8591
8661
|
const handleOnOnline = () => {
|
|
8592
8662
|
window.removeEventListener('online', handleOnOnline);
|
|
8593
8663
|
if (this.state.callingState === CallingState.OFFLINE) {
|
|
8594
|
-
|
|
8664
|
+
this.logger('info', 'Join: Going online...');
|
|
8595
8665
|
rejoin().catch(() => {
|
|
8596
|
-
|
|
8666
|
+
this.logger('error', `Rejoin failed for ${this.reconnectAttempts} times. Giving up.`);
|
|
8597
8667
|
this.state.setCallingState(CallingState.RECONNECTING_FAILED);
|
|
8598
8668
|
});
|
|
8599
8669
|
}
|
|
@@ -8650,15 +8720,20 @@ class Call {
|
|
|
8650
8720
|
clientDetails.sdk = getSdkInfo();
|
|
8651
8721
|
// 1. wait for the signal server to be ready before sending "joinRequest"
|
|
8652
8722
|
sfuClient.signalReady
|
|
8653
|
-
.catch((err) =>
|
|
8723
|
+
.catch((err) => this.logger('error', 'Signal ready failed', err))
|
|
8654
8724
|
// prepare a generic SDP and send it to the SFU.
|
|
8655
8725
|
// this is a throw-away SDP that the SFU will use to determine
|
|
8656
8726
|
// the capabilities of the client (codec support, etc.)
|
|
8657
8727
|
.then(() => getGenericSdp('recvonly', isRedEnabled, this.streamClient.options.preferredVideoCodec))
|
|
8658
|
-
.then((sdp) =>
|
|
8659
|
-
|
|
8660
|
-
|
|
8661
|
-
|
|
8728
|
+
.then((sdp) => {
|
|
8729
|
+
const joinRequest = {
|
|
8730
|
+
subscriberSdp: sdp || '',
|
|
8731
|
+
clientDetails,
|
|
8732
|
+
};
|
|
8733
|
+
this.logger('info', 'Sending join request to SFU');
|
|
8734
|
+
this.logger('debug', 'Join request payload', joinRequest);
|
|
8735
|
+
sfuClient.join(joinRequest);
|
|
8736
|
+
});
|
|
8662
8737
|
// 2. in parallel, wait for the SFU to send us the "joinResponse"
|
|
8663
8738
|
// this will throw an error if the SFU rejects the join request or
|
|
8664
8739
|
// fails to respond in time
|
|
@@ -8674,16 +8749,16 @@ class Call {
|
|
|
8674
8749
|
this.state.setStartedAt(startedAt);
|
|
8675
8750
|
this.reconnectAttempts = 0; // reset the reconnect attempts counter
|
|
8676
8751
|
this.state.setCallingState(CallingState.JOINED);
|
|
8677
|
-
|
|
8752
|
+
this.logger('info', `Joined call ${this.cid}`);
|
|
8678
8753
|
}
|
|
8679
8754
|
catch (err) {
|
|
8680
8755
|
// join failed, try to rejoin
|
|
8681
8756
|
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
|
8682
8757
|
yield rejoin();
|
|
8683
|
-
|
|
8758
|
+
this.logger('info', `Rejoin ${this.reconnectAttempts} successful!`);
|
|
8684
8759
|
}
|
|
8685
8760
|
else {
|
|
8686
|
-
|
|
8761
|
+
this.logger('error', `Rejoin failed for ${this.reconnectAttempts} times. Giving up.`);
|
|
8687
8762
|
this.state.setCallingState(CallingState.RECONNECTING_FAILED);
|
|
8688
8763
|
throw new Error('Join failed');
|
|
8689
8764
|
}
|
|
@@ -8708,7 +8783,8 @@ class Call {
|
|
|
8708
8783
|
}
|
|
8709
8784
|
const [videoTrack] = videoStream.getVideoTracks();
|
|
8710
8785
|
if (!videoTrack) {
|
|
8711
|
-
|
|
8786
|
+
this.logger('error', `There is no video track to publish in the stream.`);
|
|
8787
|
+
return;
|
|
8712
8788
|
}
|
|
8713
8789
|
yield this.publisher.publishStream(videoStream, videoTrack, TrackType.VIDEO, opts);
|
|
8714
8790
|
});
|
|
@@ -8731,7 +8807,8 @@ class Call {
|
|
|
8731
8807
|
}
|
|
8732
8808
|
const [audioTrack] = audioStream.getAudioTracks();
|
|
8733
8809
|
if (!audioTrack) {
|
|
8734
|
-
|
|
8810
|
+
this.logger('error', `There is no audio track in the stream to publish`);
|
|
8811
|
+
return;
|
|
8735
8812
|
}
|
|
8736
8813
|
yield this.publisher.publishStream(audioStream, audioTrack, TrackType.AUDIO);
|
|
8737
8814
|
});
|
|
@@ -8753,7 +8830,8 @@ class Call {
|
|
|
8753
8830
|
}
|
|
8754
8831
|
const [screenShareTrack] = screenShareStream.getVideoTracks();
|
|
8755
8832
|
if (!screenShareTrack) {
|
|
8756
|
-
|
|
8833
|
+
this.logger('error', `There is no video track in the screen share stream to publish`);
|
|
8834
|
+
return;
|
|
8757
8835
|
}
|
|
8758
8836
|
yield this.publisher.publishStream(screenShareStream, screenShareTrack, TrackType.SCREEN_SHARE);
|
|
8759
8837
|
});
|
|
@@ -8768,7 +8846,7 @@ class Call {
|
|
|
8768
8846
|
*/
|
|
8769
8847
|
this.stopPublish = (trackType) => __awaiter(this, void 0, void 0, function* () {
|
|
8770
8848
|
var _k;
|
|
8771
|
-
|
|
8849
|
+
this.logger('info', `stopPublish ${TrackType[trackType]}`);
|
|
8772
8850
|
yield ((_k = this.publisher) === null || _k === void 0 ? void 0 : _k.unpublishStream(trackType));
|
|
8773
8851
|
});
|
|
8774
8852
|
/**
|
|
@@ -8917,20 +8995,21 @@ class Call {
|
|
|
8917
8995
|
const [primaryStream] = e.streams;
|
|
8918
8996
|
// example: `e3f6aaf8-b03d-4911-be36-83f47d37a76a:TRACK_TYPE_VIDEO`
|
|
8919
8997
|
const [trackId, trackType] = primaryStream.id.split(':');
|
|
8920
|
-
|
|
8998
|
+
this.logger('info', `Got remote ${trackType} track:`);
|
|
8999
|
+
this.logger('debug', `Track: `, e.track);
|
|
8921
9000
|
const participantToUpdate = this.state.participants.find((p) => p.trackLookupPrefix === trackId);
|
|
8922
9001
|
if (!participantToUpdate) {
|
|
8923
|
-
|
|
9002
|
+
this.logger('error', `'Received track for unknown participant: ${trackId}'`, e);
|
|
8924
9003
|
return;
|
|
8925
9004
|
}
|
|
8926
9005
|
e.track.addEventListener('mute', () => {
|
|
8927
|
-
|
|
9006
|
+
this.logger('info', `Track muted: ${participantToUpdate.userId} ${trackType}:${trackId}`);
|
|
8928
9007
|
});
|
|
8929
9008
|
e.track.addEventListener('unmute', () => {
|
|
8930
|
-
|
|
9009
|
+
this.logger('info', `Track unmuted: ${participantToUpdate.userId} ${trackType}:${trackId}`);
|
|
8931
9010
|
});
|
|
8932
9011
|
e.track.addEventListener('ended', () => {
|
|
8933
|
-
|
|
9012
|
+
this.logger('info', `Track ended: ${participantToUpdate.userId} ${trackType}:${trackId}`);
|
|
8934
9013
|
});
|
|
8935
9014
|
const streamKindProp = {
|
|
8936
9015
|
TRACK_TYPE_AUDIO: 'audioStream',
|
|
@@ -8938,12 +9017,12 @@ class Call {
|
|
|
8938
9017
|
TRACK_TYPE_SCREEN_SHARE: 'screenShareStream',
|
|
8939
9018
|
}[trackType];
|
|
8940
9019
|
if (!streamKindProp) {
|
|
8941
|
-
|
|
9020
|
+
this.logger('error', `Unknown track type: ${trackType}`);
|
|
8942
9021
|
return;
|
|
8943
9022
|
}
|
|
8944
9023
|
const previousStream = participantToUpdate[streamKindProp];
|
|
8945
9024
|
if (previousStream) {
|
|
8946
|
-
|
|
9025
|
+
this.logger('info', `Cleaning up previous remote tracks: ${e.track.kind}`);
|
|
8947
9026
|
previousStream.getTracks().forEach((t) => {
|
|
8948
9027
|
t.stop();
|
|
8949
9028
|
previousStream.removeTrack(t);
|
|
@@ -9243,6 +9322,7 @@ class Call {
|
|
|
9243
9322
|
this.streamClient = streamClient;
|
|
9244
9323
|
this.clientStore = clientStore;
|
|
9245
9324
|
this.streamClientBasePath = `/call/${this.type}/${this.id}`;
|
|
9325
|
+
this.logger = getLogger(['call']);
|
|
9246
9326
|
const callTypeConfig = CallTypes.get(type);
|
|
9247
9327
|
const participantSorter = sortParticipantsBy || callTypeConfig.options.sortParticipantsBy;
|
|
9248
9328
|
if (participantSorter) {
|
|
@@ -9280,7 +9360,7 @@ class Call {
|
|
|
9280
9360
|
const hasPermission = this.permissionsContext.hasPermission(permission);
|
|
9281
9361
|
if (!hasPermission && this.publisher.isPublishing(trackType)) {
|
|
9282
9362
|
this.stopPublish(trackType).catch((err) => {
|
|
9283
|
-
|
|
9363
|
+
this.logger('error', `Error stopping publish ${trackType}`, err);
|
|
9284
9364
|
});
|
|
9285
9365
|
}
|
|
9286
9366
|
}
|
|
@@ -9501,12 +9581,12 @@ class StableWSConnection {
|
|
|
9501
9581
|
return;
|
|
9502
9582
|
const user = this.client.user;
|
|
9503
9583
|
if (!user) {
|
|
9504
|
-
|
|
9584
|
+
this.client.logger('error', `User not set, can't connect to WS`);
|
|
9505
9585
|
return;
|
|
9506
9586
|
}
|
|
9507
9587
|
const token = this.client._getToken();
|
|
9508
9588
|
if (!token) {
|
|
9509
|
-
|
|
9589
|
+
this.client.logger('error', `Token not set, can't connect authenticate`);
|
|
9510
9590
|
return;
|
|
9511
9591
|
}
|
|
9512
9592
|
const authMessage = {
|
|
@@ -9739,7 +9819,7 @@ class StableWSConnection {
|
|
|
9739
9819
|
addConnectionEventListeners(this.onlineStatusChanged);
|
|
9740
9820
|
}
|
|
9741
9821
|
_log(msg, extra = {}, level = 'info') {
|
|
9742
|
-
this.client.logger(level, 'connection:' + msg, Object.assign({
|
|
9822
|
+
this.client.logger(level, 'connection:' + msg, Object.assign({}, extra));
|
|
9743
9823
|
}
|
|
9744
9824
|
/**
|
|
9745
9825
|
* connect - Connect to the WS URL
|
|
@@ -10456,7 +10536,7 @@ class WSConnectionFallback {
|
|
|
10456
10536
|
addConnectionEventListeners(this._onlineStatusChanged);
|
|
10457
10537
|
}
|
|
10458
10538
|
_log(msg, extra = {}, level = 'info') {
|
|
10459
|
-
this.client.logger(level, 'WSConnectionFallback:' + msg, Object.assign({
|
|
10539
|
+
this.client.logger(level, 'WSConnectionFallback:' + msg, Object.assign({}, extra));
|
|
10460
10540
|
}
|
|
10461
10541
|
_setState(state) {
|
|
10462
10542
|
this._log(`_setState() - ${state}`);
|
|
@@ -10516,7 +10596,7 @@ class StreamClient {
|
|
|
10516
10596
|
* If the user id remains the same we don't throw error
|
|
10517
10597
|
*/
|
|
10518
10598
|
if (this.userID === user.id && this.setUserPromise) {
|
|
10519
|
-
|
|
10599
|
+
this.logger('warn', 'Consecutive calls to connectUser is detected, ideally you should only call this function once in your app.');
|
|
10520
10600
|
return this.setUserPromise;
|
|
10521
10601
|
}
|
|
10522
10602
|
if (this.userID) {
|
|
@@ -10524,7 +10604,7 @@ class StreamClient {
|
|
|
10524
10604
|
}
|
|
10525
10605
|
if ((this._isUsingServerAuth() || this.node) &&
|
|
10526
10606
|
!this.options.allowServerSideConnect) {
|
|
10527
|
-
|
|
10607
|
+
this.logger('warn', 'Please do not use connectUser server side. connectUser impacts MAU and concurrent connection usage and thus your bill. If you have a valid use-case, add "allowServerSideConnect: true" to the client options to disable this warning.');
|
|
10528
10608
|
}
|
|
10529
10609
|
// we generate the client id client side
|
|
10530
10610
|
this.userID = user.id;
|
|
@@ -10587,16 +10667,12 @@ class StreamClient {
|
|
|
10587
10667
|
throw Error('UserWithId is not set on client, use client.connectUser or client.connectAnonymousUser instead');
|
|
10588
10668
|
}
|
|
10589
10669
|
if (((_d = this.wsConnection) === null || _d === void 0 ? void 0 : _d.isConnecting) && this.wsPromise) {
|
|
10590
|
-
this.logger('info', 'client:openConnection() - connection already in progress'
|
|
10591
|
-
tags: ['connection', 'client'],
|
|
10592
|
-
});
|
|
10670
|
+
this.logger('info', 'client:openConnection() - connection already in progress');
|
|
10593
10671
|
return this.wsPromise;
|
|
10594
10672
|
}
|
|
10595
10673
|
if ((((_e = this.wsConnection) === null || _e === void 0 ? void 0 : _e.isHealthy) || ((_f = this.wsFallback) === null || _f === void 0 ? void 0 : _f.isHealthy())) &&
|
|
10596
10674
|
this._hasConnectionID()) {
|
|
10597
|
-
this.logger('info', 'client:openConnection() - openConnection called twice, healthy connection already exists'
|
|
10598
|
-
tags: ['connection', 'client'],
|
|
10599
|
-
});
|
|
10675
|
+
this.logger('info', 'client:openConnection() - openConnection called twice, healthy connection already exists');
|
|
10600
10676
|
return Promise.resolve();
|
|
10601
10677
|
}
|
|
10602
10678
|
this.clientID = `${this.userID}--${randomId()}`;
|
|
@@ -10619,9 +10695,7 @@ class StreamClient {
|
|
|
10619
10695
|
* https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
|
|
10620
10696
|
*/
|
|
10621
10697
|
this.disconnectUser = (timeout) => __awaiter(this, void 0, void 0, function* () {
|
|
10622
|
-
this.logger('info', 'client:disconnect() - Disconnecting the client'
|
|
10623
|
-
tags: ['connection', 'client'],
|
|
10624
|
-
});
|
|
10698
|
+
this.logger('info', 'client:disconnect() - Disconnecting the client');
|
|
10625
10699
|
// remove the user specific fields
|
|
10626
10700
|
delete this.user;
|
|
10627
10701
|
delete this._user;
|
|
@@ -10711,7 +10785,8 @@ class StreamClient {
|
|
|
10711
10785
|
this.dispatchEvent = (event) => {
|
|
10712
10786
|
if (!event.received_at)
|
|
10713
10787
|
event.received_at = new Date();
|
|
10714
|
-
|
|
10788
|
+
this.logger('info', `Dispatching event: ${event.type}`);
|
|
10789
|
+
this.logger('debug', 'Event payload:', event);
|
|
10715
10790
|
this._callClientListeners(event);
|
|
10716
10791
|
};
|
|
10717
10792
|
this.handleEvent = (messageEvent) => {
|
|
@@ -10844,9 +10919,7 @@ class StreamClient {
|
|
|
10844
10919
|
if (!(key in this.listeners)) {
|
|
10845
10920
|
this.listeners[key] = [];
|
|
10846
10921
|
}
|
|
10847
|
-
this.logger('info', `Attaching listener for ${key} event
|
|
10848
|
-
tags: ['event', 'client'],
|
|
10849
|
-
});
|
|
10922
|
+
this.logger('info', `Attaching listener for ${key} event`);
|
|
10850
10923
|
this.listeners[key].push(callback);
|
|
10851
10924
|
return () => {
|
|
10852
10925
|
this.off(key, callback);
|
|
@@ -10864,29 +10937,26 @@ class StreamClient {
|
|
|
10864
10937
|
if (!(key in this.listeners)) {
|
|
10865
10938
|
this.listeners[key] = [];
|
|
10866
10939
|
}
|
|
10867
|
-
this.logger('info', `Removing listener for ${key} event
|
|
10868
|
-
tags: ['event', 'client'],
|
|
10869
|
-
});
|
|
10940
|
+
this.logger('info', `Removing listener for ${key} event`);
|
|
10870
10941
|
this.listeners[key] = this.listeners[key].filter((value) => value !== callback);
|
|
10871
10942
|
}
|
|
10872
10943
|
_logApiRequest(type, url, data, config) {
|
|
10873
|
-
this.logger('info', `client: ${type} - Request - ${url}
|
|
10874
|
-
|
|
10875
|
-
url,
|
|
10944
|
+
this.logger('info', `client: ${type} - Request - ${url}`);
|
|
10945
|
+
this.logger('debug', `client: ${type} - Request payload`, {
|
|
10876
10946
|
payload: data,
|
|
10877
10947
|
config,
|
|
10878
10948
|
});
|
|
10879
10949
|
}
|
|
10880
10950
|
_logApiResponse(type, url, response) {
|
|
10881
10951
|
this.logger('info', `client:${type} - Response - url: ${url} > status ${response.status}`, {
|
|
10882
|
-
|
|
10883
|
-
|
|
10952
|
+
response,
|
|
10953
|
+
});
|
|
10954
|
+
this.logger('debug', `client:${type} - Response payload`, {
|
|
10884
10955
|
response,
|
|
10885
10956
|
});
|
|
10886
10957
|
}
|
|
10887
10958
|
_logApiError(type, url, error) {
|
|
10888
10959
|
this.logger('error', `client:${type} - Error - url: ${url}`, {
|
|
10889
|
-
tags: ['api', 'api_response', 'client'],
|
|
10890
10960
|
url,
|
|
10891
10961
|
error,
|
|
10892
10962
|
});
|
|
@@ -10961,7 +11031,7 @@ class StreamClient {
|
|
|
10961
11031
|
if (this.wsFallback) {
|
|
10962
11032
|
return yield this.wsFallback.connect();
|
|
10963
11033
|
}
|
|
10964
|
-
|
|
11034
|
+
this.logger('info', 'StreamClient.connect: this.wsConnection.connect()');
|
|
10965
11035
|
// if WSFallback is enabled, ws connect should timeout faster so fallback can try
|
|
10966
11036
|
return yield this.wsConnection.connect(this.options.enableWSFallback
|
|
10967
11037
|
? this.defaultWSTimeoutWithFallback
|
|
@@ -10970,9 +11040,11 @@ class StreamClient {
|
|
|
10970
11040
|
catch (err) {
|
|
10971
11041
|
// run fallback only if it's WS/Network error and not a normal API error
|
|
10972
11042
|
// make sure browser is online before even trying the longpoll
|
|
10973
|
-
|
|
10974
|
-
|
|
10975
|
-
|
|
11043
|
+
if (this.options.enableWSFallback &&
|
|
11044
|
+
// @ts-ignore
|
|
11045
|
+
isWSFailure(err) &&
|
|
11046
|
+
isOnline(this.logger)) {
|
|
11047
|
+
this.logger('warn', 'client:connect() - WS failed, fallback to longpoll');
|
|
10976
11048
|
this.dispatchEvent({ type: 'transport.changed', mode: 'longpoll' });
|
|
10977
11049
|
this.wsConnection._destroyCurrentWSConnection();
|
|
10978
11050
|
this.wsConnection.disconnect().then(); // close WS so no retry
|
|
@@ -11007,7 +11079,7 @@ class StreamClient {
|
|
|
11007
11079
|
}
|
|
11008
11080
|
getUserAgent() {
|
|
11009
11081
|
return (this.userAgent ||
|
|
11010
|
-
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.
|
|
11082
|
+
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.15"}`);
|
|
11011
11083
|
}
|
|
11012
11084
|
setUserAgent(userAgent) {
|
|
11013
11085
|
this.userAgent = userAgent;
|
|
@@ -11076,7 +11148,10 @@ class StreamClient {
|
|
|
11076
11148
|
*/
|
|
11077
11149
|
class StreamVideoClient {
|
|
11078
11150
|
constructor(apiKeyOrArgs, opts) {
|
|
11151
|
+
var _a, _b;
|
|
11152
|
+
this.logLevel = 'warn';
|
|
11079
11153
|
this.eventHandlersToUnregister = [];
|
|
11154
|
+
this.logLevels = ['debug', 'info', 'warn', 'error'];
|
|
11080
11155
|
/**
|
|
11081
11156
|
* Disconnects the currently connected user from the client.
|
|
11082
11157
|
*
|
|
@@ -11235,11 +11310,30 @@ class StreamVideoClient {
|
|
|
11235
11310
|
this.connectionPromise.finally(() => (this.connectionPromise = undefined));
|
|
11236
11311
|
return this.connectionPromise;
|
|
11237
11312
|
});
|
|
11313
|
+
this.filterLogs = (logMethod) => {
|
|
11314
|
+
return (logLevel, messeage, extraData, tags) => {
|
|
11315
|
+
if (this.logLevels.indexOf(logLevel) >=
|
|
11316
|
+
this.logLevels.indexOf(this.logLevel)) {
|
|
11317
|
+
logMethod(logLevel, messeage, extraData, tags);
|
|
11318
|
+
}
|
|
11319
|
+
};
|
|
11320
|
+
};
|
|
11321
|
+
let defaultLogger = logToConsole;
|
|
11238
11322
|
if (typeof apiKeyOrArgs === 'string') {
|
|
11239
|
-
this.
|
|
11323
|
+
this.logLevel = (opts === null || opts === void 0 ? void 0 : opts.logLevel) || this.logLevel;
|
|
11324
|
+
this.logger = (opts === null || opts === void 0 ? void 0 : opts.logger) || defaultLogger;
|
|
11240
11325
|
}
|
|
11241
11326
|
else {
|
|
11242
|
-
this.
|
|
11327
|
+
this.logLevel = ((_a = apiKeyOrArgs.options) === null || _a === void 0 ? void 0 : _a.logLevel) || this.logLevel;
|
|
11328
|
+
this.logger = ((_b = apiKeyOrArgs.options) === null || _b === void 0 ? void 0 : _b.logger) || defaultLogger;
|
|
11329
|
+
}
|
|
11330
|
+
setLogger(this.filterLogs(defaultLogger));
|
|
11331
|
+
const clientLogger = getLogger(['client']);
|
|
11332
|
+
if (typeof apiKeyOrArgs === 'string') {
|
|
11333
|
+
this.streamClient = new StreamClient(apiKeyOrArgs, Object.assign(Object.assign({ persistUserOnConnectionFailure: true }, opts), { logLevel: this.logLevel, logger: clientLogger }));
|
|
11334
|
+
}
|
|
11335
|
+
else {
|
|
11336
|
+
this.streamClient = new StreamClient(apiKeyOrArgs.apiKey, Object.assign(Object.assign({ persistUserOnConnectionFailure: true }, apiKeyOrArgs.options), { logLevel: this.logLevel, logger: clientLogger }));
|
|
11243
11337
|
this.user = apiKeyOrArgs.user;
|
|
11244
11338
|
this.token = apiKeyOrArgs.token || apiKeyOrArgs.tokenProvider;
|
|
11245
11339
|
if (this.user) {
|
|
@@ -11301,7 +11395,7 @@ class StreamVideoClient {
|
|
|
11301
11395
|
},
|
|
11302
11396
|
sort: [{ field: 'cid', direction: 1 }],
|
|
11303
11397
|
}).catch((err) => {
|
|
11304
|
-
|
|
11398
|
+
this.logger('error', 'Failed to re-watch calls', err);
|
|
11305
11399
|
});
|
|
11306
11400
|
}
|
|
11307
11401
|
}
|
|
@@ -11311,7 +11405,7 @@ class StreamVideoClient {
|
|
|
11311
11405
|
return;
|
|
11312
11406
|
const { call, members } = event;
|
|
11313
11407
|
if (userToConnect.id === call.created_by.id) {
|
|
11314
|
-
|
|
11408
|
+
this.logger('warn', 'Received `call.created` sent by the current user');
|
|
11315
11409
|
return;
|
|
11316
11410
|
}
|
|
11317
11411
|
this.writeableStateStore.registerCall(new Call({
|
|
@@ -11328,7 +11422,7 @@ class StreamVideoClient {
|
|
|
11328
11422
|
return;
|
|
11329
11423
|
const { call, members } = event;
|
|
11330
11424
|
if (userToConnect.id === call.created_by.id) {
|
|
11331
|
-
|
|
11425
|
+
this.logger('warn', 'Received `call.ring` sent by the current user');
|
|
11332
11426
|
return;
|
|
11333
11427
|
}
|
|
11334
11428
|
// The call might already be tracked by the client,
|
|
@@ -11395,7 +11489,10 @@ const getDevices = (constraints) => {
|
|
|
11395
11489
|
});
|
|
11396
11490
|
})
|
|
11397
11491
|
.catch((error) => {
|
|
11398
|
-
|
|
11492
|
+
const logger = getLogger(['devices']);
|
|
11493
|
+
if (logger) {
|
|
11494
|
+
logger('error', 'Failed to get devices', error);
|
|
11495
|
+
}
|
|
11399
11496
|
subscriber.error(error);
|
|
11400
11497
|
});
|
|
11401
11498
|
});
|
|
@@ -11466,11 +11563,15 @@ const getAudioOutputDevices = () => {
|
|
|
11466
11563
|
return audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audiooutput')));
|
|
11467
11564
|
};
|
|
11468
11565
|
const getStream = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
|
|
11566
|
+
var _a;
|
|
11469
11567
|
try {
|
|
11470
11568
|
return yield navigator.mediaDevices.getUserMedia(constraints);
|
|
11471
11569
|
}
|
|
11472
11570
|
catch (e) {
|
|
11473
|
-
|
|
11571
|
+
(_a = getLogger(['devices'])) === null || _a === void 0 ? void 0 : _a('error', `Failed get user media`, {
|
|
11572
|
+
error: e,
|
|
11573
|
+
constraints: constraints,
|
|
11574
|
+
});
|
|
11474
11575
|
throw e;
|
|
11475
11576
|
}
|
|
11476
11577
|
});
|
|
@@ -11513,11 +11614,12 @@ const getVideoStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, f
|
|
|
11513
11614
|
* @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
|
|
11514
11615
|
*/
|
|
11515
11616
|
const getScreenShareStream = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
11617
|
+
var _b;
|
|
11516
11618
|
try {
|
|
11517
11619
|
return yield navigator.mediaDevices.getDisplayMedia(Object.assign({ video: true, audio: false }, options));
|
|
11518
11620
|
}
|
|
11519
11621
|
catch (e) {
|
|
11520
|
-
|
|
11622
|
+
(_b = getLogger(['devices'])) === null || _b === void 0 ? void 0 : _b('error', 'Failed to get screen share stream', e);
|
|
11521
11623
|
throw e;
|
|
11522
11624
|
}
|
|
11523
11625
|
});
|
|
@@ -11700,5 +11802,5 @@ var browsers = /*#__PURE__*/Object.freeze({
|
|
|
11700
11802
|
isSafari: isSafari
|
|
11701
11803
|
});
|
|
11702
11804
|
|
|
11703
|
-
export { APIErrorCodeEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CreateDeviceRequestPushProviderEnum, DebounceType, ErrorFromResponse, OwnCapability, RecordSettingsModeEnum, RecordSettingsQualityEnum, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, events as SfuEvents, models as SfuModels, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoWriteableStateStore, TranscriptionSettingsModeEnum, TranscriptionSettingsRequestModeEnum, VideoSettingsCameraFacingEnum, VideoSettingsRequestCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, disposeOfMediaStream, dominantSpeaker, getAudioDevices, getAudioOutputDevices, getAudioStream, getScreenShareStream, getSdkInfo, getVideoDevices, getVideoStream, isStreamVideoLocalParticipant, livestreamOrAudioRoomSortPreset, name, noopComparator, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setSdkInfo, speakerLayoutSortPreset, speaking, watchForAddedDefaultAudioDevice, watchForAddedDefaultAudioOutputDevice, watchForAddedDefaultVideoDevice, watchForDisconnectedAudioDevice, watchForDisconnectedAudioOutputDevice, watchForDisconnectedVideoDevice };
|
|
11805
|
+
export { APIErrorCodeEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CreateDeviceRequestPushProviderEnum, DebounceType, ErrorFromResponse, OwnCapability, RecordSettingsModeEnum, RecordSettingsQualityEnum, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, events as SfuEvents, models as SfuModels, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoWriteableStateStore, TranscriptionSettingsModeEnum, TranscriptionSettingsRequestModeEnum, VideoSettingsCameraFacingEnum, VideoSettingsRequestCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, disposeOfMediaStream, dominantSpeaker, getAudioDevices, getAudioOutputDevices, getAudioStream, getLogger, getScreenShareStream, getSdkInfo, getVideoDevices, getVideoStream, isStreamVideoLocalParticipant, livestreamOrAudioRoomSortPreset, logToConsole, name, noopComparator, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setLogger, setSdkInfo, speakerLayoutSortPreset, speaking, watchForAddedDefaultAudioDevice, watchForAddedDefaultAudioOutputDevice, watchForAddedDefaultVideoDevice, watchForDisconnectedAudioDevice, watchForDisconnectedAudioOutputDevice, watchForDisconnectedVideoDevice };
|
|
11704
11806
|
//# sourceMappingURL=index.browser.es.js.map
|