@stream-io/video-client 1.13.0 → 1.14.0

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
@@ -77,6 +77,48 @@ const ChannelConfigWithInfoBlocklistBehaviorEnum = {
77
77
  BLOCK: 'block',
78
78
  SHADOW_BLOCK: 'shadow_block',
79
79
  };
80
+ /**
81
+ * All possibility of string to use
82
+ * @export
83
+ */
84
+ const ChannelOwnCapability = {
85
+ BAN_CHANNEL_MEMBERS: 'ban-channel-members',
86
+ CAST_POLL_VOTE: 'cast-poll-vote',
87
+ CONNECT_EVENTS: 'connect-events',
88
+ CREATE_ATTACHMENT: 'create-attachment',
89
+ CREATE_CALL: 'create-call',
90
+ DELETE_ANY_MESSAGE: 'delete-any-message',
91
+ DELETE_CHANNEL: 'delete-channel',
92
+ DELETE_OWN_MESSAGE: 'delete-own-message',
93
+ FLAG_MESSAGE: 'flag-message',
94
+ FREEZE_CHANNEL: 'freeze-channel',
95
+ JOIN_CALL: 'join-call',
96
+ JOIN_CHANNEL: 'join-channel',
97
+ LEAVE_CHANNEL: 'leave-channel',
98
+ MUTE_CHANNEL: 'mute-channel',
99
+ PIN_MESSAGE: 'pin-message',
100
+ QUERY_POLL_VOTES: 'query-poll-votes',
101
+ QUOTE_MESSAGE: 'quote-message',
102
+ READ_EVENTS: 'read-events',
103
+ SEARCH_MESSAGES: 'search-messages',
104
+ SEND_CUSTOM_EVENTS: 'send-custom-events',
105
+ SEND_LINKS: 'send-links',
106
+ SEND_MESSAGE: 'send-message',
107
+ SEND_POLL: 'send-poll',
108
+ SEND_REACTION: 'send-reaction',
109
+ SEND_REPLY: 'send-reply',
110
+ SEND_TYPING_EVENTS: 'send-typing-events',
111
+ SET_CHANNEL_COOLDOWN: 'set-channel-cooldown',
112
+ SKIP_SLOW_MODE: 'skip-slow-mode',
113
+ SLOW_MODE: 'slow-mode',
114
+ TYPING_EVENTS: 'typing-events',
115
+ UPDATE_ANY_MESSAGE: 'update-any-message',
116
+ UPDATE_CHANNEL: 'update-channel',
117
+ UPDATE_CHANNEL_MEMBERS: 'update-channel-members',
118
+ UPDATE_OWN_MESSAGE: 'update-own-message',
119
+ UPDATE_THREAD: 'update-thread',
120
+ UPLOAD_FILE: 'upload-file',
121
+ };
80
122
  /**
81
123
  * @export
82
124
  */
@@ -116,9 +158,11 @@ const OwnCapability = {
116
158
  SEND_AUDIO: 'send-audio',
117
159
  SEND_VIDEO: 'send-video',
118
160
  START_BROADCAST_CALL: 'start-broadcast-call',
161
+ START_CLOSED_CAPTIONS_CALL: 'start-closed-captions-call',
119
162
  START_RECORD_CALL: 'start-record-call',
120
163
  START_TRANSCRIPTION_CALL: 'start-transcription-call',
121
164
  STOP_BROADCAST_CALL: 'stop-broadcast-call',
165
+ STOP_CLOSED_CAPTIONS_CALL: 'stop-closed-captions-call',
122
166
  STOP_RECORD_CALL: 'stop-record-call',
123
167
  STOP_TRANSCRIPTION_CALL: 'stop-transcription-call',
124
168
  UPDATE_CALL: 'update-call',
@@ -149,6 +193,14 @@ const RecordSettingsRequestQualityEnum = {
149
193
  PORTRAIT_1080X1920: 'portrait-1080x1920',
150
194
  PORTRAIT_1440X2560: 'portrait-1440x2560',
151
195
  };
196
+ /**
197
+ * @export
198
+ */
199
+ const TranscriptionSettingsRequestClosedCaptionModeEnum = {
200
+ AVAILABLE: 'available',
201
+ DISABLED: 'disabled',
202
+ AUTO_ON: 'auto-on',
203
+ };
152
204
  /**
153
205
  * @export
154
206
  */
@@ -157,6 +209,14 @@ const TranscriptionSettingsRequestModeEnum = {
157
209
  DISABLED: 'disabled',
158
210
  AUTO_ON: 'auto-on',
159
211
  };
212
+ /**
213
+ * @export
214
+ */
215
+ const TranscriptionSettingsResponseClosedCaptionModeEnum = {
216
+ AVAILABLE: 'available',
217
+ DISABLED: 'disabled',
218
+ AUTO_ON: 'auto-on',
219
+ };
160
220
  /**
161
221
  * @export
162
222
  */
@@ -3320,7 +3380,7 @@ const retryable = async (rpc, signal) => {
3320
3380
  return result;
3321
3381
  };
3322
3382
 
3323
- const version = "1.13.0";
3383
+ const version = "1.14.0";
3324
3384
  const [major, minor, patch] = version.split('.');
3325
3385
  let sdkInfo = {
3326
3386
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -3331,7 +3391,7 @@ let sdkInfo = {
3331
3391
  let osInfo;
3332
3392
  let deviceInfo;
3333
3393
  let webRtcInfo;
3334
- let deviceState;
3394
+ let deviceState = { oneofKind: undefined };
3335
3395
  const setSdkInfo = (info) => {
3336
3396
  sdkInfo = info;
3337
3397
  };
@@ -4122,6 +4182,24 @@ const setCurrentValue = (subject, update) => {
4122
4182
  subject.next(next);
4123
4183
  return next;
4124
4184
  };
4185
+ /**
4186
+ * Updates the value of the provided Subject and returns the previous value
4187
+ * and a function to roll back the update.
4188
+ * This is useful when you want to optimistically update a value
4189
+ * and roll back the update if an error occurs.
4190
+ *
4191
+ * @param subject the subject to update.
4192
+ * @param update the update to apply to the subject.
4193
+ */
4194
+ const updateValue = (subject, update) => {
4195
+ const lastValue = subject.getValue();
4196
+ const value = setCurrentValue(subject, update);
4197
+ return {
4198
+ lastValue,
4199
+ value,
4200
+ rollback: () => setCurrentValue(subject, lastValue),
4201
+ };
4202
+ };
4125
4203
  /**
4126
4204
  * Creates a subscription and returns a function to unsubscribe.
4127
4205
  *
@@ -4155,7 +4233,8 @@ var rxUtils = /*#__PURE__*/Object.freeze({
4155
4233
  createSafeAsyncSubscription: createSafeAsyncSubscription,
4156
4234
  createSubscription: createSubscription,
4157
4235
  getCurrentValue: getCurrentValue,
4158
- setCurrentValue: setCurrentValue
4236
+ setCurrentValue: setCurrentValue,
4237
+ updateValue: updateValue
4159
4238
  });
4160
4239
 
4161
4240
  /**
@@ -4602,6 +4681,7 @@ class CallState {
4602
4681
  this.sessionSubject = new rxjs.BehaviorSubject(undefined);
4603
4682
  this.settingsSubject = new rxjs.BehaviorSubject(undefined);
4604
4683
  this.transcribingSubject = new rxjs.BehaviorSubject(false);
4684
+ this.captioningSubject = new rxjs.BehaviorSubject(false);
4605
4685
  this.endedBySubject = new rxjs.BehaviorSubject(undefined);
4606
4686
  this.thumbnailsSubject = new rxjs.BehaviorSubject(undefined);
4607
4687
  this.membersSubject = new rxjs.BehaviorSubject([]);
@@ -4612,6 +4692,7 @@ class CallState {
4612
4692
  this.anonymousParticipantCountSubject = new rxjs.BehaviorSubject(0);
4613
4693
  this.participantsSubject = new rxjs.BehaviorSubject([]);
4614
4694
  this.callStatsReportSubject = new rxjs.BehaviorSubject(undefined);
4695
+ this.closedCaptionsSubject = new rxjs.BehaviorSubject([]);
4615
4696
  // These are tracks that were delivered to the Subscriber's onTrack event
4616
4697
  // that we couldn't associate with a participant yet.
4617
4698
  // This happens when the participantJoined event hasn't been received yet.
@@ -4620,10 +4701,18 @@ class CallState {
4620
4701
  this.logger = getLogger(['CallState']);
4621
4702
  /**
4622
4703
  * A list of comparators that are used to sort the participants.
4623
- *
4624
- * @private
4625
4704
  */
4626
4705
  this.sortParticipantsBy = defaultSortPreset;
4706
+ this.closedCaptionsTasks = new Map();
4707
+ /**
4708
+ * Runs the cleanup tasks.
4709
+ */
4710
+ this.dispose = () => {
4711
+ for (const [ccKey, taskId] of this.closedCaptionsTasks.entries()) {
4712
+ clearTimeout(taskId);
4713
+ this.closedCaptionsTasks.delete(ccKey);
4714
+ }
4715
+ };
4627
4716
  /**
4628
4717
  * Sets the list of criteria that are used to sort the participants.
4629
4718
  * To disable sorting, you can pass `noopComparator()`.
@@ -4672,6 +4761,15 @@ class CallState {
4672
4761
  this.setStartedAt = (startedAt) => {
4673
4762
  return this.setCurrentValue(this.startedAtSubject, startedAt);
4674
4763
  };
4764
+ /**
4765
+ * Sets the closed captioning state of the current call.
4766
+ *
4767
+ * @internal
4768
+ * @param captioning the closed captioning state.
4769
+ */
4770
+ this.setCaptioning = (captioning) => {
4771
+ return updateValue(this.captioningSubject, captioning);
4772
+ };
4675
4773
  /**
4676
4774
  * Sets the number of anonymous participants in the current call.
4677
4775
  *
@@ -4770,7 +4868,6 @@ class CallState {
4770
4868
  }
4771
4869
  const thePatch = typeof patch === 'function' ? patch(participant) : patch;
4772
4870
  const updatedParticipant = {
4773
- // FIXME OL: this is not a deep merge, we might want to revisit this
4774
4871
  ...participant,
4775
4872
  ...thePatch,
4776
4873
  };
@@ -4832,7 +4929,6 @@ class CallState {
4832
4929
  *
4833
4930
  * @param trackType the kind of subscription to update.
4834
4931
  * @param changes the list of subscription changes to do.
4835
- * @param type the debounce type to use for the update.
4836
4932
  */
4837
4933
  this.updateParticipantTracks = (trackType, changes) => {
4838
4934
  return this.updateParticipants(Object.entries(changes).reduce((acc, [sessionId, change]) => {
@@ -4935,6 +5031,14 @@ class CallState {
4935
5031
  }
4936
5032
  return orphans;
4937
5033
  };
5034
+ /**
5035
+ * Updates the closed captions settings.
5036
+ *
5037
+ * @param config the new closed captions settings.
5038
+ */
5039
+ this.updateClosedCaptionSettings = (config) => {
5040
+ this.closedCaptionsSettings = { ...this.closedCaptionsSettings, ...config };
5041
+ };
4938
5042
  /**
4939
5043
  * Updates the call state with the data received from the server.
4940
5044
  *
@@ -4958,6 +5062,7 @@ class CallState {
4958
5062
  this.updateParticipantCountFromSession(s);
4959
5063
  this.setCurrentValue(this.settingsSubject, call.settings);
4960
5064
  this.setCurrentValue(this.transcribingSubject, call.transcribing);
5065
+ this.setCurrentValue(this.captioningSubject, call.captioning);
4961
5066
  this.setCurrentValue(this.thumbnailsSubject, call.thumbnails);
4962
5067
  };
4963
5068
  /**
@@ -5149,6 +5254,35 @@ class CallState {
5149
5254
  this.setCurrentValue(this.ownCapabilitiesSubject, event.own_capabilities);
5150
5255
  }
5151
5256
  };
5257
+ this.updateFromClosedCaptions = (event) => {
5258
+ this.setCurrentValue(this.closedCaptionsSubject, (queue) => {
5259
+ const { closed_caption } = event;
5260
+ const keyOf = (c) => `${c.speaker_id}/${c.start_time}`;
5261
+ const currentKey = keyOf(closed_caption);
5262
+ const duplicate = queue.some((caption) => keyOf(caption) === currentKey);
5263
+ if (duplicate)
5264
+ return queue;
5265
+ const nextQueue = [...queue, closed_caption];
5266
+ const { visibilityDurationMs = 2700, maxVisibleCaptions = 2 } = this.closedCaptionsSettings || {};
5267
+ // schedule the removal of the closed caption after the retention time
5268
+ if (visibilityDurationMs > 0) {
5269
+ const taskId = setTimeout(() => {
5270
+ this.setCurrentValue(this.closedCaptionsSubject, (captions) => captions.filter((caption) => caption !== closed_caption));
5271
+ this.closedCaptionsTasks.delete(currentKey);
5272
+ }, visibilityDurationMs);
5273
+ this.closedCaptionsTasks.set(currentKey, taskId);
5274
+ // cancel the cleanup tasks for the closed captions that are no longer in the queue
5275
+ for (let i = 0; i < nextQueue.length - maxVisibleCaptions; i++) {
5276
+ const key = keyOf(nextQueue[i]);
5277
+ const task = this.closedCaptionsTasks.get(key);
5278
+ clearTimeout(task);
5279
+ this.closedCaptionsTasks.delete(key);
5280
+ }
5281
+ }
5282
+ // trim the queue
5283
+ return nextQueue.slice(-maxVisibleCaptions);
5284
+ });
5285
+ };
5152
5286
  this.participants$ = this.participantsSubject.asObservable().pipe(
5153
5287
  // maintain stable-sort by mutating the participants stored
5154
5288
  // in the original subject
@@ -5175,6 +5309,7 @@ class CallState {
5175
5309
  this.settings$ = this.settingsSubject.asObservable();
5176
5310
  this.endedBy$ = this.endedBySubject.asObservable();
5177
5311
  this.thumbnails$ = this.thumbnailsSubject.asObservable();
5312
+ this.closedCaptions$ = this.closedCaptionsSubject.asObservable();
5178
5313
  /**
5179
5314
  * Performs shallow comparison of two arrays.
5180
5315
  * Expects primitive values: [1, 2, 3] is equal to [2, 1, 3].
@@ -5204,9 +5339,9 @@ class CallState {
5204
5339
  this.participantCount$ = duc(this.participantCountSubject);
5205
5340
  this.recording$ = duc(this.recordingSubject);
5206
5341
  this.transcribing$ = duc(this.transcribingSubject);
5342
+ this.captioning$ = duc(this.captioningSubject);
5207
5343
  this.eventHandlers = {
5208
5344
  // these events are not updating the call state:
5209
- 'call.closed_caption': undefined,
5210
5345
  'call.deleted': undefined,
5211
5346
  'call.permission_request': undefined,
5212
5347
  'call.recording_ready': undefined,
@@ -5227,6 +5362,16 @@ class CallState {
5227
5362
  // events that update call state:
5228
5363
  'call.accepted': (e) => this.updateFromCallResponse(e.call),
5229
5364
  'call.blocked_user': this.blockUser,
5365
+ 'call.closed_caption': this.updateFromClosedCaptions,
5366
+ 'call.closed_captions_failed': () => {
5367
+ this.setCurrentValue(this.captioningSubject, false);
5368
+ },
5369
+ 'call.closed_captions_started': () => {
5370
+ this.setCurrentValue(this.captioningSubject, true);
5371
+ },
5372
+ 'call.closed_captions_stopped': () => {
5373
+ this.setCurrentValue(this.captioningSubject, false);
5374
+ },
5230
5375
  'call.created': (e) => this.updateFromCallResponse(e.call),
5231
5376
  'call.ended': (e) => {
5232
5377
  this.updateFromCallResponse(e.call);
@@ -5284,6 +5429,12 @@ class CallState {
5284
5429
  get startedAt() {
5285
5430
  return this.getCurrentValue(this.startedAt$);
5286
5431
  }
5432
+ /**
5433
+ * Returns whether closed captions are enabled in the current call.
5434
+ */
5435
+ get captioning() {
5436
+ return this.getCurrentValue(this.captioning$);
5437
+ }
5287
5438
  /**
5288
5439
  * The server-side counted number of anonymous participants connected to the current call.
5289
5440
  * This number includes the anonymous participants as well.
@@ -5447,6 +5598,12 @@ class CallState {
5447
5598
  get thumbnails() {
5448
5599
  return this.getCurrentValue(this.thumbnails$);
5449
5600
  }
5601
+ /**
5602
+ * Returns the current queue of closed captions.
5603
+ */
5604
+ get closedCaptions() {
5605
+ return this.getCurrentValue(this.closedCaptions$);
5606
+ }
5450
5607
  }
5451
5608
 
5452
5609
  const getRtpMap = (line) => {
@@ -10224,6 +10381,7 @@ class Call {
10224
10381
  this.sfuClient = undefined;
10225
10382
  this.dynascaleManager.setSfuClient(undefined);
10226
10383
  this.state.setCallingState(exports.CallingState.LEFT);
10384
+ this.state.dispose();
10227
10385
  // Call all leave call hooks, e.g. to clean up global event handlers
10228
10386
  this.leaveCallHooks.forEach((hook) => hook());
10229
10387
  this.initialized = false;
@@ -11181,7 +11339,43 @@ class Call {
11181
11339
  return this.streamClient.post(`${this.streamClientBasePath}/stop_transcription`);
11182
11340
  };
11183
11341
  /**
11184
- * Sends a `call.permission_request` event to all users connected to the call. The call settings object contains infomration about which permissions can be requested during a call (for example a user might be allowed to request permission to publish audio, but not video).
11342
+ * Starts the closed captions of the call.
11343
+ */
11344
+ this.startClosedCaptions = async (options) => {
11345
+ const trx = this.state.setCaptioning(true); // optimistic update
11346
+ try {
11347
+ return await this.streamClient.post(`${this.streamClientBasePath}/start_closed_captions`, options);
11348
+ }
11349
+ catch (err) {
11350
+ trx.rollback(); // revert the optimistic update
11351
+ throw err;
11352
+ }
11353
+ };
11354
+ /**
11355
+ * Stops the closed captions of the call.
11356
+ */
11357
+ this.stopClosedCaptions = async (options) => {
11358
+ const trx = this.state.setCaptioning(false); // optimistic update
11359
+ try {
11360
+ return await this.streamClient.post(`${this.streamClientBasePath}/stop_closed_captions`, options);
11361
+ }
11362
+ catch (err) {
11363
+ trx.rollback(); // revert the optimistic update
11364
+ throw err;
11365
+ }
11366
+ };
11367
+ /**
11368
+ * Updates the closed caption settings.
11369
+ *
11370
+ * @param config the closed caption settings to apply
11371
+ */
11372
+ this.updateClosedCaptionSettings = (config) => {
11373
+ this.state.updateClosedCaptionSettings(config);
11374
+ };
11375
+ /**
11376
+ * Sends a `call.permission_request` event to all users connected to the call.
11377
+ * The call settings object contains information about which permissions can be requested during a call
11378
+ * (for example, a user might be allowed to request permission to publish audio, but not video).
11185
11379
  */
11186
11380
  this.requestPermissions = async (data) => {
11187
11381
  const { permissions } = data;
@@ -12913,7 +13107,7 @@ class StreamClient {
12913
13107
  return await this.wsConnection.connect(this.defaultWSTimeout);
12914
13108
  };
12915
13109
  this.getUserAgent = () => {
12916
- const version = "1.13.0";
13110
+ const version = "1.14.0";
12917
13111
  return (this.userAgent ||
12918
13112
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
12919
13113
  };
@@ -13439,6 +13633,7 @@ exports.CameraManagerState = CameraManagerState;
13439
13633
  exports.ChannelConfigWithInfoAutomodBehaviorEnum = ChannelConfigWithInfoAutomodBehaviorEnum;
13440
13634
  exports.ChannelConfigWithInfoAutomodEnum = ChannelConfigWithInfoAutomodEnum;
13441
13635
  exports.ChannelConfigWithInfoBlocklistBehaviorEnum = ChannelConfigWithInfoBlocklistBehaviorEnum;
13636
+ exports.ChannelOwnCapability = ChannelOwnCapability;
13442
13637
  exports.CreateDeviceRequestPushProviderEnum = CreateDeviceRequestPushProviderEnum;
13443
13638
  exports.DynascaleManager = DynascaleManager;
13444
13639
  exports.ErrorFromResponse = ErrorFromResponse;
@@ -13461,7 +13656,9 @@ exports.StreamSfuClient = StreamSfuClient;
13461
13656
  exports.StreamVideoClient = StreamVideoClient;
13462
13657
  exports.StreamVideoReadOnlyStateStore = StreamVideoReadOnlyStateStore;
13463
13658
  exports.StreamVideoWriteableStateStore = StreamVideoWriteableStateStore;
13659
+ exports.TranscriptionSettingsRequestClosedCaptionModeEnum = TranscriptionSettingsRequestClosedCaptionModeEnum;
13464
13660
  exports.TranscriptionSettingsRequestModeEnum = TranscriptionSettingsRequestModeEnum;
13661
+ exports.TranscriptionSettingsResponseClosedCaptionModeEnum = TranscriptionSettingsResponseClosedCaptionModeEnum;
13465
13662
  exports.TranscriptionSettingsResponseModeEnum = TranscriptionSettingsResponseModeEnum;
13466
13663
  exports.VideoSettingsRequestCameraFacingEnum = VideoSettingsRequestCameraFacingEnum;
13467
13664
  exports.VideoSettingsResponseCameraFacingEnum = VideoSettingsResponseCameraFacingEnum;