media-devices 0.1.0 → 0.3.0

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 CHANGED
@@ -1,12 +1,53 @@
1
1
  # Changelog
2
+
2
3
  All notable changes to this project will be documented in this file.
3
4
 
4
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
6
 
7
+ ## [0.3.0] - 2021-12-04
8
+
9
+ ### Added
10
+
11
+ - Export `DeviceChange` type which describes each object in a device change set.
12
+ - New `mediaDevices.ondevicechange` mutable field for listeners.
13
+ - Public methods are bound, no longer depending on implicit `this` context.
14
+
15
+ ### Fixed
16
+
17
+ - Querying `getDisplayMedia(...)` now refreshes the device cache for cases where browsers loosen fingerprinting countermeasures.
18
+
19
+ ### Deprecated
20
+
21
+ - Using the event emitter interface is no longer advised. It will be removed in a future release. Use the `ondevicechange` field instead:
22
+ ```diff
23
+ -mediaDevices.on('devicechange', handler)
24
+ +mediaDevices.ondevicechange = handler
25
+ ```
26
+
27
+ ## [0.2.0] - 2021-02-23
28
+
29
+ ### Added
30
+
31
+ - Another parameter added to the `devicechange` listener containing the entire list of known devices.
32
+ - Enum and type exports for `DeviceKind`, `DeviceInfo`, and `OperationType`.
33
+
34
+ ### Changed
35
+
36
+ - Made `device.groupId` a nullable field because [Safari is a monster](https://github.com/PsychoLlama/media-devices/issues/3).
37
+
38
+ ### Fixed
39
+
40
+ - No longer throws an error if you try to import in an unsupported environment.
41
+
6
42
  ## [0.1.0] - 2021-02-21
43
+
7
44
  ### Added
45
+
8
46
  - Initial API compatible with `navigator.mediaDevices`.
9
47
  - A device list-diffing implementation of `ondevicechange`.
10
48
  - Support detection via `supportsMediaDevices()`.
11
49
 
50
+ [Unreleased]: https://github.com/PsychoLlama/media-devices/compare/v0.3.0...HEAD
51
+ [0.3.0]: https://github.com/PsychoLlama/media-devices/compare/v0.2.0...v0.3.0
52
+ [0.2.0]: https://github.com/PsychoLlama/media-devices/compare/v0.1.0...v0.2.0
12
53
  [0.1.0]: https://github.com/PsychoLlama/media-devices/releases/tag/v0.1.0
package/README.md CHANGED
@@ -1,6 +1,16 @@
1
1
  <div align="center">
2
2
  <h1>Media Devices</h1>
3
3
  <p>Easily manage media devices in the browser</p>
4
+
5
+ <div>
6
+ <a href="https://github.com/PsychoLlama/media-devices/actions/workflows/main.yml">
7
+ <img src="https://img.shields.io/github/workflow/status/PsychoLlama/media-devices/CI/main" alt="Build status" />
8
+ </a>
9
+ <img src="https://img.shields.io/npm/types/media-devices" alt="Build status" />
10
+ <a href="https://www.npmjs.com/package/media-devices">
11
+ <img src="https://img.shields.io/npm/v/media-devices" alt="npm version" />
12
+ </a>
13
+ </div>
4
14
  </div>
5
15
 
6
16
  ## Purpose
@@ -9,7 +19,7 @@
9
19
  ## API
10
20
  The API is a carbon copy of [`navigator.mediaDevices`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/mediaDevices), with the exception of `ondevicechange` which was replaced for more bells and whistles.
11
21
 
12
- Here's an overview:
22
+ Here's the gist:
13
23
 
14
24
  ```js
15
25
  import MediaDevices from 'media-devices'
@@ -24,43 +34,61 @@ await MediaDevices.getUserMedia({ video: true, audio: true })
24
34
  await MediaDevices.getDisplayMedia()
25
35
 
26
36
  // Listen for changes in available devices
27
- MediaDevices.on('devicechange', changes => {
37
+ MediaDevices.ondevicechange = ({ changes }) => {
28
38
  // [{ type: 'add', ... }, { type: 'update', ... }]
29
- })
39
+ }
30
40
  ```
31
41
 
32
- ### `on('devicechange')`
33
- Notifies you whenever the device list is updated and passes you a list of changes. Each change is an update, removal, or addition.
42
+ ### `supportsMediaDevices()`
43
+ Exported as a separate utility function, this helps determine if your browser supports the `navigator.mediaDevices` API. Be aware that some browsers only expose it on secure sites.
34
44
 
35
45
  ```js
36
- interface DeviceAddEvent {
37
- type: 'add';
38
- device: DeviceInfo;
39
- }
46
+ import { supportsMediaDevices } from 'media-devices'
40
47
 
41
- interface DeviceRemoveEvent {
42
- type: 'remove';
43
- device: DeviceInfo;
48
+ if (supportsMediaDevices()) {
49
+ // yey
44
50
  }
51
+ ```
52
+
53
+ ### `ondevicechange`
54
+ `MediaDevices` emits this event whenever the list of devices changes. It passes two things:
45
55
 
46
- interface DeviceUpdateEvent {
47
- type: 'update';
48
- newInfo: DeviceInfo;
49
- oldInfo: DeviceInfo;
56
+ 1. A list of changes
57
+ 1. The full list of devices
58
+
59
+ ```js
60
+ MediaDevices.ondevicechange = ({ changes, devices }) => {
61
+ // ...
50
62
  }
51
63
  ```
52
64
 
53
- ### `supportsMediaDevices()`
54
- Exported as a separate utility function, this helps determine if your browser supports the `navigator.mediaDevices` API. Be aware that some browsers only expose it on secure sites.
65
+ The list of devices is exactly what you'd get from `enumerateDevices()`. The changes are a diff between this list and the last, showing which devices were added, which were removed, and which were updated.
55
66
 
56
67
  ```js
57
- import { supportsMediaDevices } from 'media-devices'
58
-
59
- if (supportsMediaDevices()) {
60
- // ... party
61
- }
68
+ [
69
+ // A device was just plugged in.
70
+ {
71
+ type: 'add',
72
+ device: DeviceInfo,
73
+ },
74
+
75
+ // A device was disconnected.
76
+ {
77
+ type: 'remove',
78
+ device: DeviceInfo,
79
+ },
80
+
81
+ // The browser gave us more information about a device.
82
+ {
83
+ type: 'update',
84
+ oldInfo: DeviceInfo,
85
+ newInfo: DeviceInfo,
86
+ },
87
+ ]
62
88
  ```
63
89
 
90
+ Update events are odd. Browsers redact information until the user explicitly grants trust, so things like labels and device IDs might start off null. [Another quirk](#speaker-replacement) regarding speakers may cause the device to update in-place.
91
+
64
92
  ---------------
65
93
 
66
94
  ## Known Quirks
@@ -85,8 +113,13 @@ That makes it hard to tell whether the device list actually changed. This librar
85
113
 
86
114
  Device IDs are set to `null` in this case.
87
115
 
116
+ ### Missing Group IDs
117
+ As of Safari v14, even with permissions, the browser doesn't provide group IDs. Why? Because they're monsters.
118
+
119
+ Group IDs are `null` in Safari.
120
+
88
121
  ### Hidden Devices
89
- Chrome only shows the first of each device type (mic, camera, speakers) until `getUserMedia(...)` is approved. Other options are hidden. If you have 10 cameras, you'll only see the first until you're authorized. Even then, it only shows you cameras, microphones are still hidden.
122
+ Chrome and Safari only show the first of each device type (mic, camera, speakers) until `getUserMedia(...)` is approved. Other options are hidden. If you have 10 cameras, you'll only see the first until you're authorized. Even then, Chrome only shows you cameras, microphones are still hidden.
90
123
 
91
124
  While we can't work around it, we can automatically identify that old camera in the list of 10 and show the other 9 as added devices.
92
125
 
@@ -7,33 +7,42 @@ import { DeviceInfo } from './enumerate-devices';
7
7
  * attempts graceful integration with browser fingerprinting countermeasures.
8
8
  */
9
9
  export default class DeviceManager extends EventEmitter {
10
- _knownDevices: Array<DeviceInfo>;
10
+ private _knownDevices;
11
+ private _gainedScreenAccessOnce;
12
+ /**
13
+ * Specifies a function to be called whenever the list of available devices
14
+ * changes.
15
+ *
16
+ * Note: this is different from the native event. It passes the changeset
17
+ * and full list of devices as a parameter.
18
+ */
19
+ ondevicechange: null | DeviceChangeListener;
11
20
  constructor();
12
21
  /**
13
22
  * Request a live media stream from audio and/or video devices. Streams are
14
23
  * configurable through constraints.
15
24
  * See: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
16
25
  */
17
- getUserMedia(constraints: MediaStreamConstraints): Promise<MediaStream>;
26
+ getUserMedia: (constraints: MediaStreamConstraints) => Promise<MediaStream>;
18
27
  /**
19
28
  * Ask the user to share their screen. Resolves with a media stream carrying
20
29
  * video, and potentially audio from the application window.
21
30
  * See: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia
22
31
  */
23
- getDisplayMedia(constraints?: MediaStreamConstraints): Promise<MediaStream>;
32
+ getDisplayMedia: (constraints?: MediaStreamConstraints | undefined) => Promise<MediaStream>;
24
33
  /**
25
34
  * Lists every available hardware device, including microphones, cameras,
26
35
  * and speakers (depending on browser support). May contain redacted
27
36
  * information depending on application permissions.
28
37
  */
29
- enumerateDevices(): Promise<Array<DeviceInfo>>;
38
+ enumerateDevices: () => Promise<Array<DeviceInfo>>;
30
39
  /**
31
40
  * Returns an object containing every media constraint supported by the
32
41
  * browser.
33
42
  * See: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getSupportedConstraints
34
43
  */
35
- getSupportedConstraints(): MediaTrackSupportedConstraints;
36
- _checkForDeviceChanges(newDevices: Array<DeviceInfo>): void;
44
+ getSupportedConstraints: () => MediaTrackSupportedConstraints;
45
+ private _checkForDeviceChanges;
37
46
  /**
38
47
  * Note: The device enumeration API may return null values for device IDs
39
48
  * and labels. To avoid creating erroneous "Device Added" notifications,
@@ -43,30 +52,31 @@ export default class DeviceManager extends EventEmitter {
43
52
  * correlate devices from permissioned requests with unpermissioned
44
53
  * requests.
45
54
  */
46
- _calculateDeviceDiff(newDevices: Array<DeviceInfo>, oldDevices: Array<DeviceInfo>): Array<DeviceChange>;
55
+ private _calculateDeviceDiff;
47
56
  }
48
- declare type DeviceChange = DeviceAddEvent | DeviceRemoveEvent | DeviceUpdateEvent;
57
+ export declare type DeviceChange = DeviceAddEvent | DeviceRemoveEvent | DeviceUpdateEvent;
49
58
  interface DeviceAddEvent {
50
- type: DeviceChangeType.Add;
59
+ type: OperationType.Add;
51
60
  device: DeviceInfo;
52
61
  }
53
62
  interface DeviceRemoveEvent {
54
- type: DeviceChangeType.Remove;
63
+ type: OperationType.Remove;
55
64
  device: DeviceInfo;
56
65
  }
57
66
  interface DeviceUpdateEvent {
58
- type: DeviceChangeType.Update;
67
+ type: OperationType.Update;
59
68
  newInfo: DeviceInfo;
60
69
  oldInfo: DeviceInfo;
61
70
  }
62
- export declare enum DeviceChangeType {
71
+ export declare enum OperationType {
63
72
  Add = "add",
64
73
  Remove = "remove",
65
74
  Update = "update"
66
75
  }
67
- declare global {
68
- interface MediaDevices {
69
- getDisplayMedia(constraints?: MediaStreamConstraints): Promise<MediaStream>;
70
- }
76
+ interface DeviceChangeListener {
77
+ (update: {
78
+ changes: Array<DeviceChange>;
79
+ devices: Array<DeviceInfo>;
80
+ }): unknown;
71
81
  }
72
82
  export {};
@@ -23,9 +23,10 @@ export interface DeviceInfo {
23
23
  /**
24
24
  * A unique identifier grouping one or more devices together. Two devices
25
25
  * with the same group ID symbolise that both devices belong to the same
26
- * hardware, e.g. a webcam with an integrated microphone.
26
+ * hardware, e.g. a webcam with an integrated microphone. Note: Safari
27
+ * doesn't support group IDs.
27
28
  */
28
- groupId: string;
29
+ groupId: null | string;
29
30
  /**
30
31
  * Declares the type of media provided. This covers microphones, cameras,
31
32
  * and speakers.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import DeviceManager from './device-manager';
2
2
  export { supportsMediaDevices } from './support-detection';
3
+ export { DeviceInfo, DeviceKind } from './enumerate-devices';
4
+ export { OperationType, DeviceChange } from './device-manager';
3
5
  declare const _default: DeviceManager;
4
6
  export default _default;