@stream-io/video-client 0.0.2-alpha.8 → 0.0.3

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/dist/index.cjs.js CHANGED
@@ -5469,7 +5469,7 @@ const defaultTargetResolution = {
5469
5469
  const findOptimalVideoLayers = (videoTrack, targetResolution = defaultTargetResolution) => {
5470
5470
  const optimalVideoLayers = [];
5471
5471
  const settings = videoTrack.getSettings();
5472
- const { width: w = 0, height: h = 0 } = settings;
5472
+ const { width: w = targetResolution.width, height: h = targetResolution.height, } = settings;
5473
5473
  const maxBitrate = getComputedMaxBitrate(targetResolution, w, h);
5474
5474
  let downscaleFactor = 1;
5475
5475
  ['f', 'h', 'q'].forEach((rid) => {
@@ -5737,14 +5737,13 @@ class Publisher {
5737
5737
  };
5738
5738
  this.updateVideoPublishQuality = (enabledRids) => __awaiter(this, void 0, void 0, function* () {
5739
5739
  var _a;
5740
- console.log('Updating publish quality, qualities requested by SFU:', enabledRids);
5740
+ console.log('Update publish quality, requested rids by SFU:', enabledRids);
5741
5741
  const videoSender = (_a = this.transceiverRegistry[TrackType.VIDEO]) === null || _a === void 0 ? void 0 : _a.sender;
5742
5742
  if (!videoSender)
5743
5743
  return;
5744
5744
  const params = videoSender.getParameters();
5745
5745
  let changed = false;
5746
5746
  params.encodings.forEach((enc) => {
5747
- console.log(enc.rid, enc.active);
5748
5747
  // flip 'active' flag only when necessary
5749
5748
  const shouldEnable = enabledRids.includes(enc.rid);
5750
5749
  if (shouldEnable !== enc.active) {
@@ -5757,6 +5756,10 @@ class Publisher {
5757
5756
  console.warn('No suitable video encoding quality found');
5758
5757
  }
5759
5758
  yield videoSender.setParameters(params);
5759
+ console.log(`Update publish quality, enabled rids: ${params.encodings
5760
+ .filter((e) => e.active)
5761
+ .map((e) => e.rid)
5762
+ .join(', ')}`);
5760
5763
  }
5761
5764
  });
5762
5765
  this.getCodecPreferences = (trackType, preferredCodec) => {
@@ -6132,8 +6135,9 @@ class StreamSfuClient {
6132
6135
  * @param url the URL of the SFU.
6133
6136
  * @param wsEndpoint the WebSocket endpoint of the SFU.
6134
6137
  * @param token the JWT token to use for authentication.
6138
+ * @param sessionId the `sessionId` of the currently connected participant.
6135
6139
  */
6136
- constructor(dispatcher, url, wsEndpoint, token) {
6140
+ constructor({ dispatcher, url, wsEndpoint, token, sessionId, }) {
6137
6141
  /**
6138
6142
  * A buffer for ICE Candidates that are received before
6139
6143
  * the PeerConnections are ready to handle them.
@@ -6218,7 +6222,7 @@ class StreamSfuClient {
6218
6222
  }
6219
6223
  }, this.unhealthyTimeoutInMs);
6220
6224
  };
6221
- this.sessionId = generateUUIDv4();
6225
+ this.sessionId = sessionId || generateUUIDv4();
6222
6226
  this.token = token;
6223
6227
  this.rpc = createSignalClient({
6224
6228
  baseUrl: url,
@@ -6619,6 +6623,12 @@ class CallState {
6619
6623
  * @internal
6620
6624
  */
6621
6625
  this.membersSubject = new rxjs.BehaviorSubject([]);
6626
+ /**
6627
+ * The list of capabilities of the current user.
6628
+ *
6629
+ * @private
6630
+ */
6631
+ this.ownCapabilitiesSubject = new rxjs.BehaviorSubject([]);
6622
6632
  /**
6623
6633
  * The calling state.
6624
6634
  *
@@ -6801,6 +6811,15 @@ class CallState {
6801
6811
  this.setMembers = (members) => {
6802
6812
  this.setCurrentValue(this.membersSubject, members);
6803
6813
  };
6814
+ /**
6815
+ * Sets the own capabilities.
6816
+ *
6817
+ * @internal
6818
+ * @param capabilities the capabilities to set.
6819
+ */
6820
+ this.setOwnCapabilities = (capabilities) => {
6821
+ return this.setCurrentValue(this.ownCapabilitiesSubject, capabilities);
6822
+ };
6804
6823
  /**
6805
6824
  * Will try to find the participant with the given sessionId in the current call.
6806
6825
  *
@@ -6890,6 +6909,7 @@ class CallState {
6890
6909
  this.callRecordingList$ = this.callRecordingListSubject.asObservable();
6891
6910
  this.metadata$ = this.metadataSubject.asObservable();
6892
6911
  this.members$ = this.membersSubject.asObservable();
6912
+ this.ownCapabilities$ = this.ownCapabilitiesSubject.asObservable();
6893
6913
  this.callingState$ = this.callingStateSubject.asObservable();
6894
6914
  }
6895
6915
  /**
@@ -6985,6 +7005,12 @@ class CallState {
6985
7005
  get members() {
6986
7006
  return this.getCurrentValue(this.members$);
6987
7007
  }
7008
+ /**
7009
+ * The capabilities of the current user for the current call.
7010
+ */
7011
+ get ownCapabilities() {
7012
+ return this.getCurrentValue(this.ownCapabilities$);
7013
+ }
6988
7014
  }
6989
7015
 
6990
7016
  class StreamVideoWriteableStateStore {
@@ -7249,7 +7275,10 @@ const watchCallPermissionRequest = (state) => {
7249
7275
  return function onCallPermissionRequest(event) {
7250
7276
  if (event.type !== 'call.permission_request')
7251
7277
  return;
7252
- state.setCallPermissionRequest(event);
7278
+ const { localParticipant } = state;
7279
+ if (event.user.id !== (localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.userId)) {
7280
+ state.setCallPermissionRequest(event);
7281
+ }
7253
7282
  };
7254
7283
  };
7255
7284
  /**
@@ -7261,7 +7290,7 @@ const watchCallPermissionsUpdated = (state) => {
7261
7290
  return;
7262
7291
  const { localParticipant } = state;
7263
7292
  if (event.user.id === (localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.userId)) {
7264
- state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { own_capabilities: event.own_capabilities })));
7293
+ state.setOwnCapabilities(event.own_capabilities);
7265
7294
  }
7266
7295
  };
7267
7296
  };
@@ -7272,7 +7301,6 @@ const watchCallPermissionsUpdated = (state) => {
7272
7301
  */
7273
7302
  const watchCallGrantsUpdated = (state) => {
7274
7303
  return function onCallGrantsUpdated(event) {
7275
- var _a;
7276
7304
  if (event.eventPayload.oneofKind !== 'callGrantsUpdated')
7277
7305
  return;
7278
7306
  const { currentGrants } = event.eventPayload.callGrantsUpdated;
@@ -7283,15 +7311,13 @@ const watchCallGrantsUpdated = (state) => {
7283
7311
  [OwnCapability.SEND_VIDEO]: canPublishVideo,
7284
7312
  [OwnCapability.SCREENSHARE]: canScreenshare,
7285
7313
  };
7286
- const nextCapabilities = (((_a = state.metadata) === null || _a === void 0 ? void 0 : _a.own_capabilities) || []).filter((capability) => update[capability] !== false);
7314
+ const nextCapabilities = state.ownCapabilities.filter((capability) => update[capability] !== false);
7287
7315
  Object.entries(update).forEach(([capability, value]) => {
7288
7316
  if (value && !nextCapabilities.includes(capability)) {
7289
7317
  nextCapabilities.push(capability);
7290
7318
  }
7291
7319
  });
7292
- state.setMetadata((metadata) => {
7293
- return Object.assign(Object.assign({}, metadata), { own_capabilities: nextCapabilities });
7294
- });
7320
+ state.setOwnCapabilities(nextCapabilities);
7295
7321
  }
7296
7322
  };
7297
7323
  };
@@ -7584,10 +7610,7 @@ const watchCallSessionStarted = (state) => {
7584
7610
  return function onCallSessionStarted(event) {
7585
7611
  if (event.type !== 'call.session_started')
7586
7612
  return;
7587
- const { call } = event;
7588
- state.setMetadata((metadata) => (Object.assign(Object.assign({}, call), {
7589
- // FIXME OL: temporary, until the backend sends the own_capabilities
7590
- own_capabilities: (metadata === null || metadata === void 0 ? void 0 : metadata.own_capabilities) || [] })));
7613
+ state.setMetadata(event.call);
7591
7614
  };
7592
7615
  };
7593
7616
  /**
@@ -7599,10 +7622,7 @@ const watchCallSessionEnded = (state) => {
7599
7622
  return function onCallSessionEnded(event) {
7600
7623
  if (event.type !== 'call.session_ended')
7601
7624
  return;
7602
- const { call } = event;
7603
- state.setMetadata((metadata) => (Object.assign(Object.assign({}, call), {
7604
- // FIXME OL: temporary, until the backend sends the own_capabilities
7605
- own_capabilities: (metadata === null || metadata === void 0 ? void 0 : metadata.own_capabilities) || [] })));
7625
+ state.setMetadata(event.call);
7606
7626
  };
7607
7627
  };
7608
7628
  /**
@@ -7764,13 +7784,14 @@ const registerRingingCallEventHandlers = (call) => {
7764
7784
  const join = (httpClient, type, id, data) => __awaiter(void 0, void 0, void 0, function* () {
7765
7785
  yield httpClient.connectionIdPromise;
7766
7786
  const joinCallResponse = yield doJoin(httpClient, type, id, data);
7767
- const { call, credentials, members } = joinCallResponse;
7787
+ const { call, credentials, members, own_capabilities } = joinCallResponse;
7768
7788
  return {
7769
7789
  connectionConfig: toRtcConfiguration(credentials.ice_servers),
7770
7790
  sfuServer: credentials.server,
7771
7791
  token: credentials.token,
7772
7792
  metadata: call,
7773
7793
  members,
7794
+ ownCapabilities: own_capabilities,
7774
7795
  };
7775
7796
  });
7776
7797
  const doJoin = (httpClient, type, id, data) => __awaiter(void 0, void 0, void 0, function* () {
@@ -7787,9 +7808,12 @@ const doJoin = (httpClient, type, id, data) => __awaiter(void 0, void 0, void 0,
7787
7808
  });
7788
7809
  const getLocationHint = () => __awaiter(void 0, void 0, void 0, function* () {
7789
7810
  const hintURL = `https://hint.stream-io-video.com/`;
7811
+ const abortController = new AbortController();
7812
+ const timeoutId = setTimeout(() => abortController.abort(), 1000);
7790
7813
  try {
7791
7814
  const response = yield fetch(hintURL, {
7792
7815
  method: 'HEAD',
7816
+ signal: abortController.signal,
7793
7817
  });
7794
7818
  const awsPop = response.headers.get('x-amz-cf-pop') || 'ERR';
7795
7819
  return awsPop.substring(0, 3); // AMS1-P2 -> AMS
@@ -7798,6 +7822,9 @@ const getLocationHint = () => __awaiter(void 0, void 0, void 0, function* () {
7798
7822
  console.error(`Failed to get location hint from ${hintURL}`, e);
7799
7823
  return 'ERR';
7800
7824
  }
7825
+ finally {
7826
+ clearTimeout(timeoutId);
7827
+ }
7801
7828
  });
7802
7829
  const toRtcConfiguration = (config) => {
7803
7830
  if (!config || config.length === 0)
@@ -8300,7 +8327,7 @@ class Call {
8300
8327
  * Use the [`StreamVideoClient.call`](./StreamVideoClient.md/#call)
8301
8328
  * method to construct a `Call` instance.
8302
8329
  */
8303
- constructor({ type, id, streamClient, metadata, members, sortParticipantsBy, clientStore, ringing = false, watching = false, }) {
8330
+ constructor({ type, id, streamClient, metadata, members, ownCapabilities, sortParticipantsBy, clientStore, ringing = false, watching = false, }) {
8304
8331
  /**
8305
8332
  * ViewportTracker instance
8306
8333
  */
@@ -8392,6 +8419,7 @@ class Call {
8392
8419
  }
8393
8420
  this.state.setMetadata(response.call);
8394
8421
  this.state.setMembers(response.members);
8422
+ this.state.setOwnCapabilities(response.own_capabilities);
8395
8423
  if (this.streamClient._hasConnectionID()) {
8396
8424
  this.watching = true;
8397
8425
  this.clientStore.registerCall(this);
@@ -8410,6 +8438,7 @@ class Call {
8410
8438
  }
8411
8439
  this.state.setMetadata(response.call);
8412
8440
  this.state.setMembers(response.members);
8441
+ this.state.setOwnCapabilities(response.own_capabilities);
8413
8442
  if (this.streamClient._hasConnectionID()) {
8414
8443
  this.watching = true;
8415
8444
  this.clientStore.registerCall(this);
@@ -8456,7 +8485,7 @@ class Call {
8456
8485
  * @returns a promise which resolves once the call join-flow has finished.
8457
8486
  */
8458
8487
  this.join = (data) => __awaiter(this, void 0, void 0, function* () {
8459
- var _e;
8488
+ var _e, _f;
8460
8489
  if ([exports.CallingState.JOINED, exports.CallingState.JOINING].includes(this.state.callingState)) {
8461
8490
  throw new Error(`Illegal State: Already joined.`);
8462
8491
  }
@@ -8476,6 +8505,7 @@ class Call {
8476
8505
  const call = yield join(this.streamClient, this.type, this.id, data);
8477
8506
  this.state.setMetadata(call.metadata);
8478
8507
  this.state.setMembers(call.members);
8508
+ this.state.setOwnCapabilities(call.ownCapabilities);
8479
8509
  connectionConfig = call.connectionConfig;
8480
8510
  sfuServer = call.sfuServer;
8481
8511
  sfuToken = call.token;
@@ -8501,21 +8531,28 @@ class Call {
8501
8531
  const sfuWsUrlParam = params.get('sfuWsUrl');
8502
8532
  sfuWsUrl = sfuWsUrlParam || sfuServer.ws_endpoint;
8503
8533
  }
8504
- const sfuClient = (this.sfuClient = new StreamSfuClient(this.dispatcher, sfuUrl, sfuWsUrl, sfuToken));
8534
+ const previousSessionId = (_e = this.sfuClient) === null || _e === void 0 ? void 0 : _e.sessionId;
8535
+ const sfuClient = (this.sfuClient = new StreamSfuClient({
8536
+ dispatcher: this.dispatcher,
8537
+ url: sfuUrl,
8538
+ wsEndpoint: sfuWsUrl,
8539
+ token: sfuToken,
8540
+ sessionId: previousSessionId,
8541
+ }));
8505
8542
  /**
8506
8543
  * A closure which hides away the re-connection logic.
8507
8544
  */
8508
8545
  const rejoin = () => __awaiter(this, void 0, void 0, function* () {
8509
- var _f, _g, _h;
8546
+ var _g, _h, _j;
8510
8547
  console.log(`Rejoining call ${this.cid} (${this.reconnectAttempts})...`);
8511
8548
  this.reconnectAttempts++;
8512
8549
  this.state.setCallingState(exports.CallingState.RECONNECTING);
8513
8550
  // take a snapshot of the current "local participant" state
8514
8551
  // we'll need it for restoring the previous publishing state later
8515
8552
  const localParticipant = this.state.localParticipant;
8516
- (_f = this.subscriber) === null || _f === void 0 ? void 0 : _f.close();
8517
- (_g = this.publisher) === null || _g === void 0 ? void 0 : _g.stopPublishing({ stopTracks: false });
8518
- (_h = this.statsReporter) === null || _h === void 0 ? void 0 : _h.stop();
8553
+ (_g = this.subscriber) === null || _g === void 0 ? void 0 : _g.close();
8554
+ (_h = this.publisher) === null || _h === void 0 ? void 0 : _h.stopPublishing({ stopTracks: false });
8555
+ (_j = this.statsReporter) === null || _j === void 0 ? void 0 : _j.stop();
8519
8556
  sfuClient.close(); // clean up previous connection
8520
8557
  yield sleep(retryInterval(this.reconnectAttempts));
8521
8558
  yield this.join(data);
@@ -8585,7 +8622,7 @@ class Call {
8585
8622
  connectionConfig,
8586
8623
  onTrack: this.handleOnTrack,
8587
8624
  });
8588
- const audioSettings = (_e = this.data) === null || _e === void 0 ? void 0 : _e.settings.audio;
8625
+ const audioSettings = (_f = this.data) === null || _f === void 0 ? void 0 : _f.settings.audio;
8589
8626
  const isDtxEnabled = !!(audioSettings === null || audioSettings === void 0 ? void 0 : audioSettings.opus_dtx_enabled);
8590
8627
  const isRedEnabled = !!(audioSettings === null || audioSettings === void 0 ? void 0 : audioSettings.redundant_coding_enabled);
8591
8628
  this.publisher = new Publisher({
@@ -8743,9 +8780,9 @@ class Call {
8743
8780
  * @param trackType the track type to stop publishing.
8744
8781
  */
8745
8782
  this.stopPublish = (trackType) => __awaiter(this, void 0, void 0, function* () {
8746
- var _j;
8783
+ var _k;
8747
8784
  console.log(`stopPublish`, TrackType[trackType]);
8748
- yield ((_j = this.publisher) === null || _j === void 0 ? void 0 : _j.unpublishStream(trackType));
8785
+ yield ((_k = this.publisher) === null || _k === void 0 ? void 0 : _k.unpublishStream(trackType));
8749
8786
  });
8750
8787
  /**
8751
8788
  * Update track subscription configuration for one or more participants.
@@ -8886,8 +8923,8 @@ class Call {
8886
8923
  * @returns
8887
8924
  */
8888
8925
  this.updatePublishQuality = (enabledRids) => __awaiter(this, void 0, void 0, function* () {
8889
- var _k;
8890
- return (_k = this.publisher) === null || _k === void 0 ? void 0 : _k.updateVideoPublishQuality(enabledRids);
8926
+ var _l;
8927
+ return (_l = this.publisher) === null || _l === void 0 ? void 0 : _l.updateVideoPublishQuality(enabledRids);
8891
8928
  });
8892
8929
  this.handleOnTrack = (e) => {
8893
8930
  const [primaryStream] = e.streams;
@@ -9117,7 +9154,12 @@ class Call {
9117
9154
  * @param updates the updates to apply to the call.
9118
9155
  */
9119
9156
  this.update = (updates) => __awaiter(this, void 0, void 0, function* () {
9120
- return this.streamClient.patch(`${this.streamClientBasePath}`, updates);
9157
+ const response = yield this.streamClient.patch(`${this.streamClientBasePath}`, updates);
9158
+ const { call, members, own_capabilities } = response;
9159
+ this.state.setMetadata(call);
9160
+ this.state.setMembers(members);
9161
+ this.state.setOwnCapabilities(own_capabilities);
9162
+ return response;
9121
9163
  });
9122
9164
  /**
9123
9165
  * Ends the call. Once the call is ended, it cannot be re-joined.
@@ -9198,15 +9240,6 @@ class Call {
9198
9240
  this.state.setCallRecordingsList(response.recordings);
9199
9241
  return response;
9200
9242
  });
9201
- /**
9202
- * Returns a list of Edge Serves for current call.
9203
- *
9204
- * @deprecated merged with `call.join`.
9205
- * @param data the data.
9206
- */
9207
- this.getEdgeServer = (data) => {
9208
- return this.streamClient.post(`${this.streamClientBasePath}/get_edge_server`, data);
9209
- };
9210
9243
  /**
9211
9244
  * Sends an event to all call participants.
9212
9245
  *
@@ -9230,6 +9263,7 @@ class Call {
9230
9263
  }
9231
9264
  this.state.setMetadata(metadata);
9232
9265
  this.state.setMembers(members || []);
9266
+ this.state.setOwnCapabilities(ownCapabilities || []);
9233
9267
  this.state.setCallingState(ringing ? exports.CallingState.RINGING : exports.CallingState.IDLE);
9234
9268
  this.leaveCallHooks.push(registerEventHandlers(this, this.state, this.dispatcher));
9235
9269
  this.registerEffects();
@@ -9241,23 +9275,13 @@ class Call {
9241
9275
  createSubscription(this.state.metadata$, (metadata) => {
9242
9276
  if (!metadata)
9243
9277
  return;
9244
- this.permissionsContext.setPermissions(metadata.own_capabilities);
9245
9278
  this.permissionsContext.setCallSettings(metadata.settings);
9246
9279
  }),
9247
- // handles the case when the user is blocked by the call owner.
9248
- createSubscription(this.state.metadata$, (metadata) => __awaiter(this, void 0, void 0, function* () {
9249
- if (!metadata)
9250
- return;
9251
- const currentUserId = this.currentUserId;
9252
- if (currentUserId &&
9253
- metadata.blocked_user_ids.includes(currentUserId)) {
9254
- yield this.leave();
9255
- }
9256
- })),
9257
- // handle the case when the user permissions are revoked.
9258
- createSubscription(this.state.metadata$, (metadata) => {
9259
- if (!metadata)
9260
- return;
9280
+ // handle the case when the user permissions are modified.
9281
+ createSubscription(this.state.ownCapabilities$, (ownCapabilities) => {
9282
+ // update the permission context.
9283
+ this.permissionsContext.setPermissions(ownCapabilities);
9284
+ // check if the user still has publishing permissions and stop publishing if not.
9261
9285
  const permissionToTrackType = {
9262
9286
  [OwnCapability.SEND_AUDIO]: TrackType.AUDIO,
9263
9287
  [OwnCapability.SEND_VIDEO]: TrackType.VIDEO,
@@ -9272,6 +9296,16 @@ class Call {
9272
9296
  }
9273
9297
  });
9274
9298
  }),
9299
+ // handles the case when the user is blocked by the call owner.
9300
+ createSubscription(this.state.metadata$, (metadata) => __awaiter(this, void 0, void 0, function* () {
9301
+ if (!metadata)
9302
+ return;
9303
+ const currentUserId = this.currentUserId;
9304
+ if (currentUserId &&
9305
+ metadata.blocked_user_ids.includes(currentUserId)) {
9306
+ yield this.leave();
9307
+ }
9308
+ })),
9275
9309
  // watch for auto drop cancellation
9276
9310
  createSubscription(this.state.callingState$, (callingState) => {
9277
9311
  if (!this.ringing)
@@ -10962,7 +10996,7 @@ class StreamClient {
10962
10996
  }
10963
10997
  getUserAgent() {
10964
10998
  return (this.userAgent ||
10965
- `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.2-alpha.7"}`);
10999
+ `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.2"}`);
10966
11000
  }
10967
11001
  setUserAgent(userAgent) {
10968
11002
  this.userAgent = userAgent;
@@ -11170,6 +11204,7 @@ class StreamVideoClient {
11170
11204
  type: c.call.type,
11171
11205
  metadata: c.call,
11172
11206
  members: c.members,
11207
+ ownCapabilities: c.own_capabilities,
11173
11208
  watching: data.watch,
11174
11209
  clientStore: this.writeableStateStore,
11175
11210
  });
@@ -11519,7 +11554,7 @@ const createSoundDetector = (audioStream, onSoundDetectedStateChanged, options =
11519
11554
  const percentage = averagedDataValue > audioLevelThreshold
11520
11555
  ? 100
11521
11556
  : Math.round((averagedDataValue / audioLevelThreshold) * 100);
11522
- onSoundDetectedStateChanged(isSoundDetected, percentage);
11557
+ onSoundDetectedStateChanged({ isSoundDetected, audioLevel: percentage });
11523
11558
  }, detectionFrequencyInMs);
11524
11559
  return function stop() {
11525
11560
  return __awaiter(this, void 0, void 0, function* () {