@stream-io/video-client 1.4.1 → 1.4.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/index.browser.es.js +219 -144
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +219 -142
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.es.js +219 -144
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/src/Call.d.ts +7 -7
  9. package/dist/src/StreamSfuClient.d.ts +7 -7
  10. package/dist/src/StreamVideoClient.d.ts +5 -5
  11. package/dist/src/coordinator/connection/client.d.ts +13 -14
  12. package/dist/src/coordinator/connection/connection.d.ts +3 -5
  13. package/dist/src/coordinator/connection/insights.d.ts +0 -1
  14. package/dist/src/devices/BrowserPermission.d.ts +24 -0
  15. package/dist/src/devices/InputMediaDeviceManagerState.d.ts +3 -3
  16. package/dist/src/devices/devices.d.ts +30 -11
  17. package/dist/src/gen/coordinator/index.d.ts +5 -0
  18. package/dist/src/helpers/ViewportTracker.d.ts +1 -1
  19. package/dist/src/helpers/lazy.d.ts +4 -0
  20. package/dist/src/helpers/sdp-munging.d.ts +2 -2
  21. package/dist/src/rtc/Dispatcher.d.ts +2 -2
  22. package/dist/src/rtc/codecs.d.ts +1 -1
  23. package/dist/src/rtc/signal.d.ts +0 -1
  24. package/dist/src/stats/utils.d.ts +4 -4
  25. package/dist/src/store/CallState.d.ts +1 -1
  26. package/package.json +4 -4
  27. package/src/devices/BrowserPermission.ts +152 -0
  28. package/src/devices/CameraManagerState.ts +2 -6
  29. package/src/devices/InputMediaDeviceManagerState.ts +10 -44
  30. package/src/devices/MicrophoneManagerState.ts +2 -6
  31. package/src/devices/__tests__/CameraManager.test.ts +3 -0
  32. package/src/devices/__tests__/InputMediaDeviceManager.test.ts +5 -3
  33. package/src/devices/__tests__/InputMediaDeviceManagerFilters.test.ts +6 -2
  34. package/src/devices/__tests__/InputMediaDeviceManagerState.test.ts +41 -51
  35. package/src/devices/__tests__/MicrophoneManager.test.ts +4 -1
  36. package/src/devices/__tests__/MicrophoneManagerRN.test.ts +8 -1
  37. package/src/devices/__tests__/SpeakerManager.test.ts +8 -1
  38. package/src/devices/__tests__/mocks.ts +6 -1
  39. package/src/devices/devices.ts +113 -112
  40. package/src/gen/coordinator/index.ts +5 -0
  41. package/src/helpers/RNSpeechDetector.ts +1 -1
  42. package/src/helpers/lazy.ts +15 -0
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.4.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.4.2...@stream-io/video-client-1.4.3) (2024-06-25)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * improve browser permission handling ([#1394](https://github.com/GetStream/stream-video-js/issues/1394)) ([c8ccb21](https://github.com/GetStream/stream-video-js/commit/c8ccb219a43464d1215987d99fd01d8b4a407eb5))
11
+
12
+ ### [1.4.2](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.4.1...@stream-io/video-client-1.4.2) (2024-06-24)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * support for portrait mode recording ([#1418](https://github.com/GetStream/stream-video-js/issues/1418)) ([70a304d](https://github.com/GetStream/stream-video-js/commit/70a304d3f20d93ecfffc97794e8e4974acf88e9a))
18
+
5
19
  ### [1.4.1](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.4.0...@stream-io/video-client-1.4.1) (2024-06-19)
6
20
 
7
21
 
@@ -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, merge, from, Observable, debounceTime, concatMap, pairwise, of, filter, debounce, timer } from 'rxjs';
7
+ import { ReplaySubject, combineLatest, BehaviorSubject, map as map$1, shareReplay, distinctUntilChanged, takeWhile, distinctUntilKeyChanged, fromEventPattern, startWith, concatMap, merge, from, fromEvent, debounceTime, pairwise, of, filter, 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';
@@ -122,6 +122,11 @@ const RecordSettingsRequestQualityEnum = {
122
122
  _720P: '720p',
123
123
  _1080P: '1080p',
124
124
  _1440P: '1440p',
125
+ PORTRAIT_360X640: 'portrait-360x640',
126
+ PORTRAIT_480X854: 'portrait-480x854',
127
+ PORTRAIT_720X1280: 'portrait-720x1280',
128
+ PORTRAIT_1080X1920: 'portrait-1080x1920',
129
+ PORTRAIT_1440X2560: 'portrait-1440x2560',
125
130
  };
126
131
  /**
127
132
  * @export
@@ -10807,6 +10812,127 @@ const CallTypes = new CallTypesRegistry([
10807
10812
  }),
10808
10813
  ]);
10809
10814
 
10815
+ class BrowserPermission {
10816
+ constructor(permission) {
10817
+ this.permission = permission;
10818
+ this.disposeController = new AbortController();
10819
+ this.wasPrompted = false;
10820
+ this.listeners = new Set();
10821
+ this.logger = getLogger(['permissions']);
10822
+ const signal = this.disposeController.signal;
10823
+ this.ready = (async () => {
10824
+ const assumeGranted = (error) => {
10825
+ this.logger('warn', "Can't query permissions, assuming granted", {
10826
+ permission,
10827
+ error,
10828
+ });
10829
+ this.setState('granted');
10830
+ };
10831
+ if (!canQueryPermissions()) {
10832
+ return assumeGranted();
10833
+ }
10834
+ try {
10835
+ const status = await navigator.permissions.query({
10836
+ name: permission.queryName,
10837
+ });
10838
+ if (!signal.aborted) {
10839
+ this.setState(status.state);
10840
+ status.addEventListener('change', () => this.setState(status.state), {
10841
+ signal,
10842
+ });
10843
+ }
10844
+ }
10845
+ catch (err) {
10846
+ assumeGranted(err);
10847
+ }
10848
+ })();
10849
+ }
10850
+ dispose() {
10851
+ this.state = undefined;
10852
+ this.disposeController.abort();
10853
+ }
10854
+ async getState() {
10855
+ await this.ready;
10856
+ if (!this.state) {
10857
+ throw new Error('BrowserPermission instance possibly disposed');
10858
+ }
10859
+ return this.state;
10860
+ }
10861
+ async prompt({ forcePrompt = false, throwOnNotAllowed = false, } = {}) {
10862
+ await withoutConcurrency(`permission-prompt-${this.permission.queryName}`, async () => {
10863
+ if ((await this.getState()) !== 'prompt' ||
10864
+ (this.wasPrompted && !forcePrompt)) {
10865
+ const isGranted = this.state === 'granted';
10866
+ if (!isGranted && throwOnNotAllowed) {
10867
+ throw new DOMException('Permission was not granted previously, and prompting again is not allowed', 'NotAllowedError');
10868
+ }
10869
+ return isGranted;
10870
+ }
10871
+ try {
10872
+ this.wasPrompted = true;
10873
+ const stream = await navigator.mediaDevices.getUserMedia(this.permission.constraints);
10874
+ disposeOfMediaStream(stream);
10875
+ return true;
10876
+ }
10877
+ catch (e) {
10878
+ if (e instanceof DOMException && e.name === 'NotAllowedError') {
10879
+ this.logger('info', 'Browser permission was not granted', {
10880
+ permission: this.permission,
10881
+ });
10882
+ if (throwOnNotAllowed) {
10883
+ throw e;
10884
+ }
10885
+ return false;
10886
+ }
10887
+ this.logger('error', `Failed to getUserMedia`, {
10888
+ error: e,
10889
+ permission: this.permission,
10890
+ });
10891
+ throw e;
10892
+ }
10893
+ });
10894
+ }
10895
+ listen(cb) {
10896
+ this.listeners.add(cb);
10897
+ if (this.state)
10898
+ cb(this.state);
10899
+ return () => this.listeners.delete(cb);
10900
+ }
10901
+ asObservable() {
10902
+ return fromEventPattern((handler) => this.listen(handler), (handler, unlisten) => unlisten()).pipe(
10903
+ // In some browsers, the 'change' event doesn't reliably emit and hence,
10904
+ // permissionState stays in 'prompt' state forever.
10905
+ // Typically, this happens when a user grants one-time permission.
10906
+ // Instead of checking if a permission is granted, we check if it isn't denied
10907
+ map$1((state) => state !== 'denied'));
10908
+ }
10909
+ setState(state) {
10910
+ if (this.state !== state) {
10911
+ this.state = state;
10912
+ this.listeners.forEach((listener) => listener(state));
10913
+ }
10914
+ }
10915
+ }
10916
+ function canQueryPermissions() {
10917
+ return (!isReactNative() &&
10918
+ typeof navigator !== 'undefined' &&
10919
+ !!navigator.permissions?.query);
10920
+ }
10921
+
10922
+ const uninitialized = Symbol('uninitialized');
10923
+ /**
10924
+ * Lazily creates a value using a provided factory
10925
+ */
10926
+ function lazy(factory) {
10927
+ let value = uninitialized;
10928
+ return () => {
10929
+ if (value === uninitialized) {
10930
+ value = factory();
10931
+ }
10932
+ return value;
10933
+ };
10934
+ }
10935
+
10810
10936
  /**
10811
10937
  * Returns an Observable that emits the list of available devices
10812
10938
  * that meet the given constraints.
@@ -10814,44 +10940,23 @@ const CallTypes = new CallTypesRegistry([
10814
10940
  * @param constraints the constraints to use when requesting the devices.
10815
10941
  * @param kind the kind of devices to enumerate.
10816
10942
  */
10817
- const getDevices = (constraints, kind) => {
10818
- return new Observable((subscriber) => {
10819
- const enumerate = async () => {
10820
- let devices = await navigator.mediaDevices.enumerateDevices();
10821
- // some browsers report empty device labels (Firefox).
10822
- // in that case, we need to request permissions (via getUserMedia)
10823
- // to be able to get the device labels
10824
- const needsGetUserMedia = devices.some((device) => device.kind === kind && device.label === '');
10825
- if (needsGetUserMedia) {
10826
- let mediaStream;
10827
- try {
10828
- mediaStream = await navigator.mediaDevices.getUserMedia(constraints);
10829
- devices = await navigator.mediaDevices.enumerateDevices();
10830
- }
10831
- finally {
10832
- if (mediaStream)
10833
- disposeOfMediaStream(mediaStream);
10834
- }
10835
- }
10836
- return devices;
10837
- };
10838
- enumerate()
10839
- .then((devices) => {
10840
- // notify subscribers and complete
10841
- subscriber.next(devices);
10842
- subscriber.complete();
10843
- })
10844
- .catch((error) => {
10845
- const logger = getLogger(['devices']);
10846
- logger('error', 'Failed to enumerate devices', error);
10847
- subscriber.error(error);
10848
- });
10849
- });
10943
+ const getDevices = (permission, kind) => {
10944
+ return from((async () => {
10945
+ let devices = await navigator.mediaDevices.enumerateDevices();
10946
+ // for privacy reasons, most browsers don't give you device labels
10947
+ // unless you have a corresponding camera or microphone permission
10948
+ const shouldPromptForBrowserPermission = devices.some((device) => device.kind === kind && device.label === '');
10949
+ if (shouldPromptForBrowserPermission) {
10950
+ await permission.prompt({ throwOnNotAllowed: true });
10951
+ devices = await navigator.mediaDevices.enumerateDevices();
10952
+ }
10953
+ return devices.filter((d) => d.kind === kind);
10954
+ })());
10850
10955
  };
10851
10956
  /**
10852
- * [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
10853
- *
10854
- * */
10957
+ * Tells if the browser supports audio output change on 'audio' elements,
10958
+ * see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId.
10959
+ */
10855
10960
  const checkIfAudioOutputChangeSupported = () => {
10856
10961
  if (typeof document === 'undefined')
10857
10962
  return false;
@@ -10878,72 +10983,57 @@ const videoDeviceConstraints = {
10878
10983
  },
10879
10984
  };
10880
10985
  /**
10881
- * Creates a memoized observable instance
10882
- * that will be created only once and shared between all callers.
10883
- *
10884
- * @param create a function that creates an Observable.
10885
- */
10886
- const memoizedObservable = (create) => {
10887
- let memoized;
10888
- return () => {
10889
- if (!memoized)
10890
- memoized = create();
10891
- return memoized;
10892
- };
10893
- };
10894
- const getDeviceChangeObserver = memoizedObservable(() => {
10895
- // Audio and video devices are requested in two separate requests.
10896
- // That way, users will be presented with two separate prompts
10897
- // -> they can give access to just camera, or just microphone
10898
- return new Observable((subscriber) => {
10899
- // 'addEventListener' is not available in React Native
10900
- if (!navigator.mediaDevices.addEventListener)
10901
- return;
10902
- const notify = () => subscriber.next();
10903
- navigator.mediaDevices.addEventListener('devicechange', notify);
10904
- return () => {
10905
- navigator.mediaDevices.removeEventListener('devicechange', notify);
10906
- };
10907
- }).pipe(debounceTime(500), concatMap(() => from(navigator.mediaDevices.enumerateDevices())), shareReplay(1));
10908
- });
10909
- const getAudioDevicesObserver = memoizedObservable(() => {
10910
- return merge(getDevices(audioDeviceConstraints, 'audioinput'), getDeviceChangeObserver()).pipe(shareReplay(1));
10911
- });
10912
- const getAudioOutputDevicesObserver = memoizedObservable(() => {
10913
- return merge(getDevices(audioDeviceConstraints, 'audiooutput'), getDeviceChangeObserver()).pipe(shareReplay(1));
10914
- });
10915
- const getVideoDevicesObserver = memoizedObservable(() => {
10916
- return merge(getDevices(videoDeviceConstraints, 'videoinput'), getDeviceChangeObserver()).pipe(shareReplay(1));
10986
+ * Keeps track of the browser permission to use microphone. This permission also
10987
+ * affects an ability to enumerate audio devices.
10988
+ */
10989
+ const getAudioBrowserPermission = lazy(() => new BrowserPermission({
10990
+ constraints: audioDeviceConstraints,
10991
+ queryName: 'microphone',
10992
+ }));
10993
+ /**
10994
+ * Keeps track of the browser permission to use camera. This permission also
10995
+ * affects an ability to enumerate video devices.
10996
+ */
10997
+ const getVideoBrowserPermission = lazy(() => new BrowserPermission({
10998
+ constraints: videoDeviceConstraints,
10999
+ queryName: 'camera',
11000
+ }));
11001
+ const getDeviceChangeObserver = lazy(() => {
11002
+ // 'addEventListener' is not available in React Native, returning
11003
+ // an observable that will never fire
11004
+ if (!navigator.mediaDevices.addEventListener)
11005
+ return from([]);
11006
+ return fromEvent(navigator.mediaDevices, 'devicechange').pipe(map$1(() => undefined), debounceTime(500));
10917
11007
  });
10918
11008
  /**
10919
- * Prompts the user for a permission to use audio devices (if not already granted) and lists the available 'audioinput' devices, if devices are added/removed the list is updated.
11009
+ * Prompts the user for a permission to use audio devices (if not already granted
11010
+ * and was not prompted before) and lists the available 'audioinput' devices,
11011
+ * if devices are added/removed the list is updated, and if the permission is revoked,
11012
+ * the observable errors.
10920
11013
  */
10921
- const getAudioDevices = () => {
10922
- return getAudioDevicesObserver().pipe(map$1((values) => values.filter((d) => d.kind === 'audioinput')));
10923
- };
11014
+ const getAudioDevices = lazy(() => {
11015
+ return merge(getDeviceChangeObserver(), getAudioBrowserPermission().asObservable()).pipe(startWith(undefined), concatMap(() => getDevices(getAudioBrowserPermission(), 'audioinput')), shareReplay(1));
11016
+ });
10924
11017
  /**
10925
- * Prompts the user for a permission to use video devices (if not already granted) and lists the available 'videoinput' devices, if devices are added/removed the list is updated.
11018
+ * Prompts the user for a permission to use video devices (if not already granted
11019
+ * and was not prompted before) and lists the available 'videoinput' devices,
11020
+ * if devices are added/removed the list is updated, and if the permission is revoked,
11021
+ * the observable errors.
10926
11022
  */
10927
11023
  const getVideoDevices = () => {
10928
- return getVideoDevicesObserver().pipe(map$1((values) => values.filter((d) => d.kind === 'videoinput')));
11024
+ return merge(getDeviceChangeObserver(), getVideoBrowserPermission().asObservable()).pipe(startWith(undefined), concatMap(() => getDevices(getVideoBrowserPermission(), 'videoinput')), shareReplay(1));
10929
11025
  };
10930
11026
  /**
10931
- * Prompts the user for a permission to use audio devices (if not already granted) and lists the available 'audiooutput' devices, if devices are added/removed the list is updated. Selecting 'audiooutput' device only makes sense if [the browser has support for changing audio output on 'audio' elements](#checkifaudiooutputchangesupported)
11027
+ * Prompts the user for a permission to use video devices (if not already granted
11028
+ * and was not prompted before) and lists the available 'audiooutput' devices,
11029
+ * if devices are added/removed the list is updated, and if the permission is revoked,
11030
+ * the observable errors.
10932
11031
  */
10933
11032
  const getAudioOutputDevices = () => {
10934
- return getAudioOutputDevicesObserver().pipe(map$1((values) => values.filter((d) => d.kind === 'audiooutput')));
11033
+ return merge(getDeviceChangeObserver(), getAudioBrowserPermission().asObservable()).pipe(startWith(undefined), concatMap(() => getDevices(getAudioBrowserPermission(), 'audiooutput')), shareReplay(1));
10935
11034
  };
10936
11035
  const getStream = async (constraints) => {
10937
- try {
10938
- return await navigator.mediaDevices.getUserMedia(constraints);
10939
- }
10940
- catch (e) {
10941
- getLogger(['devices'])('error', `Failed to getUserMedia`, {
10942
- error: e,
10943
- constraints: constraints,
10944
- });
10945
- throw e;
10946
- }
11036
+ return await navigator.mediaDevices.getUserMedia(constraints);
10947
11037
  };
10948
11038
  /**
10949
11039
  * Returns an audio media stream that fulfills the given constraints.
@@ -10960,7 +11050,20 @@ const getAudioStream = async (trackConstraints) => {
10960
11050
  ...trackConstraints,
10961
11051
  },
10962
11052
  };
10963
- return getStream(constraints);
11053
+ try {
11054
+ await getAudioBrowserPermission().prompt({
11055
+ throwOnNotAllowed: true,
11056
+ forcePrompt: true,
11057
+ });
11058
+ return getStream(constraints);
11059
+ }
11060
+ catch (e) {
11061
+ getLogger(['devices'])('error', 'Failed to get audio stream', {
11062
+ error: e,
11063
+ constraints: constraints,
11064
+ });
11065
+ throw e;
11066
+ }
10964
11067
  };
10965
11068
  /**
10966
11069
  * Returns a video media stream that fulfills the given constraints.
@@ -10977,7 +11080,20 @@ const getVideoStream = async (trackConstraints) => {
10977
11080
  ...trackConstraints,
10978
11081
  },
10979
11082
  };
10980
- return getStream(constraints);
11083
+ try {
11084
+ await getVideoBrowserPermission().prompt({
11085
+ throwOnNotAllowed: true,
11086
+ forcePrompt: true,
11087
+ });
11088
+ return getStream(constraints);
11089
+ }
11090
+ catch (e) {
11091
+ getLogger(['devices'])('error', 'Failed to get video stream', {
11092
+ error: e,
11093
+ constraints: constraints,
11094
+ });
11095
+ throw e;
11096
+ }
10981
11097
  };
10982
11098
  /**
10983
11099
  * Prompts the user for a permission to share a screen.
@@ -11013,7 +11129,7 @@ const getScreenShareStream = async (options) => {
11013
11129
  };
11014
11130
  const deviceIds$ = typeof navigator !== 'undefined' &&
11015
11131
  typeof navigator.mediaDevices !== 'undefined'
11016
- ? memoizedObservable(() => merge(from(navigator.mediaDevices.enumerateDevices()), getDeviceChangeObserver()).pipe(shareReplay(1)))()
11132
+ ? getDeviceChangeObserver().pipe(startWith(undefined), concatMap(() => navigator.mediaDevices.enumerateDevices()), shareReplay(1))
11017
11133
  : undefined;
11018
11134
  /**
11019
11135
  * Deactivates MediaStream (stops and removes tracks) to be later garbage collected
@@ -11396,12 +11512,11 @@ class InputMediaDeviceManagerState {
11396
11512
  * Constructs new InputMediaDeviceManagerState instance.
11397
11513
  *
11398
11514
  * @param disableMode the disable mode to use.
11399
- * @param permissionName the permission name to use for querying.
11515
+ * @param permission the BrowserPermission to use for querying.
11400
11516
  * `undefined` means no permission is required.
11401
11517
  */
11402
- constructor(disableMode = 'stop-tracks', permissionName = undefined) {
11518
+ constructor(disableMode = 'stop-tracks', permission) {
11403
11519
  this.disableMode = disableMode;
11404
- this.permissionName = permissionName;
11405
11520
  this.statusSubject = new BehaviorSubject(undefined);
11406
11521
  this.optimisticStatusSubject = new BehaviorSubject(undefined);
11407
11522
  this.mediaStreamSubject = new BehaviorSubject(undefined);
@@ -11432,43 +11547,6 @@ class InputMediaDeviceManagerState {
11432
11547
  * The default constraints for the device.
11433
11548
  */
11434
11549
  this.defaultConstraints$ = this.defaultConstraintsSubject.asObservable();
11435
- /**
11436
- * An observable that will emit `true` if browser/system permission
11437
- * is granted, `false` otherwise.
11438
- */
11439
- this.hasBrowserPermission$ = new Observable((subscriber) => {
11440
- const notifyGranted = () => subscriber.next(true);
11441
- const permissionsAPIAvailable = !!navigator?.permissions?.query;
11442
- if (isReactNative() || !this.permissionName || !permissionsAPIAvailable) {
11443
- getLogger(['devices'])('warn', `Permissions can't be queried. Assuming granted.`);
11444
- return notifyGranted();
11445
- }
11446
- let permissionState;
11447
- const notify = () => {
11448
- subscriber.next(
11449
- // In some browsers, the 'change' event doesn't reliably emit and hence,
11450
- // permissionState stays in 'prompt' state forever.
11451
- // Typically, this happens when a user grants one-time permission.
11452
- // Instead of checking if a permission is granted, we check if it isn't denied
11453
- permissionState.state !== 'denied');
11454
- };
11455
- navigator.permissions
11456
- .query({ name: this.permissionName })
11457
- .then((permissionStatus) => {
11458
- permissionState = permissionStatus;
11459
- permissionState.addEventListener('change', notify);
11460
- notify();
11461
- })
11462
- .catch(() => {
11463
- // permission doesn't exist or can't be queried -> assume it's granted
11464
- // an example would be Firefox,
11465
- // where neither camera microphone permission can be queried
11466
- notifyGranted();
11467
- });
11468
- return () => {
11469
- permissionState?.removeEventListener('change', notify);
11470
- };
11471
- }).pipe(shareReplay(1));
11472
11550
  /**
11473
11551
  * Gets the current value of an observable, or undefined if the observable has
11474
11552
  * not emitted a value yet.
@@ -11488,6 +11566,9 @@ class InputMediaDeviceManagerState {
11488
11566
  * @return the updated value.
11489
11567
  */
11490
11568
  this.setCurrentValue = setCurrentValue;
11569
+ this.hasBrowserPermission$ = permission
11570
+ ? permission.asObservable().pipe(shareReplay(1))
11571
+ : of(true);
11491
11572
  }
11492
11573
  /**
11493
11574
  * The device status
@@ -11567,10 +11648,7 @@ class InputMediaDeviceManagerState {
11567
11648
 
11568
11649
  class CameraManagerState extends InputMediaDeviceManagerState {
11569
11650
  constructor() {
11570
- super('stop-tracks',
11571
- // `camera` is not in the W3C standard yet,
11572
- // but it's supported by Chrome and Safari.
11573
- 'camera');
11651
+ super('stop-tracks', getVideoBrowserPermission());
11574
11652
  this.directionSubject = new BehaviorSubject(undefined);
11575
11653
  this.direction$ = this.directionSubject
11576
11654
  .asObservable()
@@ -11701,10 +11779,7 @@ class CameraManager extends InputMediaDeviceManager {
11701
11779
 
11702
11780
  class MicrophoneManagerState extends InputMediaDeviceManagerState {
11703
11781
  constructor(disableMode) {
11704
- super(disableMode,
11705
- // `microphone` is not in the W3C standard yet,
11706
- // but it's supported by Chrome and Safari.
11707
- 'microphone');
11782
+ super(disableMode, getAudioBrowserPermission());
11708
11783
  this.speakingWhileMutedSubject = new BehaviorSubject(false);
11709
11784
  this.speakingWhileMuted$ = this.speakingWhileMutedSubject
11710
11785
  .asObservable()
@@ -15409,7 +15484,7 @@ class StreamClient {
15409
15484
  });
15410
15485
  };
15411
15486
  this.getUserAgent = () => {
15412
- const version = "1.4.1" ;
15487
+ const version = "1.4.3" ;
15413
15488
  return (this.userAgent ||
15414
15489
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
15415
15490
  };
@@ -15888,5 +15963,5 @@ class StreamVideoClient {
15888
15963
  }
15889
15964
  }
15890
15965
 
15891
- export { AudioSettingsRequestDefaultDeviceEnum, AudioSettingsResponseDefaultDeviceEnum, BlockListOptionsBehaviorEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CameraManager, CameraManagerState, ChannelConfigWithInfoAutomodBehaviorEnum, ChannelConfigWithInfoAutomodEnum, ChannelConfigWithInfoBlocklistBehaviorEnum, CreateDeviceRequestPushProviderEnum, DebounceType, DynascaleManager, ErrorFromResponse, InputMediaDeviceManager, InputMediaDeviceManagerState, MicrophoneManager, MicrophoneManagerState, NoiseCancellationSettingsModeEnum, OwnCapability, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, ScreenShareManager, ScreenShareState, events as SfuEvents, models as SfuModels, SpeakerManager, SpeakerState, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoWriteableStateStore, TranscriptionSettingsRequestModeEnum, TranscriptionSettingsResponseModeEnum, VideoSettingsRequestCameraFacingEnum, VideoSettingsResponseCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, deviceIds$, disposeOfMediaStream, dominantSpeaker, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceInfo, getLogger, getOSInfo, getScreenShareStream, getSdkInfo, getVideoDevices, getVideoStream, getWebRTCInfo, hasAudio, hasScreenShare, hasScreenShareAudio, hasVideo, isPinned, livestreamOrAudioRoomSortPreset, logLevels, logToConsole, name, noopComparator, paginatedLayoutSortPreset, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setDeviceInfo, setLogLevel, setLogger, setOSInfo, setSdkInfo, setWebRTCInfo, speakerLayoutSortPreset, speaking };
15966
+ export { AudioSettingsRequestDefaultDeviceEnum, AudioSettingsResponseDefaultDeviceEnum, BlockListOptionsBehaviorEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CameraManager, CameraManagerState, ChannelConfigWithInfoAutomodBehaviorEnum, ChannelConfigWithInfoAutomodEnum, ChannelConfigWithInfoBlocklistBehaviorEnum, CreateDeviceRequestPushProviderEnum, DebounceType, DynascaleManager, ErrorFromResponse, InputMediaDeviceManager, InputMediaDeviceManagerState, MicrophoneManager, MicrophoneManagerState, NoiseCancellationSettingsModeEnum, OwnCapability, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, ScreenShareManager, ScreenShareState, events as SfuEvents, models as SfuModels, SpeakerManager, SpeakerState, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoWriteableStateStore, TranscriptionSettingsRequestModeEnum, TranscriptionSettingsResponseModeEnum, VideoSettingsRequestCameraFacingEnum, VideoSettingsResponseCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, deviceIds$, disposeOfMediaStream, dominantSpeaker, getAudioBrowserPermission, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceInfo, getLogger, getOSInfo, getScreenShareStream, getSdkInfo, getVideoBrowserPermission, getVideoDevices, getVideoStream, getWebRTCInfo, hasAudio, hasScreenShare, hasScreenShareAudio, hasVideo, isPinned, livestreamOrAudioRoomSortPreset, logLevels, logToConsole, name, noopComparator, paginatedLayoutSortPreset, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setDeviceInfo, setLogLevel, setLogger, setOSInfo, setSdkInfo, setWebRTCInfo, speakerLayoutSortPreset, speaking };
15892
15967
  //# sourceMappingURL=index.browser.es.js.map