@stream-io/video-client 0.4.2 → 0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-client",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "packageManager": "yarn@3.2.4",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.es.js",
@@ -12,22 +12,47 @@ import {
12
12
  } from 'rxjs';
13
13
  import { getLogger } from '../logger';
14
14
 
15
- const getDevices = (constraints?: MediaStreamConstraints) => {
15
+ /**
16
+ * Returns an Observable that emits the list of available devices
17
+ * that meet the given constraints.
18
+ *
19
+ * @param constraints the constraints to use when requesting the devices.
20
+ * @param kind the kind of devices to enumerate.
21
+ */
22
+ const getDevices = (
23
+ constraints: MediaStreamConstraints,
24
+ kind: MediaDeviceKind,
25
+ ) => {
16
26
  return new Observable<MediaDeviceInfo[]>((subscriber) => {
17
- navigator.mediaDevices
18
- .getUserMedia(constraints)
19
- .then((media) => {
20
- // in Firefox, devices can be enumerated after userMedia is requested
21
- // and permissions granted. Otherwise, device labels are empty
22
- navigator.mediaDevices.enumerateDevices().then((devices) => {
23
- subscriber.next(devices);
24
- // If we stop the tracks before enumerateDevices -> the labels won't show up in Firefox
25
- disposeOfMediaStream(media);
26
- subscriber.complete();
27
- });
27
+ const enumerate = async () => {
28
+ let devices = await navigator.mediaDevices.enumerateDevices();
29
+ // some browsers report empty device labels (Firefox).
30
+ // in that case, we need to request permissions (via getUserMedia)
31
+ // to be able to get the device labels
32
+ const needsGetUserMedia = devices.some(
33
+ (device) => device.kind === kind && device.label === '',
34
+ );
35
+ if (needsGetUserMedia) {
36
+ let mediaStream: MediaStream | undefined;
37
+ try {
38
+ mediaStream = await navigator.mediaDevices.getUserMedia(constraints);
39
+ devices = await navigator.mediaDevices.enumerateDevices();
40
+ } finally {
41
+ if (mediaStream) disposeOfMediaStream(mediaStream);
42
+ }
43
+ }
44
+ return devices;
45
+ };
46
+
47
+ enumerate()
48
+ .then((devices) => {
49
+ // notify subscribers and complete
50
+ subscriber.next(devices);
51
+ subscriber.complete();
28
52
  })
29
53
  .catch((error) => {
30
- getLogger(['devices'])('error', 'Failed to get devices', error);
54
+ const logger = getLogger(['devices']);
55
+ logger('error', 'Failed to enumerate devices', error);
31
56
  subscriber.error(error);
32
57
  });
33
58
  });
@@ -41,7 +66,7 @@ const getDevices = (constraints?: MediaStreamConstraints) => {
41
66
  export const checkIfAudioOutputChangeSupported = () => {
42
67
  if (typeof document === 'undefined') return false;
43
68
  const element = document.createElement('audio');
44
- return (element as any).sinkId !== undefined;
69
+ return 'setSinkId' in element;
45
70
  };
46
71
 
47
72
  /**
@@ -101,14 +126,21 @@ const getDeviceChangeObserver = memoizedObservable(() => {
101
126
 
102
127
  const getAudioDevicesObserver = memoizedObservable(() => {
103
128
  return merge(
104
- getDevices(audioDeviceConstraints),
129
+ getDevices(audioDeviceConstraints, 'audioinput'),
130
+ getDeviceChangeObserver(),
131
+ ).pipe(shareReplay(1));
132
+ });
133
+
134
+ const getAudioOutputDevicesObserver = memoizedObservable(() => {
135
+ return merge(
136
+ getDevices(audioDeviceConstraints, 'audiooutput'),
105
137
  getDeviceChangeObserver(),
106
138
  ).pipe(shareReplay(1));
107
139
  });
108
140
 
109
141
  const getVideoDevicesObserver = memoizedObservable(() => {
110
142
  return merge(
111
- getDevices(videoDeviceConstraints),
143
+ getDevices(videoDeviceConstraints, 'videoinput'),
112
144
  getDeviceChangeObserver(),
113
145
  ).pipe(shareReplay(1));
114
146
  });
@@ -135,7 +167,7 @@ export const getVideoDevices = () => {
135
167
  * 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)
136
168
  */
137
169
  export const getAudioOutputDevices = () => {
138
- return getAudioDevicesObserver().pipe(
170
+ return getAudioOutputDevicesObserver().pipe(
139
171
  map((values) => values.filter((d) => d.kind === 'audiooutput')),
140
172
  );
141
173
  };
@@ -324,10 +324,8 @@ export class Publisher {
324
324
  ? transceiver.sender.track.stop()
325
325
  : (transceiver.sender.track.enabled = false);
326
326
  // We don't need to notify SFU if unpublishing in response to remote soft mute
327
- if (!this.state.localParticipant?.publishedTracks.includes(trackType)) {
328
- return;
329
- } else {
330
- return this.notifyTrackMuteStateChanged(
327
+ if (this.state.localParticipant?.publishedTracks.includes(trackType)) {
328
+ await this.notifyTrackMuteStateChanged(
331
329
  undefined,
332
330
  transceiver.sender.track,
333
331
  trackType,