@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.
- package/CHANGELOG.md +14 -0
- package/dist/index.browser.es.js +219 -144
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +219 -142
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +219 -144
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +7 -7
- package/dist/src/StreamSfuClient.d.ts +7 -7
- package/dist/src/StreamVideoClient.d.ts +5 -5
- package/dist/src/coordinator/connection/client.d.ts +13 -14
- package/dist/src/coordinator/connection/connection.d.ts +3 -5
- package/dist/src/coordinator/connection/insights.d.ts +0 -1
- package/dist/src/devices/BrowserPermission.d.ts +24 -0
- package/dist/src/devices/InputMediaDeviceManagerState.d.ts +3 -3
- package/dist/src/devices/devices.d.ts +30 -11
- package/dist/src/gen/coordinator/index.d.ts +5 -0
- package/dist/src/helpers/ViewportTracker.d.ts +1 -1
- package/dist/src/helpers/lazy.d.ts +4 -0
- package/dist/src/helpers/sdp-munging.d.ts +2 -2
- package/dist/src/rtc/Dispatcher.d.ts +2 -2
- package/dist/src/rtc/codecs.d.ts +1 -1
- package/dist/src/rtc/signal.d.ts +0 -1
- package/dist/src/stats/utils.d.ts +4 -4
- package/dist/src/store/CallState.d.ts +1 -1
- package/package.json +4 -4
- package/src/devices/BrowserPermission.ts +152 -0
- package/src/devices/CameraManagerState.ts +2 -6
- package/src/devices/InputMediaDeviceManagerState.ts +10 -44
- package/src/devices/MicrophoneManagerState.ts +2 -6
- package/src/devices/__tests__/CameraManager.test.ts +3 -0
- package/src/devices/__tests__/InputMediaDeviceManager.test.ts +5 -3
- package/src/devices/__tests__/InputMediaDeviceManagerFilters.test.ts +6 -2
- package/src/devices/__tests__/InputMediaDeviceManagerState.test.ts +41 -51
- package/src/devices/__tests__/MicrophoneManager.test.ts +4 -1
- package/src/devices/__tests__/MicrophoneManagerRN.test.ts +8 -1
- package/src/devices/__tests__/SpeakerManager.test.ts +8 -1
- package/src/devices/__tests__/mocks.ts +6 -1
- package/src/devices/devices.ts +113 -112
- package/src/gen/coordinator/index.ts +5 -0
- package/src/helpers/RNSpeechDetector.ts +1 -1
- package/src/helpers/lazy.ts +15 -0
package/dist/index.cjs.js
CHANGED
|
@@ -143,6 +143,11 @@ const RecordSettingsRequestQualityEnum = {
|
|
|
143
143
|
_720P: '720p',
|
|
144
144
|
_1080P: '1080p',
|
|
145
145
|
_1440P: '1440p',
|
|
146
|
+
PORTRAIT_360X640: 'portrait-360x640',
|
|
147
|
+
PORTRAIT_480X854: 'portrait-480x854',
|
|
148
|
+
PORTRAIT_720X1280: 'portrait-720x1280',
|
|
149
|
+
PORTRAIT_1080X1920: 'portrait-1080x1920',
|
|
150
|
+
PORTRAIT_1440X2560: 'portrait-1440x2560',
|
|
146
151
|
};
|
|
147
152
|
/**
|
|
148
153
|
* @export
|
|
@@ -10828,6 +10833,127 @@ const CallTypes = new CallTypesRegistry([
|
|
|
10828
10833
|
}),
|
|
10829
10834
|
]);
|
|
10830
10835
|
|
|
10836
|
+
class BrowserPermission {
|
|
10837
|
+
constructor(permission) {
|
|
10838
|
+
this.permission = permission;
|
|
10839
|
+
this.disposeController = new AbortController();
|
|
10840
|
+
this.wasPrompted = false;
|
|
10841
|
+
this.listeners = new Set();
|
|
10842
|
+
this.logger = getLogger(['permissions']);
|
|
10843
|
+
const signal = this.disposeController.signal;
|
|
10844
|
+
this.ready = (async () => {
|
|
10845
|
+
const assumeGranted = (error) => {
|
|
10846
|
+
this.logger('warn', "Can't query permissions, assuming granted", {
|
|
10847
|
+
permission,
|
|
10848
|
+
error,
|
|
10849
|
+
});
|
|
10850
|
+
this.setState('granted');
|
|
10851
|
+
};
|
|
10852
|
+
if (!canQueryPermissions()) {
|
|
10853
|
+
return assumeGranted();
|
|
10854
|
+
}
|
|
10855
|
+
try {
|
|
10856
|
+
const status = await navigator.permissions.query({
|
|
10857
|
+
name: permission.queryName,
|
|
10858
|
+
});
|
|
10859
|
+
if (!signal.aborted) {
|
|
10860
|
+
this.setState(status.state);
|
|
10861
|
+
status.addEventListener('change', () => this.setState(status.state), {
|
|
10862
|
+
signal,
|
|
10863
|
+
});
|
|
10864
|
+
}
|
|
10865
|
+
}
|
|
10866
|
+
catch (err) {
|
|
10867
|
+
assumeGranted(err);
|
|
10868
|
+
}
|
|
10869
|
+
})();
|
|
10870
|
+
}
|
|
10871
|
+
dispose() {
|
|
10872
|
+
this.state = undefined;
|
|
10873
|
+
this.disposeController.abort();
|
|
10874
|
+
}
|
|
10875
|
+
async getState() {
|
|
10876
|
+
await this.ready;
|
|
10877
|
+
if (!this.state) {
|
|
10878
|
+
throw new Error('BrowserPermission instance possibly disposed');
|
|
10879
|
+
}
|
|
10880
|
+
return this.state;
|
|
10881
|
+
}
|
|
10882
|
+
async prompt({ forcePrompt = false, throwOnNotAllowed = false, } = {}) {
|
|
10883
|
+
await withoutConcurrency(`permission-prompt-${this.permission.queryName}`, async () => {
|
|
10884
|
+
if ((await this.getState()) !== 'prompt' ||
|
|
10885
|
+
(this.wasPrompted && !forcePrompt)) {
|
|
10886
|
+
const isGranted = this.state === 'granted';
|
|
10887
|
+
if (!isGranted && throwOnNotAllowed) {
|
|
10888
|
+
throw new DOMException('Permission was not granted previously, and prompting again is not allowed', 'NotAllowedError');
|
|
10889
|
+
}
|
|
10890
|
+
return isGranted;
|
|
10891
|
+
}
|
|
10892
|
+
try {
|
|
10893
|
+
this.wasPrompted = true;
|
|
10894
|
+
const stream = await navigator.mediaDevices.getUserMedia(this.permission.constraints);
|
|
10895
|
+
disposeOfMediaStream(stream);
|
|
10896
|
+
return true;
|
|
10897
|
+
}
|
|
10898
|
+
catch (e) {
|
|
10899
|
+
if (e instanceof DOMException && e.name === 'NotAllowedError') {
|
|
10900
|
+
this.logger('info', 'Browser permission was not granted', {
|
|
10901
|
+
permission: this.permission,
|
|
10902
|
+
});
|
|
10903
|
+
if (throwOnNotAllowed) {
|
|
10904
|
+
throw e;
|
|
10905
|
+
}
|
|
10906
|
+
return false;
|
|
10907
|
+
}
|
|
10908
|
+
this.logger('error', `Failed to getUserMedia`, {
|
|
10909
|
+
error: e,
|
|
10910
|
+
permission: this.permission,
|
|
10911
|
+
});
|
|
10912
|
+
throw e;
|
|
10913
|
+
}
|
|
10914
|
+
});
|
|
10915
|
+
}
|
|
10916
|
+
listen(cb) {
|
|
10917
|
+
this.listeners.add(cb);
|
|
10918
|
+
if (this.state)
|
|
10919
|
+
cb(this.state);
|
|
10920
|
+
return () => this.listeners.delete(cb);
|
|
10921
|
+
}
|
|
10922
|
+
asObservable() {
|
|
10923
|
+
return rxjs.fromEventPattern((handler) => this.listen(handler), (handler, unlisten) => unlisten()).pipe(
|
|
10924
|
+
// In some browsers, the 'change' event doesn't reliably emit and hence,
|
|
10925
|
+
// permissionState stays in 'prompt' state forever.
|
|
10926
|
+
// Typically, this happens when a user grants one-time permission.
|
|
10927
|
+
// Instead of checking if a permission is granted, we check if it isn't denied
|
|
10928
|
+
rxjs.map((state) => state !== 'denied'));
|
|
10929
|
+
}
|
|
10930
|
+
setState(state) {
|
|
10931
|
+
if (this.state !== state) {
|
|
10932
|
+
this.state = state;
|
|
10933
|
+
this.listeners.forEach((listener) => listener(state));
|
|
10934
|
+
}
|
|
10935
|
+
}
|
|
10936
|
+
}
|
|
10937
|
+
function canQueryPermissions() {
|
|
10938
|
+
return (!isReactNative() &&
|
|
10939
|
+
typeof navigator !== 'undefined' &&
|
|
10940
|
+
!!navigator.permissions?.query);
|
|
10941
|
+
}
|
|
10942
|
+
|
|
10943
|
+
const uninitialized = Symbol('uninitialized');
|
|
10944
|
+
/**
|
|
10945
|
+
* Lazily creates a value using a provided factory
|
|
10946
|
+
*/
|
|
10947
|
+
function lazy(factory) {
|
|
10948
|
+
let value = uninitialized;
|
|
10949
|
+
return () => {
|
|
10950
|
+
if (value === uninitialized) {
|
|
10951
|
+
value = factory();
|
|
10952
|
+
}
|
|
10953
|
+
return value;
|
|
10954
|
+
};
|
|
10955
|
+
}
|
|
10956
|
+
|
|
10831
10957
|
/**
|
|
10832
10958
|
* Returns an Observable that emits the list of available devices
|
|
10833
10959
|
* that meet the given constraints.
|
|
@@ -10835,44 +10961,23 @@ const CallTypes = new CallTypesRegistry([
|
|
|
10835
10961
|
* @param constraints the constraints to use when requesting the devices.
|
|
10836
10962
|
* @param kind the kind of devices to enumerate.
|
|
10837
10963
|
*/
|
|
10838
|
-
const getDevices = (
|
|
10839
|
-
return
|
|
10840
|
-
|
|
10841
|
-
|
|
10842
|
-
|
|
10843
|
-
|
|
10844
|
-
|
|
10845
|
-
|
|
10846
|
-
|
|
10847
|
-
|
|
10848
|
-
|
|
10849
|
-
|
|
10850
|
-
devices = await navigator.mediaDevices.enumerateDevices();
|
|
10851
|
-
}
|
|
10852
|
-
finally {
|
|
10853
|
-
if (mediaStream)
|
|
10854
|
-
disposeOfMediaStream(mediaStream);
|
|
10855
|
-
}
|
|
10856
|
-
}
|
|
10857
|
-
return devices;
|
|
10858
|
-
};
|
|
10859
|
-
enumerate()
|
|
10860
|
-
.then((devices) => {
|
|
10861
|
-
// notify subscribers and complete
|
|
10862
|
-
subscriber.next(devices);
|
|
10863
|
-
subscriber.complete();
|
|
10864
|
-
})
|
|
10865
|
-
.catch((error) => {
|
|
10866
|
-
const logger = getLogger(['devices']);
|
|
10867
|
-
logger('error', 'Failed to enumerate devices', error);
|
|
10868
|
-
subscriber.error(error);
|
|
10869
|
-
});
|
|
10870
|
-
});
|
|
10964
|
+
const getDevices = (permission, kind) => {
|
|
10965
|
+
return rxjs.from((async () => {
|
|
10966
|
+
let devices = await navigator.mediaDevices.enumerateDevices();
|
|
10967
|
+
// for privacy reasons, most browsers don't give you device labels
|
|
10968
|
+
// unless you have a corresponding camera or microphone permission
|
|
10969
|
+
const shouldPromptForBrowserPermission = devices.some((device) => device.kind === kind && device.label === '');
|
|
10970
|
+
if (shouldPromptForBrowserPermission) {
|
|
10971
|
+
await permission.prompt({ throwOnNotAllowed: true });
|
|
10972
|
+
devices = await navigator.mediaDevices.enumerateDevices();
|
|
10973
|
+
}
|
|
10974
|
+
return devices.filter((d) => d.kind === kind);
|
|
10975
|
+
})());
|
|
10871
10976
|
};
|
|
10872
10977
|
/**
|
|
10873
|
-
*
|
|
10874
|
-
*
|
|
10875
|
-
|
|
10978
|
+
* Tells if the browser supports audio output change on 'audio' elements,
|
|
10979
|
+
* see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId.
|
|
10980
|
+
*/
|
|
10876
10981
|
const checkIfAudioOutputChangeSupported = () => {
|
|
10877
10982
|
if (typeof document === 'undefined')
|
|
10878
10983
|
return false;
|
|
@@ -10899,72 +11004,57 @@ const videoDeviceConstraints = {
|
|
|
10899
11004
|
},
|
|
10900
11005
|
};
|
|
10901
11006
|
/**
|
|
10902
|
-
*
|
|
10903
|
-
*
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
//
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
const notify = () => subscriber.next();
|
|
10924
|
-
navigator.mediaDevices.addEventListener('devicechange', notify);
|
|
10925
|
-
return () => {
|
|
10926
|
-
navigator.mediaDevices.removeEventListener('devicechange', notify);
|
|
10927
|
-
};
|
|
10928
|
-
}).pipe(rxjs.debounceTime(500), rxjs.concatMap(() => rxjs.from(navigator.mediaDevices.enumerateDevices())), rxjs.shareReplay(1));
|
|
10929
|
-
});
|
|
10930
|
-
const getAudioDevicesObserver = memoizedObservable(() => {
|
|
10931
|
-
return rxjs.merge(getDevices(audioDeviceConstraints, 'audioinput'), getDeviceChangeObserver()).pipe(rxjs.shareReplay(1));
|
|
10932
|
-
});
|
|
10933
|
-
const getAudioOutputDevicesObserver = memoizedObservable(() => {
|
|
10934
|
-
return rxjs.merge(getDevices(audioDeviceConstraints, 'audiooutput'), getDeviceChangeObserver()).pipe(rxjs.shareReplay(1));
|
|
10935
|
-
});
|
|
10936
|
-
const getVideoDevicesObserver = memoizedObservable(() => {
|
|
10937
|
-
return rxjs.merge(getDevices(videoDeviceConstraints, 'videoinput'), getDeviceChangeObserver()).pipe(rxjs.shareReplay(1));
|
|
11007
|
+
* Keeps track of the browser permission to use microphone. This permission also
|
|
11008
|
+
* affects an ability to enumerate audio devices.
|
|
11009
|
+
*/
|
|
11010
|
+
const getAudioBrowserPermission = lazy(() => new BrowserPermission({
|
|
11011
|
+
constraints: audioDeviceConstraints,
|
|
11012
|
+
queryName: 'microphone',
|
|
11013
|
+
}));
|
|
11014
|
+
/**
|
|
11015
|
+
* Keeps track of the browser permission to use camera. This permission also
|
|
11016
|
+
* affects an ability to enumerate video devices.
|
|
11017
|
+
*/
|
|
11018
|
+
const getVideoBrowserPermission = lazy(() => new BrowserPermission({
|
|
11019
|
+
constraints: videoDeviceConstraints,
|
|
11020
|
+
queryName: 'camera',
|
|
11021
|
+
}));
|
|
11022
|
+
const getDeviceChangeObserver = lazy(() => {
|
|
11023
|
+
// 'addEventListener' is not available in React Native, returning
|
|
11024
|
+
// an observable that will never fire
|
|
11025
|
+
if (!navigator.mediaDevices.addEventListener)
|
|
11026
|
+
return rxjs.from([]);
|
|
11027
|
+
return rxjs.fromEvent(navigator.mediaDevices, 'devicechange').pipe(rxjs.map(() => undefined), rxjs.debounceTime(500));
|
|
10938
11028
|
});
|
|
10939
11029
|
/**
|
|
10940
|
-
* Prompts the user for a permission to use audio devices (if not already granted
|
|
11030
|
+
* Prompts the user for a permission to use audio devices (if not already granted
|
|
11031
|
+
* and was not prompted before) and lists the available 'audioinput' devices,
|
|
11032
|
+
* if devices are added/removed the list is updated, and if the permission is revoked,
|
|
11033
|
+
* the observable errors.
|
|
10941
11034
|
*/
|
|
10942
|
-
const getAudioDevices = () => {
|
|
10943
|
-
return
|
|
10944
|
-
};
|
|
11035
|
+
const getAudioDevices = lazy(() => {
|
|
11036
|
+
return rxjs.merge(getDeviceChangeObserver(), getAudioBrowserPermission().asObservable()).pipe(rxjs.startWith(undefined), rxjs.concatMap(() => getDevices(getAudioBrowserPermission(), 'audioinput')), rxjs.shareReplay(1));
|
|
11037
|
+
});
|
|
10945
11038
|
/**
|
|
10946
|
-
* Prompts the user for a permission to use video devices (if not already granted
|
|
11039
|
+
* Prompts the user for a permission to use video devices (if not already granted
|
|
11040
|
+
* and was not prompted before) and lists the available 'videoinput' devices,
|
|
11041
|
+
* if devices are added/removed the list is updated, and if the permission is revoked,
|
|
11042
|
+
* the observable errors.
|
|
10947
11043
|
*/
|
|
10948
11044
|
const getVideoDevices = () => {
|
|
10949
|
-
return
|
|
11045
|
+
return rxjs.merge(getDeviceChangeObserver(), getVideoBrowserPermission().asObservable()).pipe(rxjs.startWith(undefined), rxjs.concatMap(() => getDevices(getVideoBrowserPermission(), 'videoinput')), rxjs.shareReplay(1));
|
|
10950
11046
|
};
|
|
10951
11047
|
/**
|
|
10952
|
-
* Prompts the user for a permission to use
|
|
11048
|
+
* Prompts the user for a permission to use video devices (if not already granted
|
|
11049
|
+
* and was not prompted before) and lists the available 'audiooutput' devices,
|
|
11050
|
+
* if devices are added/removed the list is updated, and if the permission is revoked,
|
|
11051
|
+
* the observable errors.
|
|
10953
11052
|
*/
|
|
10954
11053
|
const getAudioOutputDevices = () => {
|
|
10955
|
-
return
|
|
11054
|
+
return rxjs.merge(getDeviceChangeObserver(), getAudioBrowserPermission().asObservable()).pipe(rxjs.startWith(undefined), rxjs.concatMap(() => getDevices(getAudioBrowserPermission(), 'audiooutput')), rxjs.shareReplay(1));
|
|
10956
11055
|
};
|
|
10957
11056
|
const getStream = async (constraints) => {
|
|
10958
|
-
|
|
10959
|
-
return await navigator.mediaDevices.getUserMedia(constraints);
|
|
10960
|
-
}
|
|
10961
|
-
catch (e) {
|
|
10962
|
-
getLogger(['devices'])('error', `Failed to getUserMedia`, {
|
|
10963
|
-
error: e,
|
|
10964
|
-
constraints: constraints,
|
|
10965
|
-
});
|
|
10966
|
-
throw e;
|
|
10967
|
-
}
|
|
11057
|
+
return await navigator.mediaDevices.getUserMedia(constraints);
|
|
10968
11058
|
};
|
|
10969
11059
|
/**
|
|
10970
11060
|
* Returns an audio media stream that fulfills the given constraints.
|
|
@@ -10981,7 +11071,20 @@ const getAudioStream = async (trackConstraints) => {
|
|
|
10981
11071
|
...trackConstraints,
|
|
10982
11072
|
},
|
|
10983
11073
|
};
|
|
10984
|
-
|
|
11074
|
+
try {
|
|
11075
|
+
await getAudioBrowserPermission().prompt({
|
|
11076
|
+
throwOnNotAllowed: true,
|
|
11077
|
+
forcePrompt: true,
|
|
11078
|
+
});
|
|
11079
|
+
return getStream(constraints);
|
|
11080
|
+
}
|
|
11081
|
+
catch (e) {
|
|
11082
|
+
getLogger(['devices'])('error', 'Failed to get audio stream', {
|
|
11083
|
+
error: e,
|
|
11084
|
+
constraints: constraints,
|
|
11085
|
+
});
|
|
11086
|
+
throw e;
|
|
11087
|
+
}
|
|
10985
11088
|
};
|
|
10986
11089
|
/**
|
|
10987
11090
|
* Returns a video media stream that fulfills the given constraints.
|
|
@@ -10998,7 +11101,20 @@ const getVideoStream = async (trackConstraints) => {
|
|
|
10998
11101
|
...trackConstraints,
|
|
10999
11102
|
},
|
|
11000
11103
|
};
|
|
11001
|
-
|
|
11104
|
+
try {
|
|
11105
|
+
await getVideoBrowserPermission().prompt({
|
|
11106
|
+
throwOnNotAllowed: true,
|
|
11107
|
+
forcePrompt: true,
|
|
11108
|
+
});
|
|
11109
|
+
return getStream(constraints);
|
|
11110
|
+
}
|
|
11111
|
+
catch (e) {
|
|
11112
|
+
getLogger(['devices'])('error', 'Failed to get video stream', {
|
|
11113
|
+
error: e,
|
|
11114
|
+
constraints: constraints,
|
|
11115
|
+
});
|
|
11116
|
+
throw e;
|
|
11117
|
+
}
|
|
11002
11118
|
};
|
|
11003
11119
|
/**
|
|
11004
11120
|
* Prompts the user for a permission to share a screen.
|
|
@@ -11034,7 +11150,7 @@ const getScreenShareStream = async (options) => {
|
|
|
11034
11150
|
};
|
|
11035
11151
|
const deviceIds$ = typeof navigator !== 'undefined' &&
|
|
11036
11152
|
typeof navigator.mediaDevices !== 'undefined'
|
|
11037
|
-
?
|
|
11153
|
+
? getDeviceChangeObserver().pipe(rxjs.startWith(undefined), rxjs.concatMap(() => navigator.mediaDevices.enumerateDevices()), rxjs.shareReplay(1))
|
|
11038
11154
|
: undefined;
|
|
11039
11155
|
/**
|
|
11040
11156
|
* Deactivates MediaStream (stops and removes tracks) to be later garbage collected
|
|
@@ -11417,12 +11533,11 @@ class InputMediaDeviceManagerState {
|
|
|
11417
11533
|
* Constructs new InputMediaDeviceManagerState instance.
|
|
11418
11534
|
*
|
|
11419
11535
|
* @param disableMode the disable mode to use.
|
|
11420
|
-
* @param
|
|
11536
|
+
* @param permission the BrowserPermission to use for querying.
|
|
11421
11537
|
* `undefined` means no permission is required.
|
|
11422
11538
|
*/
|
|
11423
|
-
constructor(disableMode = 'stop-tracks',
|
|
11539
|
+
constructor(disableMode = 'stop-tracks', permission) {
|
|
11424
11540
|
this.disableMode = disableMode;
|
|
11425
|
-
this.permissionName = permissionName;
|
|
11426
11541
|
this.statusSubject = new rxjs.BehaviorSubject(undefined);
|
|
11427
11542
|
this.optimisticStatusSubject = new rxjs.BehaviorSubject(undefined);
|
|
11428
11543
|
this.mediaStreamSubject = new rxjs.BehaviorSubject(undefined);
|
|
@@ -11453,43 +11568,6 @@ class InputMediaDeviceManagerState {
|
|
|
11453
11568
|
* The default constraints for the device.
|
|
11454
11569
|
*/
|
|
11455
11570
|
this.defaultConstraints$ = this.defaultConstraintsSubject.asObservable();
|
|
11456
|
-
/**
|
|
11457
|
-
* An observable that will emit `true` if browser/system permission
|
|
11458
|
-
* is granted, `false` otherwise.
|
|
11459
|
-
*/
|
|
11460
|
-
this.hasBrowserPermission$ = new rxjs.Observable((subscriber) => {
|
|
11461
|
-
const notifyGranted = () => subscriber.next(true);
|
|
11462
|
-
const permissionsAPIAvailable = !!navigator?.permissions?.query;
|
|
11463
|
-
if (isReactNative() || !this.permissionName || !permissionsAPIAvailable) {
|
|
11464
|
-
getLogger(['devices'])('warn', `Permissions can't be queried. Assuming granted.`);
|
|
11465
|
-
return notifyGranted();
|
|
11466
|
-
}
|
|
11467
|
-
let permissionState;
|
|
11468
|
-
const notify = () => {
|
|
11469
|
-
subscriber.next(
|
|
11470
|
-
// In some browsers, the 'change' event doesn't reliably emit and hence,
|
|
11471
|
-
// permissionState stays in 'prompt' state forever.
|
|
11472
|
-
// Typically, this happens when a user grants one-time permission.
|
|
11473
|
-
// Instead of checking if a permission is granted, we check if it isn't denied
|
|
11474
|
-
permissionState.state !== 'denied');
|
|
11475
|
-
};
|
|
11476
|
-
navigator.permissions
|
|
11477
|
-
.query({ name: this.permissionName })
|
|
11478
|
-
.then((permissionStatus) => {
|
|
11479
|
-
permissionState = permissionStatus;
|
|
11480
|
-
permissionState.addEventListener('change', notify);
|
|
11481
|
-
notify();
|
|
11482
|
-
})
|
|
11483
|
-
.catch(() => {
|
|
11484
|
-
// permission doesn't exist or can't be queried -> assume it's granted
|
|
11485
|
-
// an example would be Firefox,
|
|
11486
|
-
// where neither camera microphone permission can be queried
|
|
11487
|
-
notifyGranted();
|
|
11488
|
-
});
|
|
11489
|
-
return () => {
|
|
11490
|
-
permissionState?.removeEventListener('change', notify);
|
|
11491
|
-
};
|
|
11492
|
-
}).pipe(rxjs.shareReplay(1));
|
|
11493
11571
|
/**
|
|
11494
11572
|
* Gets the current value of an observable, or undefined if the observable has
|
|
11495
11573
|
* not emitted a value yet.
|
|
@@ -11509,6 +11587,9 @@ class InputMediaDeviceManagerState {
|
|
|
11509
11587
|
* @return the updated value.
|
|
11510
11588
|
*/
|
|
11511
11589
|
this.setCurrentValue = setCurrentValue;
|
|
11590
|
+
this.hasBrowserPermission$ = permission
|
|
11591
|
+
? permission.asObservable().pipe(rxjs.shareReplay(1))
|
|
11592
|
+
: rxjs.of(true);
|
|
11512
11593
|
}
|
|
11513
11594
|
/**
|
|
11514
11595
|
* The device status
|
|
@@ -11588,10 +11669,7 @@ class InputMediaDeviceManagerState {
|
|
|
11588
11669
|
|
|
11589
11670
|
class CameraManagerState extends InputMediaDeviceManagerState {
|
|
11590
11671
|
constructor() {
|
|
11591
|
-
super('stop-tracks',
|
|
11592
|
-
// `camera` is not in the W3C standard yet,
|
|
11593
|
-
// but it's supported by Chrome and Safari.
|
|
11594
|
-
'camera');
|
|
11672
|
+
super('stop-tracks', getVideoBrowserPermission());
|
|
11595
11673
|
this.directionSubject = new rxjs.BehaviorSubject(undefined);
|
|
11596
11674
|
this.direction$ = this.directionSubject
|
|
11597
11675
|
.asObservable()
|
|
@@ -11722,10 +11800,7 @@ class CameraManager extends InputMediaDeviceManager {
|
|
|
11722
11800
|
|
|
11723
11801
|
class MicrophoneManagerState extends InputMediaDeviceManagerState {
|
|
11724
11802
|
constructor(disableMode) {
|
|
11725
|
-
super(disableMode,
|
|
11726
|
-
// `microphone` is not in the W3C standard yet,
|
|
11727
|
-
// but it's supported by Chrome and Safari.
|
|
11728
|
-
'microphone');
|
|
11803
|
+
super(disableMode, getAudioBrowserPermission());
|
|
11729
11804
|
this.speakingWhileMutedSubject = new rxjs.BehaviorSubject(false);
|
|
11730
11805
|
this.speakingWhileMuted$ = this.speakingWhileMutedSubject
|
|
11731
11806
|
.asObservable()
|
|
@@ -15428,7 +15503,7 @@ class StreamClient {
|
|
|
15428
15503
|
});
|
|
15429
15504
|
};
|
|
15430
15505
|
this.getUserAgent = () => {
|
|
15431
|
-
const version = "1.4.
|
|
15506
|
+
const version = "1.4.3" ;
|
|
15432
15507
|
return (this.userAgent ||
|
|
15433
15508
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
15434
15509
|
};
|
|
@@ -15960,6 +16035,7 @@ exports.descending = descending;
|
|
|
15960
16035
|
exports.deviceIds$ = deviceIds$;
|
|
15961
16036
|
exports.disposeOfMediaStream = disposeOfMediaStream;
|
|
15962
16037
|
exports.dominantSpeaker = dominantSpeaker;
|
|
16038
|
+
exports.getAudioBrowserPermission = getAudioBrowserPermission;
|
|
15963
16039
|
exports.getAudioDevices = getAudioDevices;
|
|
15964
16040
|
exports.getAudioOutputDevices = getAudioOutputDevices;
|
|
15965
16041
|
exports.getAudioStream = getAudioStream;
|
|
@@ -15969,6 +16045,7 @@ exports.getLogger = getLogger;
|
|
|
15969
16045
|
exports.getOSInfo = getOSInfo;
|
|
15970
16046
|
exports.getScreenShareStream = getScreenShareStream;
|
|
15971
16047
|
exports.getSdkInfo = getSdkInfo;
|
|
16048
|
+
exports.getVideoBrowserPermission = getVideoBrowserPermission;
|
|
15972
16049
|
exports.getVideoDevices = getVideoDevices;
|
|
15973
16050
|
exports.getVideoStream = getVideoStream;
|
|
15974
16051
|
exports.getWebRTCInfo = getWebRTCInfo;
|