@livedigital/client 2.18.2 → 2.19.1

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.
@@ -212,3 +212,9 @@ export declare type TransportConnectionTimeoutPayload = {
212
212
  direction: 'receive' | 'send';
213
213
  timeout: number;
214
214
  };
215
+ export declare enum DeviceErrors {
216
+ NotFoundError = "NotFoundError",
217
+ NoDevices = "NoDevices",
218
+ DeviceIsBusy = "DeviceIsBusy",
219
+ NotAllowedError = "NotAllowedError"
220
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@livedigital/client",
3
3
  "author": "vlprojects",
4
4
  "license": "MIT",
5
- "version": "2.18.2",
5
+ "version": "2.19.1",
6
6
  "private": false,
7
7
  "bugs": {
8
8
  "url": "https://github.com/vlprojects/livedigital-sdk/issues"
@@ -208,6 +208,11 @@ class Engine {
208
208
  }
209
209
 
210
210
  public setPeer(peerData: PeerResponse): Peer {
211
+ const existingPeer = this.peersRepository.get(peerData.id);
212
+ if (existingPeer) {
213
+ return existingPeer;
214
+ }
215
+
211
216
  const peer = new Peer({
212
217
  ...peerData,
213
218
  engine: this,
@@ -1,7 +1,7 @@
1
1
  import { CreateSystemParams } from '../../types/engine';
2
2
  import { CLIENT_EVENTS } from '../../constants/events';
3
3
  import EnhancedEventEmitter from '../../EnhancedEventEmitter';
4
- import { AvailableMediaDevices } from '../../types/common';
4
+ import { AvailableMediaDevices, DeviceErrors } from '../../types/common';
5
5
  import Logger from '../Logger';
6
6
 
7
7
  class System {
@@ -15,8 +15,6 @@ class System {
15
15
 
16
16
  public availableAudioDevices: MediaDeviceInfo[] = [];
17
17
 
18
- private isMediaDevicesAccessGranted = false;
19
-
20
18
  public clientEventEmitter: EnhancedEventEmitter;
21
19
 
22
20
  private readonly logger: Logger;
@@ -28,6 +26,9 @@ class System {
28
26
  namespace: 'System',
29
27
  logLevel,
30
28
  });
29
+
30
+ this.deviceChangeHandler = this.deviceChangeHandler.bind(this);
31
+
31
32
  this.listenDevices();
32
33
  }
33
34
 
@@ -47,23 +48,28 @@ class System {
47
48
  this.availableAudioDevices = availableAudioDevices;
48
49
  }
49
50
 
50
- async requestMediaDevicesAccess(): Promise<void> {
51
+ async requestMediaDevicesAccess(constraints: MediaStreamConstraints = { video: true, audio: true }): Promise<void> {
51
52
  try {
52
- const stream = await navigator.mediaDevices.getUserMedia({
53
- video: true,
54
- audio: true,
55
- });
53
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
56
54
  stream.getTracks().forEach((track) => track.stop());
57
- this.isMediaDevicesAccessGranted = true;
58
55
  } catch (error) {
59
- this.logger.error('getUserMedia()', { error });
56
+ this.logger.error('getUserMedia()', { error, constraints });
57
+
58
+ if (error.name === 'NotAllowedError') {
59
+ throw new Error(DeviceErrors.NotAllowedError);
60
+ }
61
+
60
62
  if (error.name === 'NotReadableError') {
61
- throw new Error('DeviceIsBusy');
63
+ throw new Error(DeviceErrors.DeviceIsBusy);
64
+ }
65
+
66
+ if (error.name === 'NotFoundError') {
67
+ throw new Error(DeviceErrors.NotFoundError);
62
68
  }
63
69
  }
64
70
  }
65
71
 
66
- async refreshAvailableMediaDevicesList(): Promise<void> {
72
+ async refreshAvailableMediaDevicesList(): Promise<MediaDeviceInfo[]> {
67
73
  const devices = await navigator.mediaDevices.enumerateDevices();
68
74
  const videoDevices = [] as MediaDeviceInfo[];
69
75
  const audioDevices = [] as MediaDeviceInfo[];
@@ -72,10 +78,6 @@ class System {
72
78
  return;
73
79
  }
74
80
 
75
- if (device.deviceId === 'default') {
76
- return;
77
- }
78
-
79
81
  if (device.kind === 'videoinput') {
80
82
  videoDevices.push(device);
81
83
  }
@@ -89,6 +91,8 @@ class System {
89
91
  this.setAvailableAudioDevices(audioDevices);
90
92
 
91
93
  this.logger.debug('Devices list updated');
94
+
95
+ return devices;
92
96
  }
93
97
 
94
98
  async detectDevices(): Promise<void> {
@@ -96,31 +100,52 @@ class System {
96
100
  return;
97
101
  }
98
102
 
99
- if (!this.isMediaDevicesAccessGranted) {
103
+ try {
100
104
  await this.requestMediaDevicesAccess();
105
+ } catch (errorVideoAndAudio) {
106
+ if (errorVideoAndAudio.message !== DeviceErrors.NotFoundError) {
107
+ throw errorVideoAndAudio;
108
+ }
109
+
110
+ try {
111
+ await this.requestMediaDevicesAccess({ audio: true });
112
+ } catch (errorAudioOnly) {
113
+ if (errorAudioOnly.message !== DeviceErrors.NotFoundError) {
114
+ throw errorAudioOnly;
115
+ }
116
+
117
+ await this.requestMediaDevicesAccess({ video: true });
118
+ }
101
119
  }
102
120
 
103
- navigator.mediaDevices.addEventListener('devicechange', () => {
104
- this.refreshAvailableMediaDevicesList();
105
- });
121
+ this.isDevicesDetected = true;
122
+
123
+ // at this moment or access to device granted or no devices exists
124
+
125
+ const rawDevices = await this.refreshAvailableMediaDevicesList();
126
+ const hasAudioInputDevices = rawDevices.some((x) => x.kind === 'audioinput');
127
+ const hasVideoInputDevices = rawDevices.some((x) => x.kind === 'videoinput');
128
+
129
+ if (!hasAudioInputDevices && !hasVideoInputDevices) {
130
+ throw new Error(DeviceErrors.NoDevices);
131
+ }
132
+ }
133
+
134
+ async deviceChangeHandler(): Promise<void> {
135
+ if (!this.isDevicesDetected) {
136
+ return;
137
+ }
106
138
 
107
139
  await this.refreshAvailableMediaDevicesList();
108
140
 
109
- this.isDevicesDetected = true;
141
+ this.clientEventEmitter.safeEmit(CLIENT_EVENTS.devicesListUpdated, {
142
+ audio: this.availableAudioDevices,
143
+ video: this.availableVideoDevices,
144
+ } as AvailableMediaDevices);
110
145
  }
111
146
 
112
147
  listenDevices(): void {
113
- navigator.mediaDevices.ondevicechange = async () => {
114
- if (!this.isDevicesDetected) {
115
- return;
116
- }
117
-
118
- await this.refreshAvailableMediaDevicesList();
119
- this.clientEventEmitter.safeEmit(CLIENT_EVENTS.devicesListUpdated, {
120
- audio: this.availableAudioDevices,
121
- video: this.availableVideoDevices,
122
- } as AvailableMediaDevices);
123
- };
148
+ navigator.mediaDevices.addEventListener('devicechange', this.deviceChangeHandler);
124
149
  }
125
150
  }
126
151
 
@@ -245,3 +245,10 @@ export type TransportConnectionTimeoutPayload = {
245
245
  direction: 'receive' | 'send',
246
246
  timeout: number,
247
247
  };
248
+
249
+ export enum DeviceErrors {
250
+ NotFoundError = 'NotFoundError',
251
+ NoDevices = 'NoDevices',
252
+ DeviceIsBusy = 'DeviceIsBusy',
253
+ NotAllowedError = 'NotAllowedError',
254
+ }