@stream-io/video-client 1.6.0 → 1.6.2

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 CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ## [1.6.2](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.6.1...@stream-io/video-client-1.6.2) (2024-09-09)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * prioritize h264 baseline profile ([#1482](https://github.com/GetStream/stream-video-js/issues/1482)) ([3ea3c5e](https://github.com/GetStream/stream-video-js/commit/3ea3c5ecf57b50d3f909d59a96811f636b07d8aa))
11
+
12
+ ## [1.6.1](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.6.0...@stream-io/video-client-1.6.1) (2024-09-05)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * update state.endedAt after the SFU terminates the call ([#1477](https://github.com/GetStream/stream-video-js/issues/1477)) ([135b11f](https://github.com/GetStream/stream-video-js/commit/135b11f2e29f486f2f43b9ac2a84848d0fd0b5b4))
18
+
5
19
  ## [1.6.0](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.5.2...@stream-io/video-client-1.6.0) (2024-09-03)
6
20
 
7
21
 
@@ -6735,7 +6735,7 @@ const logLevels = Object.freeze({
6735
6735
  warn: 3,
6736
6736
  error: 4,
6737
6737
  });
6738
- let logger$2;
6738
+ let logger$1;
6739
6739
  let level = 'info';
6740
6740
  const logToConsole = (logLevel, message, ...args) => {
6741
6741
  let logMethod;
@@ -6769,7 +6769,7 @@ const logToConsole = (logLevel, message, ...args) => {
6769
6769
  logMethod(message, ...args);
6770
6770
  };
6771
6771
  const setLogger = (l, lvl) => {
6772
- logger$2 = l;
6772
+ logger$1 = l;
6773
6773
  if (lvl) {
6774
6774
  setLogLevel(lvl);
6775
6775
  }
@@ -6779,7 +6779,7 @@ const setLogLevel = (l) => {
6779
6779
  };
6780
6780
  const getLogLevel = () => level;
6781
6781
  const getLogger = (withTags) => {
6782
- const loggerMethod = logger$2 || logToConsole;
6782
+ const loggerMethod = logger$1 || logToConsole;
6783
6783
  const tags = (withTags || []).filter(Boolean).join(':');
6784
6784
  const result = (logLevel, message, ...args) => {
6785
6785
  if (logLevels[logLevel] >= logLevels[level]) {
@@ -6820,50 +6820,74 @@ const retryable = async (rpc, signal) => {
6820
6820
  return result;
6821
6821
  };
6822
6822
 
6823
+ /**
6824
+ * Returns back a list of sorted codecs, with the preferred codec first.
6825
+ *
6826
+ * @param kind the kind of codec to get.
6827
+ * @param preferredCodec the codec to prioritize (vp8, h264, vp9, av1...).
6828
+ * @param codecToRemove the codec to exclude from the list.
6829
+ */
6823
6830
  const getPreferredCodecs = (kind, preferredCodec, codecToRemove) => {
6824
- const logger = getLogger(['codecs']);
6825
- if (!('getCapabilities' in RTCRtpReceiver)) {
6826
- logger('warn', 'RTCRtpReceiver.getCapabilities is not supported');
6831
+ if (!('getCapabilities' in RTCRtpReceiver))
6827
6832
  return;
6828
- }
6829
- const cap = RTCRtpReceiver.getCapabilities(kind);
6830
- if (!cap)
6833
+ const capabilities = RTCRtpReceiver.getCapabilities(kind);
6834
+ if (!capabilities)
6831
6835
  return;
6832
- const matched = [];
6833
- const partialMatched = [];
6834
- const unmatched = [];
6835
- cap.codecs.forEach((c) => {
6836
- const codec = c.mimeType.toLowerCase();
6837
- logger('debug', `Found supported codec: ${codec}`);
6838
- const shouldRemoveCodec = codecToRemove && codec === `${kind}/${codecToRemove.toLowerCase()}`;
6836
+ const preferred = [];
6837
+ const partiallyPreferred = [];
6838
+ const unpreferred = [];
6839
+ const preferredCodecMimeType = `${kind}/${preferredCodec.toLowerCase()}`;
6840
+ const codecToRemoveMimeType = codecToRemove && `${kind}/${codecToRemove.toLowerCase()}`;
6841
+ for (const codec of capabilities.codecs) {
6842
+ const codecMimeType = codec.mimeType.toLowerCase();
6843
+ const shouldRemoveCodec = codecMimeType === codecToRemoveMimeType;
6839
6844
  if (shouldRemoveCodec)
6840
- return;
6841
- const matchesCodec = codec === `${kind}/${preferredCodec.toLowerCase()}`;
6842
- if (!matchesCodec) {
6843
- unmatched.push(c);
6844
- return;
6845
+ continue; // skip this codec
6846
+ const isPreferredCodec = codecMimeType === preferredCodecMimeType;
6847
+ if (!isPreferredCodec) {
6848
+ unpreferred.push(codec);
6849
+ continue;
6845
6850
  }
6846
- // for h264 codecs that have sdpFmtpLine available, use only if the
6847
- // profile-level-id is 42e01f for cross-browser compatibility
6848
- if (codec === 'h264') {
6849
- if (c.sdpFmtpLine && c.sdpFmtpLine.includes('profile-level-id=42e01f')) {
6850
- matched.push(c);
6851
- }
6852
- else {
6853
- partialMatched.push(c);
6854
- }
6855
- return;
6851
+ // h264 is a special case, we want to prioritize the baseline codec with
6852
+ // profile-level-id is 42e01f and packetization-mode=0 for maximum
6853
+ // cross-browser compatibility.
6854
+ // this branch covers the other cases, such as vp8.
6855
+ if (codecMimeType !== 'video/h264') {
6856
+ preferred.push(codec);
6857
+ continue;
6856
6858
  }
6857
- matched.push(c);
6858
- });
6859
- return [...matched, ...partialMatched, ...unmatched];
6859
+ const sdpFmtpLine = codec.sdpFmtpLine;
6860
+ if (!sdpFmtpLine || !sdpFmtpLine.includes('profile-level-id=42e01f')) {
6861
+ // this is not the baseline h264 codec, prioritize it lower
6862
+ partiallyPreferred.push(codec);
6863
+ continue;
6864
+ }
6865
+ // packetization-mode mode is optional; when not present it defaults to 0:
6866
+ // https://datatracker.ietf.org/doc/html/rfc6184#section-6.2
6867
+ if (sdpFmtpLine.includes('packetization-mode=0') ||
6868
+ !sdpFmtpLine.includes('packetization-mode')) {
6869
+ preferred.unshift(codec);
6870
+ }
6871
+ else {
6872
+ preferred.push(codec);
6873
+ }
6874
+ }
6875
+ // return a sorted list of codecs, with the preferred codecs first
6876
+ return [...preferred, ...partiallyPreferred, ...unpreferred];
6860
6877
  };
6878
+ /**
6879
+ * Returns a generic SDP for the given direction.
6880
+ * We use this SDP to send it as part of our JoinRequest so that the SFU
6881
+ * can use it to determine client's codec capabilities.
6882
+ *
6883
+ * @param direction the direction of the transceiver.
6884
+ */
6861
6885
  const getGenericSdp = async (direction) => {
6862
6886
  const tempPc = new RTCPeerConnection();
6863
6887
  tempPc.addTransceiver('video', { direction });
6864
6888
  tempPc.addTransceiver('audio', { direction });
6865
6889
  const offer = await tempPc.createOffer();
6866
- let sdp = offer.sdp ?? '';
6890
+ const sdp = offer.sdp ?? '';
6867
6891
  tempPc.getTransceivers().forEach((t) => {
6868
6892
  t.stop?.();
6869
6893
  });
@@ -7882,6 +7906,13 @@ class CallState {
7882
7906
  this.setOwnCapabilities = (capabilities) => {
7883
7907
  return this.setCurrentValue(this.ownCapabilitiesSubject, capabilities);
7884
7908
  };
7909
+ /**
7910
+ * Sets the time when this call has been ended.
7911
+ * @param endedAt the time when this call has been ended.
7912
+ */
7913
+ this.setEndedAt = (endedAt) => {
7914
+ return this.setCurrentValue(this.endedAtSubject, endedAt);
7915
+ };
7885
7916
  /**
7886
7917
  * Will try to find the participant with the given sessionId in the current call.
7887
7918
  *
@@ -8068,7 +8099,7 @@ class CallState {
8068
8099
  this.setCurrentValue(this.createdAtSubject, new Date(call.created_at));
8069
8100
  this.setCurrentValue(this.updatedAtSubject, new Date(call.updated_at));
8070
8101
  this.setCurrentValue(this.startsAtSubject, call.starts_at ? new Date(call.starts_at) : undefined);
8071
- this.setCurrentValue(this.endedAtSubject, call.ended_at ? new Date(call.ended_at) : undefined);
8102
+ this.setEndedAt(call.ended_at ? new Date(call.ended_at) : undefined);
8072
8103
  this.setCurrentValue(this.createdBySubject, call.created_by);
8073
8104
  this.setCurrentValue(this.customSubject, call.custom);
8074
8105
  this.setCurrentValue(this.egressSubject, call.egress);
@@ -8717,7 +8748,7 @@ const enableHighQualityAudio = (sdp, trackMid, maxBitrate = 510000) => {
8717
8748
  return SDP.write(parsedSdp);
8718
8749
  };
8719
8750
 
8720
- const version = "1.6.0" ;
8751
+ const version = "1.6.2" ;
8721
8752
  const [major, minor, patch] = version.split('.');
8722
8753
  let sdkInfo = {
8723
8754
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -10007,15 +10038,37 @@ const watchCallRejected = (call) => {
10007
10038
  * Event handler that watches the delivery of `call.ended` Websocket event.
10008
10039
  */
10009
10040
  const watchCallEnded = (call) => {
10010
- return async function onCallEnded() {
10041
+ return function onCallEnded() {
10011
10042
  const { callingState } = call.state;
10012
10043
  if (callingState === CallingState.RINGING ||
10013
10044
  callingState === CallingState.JOINED ||
10014
10045
  callingState === CallingState.JOINING) {
10015
- await call.leave({ reason: 'call.ended event received' });
10046
+ call.leave({ reason: 'call.ended event received' }).catch((err) => {
10047
+ call.logger('error', 'Failed to leave call after call.ended ', err);
10048
+ });
10016
10049
  }
10017
10050
  };
10018
10051
  };
10052
+ /**
10053
+ * Watches for `callEnded` events.
10054
+ */
10055
+ const watchSfuCallEnded = (call) => {
10056
+ return call.on('callEnded', async (e) => {
10057
+ if (call.state.callingState === CallingState.LEFT)
10058
+ return;
10059
+ try {
10060
+ // `call.ended` event arrived after the call is already left
10061
+ // and all event handlers are detached. We need to manually
10062
+ // update the call state to reflect the call has ended.
10063
+ call.state.setEndedAt(new Date());
10064
+ const reason = CallEndedReason[e.reason];
10065
+ await call.leave({ reason: `callEnded received: ${reason}` });
10066
+ }
10067
+ catch (err) {
10068
+ call.logger('error', 'Failed to leave call after being ended by the SFU', err);
10069
+ }
10070
+ });
10071
+ };
10019
10072
 
10020
10073
  /**
10021
10074
  * Event handler that watches for `callGrantsUpdated` events.
@@ -10043,7 +10096,6 @@ const watchCallGrantsUpdated = (state) => {
10043
10096
  };
10044
10097
  };
10045
10098
 
10046
- const logger$1 = getLogger(['events']);
10047
10099
  /**
10048
10100
  * An event responder which handles the `changePublishQuality` event.
10049
10101
  */
@@ -10089,7 +10141,7 @@ const watchLiveEnded = (dispatcher, call) => {
10089
10141
  return;
10090
10142
  if (!call.permissionsContext.hasPermission(OwnCapability.JOIN_BACKSTAGE)) {
10091
10143
  call.leave({ reason: 'live ended' }).catch((err) => {
10092
- logger$1('error', 'Failed to leave call after live ended', err);
10144
+ call.logger('error', 'Failed to leave call after live ended', err);
10093
10145
  });
10094
10146
  }
10095
10147
  });
@@ -10101,8 +10153,9 @@ const watchSfuErrorReports = (dispatcher) => {
10101
10153
  return dispatcher.on('error', (e) => {
10102
10154
  if (!e.error)
10103
10155
  return;
10156
+ const logger = getLogger(['SfuClient']);
10104
10157
  const { error, reconnectStrategy } = e;
10105
- logger$1('error', 'SFU reported error', {
10158
+ logger('error', 'SFU reported error', {
10106
10159
  code: ErrorCode[error.code],
10107
10160
  reconnectStrategy: WebsocketReconnectStrategy[reconnectStrategy],
10108
10161
  message: error.message,
@@ -10120,17 +10173,6 @@ const watchPinsUpdated = (state) => {
10120
10173
  state.setServerSidePins(pins);
10121
10174
  };
10122
10175
  };
10123
- /**
10124
- * Watches for `callEnded` events.
10125
- */
10126
- const watchSfuCallEnded = (call) => {
10127
- return call.on('callEnded', (e) => {
10128
- const reason = CallEndedReason[e.reason];
10129
- call.leave({ reason }).catch((err) => {
10130
- logger$1('error', 'Failed to leave call after call ended by the SFU', err);
10131
- });
10132
- });
10133
- };
10134
10176
 
10135
10177
  /**
10136
10178
  * An event handler that handles soft mutes.
@@ -16050,7 +16092,7 @@ class StreamClient {
16050
16092
  });
16051
16093
  };
16052
16094
  this.getUserAgent = () => {
16053
- const version = "1.6.0" ;
16095
+ const version = "1.6.2" ;
16054
16096
  return (this.userAgent ||
16055
16097
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
16056
16098
  };