@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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
### [0.4.6](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-0.4.5...@stream-io/video-client-0.4.6) (2023-11-13)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* handle device disconnection ([#1174](https://github.com/GetStream/stream-video-js/issues/1174)) ([ae3779f](https://github.com/GetStream/stream-video-js/commit/ae3779fbfd820d8ef85ad58dafb698e06c00a3e3))
|
|
11
|
+
|
|
5
12
|
### [0.4.5](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-0.4.4...@stream-io/video-client-0.4.5) (2023-11-07)
|
|
6
13
|
|
|
7
14
|
|
package/dist/index.browser.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';
|
|
@@ -9978,8 +9978,7 @@ const getDevices = (constraints, kind) => {
|
|
|
9978
9978
|
/**
|
|
9979
9979
|
* [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
|
|
9980
9980
|
*
|
|
9981
|
-
*
|
|
9982
|
-
*/
|
|
9981
|
+
* */
|
|
9983
9982
|
const checkIfAudioOutputChangeSupported = () => {
|
|
9984
9983
|
if (typeof document === 'undefined')
|
|
9985
9984
|
return false;
|
|
@@ -10139,90 +10138,10 @@ const getScreenShareStream = async (options) => {
|
|
|
10139
10138
|
throw e;
|
|
10140
10139
|
}
|
|
10141
10140
|
};
|
|
10142
|
-
const
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
|
|
10146
|
-
devices$ = getAudioDevices();
|
|
10147
|
-
break;
|
|
10148
|
-
case 'videoinput':
|
|
10149
|
-
devices$ = getVideoDevices();
|
|
10150
|
-
break;
|
|
10151
|
-
case 'audiooutput':
|
|
10152
|
-
devices$ = getAudioOutputDevices();
|
|
10153
|
-
break;
|
|
10154
|
-
}
|
|
10155
|
-
return combineLatest([devices$, deviceId$]).pipe(filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), map$1(() => true));
|
|
10156
|
-
};
|
|
10157
|
-
/**
|
|
10158
|
-
* Notifies the subscriber if a given 'audioinput' device is disconnected
|
|
10159
|
-
*
|
|
10160
|
-
* @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.
|
|
10161
|
-
* @param deviceId$ an Observable that specifies which device to watch for
|
|
10162
|
-
* @returns
|
|
10163
|
-
*/
|
|
10164
|
-
const watchForDisconnectedAudioDevice = (deviceId$) => {
|
|
10165
|
-
return watchForDisconnectedDevice('audioinput', deviceId$);
|
|
10166
|
-
};
|
|
10167
|
-
/**
|
|
10168
|
-
* Notifies the subscriber if a given 'videoinput' device is disconnected
|
|
10169
|
-
*
|
|
10170
|
-
* @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.
|
|
10171
|
-
* @param deviceId$ an Observable that specifies which device to watch for
|
|
10172
|
-
* @returns
|
|
10173
|
-
*/
|
|
10174
|
-
const watchForDisconnectedVideoDevice = (deviceId$) => {
|
|
10175
|
-
return watchForDisconnectedDevice('videoinput', deviceId$);
|
|
10176
|
-
};
|
|
10177
|
-
/**
|
|
10178
|
-
* Notifies the subscriber if a given 'audiooutput' device is disconnected
|
|
10179
|
-
*
|
|
10180
|
-
* @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.
|
|
10181
|
-
* @param deviceId$ an Observable that specifies which device to watch for
|
|
10182
|
-
* @returns
|
|
10183
|
-
*/
|
|
10184
|
-
const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
|
|
10185
|
-
return watchForDisconnectedDevice('audiooutput', deviceId$);
|
|
10186
|
-
};
|
|
10187
|
-
const watchForAddedDefaultDevice = (kind) => {
|
|
10188
|
-
let devices$;
|
|
10189
|
-
switch (kind) {
|
|
10190
|
-
case 'audioinput':
|
|
10191
|
-
devices$ = getAudioDevices();
|
|
10192
|
-
break;
|
|
10193
|
-
case 'videoinput':
|
|
10194
|
-
devices$ = getVideoDevices();
|
|
10195
|
-
break;
|
|
10196
|
-
case 'audiooutput':
|
|
10197
|
-
devices$ = getAudioOutputDevices();
|
|
10198
|
-
break;
|
|
10199
|
-
default:
|
|
10200
|
-
throw new Error('Unknown MediaDeviceKind', kind);
|
|
10201
|
-
}
|
|
10202
|
-
return devices$.pipe(pairwise(), filter(([prev, current]) => {
|
|
10203
|
-
const prevDefault = prev.find((device) => device.deviceId === 'default');
|
|
10204
|
-
const currentDefault = current.find((device) => device.deviceId === 'default');
|
|
10205
|
-
return !!(current.length > prev.length &&
|
|
10206
|
-
prevDefault &&
|
|
10207
|
-
currentDefault &&
|
|
10208
|
-
prevDefault.groupId !== currentDefault.groupId);
|
|
10209
|
-
}), map$1(() => true));
|
|
10210
|
-
};
|
|
10211
|
-
/**
|
|
10212
|
-
* Notifies the subscriber about newly added default audio input device.
|
|
10213
|
-
* @returns Observable<boolean>
|
|
10214
|
-
*/
|
|
10215
|
-
const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
|
|
10216
|
-
/**
|
|
10217
|
-
* Notifies the subscriber about newly added default audio output device.
|
|
10218
|
-
* @returns Observable<boolean>
|
|
10219
|
-
*/
|
|
10220
|
-
const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
|
|
10221
|
-
/**
|
|
10222
|
-
* Notifies the subscriber about newly added default video input device.
|
|
10223
|
-
* @returns Observable<boolean>
|
|
10224
|
-
*/
|
|
10225
|
-
const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
|
|
10141
|
+
const deviceIds$ = typeof navigator !== 'undefined' &&
|
|
10142
|
+
typeof navigator.mediaDevices !== 'undefined'
|
|
10143
|
+
? memoizedObservable(() => merge(from(navigator.mediaDevices.enumerateDevices()), getDeviceChangeObserver()).pipe(shareReplay(1)))()
|
|
10144
|
+
: undefined;
|
|
10226
10145
|
/**
|
|
10227
10146
|
* Deactivates MediaStream (stops and removes tracks) to be later garbage collected
|
|
10228
10147
|
*
|
|
@@ -10248,7 +10167,17 @@ class InputMediaDeviceManager {
|
|
|
10248
10167
|
this.call = call;
|
|
10249
10168
|
this.state = state;
|
|
10250
10169
|
this.trackType = trackType;
|
|
10170
|
+
this.subscriptions = [];
|
|
10171
|
+
this.isTrackStoppedDueToTrackEnd = false;
|
|
10172
|
+
this.removeSubscriptions = () => {
|
|
10173
|
+
this.subscriptions.forEach((s) => s.unsubscribe());
|
|
10174
|
+
};
|
|
10251
10175
|
this.logger = getLogger([`${TrackType[trackType].toLowerCase()} manager`]);
|
|
10176
|
+
if (deviceIds$ &&
|
|
10177
|
+
!isReactNative() &&
|
|
10178
|
+
(this.trackType === TrackType.AUDIO || this.trackType === TrackType.VIDEO)) {
|
|
10179
|
+
this.handleDisconnectedOrReplacedDevices();
|
|
10180
|
+
}
|
|
10252
10181
|
}
|
|
10253
10182
|
/**
|
|
10254
10183
|
* Lists the available audio/video devices
|
|
@@ -10408,9 +10337,6 @@ class InputMediaDeviceManager {
|
|
|
10408
10337
|
this.unmuteTracks();
|
|
10409
10338
|
}
|
|
10410
10339
|
else {
|
|
10411
|
-
if (this.state.mediaStream) {
|
|
10412
|
-
this.stopTracks();
|
|
10413
|
-
}
|
|
10414
10340
|
const defaultConstraints = this.state.defaultConstraints;
|
|
10415
10341
|
const constraints = {
|
|
10416
10342
|
...defaultConstraints,
|
|
@@ -10423,7 +10349,79 @@ class InputMediaDeviceManager {
|
|
|
10423
10349
|
}
|
|
10424
10350
|
if (this.state.mediaStream !== stream) {
|
|
10425
10351
|
this.state.setMediaStream(stream);
|
|
10352
|
+
this.getTracks().forEach((track) => {
|
|
10353
|
+
track.addEventListener('ended', async () => {
|
|
10354
|
+
if (this.enablePromise) {
|
|
10355
|
+
await this.enablePromise;
|
|
10356
|
+
}
|
|
10357
|
+
if (this.disablePromise) {
|
|
10358
|
+
await this.disablePromise;
|
|
10359
|
+
}
|
|
10360
|
+
if (this.state.status === 'enabled') {
|
|
10361
|
+
this.isTrackStoppedDueToTrackEnd = true;
|
|
10362
|
+
setTimeout(() => {
|
|
10363
|
+
this.isTrackStoppedDueToTrackEnd = false;
|
|
10364
|
+
}, 2000);
|
|
10365
|
+
await this.disable();
|
|
10366
|
+
}
|
|
10367
|
+
});
|
|
10368
|
+
});
|
|
10369
|
+
}
|
|
10370
|
+
}
|
|
10371
|
+
get mediaDeviceKind() {
|
|
10372
|
+
if (this.trackType === TrackType.AUDIO) {
|
|
10373
|
+
return 'audioinput';
|
|
10374
|
+
}
|
|
10375
|
+
if (this.trackType === TrackType.VIDEO) {
|
|
10376
|
+
return 'videoinput';
|
|
10426
10377
|
}
|
|
10378
|
+
return '';
|
|
10379
|
+
}
|
|
10380
|
+
handleDisconnectedOrReplacedDevices() {
|
|
10381
|
+
this.subscriptions.push(combineLatest([
|
|
10382
|
+
deviceIds$.pipe(pairwise()),
|
|
10383
|
+
this.state.selectedDevice$,
|
|
10384
|
+
]).subscribe(async ([[prevDevices, currentDevices], deviceId]) => {
|
|
10385
|
+
if (!deviceId) {
|
|
10386
|
+
return;
|
|
10387
|
+
}
|
|
10388
|
+
if (this.enablePromise) {
|
|
10389
|
+
await this.enablePromise;
|
|
10390
|
+
}
|
|
10391
|
+
if (this.disablePromise) {
|
|
10392
|
+
await this.disablePromise;
|
|
10393
|
+
}
|
|
10394
|
+
let isDeviceDisconnected = false;
|
|
10395
|
+
let isDeviceReplaced = false;
|
|
10396
|
+
const currentDevice = this.findDeviceInList(currentDevices, deviceId);
|
|
10397
|
+
const prevDevice = this.findDeviceInList(prevDevices, deviceId);
|
|
10398
|
+
if (!currentDevice && prevDevice) {
|
|
10399
|
+
isDeviceDisconnected = true;
|
|
10400
|
+
}
|
|
10401
|
+
else if (currentDevice &&
|
|
10402
|
+
prevDevice &&
|
|
10403
|
+
currentDevice.deviceId === prevDevice.deviceId &&
|
|
10404
|
+
currentDevice.groupId !== prevDevice.groupId) {
|
|
10405
|
+
isDeviceReplaced = true;
|
|
10406
|
+
}
|
|
10407
|
+
if (isDeviceDisconnected) {
|
|
10408
|
+
await this.disable();
|
|
10409
|
+
this.select(undefined);
|
|
10410
|
+
}
|
|
10411
|
+
if (isDeviceReplaced) {
|
|
10412
|
+
if (this.isTrackStoppedDueToTrackEnd &&
|
|
10413
|
+
this.state.status === 'disabled') {
|
|
10414
|
+
await this.enable();
|
|
10415
|
+
this.isTrackStoppedDueToTrackEnd = false;
|
|
10416
|
+
}
|
|
10417
|
+
else {
|
|
10418
|
+
await this.applySettingsToStream();
|
|
10419
|
+
}
|
|
10420
|
+
}
|
|
10421
|
+
}));
|
|
10422
|
+
}
|
|
10423
|
+
findDeviceInList(devices, deviceId) {
|
|
10424
|
+
return devices.find((d) => d.deviceId === deviceId && d.kind === this.mediaDeviceKind);
|
|
10427
10425
|
}
|
|
10428
10426
|
}
|
|
10429
10427
|
|
|
@@ -10991,6 +10989,21 @@ class SpeakerState {
|
|
|
10991
10989
|
class SpeakerManager {
|
|
10992
10990
|
constructor() {
|
|
10993
10991
|
this.state = new SpeakerState();
|
|
10992
|
+
this.subscriptions = [];
|
|
10993
|
+
this.removeSubscriptions = () => {
|
|
10994
|
+
this.subscriptions.forEach((s) => s.unsubscribe());
|
|
10995
|
+
};
|
|
10996
|
+
if (deviceIds$ && !isReactNative()) {
|
|
10997
|
+
this.subscriptions.push(combineLatest([deviceIds$, this.state.selectedDevice$]).subscribe(([devices, deviceId]) => {
|
|
10998
|
+
if (!deviceId) {
|
|
10999
|
+
return;
|
|
11000
|
+
}
|
|
11001
|
+
const device = devices.find((d) => d.deviceId === deviceId && d.kind === 'audiooutput');
|
|
11002
|
+
if (!device) {
|
|
11003
|
+
this.select('');
|
|
11004
|
+
}
|
|
11005
|
+
}));
|
|
11006
|
+
}
|
|
10994
11007
|
}
|
|
10995
11008
|
/**
|
|
10996
11009
|
* Lists the available audio output devices
|
|
@@ -11108,6 +11121,10 @@ class Call {
|
|
|
11108
11121
|
this.leaveCallHooks.forEach((hook) => hook());
|
|
11109
11122
|
this.clientStore.unregisterCall(this);
|
|
11110
11123
|
this.state.setCallingState(CallingState.LEFT);
|
|
11124
|
+
this.camera.removeSubscriptions();
|
|
11125
|
+
this.microphone.removeSubscriptions();
|
|
11126
|
+
this.screenShare.removeSubscriptions();
|
|
11127
|
+
this.speaker.removeSubscriptions();
|
|
11111
11128
|
};
|
|
11112
11129
|
/**
|
|
11113
11130
|
* Loads the information about the call.
|
|
@@ -11481,7 +11498,7 @@ class Call {
|
|
|
11481
11498
|
await this.initMic({ setStatus: true });
|
|
11482
11499
|
}
|
|
11483
11500
|
catch (error) {
|
|
11484
|
-
this.logger('warn', 'Camera and/or mic init failed during join call');
|
|
11501
|
+
this.logger('warn', 'Camera and/or mic init failed during join call', error);
|
|
11485
11502
|
}
|
|
11486
11503
|
// 3. once we have the "joinResponse", and possibly reconciled the local state
|
|
11487
11504
|
// we schedule a fast subscription update for all remote participants
|
|
@@ -13953,7 +13970,7 @@ class StreamClient {
|
|
|
13953
13970
|
});
|
|
13954
13971
|
};
|
|
13955
13972
|
this.getUserAgent = () => {
|
|
13956
|
-
const version = "0.4.
|
|
13973
|
+
const version = "0.4.6" ;
|
|
13957
13974
|
return (this.userAgent ||
|
|
13958
13975
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
13959
13976
|
};
|
|
@@ -14488,5 +14505,5 @@ class StreamVideoServerClient extends StreamVideoClient {
|
|
|
14488
14505
|
}
|
|
14489
14506
|
}
|
|
14490
14507
|
|
|
14491
|
-
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
|
|
14508
|
+
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 };
|
|
14492
14509
|
//# sourceMappingURL=index.browser.es.js.map
|