@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/CHANGELOG.md +7 -0
- package/dist/index.browser.es.js +110 -93
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +109 -97
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +110 -93
- package/dist/index.es.js.map +1 -1
- package/dist/src/devices/InputMediaDeviceManager.d.ts +6 -0
- package/dist/src/devices/SpeakerManager.d.ts +3 -0
- package/dist/src/devices/devices.d.ts +2 -41
- package/package.json +1 -1
- package/src/Call.ts +10 -1
- package/src/devices/InputMediaDeviceManager.ts +98 -4
- package/src/devices/SpeakerManager.ts +27 -1
- package/src/devices/__tests__/CameraManager.test.ts +7 -1
- package/src/devices/__tests__/InputMediaDeviceManager.test.ts +105 -2
- package/src/devices/__tests__/MicrophoneManager.test.ts +7 -1
- package/src/devices/__tests__/ScreenShareManager.test.ts +2 -1
- package/src/devices/__tests__/SpeakerManager.test.ts +12 -1
- package/src/devices/__tests__/mocks.ts +56 -7
- package/src/devices/devices.ts +11 -123
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,
|
|
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
|
-
*
|
|
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
|
|
10146
|
-
|
|
10147
|
-
|
|
10148
|
-
|
|
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.
|
|
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
|
|
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
|