@stream-io/video-client 0.0.13 → 0.0.15

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/index.browser.es.js +237 -130
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +239 -129
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.es.js +237 -130
  8. package/dist/index.es.js.map +1 -1
  9. package/dist/src/Call.d.ts +2 -1
  10. package/dist/src/StreamSfuClient.d.ts +1 -0
  11. package/dist/src/StreamVideoClient.d.ts +5 -1
  12. package/dist/src/coordinator/connection/types.d.ts +3 -2
  13. package/dist/src/coordinator/connection/utils.d.ts +2 -1
  14. package/dist/src/logger.d.ts +4 -0
  15. package/dist/src/rtc/Dispatcher.d.ts +2 -0
  16. package/dist/src/rtc/IceTrickleBuffer.d.ts +2 -0
  17. package/dist/src/rtc/publisher.d.ts +1 -0
  18. package/dist/src/store/CallState.d.ts +2 -0
  19. package/dist/src/types.d.ts +1 -1
  20. package/index.ts +1 -0
  21. package/package.json +1 -1
  22. package/src/Call.ts +69 -42
  23. package/src/StreamSfuClient.ts +70 -29
  24. package/src/StreamVideoClient.ts +46 -3
  25. package/src/coordinator/connection/client.ts +22 -29
  26. package/src/coordinator/connection/connection.ts +2 -3
  27. package/src/coordinator/connection/connection_fallback.ts +0 -1
  28. package/src/coordinator/connection/types.ts +4 -2
  29. package/src/coordinator/connection/utils.ts +5 -2
  30. package/src/devices/devices.ts +10 -3
  31. package/src/events/__tests__/call-permissions.test.ts +2 -2
  32. package/src/events/call.ts +11 -4
  33. package/src/events/sessions.ts +7 -2
  34. package/src/logger.ts +45 -0
  35. package/src/rtc/Dispatcher.ts +14 -4
  36. package/src/rtc/IceTrickleBuffer.ts +8 -1
  37. package/src/rtc/__tests__/publisher.test.ts +1 -1
  38. package/src/rtc/codecs.ts +7 -5
  39. package/src/rtc/flows/join.ts +4 -1
  40. package/src/rtc/publisher.ts +31 -12
  41. package/src/rtc/signal.ts +8 -7
  42. package/src/rtc/subscriber.ts +16 -10
  43. package/src/stats/state-store-stats-reporter.ts +12 -4
  44. package/src/store/CallState.ts +7 -2
  45. package/src/types.ts +3 -2
package/dist/index.es.js CHANGED
@@ -4249,7 +4249,7 @@ var DebounceType;
4249
4249
  DebounceType[DebounceType["SLOW"] = 1200] = "SLOW";
4250
4250
  })(DebounceType || (DebounceType = {}));
4251
4251
  const isStreamVideoLocalParticipant = (p) => {
4252
- return !!p.isLoggedInUser;
4252
+ return !!p.isLocalParticipant;
4253
4253
  };
4254
4254
 
4255
4255
  /******************************************************************************
@@ -5276,13 +5276,41 @@ const toggleDtx = (sdp, enable) => {
5276
5276
  return sdp;
5277
5277
  };
5278
5278
 
5279
+ let logger;
5280
+ const logToConsole = (logLevel, message, extraData, tags) => {
5281
+ let logMethod;
5282
+ if (logLevel === 'error') {
5283
+ logMethod = console.error;
5284
+ }
5285
+ else if (logLevel === 'warn') {
5286
+ logMethod = console.warn;
5287
+ }
5288
+ else {
5289
+ logMethod = console.log;
5290
+ }
5291
+ logMethod(logLevel, `${tags === null || tags === void 0 ? void 0 : tags.join(':')} - ${message}`, extraData ? extraData : '');
5292
+ };
5293
+ const setLogger = (l) => {
5294
+ logger = l;
5295
+ };
5296
+ const getLogger = (withTags) => {
5297
+ const loggerMethod = logger || (() => { });
5298
+ const result = (logLevel, messeage, extraData, tags) => {
5299
+ loggerMethod(logLevel, messeage, extraData, [
5300
+ ...(tags || []),
5301
+ ...(withTags || []),
5302
+ ]);
5303
+ };
5304
+ return result;
5305
+ };
5306
+
5279
5307
  const getPreferredCodecs = (kind, preferredCodec, codecToRemove) => {
5308
+ const logger = getLogger(['codecs']);
5280
5309
  if (!('getCapabilities' in RTCRtpSender)) {
5281
- console.warn('RTCRtpSender.getCapabilities is not supported');
5310
+ logger === null || logger === void 0 ? void 0 : logger('warn', 'RTCRtpSender.getCapabilities is not supported');
5282
5311
  return;
5283
5312
  }
5284
5313
  const cap = RTCRtpSender.getCapabilities(kind);
5285
- console.log('s4e');
5286
5314
  if (!cap)
5287
5315
  return;
5288
5316
  const matched = [];
@@ -5290,7 +5318,7 @@ const getPreferredCodecs = (kind, preferredCodec, codecToRemove) => {
5290
5318
  const unmatched = [];
5291
5319
  cap.codecs.forEach((c) => {
5292
5320
  const codec = c.mimeType.toLowerCase();
5293
- console.log(c);
5321
+ logger === null || logger === void 0 ? void 0 : logger('debug', `Found supported codec: ${codec}`);
5294
5322
  const shouldRemoveCodec = codecToRemove && codec === `${kind}/${codecToRemove}`;
5295
5323
  if (shouldRemoveCodec)
5296
5324
  return;
@@ -5310,10 +5338,11 @@ const getPreferredCodecs = (kind, preferredCodec, codecToRemove) => {
5310
5338
  }
5311
5339
  return;
5312
5340
  }
5313
- console.log('matched', matched);
5314
5341
  matched.push(c);
5315
5342
  });
5316
- return [...matched, ...partialMatched, ...unmatched];
5343
+ const result = [...matched, ...partialMatched, ...unmatched];
5344
+ logger === null || logger === void 0 ? void 0 : logger('info', `Preffered codecs: `, result);
5345
+ return result;
5317
5346
  };
5318
5347
  const getGenericSdp = (direction, isRedEnabled, preferredVideoCodec) => __awaiter(void 0, void 0, void 0, function* () {
5319
5348
  var _a;
@@ -5379,17 +5408,19 @@ class Dispatcher {
5379
5408
  constructor() {
5380
5409
  this.subscribers = {};
5381
5410
  this.dispatch = (message) => {
5411
+ var _a, _b;
5382
5412
  const eventKind = message.eventPayload.oneofKind;
5383
5413
  if (eventKind) {
5384
- // @ts-ignore
5385
- console.log(`Dispatching`, eventKind, message.eventPayload[eventKind]);
5414
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'info', `Dispatching ${eventKind}`);
5415
+ (_b = this.logger) === null || _b === void 0 ? void 0 : _b.call(this, 'debug', `Event payload`, message.eventPayload[eventKind]);
5386
5416
  const listeners = this.subscribers[eventKind];
5387
5417
  listeners === null || listeners === void 0 ? void 0 : listeners.forEach((fn) => {
5418
+ var _a;
5388
5419
  try {
5389
5420
  fn(message);
5390
5421
  }
5391
5422
  catch (e) {
5392
- console.warn(`Listener failed with error`, e);
5423
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'warn', 'Listener failed with error', e);
5393
5424
  }
5394
5425
  });
5395
5426
  }
@@ -5413,6 +5444,7 @@ class Dispatcher {
5413
5444
  this.subscribers = {};
5414
5445
  }
5415
5446
  };
5447
+ this.logger = getLogger(['sfu-client']);
5416
5448
  }
5417
5449
  }
5418
5450
 
@@ -5425,6 +5457,7 @@ class IceTrickleBuffer {
5425
5457
  this.subscriberCandidates = new ReplaySubject();
5426
5458
  this.publisherCandidates = new ReplaySubject();
5427
5459
  this.push = (iceTrickle) => {
5460
+ var _a;
5428
5461
  if (iceTrickle.peerType === PeerType.SUBSCRIBER) {
5429
5462
  this.subscriberCandidates.next(iceTrickle);
5430
5463
  }
@@ -5432,9 +5465,10 @@ class IceTrickleBuffer {
5432
5465
  this.publisherCandidates.next(iceTrickle);
5433
5466
  }
5434
5467
  else {
5435
- console.warn(`ICETrickle, Unknown peer type`, iceTrickle);
5468
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'warn', `ICETrickle, Unknown peer type`, iceTrickle);
5436
5469
  }
5437
5470
  };
5471
+ this.logger = getLogger(['sfu-client']);
5438
5472
  }
5439
5473
  }
5440
5474
 
@@ -5625,6 +5659,7 @@ class Publisher {
5625
5659
  * @param opts
5626
5660
  */
5627
5661
  this.publishStream = (mediaStream, track, trackType, opts = {}) => __awaiter(this, void 0, void 0, function* () {
5662
+ var _a;
5628
5663
  let transceiver = this.publisher
5629
5664
  .getTransceivers()
5630
5665
  .find((t) => {
@@ -5638,7 +5673,8 @@ class Publisher {
5638
5673
  * Once the track has ended, it will notify the SFU and update the state.
5639
5674
  */
5640
5675
  const handleTrackEnded = () => __awaiter(this, void 0, void 0, function* () {
5641
- console.log(`Track ${TrackType[trackType]} has ended, notifying the SFU`);
5676
+ var _b;
5677
+ (_b = this.logger) === null || _b === void 0 ? void 0 : _b.call(this, 'info', `Track ${TrackType[trackType]} has ended, notifying the SFU`);
5642
5678
  yield this.notifyTrackMuteStateChanged(mediaStream, track, trackType, true);
5643
5679
  // clean-up, this event listener needs to run only once.
5644
5680
  track.removeEventListener('ended', handleTrackEnded);
@@ -5663,7 +5699,7 @@ class Publisher {
5663
5699
  });
5664
5700
  this.transceiverRegistry[trackType] = transceiver;
5665
5701
  if ('setCodecPreferences' in transceiver && codecPreferences) {
5666
- console.log(`Setting ${TrackType[trackType]} codec preferences`, codecPreferences);
5702
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'info', `Setting ${TrackType[trackType]} codec preferences`, codecPreferences);
5667
5703
  transceiver.setCodecPreferences(codecPreferences);
5668
5704
  }
5669
5705
  }
@@ -5747,9 +5783,9 @@ class Publisher {
5747
5783
  this.publisher.close();
5748
5784
  };
5749
5785
  this.updateVideoPublishQuality = (enabledRids) => __awaiter(this, void 0, void 0, function* () {
5750
- var _a;
5751
- console.log('Update publish quality, requested rids by SFU:', enabledRids);
5752
- const videoSender = (_a = this.transceiverRegistry[TrackType.VIDEO]) === null || _a === void 0 ? void 0 : _a.sender;
5786
+ var _c, _d, _e, _f;
5787
+ (_c = this.logger) === null || _c === void 0 ? void 0 : _c.call(this, 'info', 'Update publish quality, requested rids by SFU:', enabledRids);
5788
+ const videoSender = (_d = this.transceiverRegistry[TrackType.VIDEO]) === null || _d === void 0 ? void 0 : _d.sender;
5753
5789
  if (!videoSender)
5754
5790
  return;
5755
5791
  const params = videoSender.getParameters();
@@ -5764,10 +5800,10 @@ class Publisher {
5764
5800
  });
5765
5801
  if (changed) {
5766
5802
  if (params.encodings.length === 0) {
5767
- console.warn('No suitable video encoding quality found');
5803
+ (_e = this.logger) === null || _e === void 0 ? void 0 : _e.call(this, 'warn', 'No suitable video encoding quality found');
5768
5804
  }
5769
5805
  yield videoSender.setParameters(params);
5770
- console.log(`Update publish quality, enabled rids: ${params.encodings
5806
+ (_f = this.logger) === null || _f === void 0 ? void 0 : _f.call(this, 'info', `Update publish quality, enabled rids: ${params.encodings
5771
5807
  .filter((e) => e.active)
5772
5808
  .map((e) => e.rid)
5773
5809
  .join(', ')}`);
@@ -5784,9 +5820,10 @@ class Publisher {
5784
5820
  }
5785
5821
  };
5786
5822
  this.onIceCandidate = (e) => __awaiter(this, void 0, void 0, function* () {
5823
+ var _g;
5787
5824
  const { candidate } = e;
5788
5825
  if (!candidate) {
5789
- console.log('null ice candidate');
5826
+ (_g = this.logger) === null || _g === void 0 ? void 0 : _g.call(this, 'warn', 'null ice candidate');
5790
5827
  return;
5791
5828
  }
5792
5829
  yield this.sfuClient.iceTrickle({
@@ -5795,7 +5832,8 @@ class Publisher {
5795
5832
  });
5796
5833
  });
5797
5834
  this.onNegotiationNeeded = () => __awaiter(this, void 0, void 0, function* () {
5798
- console.log('AAA onNegotiationNeeded');
5835
+ var _h, _j;
5836
+ (_h = this.logger) === null || _h === void 0 ? void 0 : _h.call(this, 'info', 'AAA onNegotiationNeeded');
5799
5837
  const offer = yield this.publisher.createOffer();
5800
5838
  let sdp = offer.sdp;
5801
5839
  if (sdp) {
@@ -5858,28 +5896,38 @@ class Publisher {
5858
5896
  });
5859
5897
  }
5860
5898
  catch (e) {
5861
- console.error(`Publisher: setRemoteDescription error`, response.sdp, e);
5899
+ (_j = this.logger) === null || _j === void 0 ? void 0 : _j.call(this, 'error', `Publisher: setRemoteDescription error`, {
5900
+ sdp: response.sdp,
5901
+ error: e,
5902
+ });
5862
5903
  }
5863
5904
  this.sfuClient.iceTrickleBuffer.publisherCandidates.subscribe((candidate) => __awaiter(this, void 0, void 0, function* () {
5905
+ var _k;
5864
5906
  try {
5865
5907
  const iceCandidate = JSON.parse(candidate.iceCandidate);
5866
5908
  yield this.publisher.addIceCandidate(iceCandidate);
5867
5909
  }
5868
5910
  catch (e) {
5869
- console.error(`Publisher: ICE candidate error`, e, candidate);
5911
+ (_k = this.logger) === null || _k === void 0 ? void 0 : _k.call(this, 'error', `Publisher: ICE candidate error`, {
5912
+ error: e,
5913
+ candidate,
5914
+ });
5870
5915
  }
5871
5916
  }));
5872
5917
  });
5873
5918
  this.onIceCandidateError = (e) => {
5919
+ var _a;
5874
5920
  const errorMessage = e instanceof RTCPeerConnectionIceErrorEvent &&
5875
5921
  `${e.errorCode}: ${e.errorText}`;
5876
- console.error(`Publisher: ICE Candidate error`, errorMessage);
5922
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'error', `Publisher: ICE Candidate error`, errorMessage);
5877
5923
  };
5878
5924
  this.onIceConnectionStateChange = () => {
5879
- console.log(`Publisher: ICE Connection state changed`, this.publisher.iceConnectionState);
5925
+ var _a;
5926
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'error', `Publisher: ICE Connection state changed`, this.publisher.iceConnectionState);
5880
5927
  };
5881
5928
  this.onIceGatheringStateChange = () => {
5882
- console.log(`Publisher: ICE Gathering State`, this.publisher.iceGatheringState);
5929
+ var _a;
5930
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, 'error', `Publisher: ICE Gathering State`, this.publisher.iceGatheringState);
5883
5931
  };
5884
5932
  this.ridToVideoQuality = (rid) => {
5885
5933
  return rid === 'q'
@@ -5912,12 +5960,13 @@ class Publisher {
5912
5960
  }
5913
5961
 
5914
5962
  const createSubscriber = ({ sfuClient, dispatcher, connectionConfig, onTrack, }) => {
5963
+ const logger = getLogger(['sfu-client']);
5915
5964
  const subscriber = new RTCPeerConnection(connectionConfig);
5916
5965
  attachDebugEventListeners(subscriber);
5917
5966
  subscriber.addEventListener('icecandidate', (e) => __awaiter(void 0, void 0, void 0, function* () {
5918
5967
  const { candidate } = e;
5919
5968
  if (!candidate) {
5920
- console.log('null ice candidate');
5969
+ logger === null || logger === void 0 ? void 0 : logger('warn', 'null ice candidate');
5921
5970
  return;
5922
5971
  }
5923
5972
  yield sfuClient.iceTrickle({
@@ -5933,7 +5982,7 @@ const createSubscriber = ({ sfuClient, dispatcher, connectionConfig, onTrack, })
5933
5982
  if (message.eventPayload.oneofKind !== 'subscriberOffer')
5934
5983
  return;
5935
5984
  const { subscriberOffer } = message.eventPayload;
5936
- console.log(`Received subscriberOffer`, subscriberOffer);
5985
+ logger === null || logger === void 0 ? void 0 : logger('info', 'Received subscriberOffer', subscriberOffer);
5937
5986
  yield subscriber.setRemoteDescription({
5938
5987
  type: 'offer',
5939
5988
  sdp: subscriberOffer.sdp,
@@ -5944,7 +5993,10 @@ const createSubscriber = ({ sfuClient, dispatcher, connectionConfig, onTrack, })
5944
5993
  yield subscriber.addIceCandidate(iceCandidate);
5945
5994
  }
5946
5995
  catch (e) {
5947
- console.error(`Subscriber: ICE candidate error`, e, candidate);
5996
+ logger === null || logger === void 0 ? void 0 : logger('error', `Subscriber: ICE candidate error`, {
5997
+ error: e,
5998
+ candidate,
5999
+ });
5948
6000
  }
5949
6001
  }));
5950
6002
  // apply ice candidates
@@ -5967,31 +6019,33 @@ const createSubscriber = ({ sfuClient, dispatcher, connectionConfig, onTrack, })
5967
6019
  return subscriber;
5968
6020
  };
5969
6021
  const attachDebugEventListeners = (subscriber) => {
6022
+ const logger = getLogger(['sfu-client']);
5970
6023
  subscriber.addEventListener('icecandidateerror', (e) => {
5971
6024
  const errorMessage = e instanceof RTCPeerConnectionIceErrorEvent &&
5972
6025
  `${e.errorCode}: ${e.errorText}`;
5973
- console.error(`Subscriber: ICE Candidate error`, errorMessage);
6026
+ logger === null || logger === void 0 ? void 0 : logger('error', `Subscriber: ICE Candidate error: ${errorMessage}`);
5974
6027
  });
5975
6028
  subscriber.addEventListener('iceconnectionstatechange', () => {
5976
- console.log(`Subscriber: ICE Connection state changed`, subscriber.iceConnectionState);
6029
+ logger === null || logger === void 0 ? void 0 : logger('info', `Subscriber: ICE Connection state changed: ${subscriber.iceConnectionState}`);
5977
6030
  });
5978
6031
  subscriber.addEventListener('icegatheringstatechange', () => {
5979
- console.log(`Subscriber: ICE Gathering State`, subscriber.iceGatheringState);
6032
+ logger === null || logger === void 0 ? void 0 : logger('info', `Subscriber: ICE Gathering State: ${subscriber.iceGatheringState}`);
5980
6033
  });
5981
6034
  };
5982
6035
 
5983
6036
  const createWebSocketSignalChannel = (opts) => {
6037
+ const logger = getLogger(['sfu-client']);
5984
6038
  const { endpoint, onMessage } = opts;
5985
6039
  const ws = new WebSocket(endpoint);
5986
6040
  ws.binaryType = 'arraybuffer'; // do we need this?
5987
6041
  ws.addEventListener('error', (e) => {
5988
- console.log('Signaling WS channel error', e);
6042
+ logger === null || logger === void 0 ? void 0 : logger('error', 'Signaling WS channel error', e);
5989
6043
  });
5990
6044
  ws.addEventListener('close', (e) => {
5991
- console.log('Signaling WS channel is closed', e);
6045
+ logger === null || logger === void 0 ? void 0 : logger('info', 'Signaling WS channel is closed', e);
5992
6046
  });
5993
6047
  ws.addEventListener('open', (e) => {
5994
- console.log('Signaling WS channel is open', e);
6048
+ logger === null || logger === void 0 ? void 0 : logger('info', 'Signaling WS channel is open', e);
5995
6049
  });
5996
6050
  if (onMessage) {
5997
6051
  ws.addEventListener('message', (e) => {
@@ -6002,7 +6056,7 @@ const createWebSocketSignalChannel = (opts) => {
6002
6056
  onMessage(message);
6003
6057
  }
6004
6058
  catch (err) {
6005
- console.error('Failed to decode a message. Check whether the Proto models match.', e.data, e, err);
6059
+ logger === null || logger === void 0 ? void 0 : logger('error', 'Failed to decode a message. Check whether the Proto models match.', { event: e, error: err });
6006
6060
  }
6007
6061
  });
6008
6062
  }
@@ -6103,14 +6157,14 @@ function convertErrorToJson(err) {
6103
6157
  * isOnline safely return the navigator.online value for browser env
6104
6158
  * if navigator is not in global object, it always return true
6105
6159
  */
6106
- function isOnline() {
6160
+ function isOnline(logger) {
6107
6161
  const nav = typeof navigator !== 'undefined'
6108
6162
  ? navigator
6109
6163
  : typeof window !== 'undefined' && window.navigator
6110
6164
  ? window.navigator
6111
6165
  : undefined;
6112
6166
  if (!nav) {
6113
- console.warn('isOnline failed to access window.navigator and assume browser is online');
6167
+ logger('warn', 'isOnline failed to access window.navigator and assume browser is online');
6114
6168
  return true;
6115
6169
  }
6116
6170
  // RN navigator has undefined for onLine
@@ -6166,16 +6220,16 @@ class StreamSfuClient {
6166
6220
  return retryable(() => this.rpc.updateSubscriptions({
6167
6221
  sessionId: this.sessionId,
6168
6222
  tracks: subscriptions,
6169
- }));
6223
+ }), this.logger);
6170
6224
  });
6171
6225
  this.setPublisher = (data) => __awaiter(this, void 0, void 0, function* () {
6172
- return retryable(() => this.rpc.setPublisher(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })));
6226
+ return retryable(() => this.rpc.setPublisher(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })), this.logger);
6173
6227
  });
6174
6228
  this.sendAnswer = (data) => __awaiter(this, void 0, void 0, function* () {
6175
- return retryable(() => this.rpc.sendAnswer(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })));
6229
+ return retryable(() => this.rpc.sendAnswer(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })), this.logger);
6176
6230
  });
6177
6231
  this.iceTrickle = (data) => __awaiter(this, void 0, void 0, function* () {
6178
- return retryable(() => this.rpc.iceTrickle(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })));
6232
+ return retryable(() => this.rpc.iceTrickle(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })), this.logger);
6179
6233
  });
6180
6234
  this.updateMuteState = (trackType, muted) => __awaiter(this, void 0, void 0, function* () {
6181
6235
  return this.updateMuteStates({
@@ -6188,7 +6242,7 @@ class StreamSfuClient {
6188
6242
  });
6189
6243
  });
6190
6244
  this.updateMuteStates = (data) => __awaiter(this, void 0, void 0, function* () {
6191
- return retryable(() => this.rpc.updateMuteStates(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })));
6245
+ return retryable(() => this.rpc.updateMuteStates(Object.assign(Object.assign({}, data), { sessionId: this.sessionId })), this.logger);
6192
6246
  });
6193
6247
  this.join = (data) => __awaiter(this, void 0, void 0, function* () {
6194
6248
  const joinRequest = JoinRequest.create(Object.assign(Object.assign({}, data), { sessionId: this.sessionId, token: this.token }));
@@ -6209,7 +6263,7 @@ class StreamSfuClient {
6209
6263
  clearInterval(this.keepAliveInterval);
6210
6264
  }
6211
6265
  this.keepAliveInterval = setInterval(() => {
6212
- console.log('Sending healthCheckRequest to SFU');
6266
+ this.logger('info', 'Sending healthCheckRequest to SFU');
6213
6267
  const message = SfuRequest.create({
6214
6268
  requestPayload: {
6215
6269
  oneofKind: 'healthCheckRequest',
@@ -6227,7 +6281,7 @@ class StreamSfuClient {
6227
6281
  if (this.lastMessageTimestamp) {
6228
6282
  const timeSinceLastMessage = new Date().getTime() - this.lastMessageTimestamp.getTime();
6229
6283
  if (timeSinceLastMessage > this.unhealthyTimeoutInMs) {
6230
- console.log('SFU connection unhealthy, closing');
6284
+ this.logger('error', 'SFU connection unhealthy, closing');
6231
6285
  this.close(4001, `SFU connection unhealthy. Didn't receive any healthcheck messages for ${this.unhealthyTimeoutInMs}ms`);
6232
6286
  }
6233
6287
  }
@@ -6235,12 +6289,22 @@ class StreamSfuClient {
6235
6289
  };
6236
6290
  this.sessionId = sessionId || generateUUIDv4();
6237
6291
  this.token = token;
6292
+ this.logger = getLogger(['sfu-client']);
6293
+ const logger = this.logger;
6294
+ const logInterceptor = {
6295
+ interceptUnary(next, method, input, options) {
6296
+ logger('info', `Calling SFU RPC method ${method.name}`);
6297
+ logger('debug', `Method call payload`, { input, options });
6298
+ return next(method, input, options);
6299
+ },
6300
+ };
6238
6301
  this.rpc = createSignalClient({
6239
6302
  baseUrl: url,
6240
6303
  interceptors: [
6241
6304
  withHeaders({
6242
6305
  Authorization: `Bearer ${token}`,
6243
6306
  }),
6307
+ logInterceptor,
6244
6308
  ],
6245
6309
  });
6246
6310
  // Special handling for the ICETrickle kind of events.
@@ -6282,7 +6346,7 @@ const MAX_RETRIES = 5;
6282
6346
  * @param <I> the type of the request object.
6283
6347
  * @param <O> the type of the response object.
6284
6348
  */
6285
- const retryable = (rpc) => __awaiter(void 0, void 0, void 0, function* () {
6349
+ const retryable = (rpc, logger) => __awaiter(void 0, void 0, void 0, function* () {
6286
6350
  var _a;
6287
6351
  let retryAttempt = 0;
6288
6352
  let rpcCallResult;
@@ -6292,9 +6356,11 @@ const retryable = (rpc) => __awaiter(void 0, void 0, void 0, function* () {
6292
6356
  yield sleep(retryInterval(retryAttempt));
6293
6357
  }
6294
6358
  rpcCallResult = yield rpc();
6359
+ logger('info', `SFU RPC response received for ${rpcCallResult.method.name}`);
6360
+ logger('debug', `Response payload`, rpcCallResult);
6295
6361
  // if the RPC call failed, log the error and retry
6296
6362
  if (rpcCallResult.response.error) {
6297
- console.error('SFU Error:', rpcCallResult.response.error);
6363
+ logger('error', 'SFU RPC Error:', rpcCallResult.response.error);
6298
6364
  }
6299
6365
  retryAttempt++;
6300
6366
  } while (((_a = rpcCallResult.response.error) === null || _a === void 0 ? void 0 : _a.shouldRetry) &&
@@ -6977,7 +7043,7 @@ class CallState {
6977
7043
  this.updateParticipant = (sessionId, patch) => {
6978
7044
  const participant = this.findParticipantBySessionId(sessionId);
6979
7045
  if (!participant) {
6980
- console.warn(`Participant with sessionId ${sessionId} not found`);
7046
+ this.logger('warn', `Participant with sessionId ${sessionId} not found`);
6981
7047
  return;
6982
7048
  }
6983
7049
  const thePatch = typeof patch === 'function' ? patch(participant) : patch;
@@ -7026,9 +7092,10 @@ class CallState {
7026
7092
  return p;
7027
7093
  }));
7028
7094
  };
7095
+ this.logger = getLogger(['call-state']);
7029
7096
  this.participants$ = this.participantsSubject.pipe(map$1((ps) => ps.sort(this.sortParticipantsBy)));
7030
7097
  this.localParticipant$ = this.participants$.pipe(map$1((participants) => participants.find(isStreamVideoLocalParticipant)));
7031
- this.remoteParticipants$ = this.participants$.pipe(map$1((participants) => participants.filter((p) => !p.isLoggedInUser)));
7098
+ this.remoteParticipants$ = this.participants$.pipe(map$1((participants) => participants.filter((p) => !p.isLocalParticipant)));
7032
7099
  this.pinnedParticipants$ = this.participants$.pipe(map$1((participants) => participants.filter((p) => p.pinnedAt)));
7033
7100
  this.dominantSpeaker$ = this.participants$.pipe(map$1((participants) => participants.find((p) => p.isDominantSpeaker)));
7034
7101
  this.hasOngoingScreenShare$ = this.participants$.pipe(map$1((participants) => {
@@ -7182,13 +7249,13 @@ const watchCallRejected = (call) => {
7182
7249
  const { call: eventCall } = event;
7183
7250
  const { session: callSession } = eventCall;
7184
7251
  if (!callSession) {
7185
- console.log('No call session provided. Ignoring call.rejected event.');
7252
+ call.logger('warn', 'No call session provided. Ignoring call.rejected event.', event);
7186
7253
  return;
7187
7254
  }
7188
7255
  const rejectedBy = callSession.rejected_by;
7189
7256
  const { members, callingState } = call.state;
7190
7257
  if (callingState !== CallingState.RINGING) {
7191
- console.log('Call is not in ringing mode (it is either accepted or rejected already). Ignoring call.rejected event.');
7258
+ call.logger('warn', 'Call is not in ringing mode (it is either accepted or rejected already). Ignoring call.rejected event.', event);
7192
7259
  return;
7193
7260
  }
7194
7261
  if (call.isCreatedByMe) {
@@ -7196,13 +7263,13 @@ const watchCallRejected = (call) => {
7196
7263
  .filter((m) => m.user_id !== call.currentUserId)
7197
7264
  .every((m) => rejectedBy[m.user_id]);
7198
7265
  if (everyoneElseRejected) {
7199
- console.log('everyone rejected, leaving the call');
7266
+ call.logger('info', 'everyone rejected, leaving the call');
7200
7267
  yield call.leave();
7201
7268
  }
7202
7269
  }
7203
7270
  else {
7204
7271
  if (rejectedBy[eventCall.created_by.id]) {
7205
- console.log('call creator rejected, leaving call');
7272
+ call.logger('info', 'call creator rejected, leaving call');
7206
7273
  yield call.leave();
7207
7274
  }
7208
7275
  }
@@ -7610,7 +7677,7 @@ const watchCallSessionParticipantJoined = (state) => {
7610
7677
  const { user } = event;
7611
7678
  state.setMetadata((metadata) => {
7612
7679
  if (!metadata || !metadata.session) {
7613
- console.warn(`Received call.session_participant_joined event but the metadata structure is invalid.`);
7680
+ state.logger('warn', `Received call.session_participant_joined event but the metadata structure is invalid.`, event);
7614
7681
  return metadata;
7615
7682
  }
7616
7683
  const { session } = metadata;
@@ -7638,7 +7705,7 @@ const watchCallSessionParticipantLeft = (state) => {
7638
7705
  const { user } = event;
7639
7706
  state.setMetadata((metadata) => {
7640
7707
  if (!metadata || !metadata.session) {
7641
- console.warn(`Received call.session_participant_left event but the metadata structure is invalid.`);
7708
+ state.logger('warn', `Received call.session_participant_left event but the metadata structure is invalid.`, event);
7642
7709
  return metadata;
7643
7710
  }
7644
7711
  const { session } = metadata;
@@ -7783,16 +7850,18 @@ const getLocationHint = () => __awaiter(void 0, void 0, void 0, function* () {
7783
7850
  const hintURL = `https://hint.stream-io-video.com/`;
7784
7851
  const abortController = new AbortController();
7785
7852
  const timeoutId = setTimeout(() => abortController.abort(), 1000);
7853
+ const logger = getLogger(['call']);
7786
7854
  try {
7787
7855
  const response = yield fetch(hintURL, {
7788
7856
  method: 'HEAD',
7789
7857
  signal: abortController.signal,
7790
7858
  });
7791
7859
  const awsPop = response.headers.get('x-amz-cf-pop') || 'ERR';
7860
+ logger === null || logger === void 0 ? void 0 : logger('info', `Location header: ${awsPop}`);
7792
7861
  return awsPop.substring(0, 3); // AMS1-P2 -> AMS
7793
7862
  }
7794
7863
  catch (e) {
7795
- console.error(`Failed to get location hint from ${hintURL}`, e);
7864
+ logger === null || logger === void 0 ? void 0 : logger('error', `Failed to get location hint from ${hintURL}`, e);
7796
7865
  return 'ERR';
7797
7866
  }
7798
7867
  finally {
@@ -7831,6 +7900,7 @@ const getCascadingModeParams = () => {
7831
7900
  * Creates a new StatsReporter instance that collects metrics about the ongoing call and reports them to the state store
7832
7901
  */
7833
7902
  const createStatsReporter = ({ subscriber, publisher, state, edgeName, pollingIntervalInMs = 2000, }) => {
7903
+ const logger = getLogger(['stats']);
7834
7904
  const getRawStatsForTrack = (kind, selector) => __awaiter(void 0, void 0, void 0, function* () {
7835
7905
  if (kind === 'subscriber' && subscriber) {
7836
7906
  return subscriber.getStats(selector);
@@ -7839,7 +7909,7 @@ const createStatsReporter = ({ subscriber, publisher, state, edgeName, pollingIn
7839
7909
  return publisher.getStats(selector);
7840
7910
  }
7841
7911
  else {
7842
- console.warn(`Can't retrieve RTC stats for`, kind);
7912
+ logger('warn', `Can't retrieve RTC stats for ${kind}`);
7843
7913
  return undefined;
7844
7914
  }
7845
7915
  });
@@ -7877,7 +7947,9 @@ const createStatsReporter = ({ subscriber, publisher, state, edgeName, pollingIn
7877
7947
  for (let participant of state.participants) {
7878
7948
  if (!sessionIds.has(participant.sessionId))
7879
7949
  continue;
7880
- const kind = participant.isLoggedInUser ? 'publisher' : 'subscriber';
7950
+ const kind = participant.isLocalParticipant
7951
+ ? 'publisher'
7952
+ : 'subscriber';
7881
7953
  try {
7882
7954
  const mergedStream = new MediaStream([
7883
7955
  ...(((_a = participant.videoStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks()) || []),
@@ -7889,7 +7961,7 @@ const createStatsReporter = ({ subscriber, publisher, state, edgeName, pollingIn
7889
7961
  });
7890
7962
  }
7891
7963
  catch (e) {
7892
- console.error(`Failed to collect stats for ${kind}`, participant, e);
7964
+ logger('error', `Failed to collect stats for ${kind} if ${participant.userId}`, e);
7893
7965
  }
7894
7966
  }
7895
7967
  }
@@ -7927,7 +7999,7 @@ const createStatsReporter = ({ subscriber, publisher, state, edgeName, pollingIn
7927
7999
  if (pollingIntervalInMs > 0) {
7928
8000
  const loop = () => __awaiter(void 0, void 0, void 0, function* () {
7929
8001
  yield run().catch((e) => {
7930
- console.log('Failed to collect stats', e);
8002
+ logger('warn', 'Failed to collect stats', e);
7931
8003
  });
7932
8004
  timeoutId = setTimeout(loop, pollingIntervalInMs);
7933
8005
  });
@@ -8470,6 +8542,9 @@ class Call {
8470
8542
  if ([CallingState.JOINED, CallingState.JOINING].includes(this.state.callingState)) {
8471
8543
  throw new Error(`Illegal State: Already joined.`);
8472
8544
  }
8545
+ if (this.state.callingState === CallingState.LEFT) {
8546
+ throw new Error('Illegal State: Cannot join already left call. Create a new Call instance to join a call.');
8547
+ }
8473
8548
  const previousCallingState = this.state.callingState;
8474
8549
  this.state.setCallingState(CallingState.JOINING);
8475
8550
  if ((data === null || data === void 0 ? void 0 : data.ring) && !this.ringing) {
@@ -8525,7 +8600,7 @@ class Call {
8525
8600
  */
8526
8601
  const rejoin = () => __awaiter(this, void 0, void 0, function* () {
8527
8602
  var _g, _h, _j;
8528
- console.log(`Rejoining call ${this.cid} (${this.reconnectAttempts})...`);
8603
+ this.logger('debug', `Rejoining call ${this.cid} (${this.reconnectAttempts})...`);
8529
8604
  this.reconnectAttempts++;
8530
8605
  this.state.setCallingState(CallingState.RECONNECTING);
8531
8606
  // take a snapshot of the current "local participant" state
@@ -8537,7 +8612,7 @@ class Call {
8537
8612
  sfuClient.close(); // clean up previous connection
8538
8613
  yield sleep(retryInterval(this.reconnectAttempts));
8539
8614
  yield this.join(data);
8540
- console.log(`Rejoin: ${this.reconnectAttempts} successful!`);
8615
+ this.logger('info', `Rejoin: ${this.reconnectAttempts} successful!`);
8541
8616
  if (localParticipant && !isReactNative()) {
8542
8617
  const { audioStream, videoStream, screenShareStream: screenShare, } = localParticipant;
8543
8618
  // restore previous publishing state
@@ -8548,7 +8623,7 @@ class Call {
8548
8623
  if (screenShare)
8549
8624
  yield this.publishScreenShareStream(screenShare);
8550
8625
  }
8551
- console.log(`Rejoin: state restored ${this.reconnectAttempts}`);
8626
+ this.logger('info', `Rejoin: state restored ${this.reconnectAttempts}`);
8552
8627
  });
8553
8628
  this.rejoinPromise = rejoin;
8554
8629
  // reconnect if the connection was closed unexpectedly. example:
@@ -8568,12 +8643,12 @@ class Call {
8568
8643
  return;
8569
8644
  if (this.reconnectAttempts < this.maxReconnectAttempts) {
8570
8645
  rejoin().catch(() => {
8571
- console.log(`Rejoin failed for ${this.reconnectAttempts} times. Giving up.`);
8646
+ this.logger('error', `Rejoin failed for ${this.reconnectAttempts} times. Giving up.`);
8572
8647
  this.state.setCallingState(CallingState.RECONNECTING_FAILED);
8573
8648
  });
8574
8649
  }
8575
8650
  else {
8576
- console.log('Reconnect attempts exceeded. Giving up...');
8651
+ this.logger('error', 'Reconnect attempts exceeded. Giving up...');
8577
8652
  this.state.setCallingState(CallingState.RECONNECTING_FAILED);
8578
8653
  }
8579
8654
  });
@@ -8583,15 +8658,15 @@ class Call {
8583
8658
  if (typeof window !== 'undefined' && window.addEventListener) {
8584
8659
  const handleOnOffline = () => {
8585
8660
  window.removeEventListener('offline', handleOnOffline);
8586
- console.log('Join: Going offline...');
8661
+ this.logger('warn', 'Join: Going offline...');
8587
8662
  this.state.setCallingState(CallingState.OFFLINE);
8588
8663
  };
8589
8664
  const handleOnOnline = () => {
8590
8665
  window.removeEventListener('online', handleOnOnline);
8591
8666
  if (this.state.callingState === CallingState.OFFLINE) {
8592
- console.log('Join: Going online...');
8667
+ this.logger('info', 'Join: Going online...');
8593
8668
  rejoin().catch(() => {
8594
- console.log(`Rejoin failed for ${this.reconnectAttempts} times. Giving up.`);
8669
+ this.logger('error', `Rejoin failed for ${this.reconnectAttempts} times. Giving up.`);
8595
8670
  this.state.setCallingState(CallingState.RECONNECTING_FAILED);
8596
8671
  });
8597
8672
  }
@@ -8648,15 +8723,20 @@ class Call {
8648
8723
  clientDetails.sdk = getSdkInfo();
8649
8724
  // 1. wait for the signal server to be ready before sending "joinRequest"
8650
8725
  sfuClient.signalReady
8651
- .catch((err) => console.warn('Signal ready failed', err))
8726
+ .catch((err) => this.logger('error', 'Signal ready failed', err))
8652
8727
  // prepare a generic SDP and send it to the SFU.
8653
8728
  // this is a throw-away SDP that the SFU will use to determine
8654
8729
  // the capabilities of the client (codec support, etc.)
8655
8730
  .then(() => getGenericSdp('recvonly', isRedEnabled, this.streamClient.options.preferredVideoCodec))
8656
- .then((sdp) => sfuClient.join({
8657
- subscriberSdp: sdp || '',
8658
- clientDetails,
8659
- }));
8731
+ .then((sdp) => {
8732
+ const joinRequest = {
8733
+ subscriberSdp: sdp || '',
8734
+ clientDetails,
8735
+ };
8736
+ this.logger('info', 'Sending join request to SFU');
8737
+ this.logger('debug', 'Join request payload', joinRequest);
8738
+ sfuClient.join(joinRequest);
8739
+ });
8660
8740
  // 2. in parallel, wait for the SFU to send us the "joinResponse"
8661
8741
  // this will throw an error if the SFU rejects the join request or
8662
8742
  // fails to respond in time
@@ -8666,22 +8746,22 @@ class Call {
8666
8746
  const startedAt = (callState === null || callState === void 0 ? void 0 : callState.startedAt)
8667
8747
  ? Timestamp.toDate(callState.startedAt)
8668
8748
  : new Date();
8669
- this.state.setParticipants(currentParticipants.map((participant) => (Object.assign(Object.assign({}, participant), { isLoggedInUser: participant.sessionId === sfuClient.sessionId, viewportVisibilityState: VisibilityState.UNKNOWN }))));
8749
+ this.state.setParticipants(currentParticipants.map((participant) => (Object.assign(Object.assign({}, participant), { isLocalParticipant: participant.sessionId === sfuClient.sessionId, viewportVisibilityState: VisibilityState.UNKNOWN }))));
8670
8750
  this.state.setParticipantCount((participantCount === null || participantCount === void 0 ? void 0 : participantCount.total) || 0);
8671
8751
  this.state.setAnonymousParticipantCount((participantCount === null || participantCount === void 0 ? void 0 : participantCount.anonymous) || 0);
8672
8752
  this.state.setStartedAt(startedAt);
8673
8753
  this.reconnectAttempts = 0; // reset the reconnect attempts counter
8674
8754
  this.state.setCallingState(CallingState.JOINED);
8675
- console.log(`Joined call ${this.cid}`);
8755
+ this.logger('info', `Joined call ${this.cid}`);
8676
8756
  }
8677
8757
  catch (err) {
8678
8758
  // join failed, try to rejoin
8679
8759
  if (this.reconnectAttempts < this.maxReconnectAttempts) {
8680
8760
  yield rejoin();
8681
- console.log(`Rejoin ${this.reconnectAttempts} successful!`);
8761
+ this.logger('info', `Rejoin ${this.reconnectAttempts} successful!`);
8682
8762
  }
8683
8763
  else {
8684
- console.log(`Rejoin failed for ${this.reconnectAttempts} times. Giving up.`);
8764
+ this.logger('error', `Rejoin failed for ${this.reconnectAttempts} times. Giving up.`);
8685
8765
  this.state.setCallingState(CallingState.RECONNECTING_FAILED);
8686
8766
  throw new Error('Join failed');
8687
8767
  }
@@ -8706,7 +8786,8 @@ class Call {
8706
8786
  }
8707
8787
  const [videoTrack] = videoStream.getVideoTracks();
8708
8788
  if (!videoTrack) {
8709
- return console.error(`There is no video track in the stream.`);
8789
+ this.logger('error', `There is no video track to publish in the stream.`);
8790
+ return;
8710
8791
  }
8711
8792
  yield this.publisher.publishStream(videoStream, videoTrack, TrackType.VIDEO, opts);
8712
8793
  });
@@ -8729,7 +8810,8 @@ class Call {
8729
8810
  }
8730
8811
  const [audioTrack] = audioStream.getAudioTracks();
8731
8812
  if (!audioTrack) {
8732
- return console.error(`There is no audio track in the stream`);
8813
+ this.logger('error', `There is no audio track in the stream to publish`);
8814
+ return;
8733
8815
  }
8734
8816
  yield this.publisher.publishStream(audioStream, audioTrack, TrackType.AUDIO);
8735
8817
  });
@@ -8751,7 +8833,8 @@ class Call {
8751
8833
  }
8752
8834
  const [screenShareTrack] = screenShareStream.getVideoTracks();
8753
8835
  if (!screenShareTrack) {
8754
- return console.error(`There is no video track in the stream`);
8836
+ this.logger('error', `There is no video track in the screen share stream to publish`);
8837
+ return;
8755
8838
  }
8756
8839
  yield this.publisher.publishStream(screenShareStream, screenShareTrack, TrackType.SCREEN_SHARE);
8757
8840
  });
@@ -8766,7 +8849,7 @@ class Call {
8766
8849
  */
8767
8850
  this.stopPublish = (trackType) => __awaiter(this, void 0, void 0, function* () {
8768
8851
  var _k;
8769
- console.log(`stopPublish`, TrackType[trackType]);
8852
+ this.logger('info', `stopPublish ${TrackType[trackType]}`);
8770
8853
  yield ((_k = this.publisher) === null || _k === void 0 ? void 0 : _k.unpublishStream(trackType));
8771
8854
  });
8772
8855
  /**
@@ -8800,7 +8883,7 @@ class Call {
8800
8883
  const subscriptions = [];
8801
8884
  participants.forEach((p) => {
8802
8885
  // we don't want to subscribe to our own tracks
8803
- if (p.isLoggedInUser)
8886
+ if (p.isLocalParticipant)
8804
8887
  return;
8805
8888
  // NOTE: audio tracks don't have to be requested explicitly
8806
8889
  // as the SFU will implicitly subscribe us to all of them,
@@ -8915,20 +8998,21 @@ class Call {
8915
8998
  const [primaryStream] = e.streams;
8916
8999
  // example: `e3f6aaf8-b03d-4911-be36-83f47d37a76a:TRACK_TYPE_VIDEO`
8917
9000
  const [trackId, trackType] = primaryStream.id.split(':');
8918
- console.log(`Got remote ${trackType} track:`, e.track);
9001
+ this.logger('info', `Got remote ${trackType} track:`);
9002
+ this.logger('debug', `Track: `, e.track);
8919
9003
  const participantToUpdate = this.state.participants.find((p) => p.trackLookupPrefix === trackId);
8920
9004
  if (!participantToUpdate) {
8921
- console.error('Received track for unknown participant', trackId, e);
9005
+ this.logger('error', `'Received track for unknown participant: ${trackId}'`, e);
8922
9006
  return;
8923
9007
  }
8924
9008
  e.track.addEventListener('mute', () => {
8925
- console.log(`Track muted:`, participantToUpdate.userId, `${trackType}:${trackId}`, e.track);
9009
+ this.logger('info', `Track muted: ${participantToUpdate.userId} ${trackType}:${trackId}`);
8926
9010
  });
8927
9011
  e.track.addEventListener('unmute', () => {
8928
- console.log(`Track unmuted:`, participantToUpdate.userId, `${trackType}:${trackId}`, e.track);
9012
+ this.logger('info', `Track unmuted: ${participantToUpdate.userId} ${trackType}:${trackId}`);
8929
9013
  });
8930
9014
  e.track.addEventListener('ended', () => {
8931
- console.log(`Track ended:`, participantToUpdate.userId, `${trackType}:${trackId}`, e.track);
9015
+ this.logger('info', `Track ended: ${participantToUpdate.userId} ${trackType}:${trackId}`);
8932
9016
  });
8933
9017
  const streamKindProp = {
8934
9018
  TRACK_TYPE_AUDIO: 'audioStream',
@@ -8936,12 +9020,12 @@ class Call {
8936
9020
  TRACK_TYPE_SCREEN_SHARE: 'screenShareStream',
8937
9021
  }[trackType];
8938
9022
  if (!streamKindProp) {
8939
- console.error('Unknown track type', trackType);
9023
+ this.logger('error', `Unknown track type: ${trackType}`);
8940
9024
  return;
8941
9025
  }
8942
9026
  const previousStream = participantToUpdate[streamKindProp];
8943
9027
  if (previousStream) {
8944
- console.log(`Cleaning up previous remote tracks`, e.track.kind);
9028
+ this.logger('info', `Cleaning up previous remote tracks: ${e.track.kind}`);
8945
9029
  previousStream.getTracks().forEach((t) => {
8946
9030
  t.stop();
8947
9031
  previousStream.removeTrack(t);
@@ -9241,6 +9325,7 @@ class Call {
9241
9325
  this.streamClient = streamClient;
9242
9326
  this.clientStore = clientStore;
9243
9327
  this.streamClientBasePath = `/call/${this.type}/${this.id}`;
9328
+ this.logger = getLogger(['call']);
9244
9329
  const callTypeConfig = CallTypes.get(type);
9245
9330
  const participantSorter = sortParticipantsBy || callTypeConfig.options.sortParticipantsBy;
9246
9331
  if (participantSorter) {
@@ -9278,7 +9363,7 @@ class Call {
9278
9363
  const hasPermission = this.permissionsContext.hasPermission(permission);
9279
9364
  if (!hasPermission && this.publisher.isPublishing(trackType)) {
9280
9365
  this.stopPublish(trackType).catch((err) => {
9281
- console.error('Error stopping publish', trackType, err);
9366
+ this.logger('error', `Error stopping publish ${trackType}`, err);
9282
9367
  });
9283
9368
  }
9284
9369
  }
@@ -9497,12 +9582,12 @@ class StableWSConnection {
9497
9582
  return;
9498
9583
  const user = this.client.user;
9499
9584
  if (!user) {
9500
- console.error(`User not set, can't connect to WS`);
9585
+ this.client.logger('error', `User not set, can't connect to WS`);
9501
9586
  return;
9502
9587
  }
9503
9588
  const token = this.client._getToken();
9504
9589
  if (!token) {
9505
- console.error(`Token not set, can't connect authenticate`);
9590
+ this.client.logger('error', `Token not set, can't connect authenticate`);
9506
9591
  return;
9507
9592
  }
9508
9593
  const authMessage = {
@@ -9735,7 +9820,7 @@ class StableWSConnection {
9735
9820
  addConnectionEventListeners(this.onlineStatusChanged);
9736
9821
  }
9737
9822
  _log(msg, extra = {}, level = 'info') {
9738
- this.client.logger(level, 'connection:' + msg, Object.assign({ tags: ['connection'] }, extra));
9823
+ this.client.logger(level, 'connection:' + msg, Object.assign({}, extra));
9739
9824
  }
9740
9825
  /**
9741
9826
  * connect - Connect to the WS URL
@@ -10455,7 +10540,7 @@ class WSConnectionFallback {
10455
10540
  addConnectionEventListeners(this._onlineStatusChanged);
10456
10541
  }
10457
10542
  _log(msg, extra = {}, level = 'info') {
10458
- this.client.logger(level, 'WSConnectionFallback:' + msg, Object.assign({ tags: ['connection_fallback', 'connection'] }, extra));
10543
+ this.client.logger(level, 'WSConnectionFallback:' + msg, Object.assign({}, extra));
10459
10544
  }
10460
10545
  _setState(state) {
10461
10546
  this._log(`_setState() - ${state}`);
@@ -10515,7 +10600,7 @@ class StreamClient {
10515
10600
  * If the user id remains the same we don't throw error
10516
10601
  */
10517
10602
  if (this.userID === user.id && this.setUserPromise) {
10518
- console.warn('Consecutive calls to connectUser is detected, ideally you should only call this function once in your app.');
10603
+ this.logger('warn', 'Consecutive calls to connectUser is detected, ideally you should only call this function once in your app.');
10519
10604
  return this.setUserPromise;
10520
10605
  }
10521
10606
  if (this.userID) {
@@ -10523,7 +10608,7 @@ class StreamClient {
10523
10608
  }
10524
10609
  if ((this._isUsingServerAuth() || this.node) &&
10525
10610
  !this.options.allowServerSideConnect) {
10526
- console.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.');
10611
+ 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.');
10527
10612
  }
10528
10613
  // we generate the client id client side
10529
10614
  this.userID = user.id;
@@ -10586,16 +10671,12 @@ class StreamClient {
10586
10671
  throw Error('UserWithId is not set on client, use client.connectUser or client.connectAnonymousUser instead');
10587
10672
  }
10588
10673
  if (((_d = this.wsConnection) === null || _d === void 0 ? void 0 : _d.isConnecting) && this.wsPromise) {
10589
- this.logger('info', 'client:openConnection() - connection already in progress', {
10590
- tags: ['connection', 'client'],
10591
- });
10674
+ this.logger('info', 'client:openConnection() - connection already in progress');
10592
10675
  return this.wsPromise;
10593
10676
  }
10594
10677
  if ((((_e = this.wsConnection) === null || _e === void 0 ? void 0 : _e.isHealthy) || ((_f = this.wsFallback) === null || _f === void 0 ? void 0 : _f.isHealthy())) &&
10595
10678
  this._hasConnectionID()) {
10596
- this.logger('info', 'client:openConnection() - openConnection called twice, healthy connection already exists', {
10597
- tags: ['connection', 'client'],
10598
- });
10679
+ this.logger('info', 'client:openConnection() - openConnection called twice, healthy connection already exists');
10599
10680
  return Promise.resolve();
10600
10681
  }
10601
10682
  this.clientID = `${this.userID}--${randomId()}`;
@@ -10618,9 +10699,7 @@ class StreamClient {
10618
10699
  * https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
10619
10700
  */
10620
10701
  this.disconnectUser = (timeout) => __awaiter(this, void 0, void 0, function* () {
10621
- this.logger('info', 'client:disconnect() - Disconnecting the client', {
10622
- tags: ['connection', 'client'],
10623
- });
10702
+ this.logger('info', 'client:disconnect() - Disconnecting the client');
10624
10703
  // remove the user specific fields
10625
10704
  delete this.user;
10626
10705
  delete this._user;
@@ -10710,7 +10789,8 @@ class StreamClient {
10710
10789
  this.dispatchEvent = (event) => {
10711
10790
  if (!event.received_at)
10712
10791
  event.received_at = new Date();
10713
- console.log(`Dispatching event: ${event.type}`, event);
10792
+ this.logger('info', `Dispatching event: ${event.type}`);
10793
+ this.logger('debug', 'Event payload:', event);
10714
10794
  this._callClientListeners(event);
10715
10795
  };
10716
10796
  this.handleEvent = (messageEvent) => {
@@ -10843,9 +10923,7 @@ class StreamClient {
10843
10923
  if (!(key in this.listeners)) {
10844
10924
  this.listeners[key] = [];
10845
10925
  }
10846
- this.logger('info', `Attaching listener for ${key} event`, {
10847
- tags: ['event', 'client'],
10848
- });
10926
+ this.logger('info', `Attaching listener for ${key} event`);
10849
10927
  this.listeners[key].push(callback);
10850
10928
  return () => {
10851
10929
  this.off(key, callback);
@@ -10863,29 +10941,26 @@ class StreamClient {
10863
10941
  if (!(key in this.listeners)) {
10864
10942
  this.listeners[key] = [];
10865
10943
  }
10866
- this.logger('info', `Removing listener for ${key} event`, {
10867
- tags: ['event', 'client'],
10868
- });
10944
+ this.logger('info', `Removing listener for ${key} event`);
10869
10945
  this.listeners[key] = this.listeners[key].filter((value) => value !== callback);
10870
10946
  }
10871
10947
  _logApiRequest(type, url, data, config) {
10872
- this.logger('info', `client: ${type} - Request - ${url}`, {
10873
- tags: ['api', 'api_request', 'client'],
10874
- url,
10948
+ this.logger('info', `client: ${type} - Request - ${url}`);
10949
+ this.logger('debug', `client: ${type} - Request payload`, {
10875
10950
  payload: data,
10876
10951
  config,
10877
10952
  });
10878
10953
  }
10879
10954
  _logApiResponse(type, url, response) {
10880
10955
  this.logger('info', `client:${type} - Response - url: ${url} > status ${response.status}`, {
10881
- tags: ['api', 'api_response', 'client'],
10882
- url,
10956
+ response,
10957
+ });
10958
+ this.logger('debug', `client:${type} - Response payload`, {
10883
10959
  response,
10884
10960
  });
10885
10961
  }
10886
10962
  _logApiError(type, url, error) {
10887
10963
  this.logger('error', `client:${type} - Error - url: ${url}`, {
10888
- tags: ['api', 'api_response', 'client'],
10889
10964
  url,
10890
10965
  error,
10891
10966
  });
@@ -10960,7 +11035,7 @@ class StreamClient {
10960
11035
  if (this.wsFallback) {
10961
11036
  return yield this.wsFallback.connect();
10962
11037
  }
10963
- console.log('StreamClient.connect: this.wsConnection.connect()');
11038
+ this.logger('info', 'StreamClient.connect: this.wsConnection.connect()');
10964
11039
  // if WSFallback is enabled, ws connect should timeout faster so fallback can try
10965
11040
  return yield this.wsConnection.connect(this.options.enableWSFallback
10966
11041
  ? this.defaultWSTimeoutWithFallback
@@ -10969,9 +11044,11 @@ class StreamClient {
10969
11044
  catch (err) {
10970
11045
  // run fallback only if it's WS/Network error and not a normal API error
10971
11046
  // make sure browser is online before even trying the longpoll
10972
- // @ts-ignore
10973
- if (this.options.enableWSFallback && isWSFailure(err) && isOnline()) {
10974
- this.logger('info', 'client:connect() - WS failed, fallback to longpoll', { tags: ['connection', 'client'] });
11047
+ if (this.options.enableWSFallback &&
11048
+ // @ts-ignore
11049
+ isWSFailure(err) &&
11050
+ isOnline(this.logger)) {
11051
+ this.logger('warn', 'client:connect() - WS failed, fallback to longpoll');
10975
11052
  this.dispatchEvent({ type: 'transport.changed', mode: 'longpoll' });
10976
11053
  this.wsConnection._destroyCurrentWSConnection();
10977
11054
  this.wsConnection.disconnect().then(); // close WS so no retry
@@ -11006,7 +11083,7 @@ class StreamClient {
11006
11083
  }
11007
11084
  getUserAgent() {
11008
11085
  return (this.userAgent ||
11009
- `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.12"}`);
11086
+ `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.14"}`);
11010
11087
  }
11011
11088
  setUserAgent(userAgent) {
11012
11089
  this.userAgent = userAgent;
@@ -11075,7 +11152,10 @@ class StreamClient {
11075
11152
  */
11076
11153
  class StreamVideoClient {
11077
11154
  constructor(apiKeyOrArgs, opts) {
11155
+ var _a, _b;
11156
+ this.logLevel = 'warn';
11078
11157
  this.eventHandlersToUnregister = [];
11158
+ this.logLevels = ['debug', 'info', 'warn', 'error'];
11079
11159
  /**
11080
11160
  * Disconnects the currently connected user from the client.
11081
11161
  *
@@ -11234,11 +11314,30 @@ class StreamVideoClient {
11234
11314
  this.connectionPromise.finally(() => (this.connectionPromise = undefined));
11235
11315
  return this.connectionPromise;
11236
11316
  });
11317
+ this.filterLogs = (logMethod) => {
11318
+ return (logLevel, messeage, extraData, tags) => {
11319
+ if (this.logLevels.indexOf(logLevel) >=
11320
+ this.logLevels.indexOf(this.logLevel)) {
11321
+ logMethod(logLevel, messeage, extraData, tags);
11322
+ }
11323
+ };
11324
+ };
11325
+ let defaultLogger = logToConsole;
11237
11326
  if (typeof apiKeyOrArgs === 'string') {
11238
- this.streamClient = new StreamClient(apiKeyOrArgs, Object.assign({ persistUserOnConnectionFailure: true }, opts));
11327
+ this.logLevel = (opts === null || opts === void 0 ? void 0 : opts.logLevel) || this.logLevel;
11328
+ this.logger = (opts === null || opts === void 0 ? void 0 : opts.logger) || defaultLogger;
11239
11329
  }
11240
11330
  else {
11241
- this.streamClient = new StreamClient(apiKeyOrArgs.apiKey, Object.assign({ persistUserOnConnectionFailure: true }, apiKeyOrArgs.options));
11331
+ this.logLevel = ((_a = apiKeyOrArgs.options) === null || _a === void 0 ? void 0 : _a.logLevel) || this.logLevel;
11332
+ this.logger = ((_b = apiKeyOrArgs.options) === null || _b === void 0 ? void 0 : _b.logger) || defaultLogger;
11333
+ }
11334
+ setLogger(this.filterLogs(defaultLogger));
11335
+ const clientLogger = getLogger(['client']);
11336
+ if (typeof apiKeyOrArgs === 'string') {
11337
+ this.streamClient = new StreamClient(apiKeyOrArgs, Object.assign(Object.assign({ persistUserOnConnectionFailure: true }, opts), { logLevel: this.logLevel, logger: clientLogger }));
11338
+ }
11339
+ else {
11340
+ this.streamClient = new StreamClient(apiKeyOrArgs.apiKey, Object.assign(Object.assign({ persistUserOnConnectionFailure: true }, apiKeyOrArgs.options), { logLevel: this.logLevel, logger: clientLogger }));
11242
11341
  this.user = apiKeyOrArgs.user;
11243
11342
  this.token = apiKeyOrArgs.token || apiKeyOrArgs.tokenProvider;
11244
11343
  if (this.user) {
@@ -11300,7 +11399,7 @@ class StreamVideoClient {
11300
11399
  },
11301
11400
  sort: [{ field: 'cid', direction: 1 }],
11302
11401
  }).catch((err) => {
11303
- console.warn('Failed to re-watch calls', err);
11402
+ this.logger('error', 'Failed to re-watch calls', err);
11304
11403
  });
11305
11404
  }
11306
11405
  }
@@ -11310,7 +11409,7 @@ class StreamVideoClient {
11310
11409
  return;
11311
11410
  const { call, members } = event;
11312
11411
  if (userToConnect.id === call.created_by.id) {
11313
- console.warn('Received `call.created` sent by the current user');
11412
+ this.logger('warn', 'Received `call.created` sent by the current user');
11314
11413
  return;
11315
11414
  }
11316
11415
  this.writeableStateStore.registerCall(new Call({
@@ -11327,7 +11426,7 @@ class StreamVideoClient {
11327
11426
  return;
11328
11427
  const { call, members } = event;
11329
11428
  if (userToConnect.id === call.created_by.id) {
11330
- console.warn('Received `call.ring` sent by the current user');
11429
+ this.logger('warn', 'Received `call.ring` sent by the current user');
11331
11430
  return;
11332
11431
  }
11333
11432
  // The call might already be tracked by the client,
@@ -11394,7 +11493,10 @@ const getDevices = (constraints) => {
11394
11493
  });
11395
11494
  })
11396
11495
  .catch((error) => {
11397
- console.error('Failed to get devices', error);
11496
+ const logger = getLogger(['devices']);
11497
+ if (logger) {
11498
+ logger('error', 'Failed to get devices', error);
11499
+ }
11398
11500
  subscriber.error(error);
11399
11501
  });
11400
11502
  });
@@ -11465,11 +11567,15 @@ const getAudioOutputDevices = () => {
11465
11567
  return audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audiooutput')));
11466
11568
  };
11467
11569
  const getStream = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
11570
+ var _a;
11468
11571
  try {
11469
11572
  return yield navigator.mediaDevices.getUserMedia(constraints);
11470
11573
  }
11471
11574
  catch (e) {
11472
- console.error(`Failed get user media`, constraints, e);
11575
+ (_a = getLogger(['devices'])) === null || _a === void 0 ? void 0 : _a('error', `Failed get user media`, {
11576
+ error: e,
11577
+ constraints: constraints,
11578
+ });
11473
11579
  throw e;
11474
11580
  }
11475
11581
  });
@@ -11512,11 +11618,12 @@ const getVideoStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, f
11512
11618
  * @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
11513
11619
  */
11514
11620
  const getScreenShareStream = (options) => __awaiter(void 0, void 0, void 0, function* () {
11621
+ var _b;
11515
11622
  try {
11516
11623
  return yield navigator.mediaDevices.getDisplayMedia(Object.assign({ video: true, audio: false }, options));
11517
11624
  }
11518
11625
  catch (e) {
11519
- console.error('Failed to get screen share stream', e);
11626
+ (_b = getLogger(['devices'])) === null || _b === void 0 ? void 0 : _b('error', 'Failed to get screen share stream', e);
11520
11627
  throw e;
11521
11628
  }
11522
11629
  });
@@ -11699,5 +11806,5 @@ var browsers = /*#__PURE__*/Object.freeze({
11699
11806
  isSafari: isSafari
11700
11807
  });
11701
11808
 
11702
- 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 };
11809
+ 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 };
11703
11810
  //# sourceMappingURL=index.es.js.map