@stream-io/video-client 0.4.5 → 0.4.6

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.es.js CHANGED
@@ -4,7 +4,7 @@ import { ServiceType, stackIntercept } from '@protobuf-ts/runtime-rpc';
4
4
  import axios, { AxiosHeaders } from 'axios';
5
5
  export { AxiosError } from 'axios';
6
6
  import { TwirpFetchTransport } from '@protobuf-ts/twirp-transport';
7
- import { ReplaySubject, combineLatest, BehaviorSubject, map as map$1, shareReplay, distinctUntilChanged, takeWhile, distinctUntilKeyChanged, filter, pairwise, merge, Observable, debounceTime, concatMap, from, of, tap, debounce, timer } from 'rxjs';
7
+ import { ReplaySubject, combineLatest, BehaviorSubject, map as map$1, shareReplay, distinctUntilChanged, takeWhile, distinctUntilKeyChanged, merge, from, Observable, debounceTime, concatMap, pairwise, of, filter, tap, debounce, timer } from 'rxjs';
8
8
  import * as SDP from 'sdp-transform';
9
9
  import { UAParser } from 'ua-parser-js';
10
10
  import WebSocket from 'isomorphic-ws';
@@ -9981,8 +9981,7 @@ const getDevices = (constraints, kind) => {
9981
9981
  /**
9982
9982
  * [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
9983
9983
  *
9984
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
9985
- */
9984
+ * */
9986
9985
  const checkIfAudioOutputChangeSupported = () => {
9987
9986
  if (typeof document === 'undefined')
9988
9987
  return false;
@@ -10142,90 +10141,10 @@ const getScreenShareStream = async (options) => {
10142
10141
  throw e;
10143
10142
  }
10144
10143
  };
10145
- const watchForDisconnectedDevice = (kind, deviceId$) => {
10146
- let devices$;
10147
- switch (kind) {
10148
- case 'audioinput':
10149
- devices$ = getAudioDevices();
10150
- break;
10151
- case 'videoinput':
10152
- devices$ = getVideoDevices();
10153
- break;
10154
- case 'audiooutput':
10155
- devices$ = getAudioOutputDevices();
10156
- break;
10157
- }
10158
- return combineLatest([devices$, deviceId$]).pipe(filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), map$1(() => true));
10159
- };
10160
- /**
10161
- * Notifies the subscriber if a given 'audioinput' device is disconnected
10162
- *
10163
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
10164
- * @param deviceId$ an Observable that specifies which device to watch for
10165
- * @returns
10166
- */
10167
- const watchForDisconnectedAudioDevice = (deviceId$) => {
10168
- return watchForDisconnectedDevice('audioinput', deviceId$);
10169
- };
10170
- /**
10171
- * Notifies the subscriber if a given 'videoinput' device is disconnected
10172
- *
10173
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
10174
- * @param deviceId$ an Observable that specifies which device to watch for
10175
- * @returns
10176
- */
10177
- const watchForDisconnectedVideoDevice = (deviceId$) => {
10178
- return watchForDisconnectedDevice('videoinput', deviceId$);
10179
- };
10180
- /**
10181
- * Notifies the subscriber if a given 'audiooutput' device is disconnected
10182
- *
10183
- * @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
10184
- * @param deviceId$ an Observable that specifies which device to watch for
10185
- * @returns
10186
- */
10187
- const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
10188
- return watchForDisconnectedDevice('audiooutput', deviceId$);
10189
- };
10190
- const watchForAddedDefaultDevice = (kind) => {
10191
- let devices$;
10192
- switch (kind) {
10193
- case 'audioinput':
10194
- devices$ = getAudioDevices();
10195
- break;
10196
- case 'videoinput':
10197
- devices$ = getVideoDevices();
10198
- break;
10199
- case 'audiooutput':
10200
- devices$ = getAudioOutputDevices();
10201
- break;
10202
- default:
10203
- throw new Error('Unknown MediaDeviceKind', kind);
10204
- }
10205
- return devices$.pipe(pairwise(), filter(([prev, current]) => {
10206
- const prevDefault = prev.find((device) => device.deviceId === 'default');
10207
- const currentDefault = current.find((device) => device.deviceId === 'default');
10208
- return !!(current.length > prev.length &&
10209
- prevDefault &&
10210
- currentDefault &&
10211
- prevDefault.groupId !== currentDefault.groupId);
10212
- }), map$1(() => true));
10213
- };
10214
- /**
10215
- * Notifies the subscriber about newly added default audio input device.
10216
- * @returns Observable<boolean>
10217
- */
10218
- const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
10219
- /**
10220
- * Notifies the subscriber about newly added default audio output device.
10221
- * @returns Observable<boolean>
10222
- */
10223
- const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
10224
- /**
10225
- * Notifies the subscriber about newly added default video input device.
10226
- * @returns Observable<boolean>
10227
- */
10228
- const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
10144
+ const deviceIds$ = typeof navigator !== 'undefined' &&
10145
+ typeof navigator.mediaDevices !== 'undefined'
10146
+ ? memoizedObservable(() => merge(from(navigator.mediaDevices.enumerateDevices()), getDeviceChangeObserver()).pipe(shareReplay(1)))()
10147
+ : undefined;
10229
10148
  /**
10230
10149
  * Deactivates MediaStream (stops and removes tracks) to be later garbage collected
10231
10150
  *
@@ -10251,7 +10170,17 @@ class InputMediaDeviceManager {
10251
10170
  this.call = call;
10252
10171
  this.state = state;
10253
10172
  this.trackType = trackType;
10173
+ this.subscriptions = [];
10174
+ this.isTrackStoppedDueToTrackEnd = false;
10175
+ this.removeSubscriptions = () => {
10176
+ this.subscriptions.forEach((s) => s.unsubscribe());
10177
+ };
10254
10178
  this.logger = getLogger([`${TrackType[trackType].toLowerCase()} manager`]);
10179
+ if (deviceIds$ &&
10180
+ !isReactNative() &&
10181
+ (this.trackType === TrackType.AUDIO || this.trackType === TrackType.VIDEO)) {
10182
+ this.handleDisconnectedOrReplacedDevices();
10183
+ }
10255
10184
  }
10256
10185
  /**
10257
10186
  * Lists the available audio/video devices
@@ -10411,9 +10340,6 @@ class InputMediaDeviceManager {
10411
10340
  this.unmuteTracks();
10412
10341
  }
10413
10342
  else {
10414
- if (this.state.mediaStream) {
10415
- this.stopTracks();
10416
- }
10417
10343
  const defaultConstraints = this.state.defaultConstraints;
10418
10344
  const constraints = {
10419
10345
  ...defaultConstraints,
@@ -10426,7 +10352,79 @@ class InputMediaDeviceManager {
10426
10352
  }
10427
10353
  if (this.state.mediaStream !== stream) {
10428
10354
  this.state.setMediaStream(stream);
10355
+ this.getTracks().forEach((track) => {
10356
+ track.addEventListener('ended', async () => {
10357
+ if (this.enablePromise) {
10358
+ await this.enablePromise;
10359
+ }
10360
+ if (this.disablePromise) {
10361
+ await this.disablePromise;
10362
+ }
10363
+ if (this.state.status === 'enabled') {
10364
+ this.isTrackStoppedDueToTrackEnd = true;
10365
+ setTimeout(() => {
10366
+ this.isTrackStoppedDueToTrackEnd = false;
10367
+ }, 2000);
10368
+ await this.disable();
10369
+ }
10370
+ });
10371
+ });
10372
+ }
10373
+ }
10374
+ get mediaDeviceKind() {
10375
+ if (this.trackType === TrackType.AUDIO) {
10376
+ return 'audioinput';
10377
+ }
10378
+ if (this.trackType === TrackType.VIDEO) {
10379
+ return 'videoinput';
10429
10380
  }
10381
+ return '';
10382
+ }
10383
+ handleDisconnectedOrReplacedDevices() {
10384
+ this.subscriptions.push(combineLatest([
10385
+ deviceIds$.pipe(pairwise()),
10386
+ this.state.selectedDevice$,
10387
+ ]).subscribe(async ([[prevDevices, currentDevices], deviceId]) => {
10388
+ if (!deviceId) {
10389
+ return;
10390
+ }
10391
+ if (this.enablePromise) {
10392
+ await this.enablePromise;
10393
+ }
10394
+ if (this.disablePromise) {
10395
+ await this.disablePromise;
10396
+ }
10397
+ let isDeviceDisconnected = false;
10398
+ let isDeviceReplaced = false;
10399
+ const currentDevice = this.findDeviceInList(currentDevices, deviceId);
10400
+ const prevDevice = this.findDeviceInList(prevDevices, deviceId);
10401
+ if (!currentDevice && prevDevice) {
10402
+ isDeviceDisconnected = true;
10403
+ }
10404
+ else if (currentDevice &&
10405
+ prevDevice &&
10406
+ currentDevice.deviceId === prevDevice.deviceId &&
10407
+ currentDevice.groupId !== prevDevice.groupId) {
10408
+ isDeviceReplaced = true;
10409
+ }
10410
+ if (isDeviceDisconnected) {
10411
+ await this.disable();
10412
+ this.select(undefined);
10413
+ }
10414
+ if (isDeviceReplaced) {
10415
+ if (this.isTrackStoppedDueToTrackEnd &&
10416
+ this.state.status === 'disabled') {
10417
+ await this.enable();
10418
+ this.isTrackStoppedDueToTrackEnd = false;
10419
+ }
10420
+ else {
10421
+ await this.applySettingsToStream();
10422
+ }
10423
+ }
10424
+ }));
10425
+ }
10426
+ findDeviceInList(devices, deviceId) {
10427
+ return devices.find((d) => d.deviceId === deviceId && d.kind === this.mediaDeviceKind);
10430
10428
  }
10431
10429
  }
10432
10430
 
@@ -10994,6 +10992,21 @@ class SpeakerState {
10994
10992
  class SpeakerManager {
10995
10993
  constructor() {
10996
10994
  this.state = new SpeakerState();
10995
+ this.subscriptions = [];
10996
+ this.removeSubscriptions = () => {
10997
+ this.subscriptions.forEach((s) => s.unsubscribe());
10998
+ };
10999
+ if (deviceIds$ && !isReactNative()) {
11000
+ this.subscriptions.push(combineLatest([deviceIds$, this.state.selectedDevice$]).subscribe(([devices, deviceId]) => {
11001
+ if (!deviceId) {
11002
+ return;
11003
+ }
11004
+ const device = devices.find((d) => d.deviceId === deviceId && d.kind === 'audiooutput');
11005
+ if (!device) {
11006
+ this.select('');
11007
+ }
11008
+ }));
11009
+ }
10997
11010
  }
10998
11011
  /**
10999
11012
  * Lists the available audio output devices
@@ -11111,6 +11124,10 @@ class Call {
11111
11124
  this.leaveCallHooks.forEach((hook) => hook());
11112
11125
  this.clientStore.unregisterCall(this);
11113
11126
  this.state.setCallingState(CallingState.LEFT);
11127
+ this.camera.removeSubscriptions();
11128
+ this.microphone.removeSubscriptions();
11129
+ this.screenShare.removeSubscriptions();
11130
+ this.speaker.removeSubscriptions();
11114
11131
  };
11115
11132
  /**
11116
11133
  * Loads the information about the call.
@@ -11484,7 +11501,7 @@ class Call {
11484
11501
  await this.initMic({ setStatus: true });
11485
11502
  }
11486
11503
  catch (error) {
11487
- this.logger('warn', 'Camera and/or mic init failed during join call');
11504
+ this.logger('warn', 'Camera and/or mic init failed during join call', error);
11488
11505
  }
11489
11506
  // 3. once we have the "joinResponse", and possibly reconciled the local state
11490
11507
  // we schedule a fast subscription update for all remote participants
@@ -13957,7 +13974,7 @@ class StreamClient {
13957
13974
  });
13958
13975
  };
13959
13976
  this.getUserAgent = () => {
13960
- const version = "0.4.5" ;
13977
+ const version = "0.4.6" ;
13961
13978
  return (this.userAgent ||
13962
13979
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
13963
13980
  };
@@ -14492,5 +14509,5 @@ class StreamVideoServerClient extends StreamVideoClient {
14492
14509
  }
14493
14510
  }
14494
14511
 
14495
- export { AudioSettingsDefaultDeviceEnum, AudioSettingsRequestDefaultDeviceEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CameraManager, CameraManagerState, CreateDeviceRequestPushProviderEnum, DebounceType, DynascaleManager, ErrorFromResponse, InputMediaDeviceManager, InputMediaDeviceManagerState, LayoutSettingsNameEnum, LayoutSettingsRequestNameEnum, MicrophoneManager, MicrophoneManagerState, OwnCapability, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, ScreenShareManager, ScreenShareState, events as SfuEvents, models as SfuModels, SpeakerManager, SpeakerState, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoServerClient, StreamVideoWriteableStateStore, TranscriptionSettingsModeEnum, TranscriptionSettingsRequestModeEnum, VideoSettingsCameraFacingEnum, VideoSettingsRequestCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, disposeOfMediaStream, dominantSpeaker, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceInfo, getLogger, getOSInfo, getScreenShareStream, getSdkInfo, getVideoDevices, getVideoStream, livestreamOrAudioRoomSortPreset, logLevels, logToConsole, name, noopComparator, paginatedLayoutSortPreset, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setDeviceInfo, setLogLevel, setLogger, setOSInfo, setSdkInfo, speakerLayoutSortPreset, speaking, watchForAddedDefaultAudioDevice, watchForAddedDefaultAudioOutputDevice, watchForAddedDefaultVideoDevice, watchForDisconnectedAudioDevice, watchForDisconnectedAudioOutputDevice, watchForDisconnectedVideoDevice };
14512
+ export { AudioSettingsDefaultDeviceEnum, AudioSettingsRequestDefaultDeviceEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CameraManager, CameraManagerState, CreateDeviceRequestPushProviderEnum, DebounceType, DynascaleManager, ErrorFromResponse, InputMediaDeviceManager, InputMediaDeviceManagerState, LayoutSettingsNameEnum, LayoutSettingsRequestNameEnum, MicrophoneManager, MicrophoneManagerState, OwnCapability, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, ScreenShareManager, ScreenShareState, events as SfuEvents, models as SfuModels, SpeakerManager, SpeakerState, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoServerClient, StreamVideoWriteableStateStore, TranscriptionSettingsModeEnum, TranscriptionSettingsRequestModeEnum, VideoSettingsCameraFacingEnum, VideoSettingsRequestCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, deviceIds$, disposeOfMediaStream, dominantSpeaker, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceInfo, getLogger, getOSInfo, getScreenShareStream, getSdkInfo, getVideoDevices, getVideoStream, livestreamOrAudioRoomSortPreset, logLevels, logToConsole, name, noopComparator, paginatedLayoutSortPreset, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setDeviceInfo, setLogLevel, setLogger, setOSInfo, setSdkInfo, speakerLayoutSortPreset, speaking };
14496
14513
  //# sourceMappingURL=index.es.js.map