@pexip/media-control 17.2.0 → 17.4.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 +25 -0
- package/dist/baseLogger.d.ts +37 -0
- package/dist/baseLogger.js +29 -0
- package/dist/constants.d.ts +43 -0
- package/dist/constants.js +26 -0
- package/dist/constraints.d.ts +174 -0
- package/dist/constraints.js +653 -0
- package/dist/devices.d.ts +416 -0
- package/dist/devices.js +766 -0
- package/dist/displayMedia.d.ts +10 -0
- package/dist/displayMedia.js +31 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.js +105 -0
- package/dist/eventEmitter.d.ts +119 -0
- package/dist/eventEmitter.js +81 -0
- package/dist/getMediaStream.d.ts +11 -0
- package/dist/getMediaStream.js +41 -0
- package/dist/index.d.ts +18 -979
- package/dist/index.js +105 -0
- package/dist/logger.d.ts +3 -0
- package/dist/logger.js +5 -0
- package/dist/streamTrackMap.d.ts +9 -0
- package/dist/streamTrackMap.js +79 -0
- package/dist/streams.d.ts +26 -0
- package/dist/streams.js +99 -0
- package/dist/typeGuards.d.ts +89 -0
- package/dist/typeGuards.js +185 -0
- package/dist/types.d.ts +265 -0
- package/dist/types.js +88 -0
- package/dist/utils.d.ts +37 -0
- package/dist/utils.js +47 -0
- package/package.json +7 -7
- package/dist/index.mjs +0 -1699
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DisplayMediaOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* A fallback implementation of `monitorTypeSurfaces` limitation when it is not
|
|
4
|
+
* supported by the current browser and the source of the `displaySurface` is
|
|
5
|
+
* available.
|
|
6
|
+
*
|
|
7
|
+
* @param constraints - The constraints used to request display media.
|
|
8
|
+
* @param stream - The MediaStream returned from the requesting display media.
|
|
9
|
+
*/
|
|
10
|
+
export declare const limitSharingMonitorInterface: (constraints: DisplayMediaOptions, stream: MediaStream) => MediaStream;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { stopMediaStream } from './devices';
|
|
2
|
+
/**
|
|
3
|
+
* A fallback implementation of `monitorTypeSurfaces` limitation when it is not
|
|
4
|
+
* supported by the current browser and the source of the `displaySurface` is
|
|
5
|
+
* available.
|
|
6
|
+
*
|
|
7
|
+
* @param constraints - The constraints used to request display media.
|
|
8
|
+
* @param stream - The MediaStream returned from the requesting display media.
|
|
9
|
+
*/
|
|
10
|
+
export const limitSharingMonitorInterface = (constraints, stream) => {
|
|
11
|
+
// Fallback implementation of `monitorTypeSurfaces`
|
|
12
|
+
if (!constraints.monitorTypeSurfaces ||
|
|
13
|
+
constraints.monitorTypeSurfaces !== 'exclude') {
|
|
14
|
+
return stream;
|
|
15
|
+
}
|
|
16
|
+
for (const track of stream.getTracks()) {
|
|
17
|
+
const { displaySurface } = track.getSettings();
|
|
18
|
+
if (!displaySurface || displaySurface !== 'monitor') {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
stopMediaStream(stream);
|
|
22
|
+
throw new TypeError('MonitorSharingNotAllowed', {
|
|
23
|
+
cause: {
|
|
24
|
+
monitorTypeSurfaces: constraints.monitorTypeSurfaces,
|
|
25
|
+
track,
|
|
26
|
+
displaySurface,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return stream;
|
|
31
|
+
};
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MediaDeviceInfoLike, MediaDeviceKinds, MediaDeviceRequest } from './types';
|
|
2
|
+
import { MediaDeviceFailure } from './types';
|
|
3
|
+
export interface InputNotFoundErrorParams {
|
|
4
|
+
input: MediaTrackConstraints | boolean | undefined;
|
|
5
|
+
kind: MediaDeviceKinds;
|
|
6
|
+
devices: MediaDeviceInfoLike[];
|
|
7
|
+
}
|
|
8
|
+
export declare const isInputNotFoundError: ({ input, kind, devices }: InputNotFoundErrorParams) => (error: string) => boolean;
|
|
9
|
+
export declare const normalizeGetUserMediaError: (browserError: Error, constraints: MediaStreamConstraints, devices: MediaDeviceInfoLike[]) => MediaDeviceFailure | string;
|
|
10
|
+
export declare const normalizeDeviceError: ({ audio, video, streamingAudioInput, streamingVideoInput, }: {
|
|
11
|
+
streamingAudioInput?: boolean | undefined;
|
|
12
|
+
streamingVideoInput?: boolean | undefined;
|
|
13
|
+
} & MediaDeviceRequest) => false | MediaDeviceFailure;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { isMediaTrackConstraints } from './typeGuards';
|
|
2
|
+
import { extractDeviceId } from './constraints';
|
|
3
|
+
import { MediaDeviceFailure } from './types';
|
|
4
|
+
const isDeviceInUseError = (error) => {
|
|
5
|
+
return (error === MediaDeviceFailure.NotReadableError ||
|
|
6
|
+
error === MediaDeviceFailure.TrackStartError);
|
|
7
|
+
};
|
|
8
|
+
const isPermissionDeniedError = (error) => {
|
|
9
|
+
return (error === MediaDeviceFailure.NotAllowedError ||
|
|
10
|
+
error === MediaDeviceFailure.PermissionDeniedError);
|
|
11
|
+
};
|
|
12
|
+
export const isInputNotFoundError = ({ input, kind, devices }) => (error) => {
|
|
13
|
+
if (error === MediaDeviceFailure.NotFoundError) {
|
|
14
|
+
const hasDevices = devices.some(d => d.kind === kind);
|
|
15
|
+
if (typeof input === 'boolean') {
|
|
16
|
+
if (!hasDevices && input) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return input && !hasDevices;
|
|
20
|
+
}
|
|
21
|
+
if (isMediaTrackConstraints(input)) {
|
|
22
|
+
const [deviceIds, requirement] = extractDeviceId(input);
|
|
23
|
+
if (requirement === 'ideal') {
|
|
24
|
+
return !hasDevices;
|
|
25
|
+
}
|
|
26
|
+
if (requirement === 'exact') {
|
|
27
|
+
return !devices.some(device => deviceIds?.some(id => device.kind === kind && id === device.deviceId));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
};
|
|
33
|
+
const normalizeError = (errors, parameters = []) => {
|
|
34
|
+
const error = errors.find(e => e.fn(...parameters));
|
|
35
|
+
if (error) {
|
|
36
|
+
return error.type;
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
};
|
|
40
|
+
export const normalizeGetUserMediaError = (browserError, constraints, devices) => {
|
|
41
|
+
const isAudioInputNotFoundError = isInputNotFoundError({
|
|
42
|
+
input: constraints.audio,
|
|
43
|
+
kind: 'audioinput',
|
|
44
|
+
devices,
|
|
45
|
+
});
|
|
46
|
+
const isVideoInputNotFoundError = isInputNotFoundError({
|
|
47
|
+
input: constraints.video,
|
|
48
|
+
kind: 'videoinput',
|
|
49
|
+
devices,
|
|
50
|
+
});
|
|
51
|
+
const areBothInputsNotFoundError = (error) => isAudioInputNotFoundError(error) && isVideoInputNotFoundError(error);
|
|
52
|
+
const errorsFn = [
|
|
53
|
+
{
|
|
54
|
+
fn: isDeviceInUseError,
|
|
55
|
+
type: MediaDeviceFailure.NotReadableError, // For now just normalize to current spec
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
fn: isPermissionDeniedError,
|
|
59
|
+
type: MediaDeviceFailure.NotAllowedError,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
fn: areBothInputsNotFoundError,
|
|
63
|
+
type: MediaDeviceFailure.AudioAndVideoDeviceNotFoundError,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
fn: isAudioInputNotFoundError,
|
|
67
|
+
type: MediaDeviceFailure.AudioInputDeviceNotFoundError,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
fn: isVideoInputNotFoundError,
|
|
71
|
+
type: MediaDeviceFailure.VideoInputDeviceNotFoundError,
|
|
72
|
+
},
|
|
73
|
+
];
|
|
74
|
+
const errorMsg = browserError.name === 'Error'
|
|
75
|
+
? browserError.message
|
|
76
|
+
: browserError.name;
|
|
77
|
+
const error = normalizeError(errorsFn, [errorMsg]);
|
|
78
|
+
return error ? error : errorMsg;
|
|
79
|
+
};
|
|
80
|
+
export const normalizeDeviceError = ({ audio, video, streamingAudioInput, streamingVideoInput, }) => {
|
|
81
|
+
let audioError = false;
|
|
82
|
+
let videoError = false;
|
|
83
|
+
if (audio) {
|
|
84
|
+
audioError = !streamingAudioInput;
|
|
85
|
+
}
|
|
86
|
+
if (video) {
|
|
87
|
+
videoError = !streamingVideoInput;
|
|
88
|
+
}
|
|
89
|
+
const errorsFn = [
|
|
90
|
+
{
|
|
91
|
+
fn: () => audioError && videoError,
|
|
92
|
+
type: MediaDeviceFailure.AudioAndVideoDeviceNotFoundError,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
fn: () => audioError,
|
|
96
|
+
type: MediaDeviceFailure.AudioInputDeviceNotFoundError,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
fn: () => videoError,
|
|
100
|
+
type: MediaDeviceFailure.VideoInputDeviceNotFoundError,
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
const error = normalizeError(errorsFn, []);
|
|
104
|
+
return error ? error : false;
|
|
105
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { MediaDeviceInfoLike } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* MediaStreamTrack Events
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* See MDN {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack#Events | Events}
|
|
7
|
+
*
|
|
8
|
+
* @beta
|
|
9
|
+
*/
|
|
10
|
+
export declare enum MediaEventType {
|
|
11
|
+
/**
|
|
12
|
+
* Sent to the MediaStreamTrack when the value of the muted property is
|
|
13
|
+
* changed to true, indicating that the track is unable to provide data
|
|
14
|
+
* temporarily (such as when the network is experiencing a service
|
|
15
|
+
* malfunction).
|
|
16
|
+
*/
|
|
17
|
+
Mute = "mute",
|
|
18
|
+
/**
|
|
19
|
+
* Sent to the track when data becomes available again, ending the muted state.
|
|
20
|
+
*/
|
|
21
|
+
Unmute = "unmute",
|
|
22
|
+
/**
|
|
23
|
+
* Sent when playback of the track ends (when the value readyState changes to
|
|
24
|
+
* ended).
|
|
25
|
+
*/
|
|
26
|
+
Ended = "ended",
|
|
27
|
+
/**
|
|
28
|
+
* Fired when a media input or output device is attached to or removed from
|
|
29
|
+
* the user's computer.
|
|
30
|
+
*
|
|
31
|
+
* @remarks
|
|
32
|
+
* See MDN {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices#Events | Events}
|
|
33
|
+
*/
|
|
34
|
+
DevicesChanged = "devices:changed",
|
|
35
|
+
/**
|
|
36
|
+
* Found new devices from authorized device list
|
|
37
|
+
*/
|
|
38
|
+
DevicesFound = "devices:found",
|
|
39
|
+
/**
|
|
40
|
+
* Lost devices from authorized device list
|
|
41
|
+
*/
|
|
42
|
+
DevicesLost = "devices:lost",
|
|
43
|
+
/**
|
|
44
|
+
* Lost device from authorized device list
|
|
45
|
+
*/
|
|
46
|
+
DeviceLost = "device:lost",
|
|
47
|
+
/**
|
|
48
|
+
* Unauthorized devices
|
|
49
|
+
*/
|
|
50
|
+
DevicesUnauthorized = "devices:unauthorized",
|
|
51
|
+
/**
|
|
52
|
+
* No Input Devices, and no further device events will be emitted
|
|
53
|
+
*/
|
|
54
|
+
NoInputDevices = "devices:noinput",
|
|
55
|
+
/**
|
|
56
|
+
* Other errors
|
|
57
|
+
*/
|
|
58
|
+
Error = "error",
|
|
59
|
+
/**
|
|
60
|
+
* When stream
|
|
61
|
+
*/
|
|
62
|
+
Stream = "stream"
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Event object by MediaEventType
|
|
66
|
+
*
|
|
67
|
+
* @beta
|
|
68
|
+
*/
|
|
69
|
+
export type Events = {
|
|
70
|
+
id: string;
|
|
71
|
+
type: MediaEventType.Mute;
|
|
72
|
+
} | {
|
|
73
|
+
id: string;
|
|
74
|
+
type: MediaEventType.Unmute;
|
|
75
|
+
} | {
|
|
76
|
+
id: string;
|
|
77
|
+
type: MediaEventType.Ended;
|
|
78
|
+
} | {
|
|
79
|
+
devices: MediaDeviceInfoLike[];
|
|
80
|
+
type: MediaEventType.DevicesChanged;
|
|
81
|
+
} | {
|
|
82
|
+
devices: MediaDeviceInfoLike[];
|
|
83
|
+
authorizedDevices: MediaDeviceInfoLike[];
|
|
84
|
+
unauthorizedDevices: MediaDeviceInfoLike[];
|
|
85
|
+
type: MediaEventType.DevicesFound;
|
|
86
|
+
} | {
|
|
87
|
+
devices: MediaDeviceInfoLike[];
|
|
88
|
+
authorizedDevices: MediaDeviceInfoLike[];
|
|
89
|
+
unauthorizedDevices: MediaDeviceInfoLike[];
|
|
90
|
+
type: MediaEventType.DevicesLost;
|
|
91
|
+
} | {
|
|
92
|
+
devices: MediaDeviceInfoLike[];
|
|
93
|
+
authorizedDevices: MediaDeviceInfoLike[];
|
|
94
|
+
type: MediaEventType.DevicesUnauthorized;
|
|
95
|
+
} | {
|
|
96
|
+
devices: MediaDeviceInfoLike[];
|
|
97
|
+
type: MediaEventType.NoInputDevices;
|
|
98
|
+
} | {
|
|
99
|
+
device: MediaDeviceInfoLike;
|
|
100
|
+
type: MediaEventType.DeviceLost;
|
|
101
|
+
} | {
|
|
102
|
+
error: Error;
|
|
103
|
+
type: MediaEventType.Error;
|
|
104
|
+
} | {
|
|
105
|
+
facingMode: boolean;
|
|
106
|
+
stream: MediaStream;
|
|
107
|
+
type: MediaEventType.Stream;
|
|
108
|
+
video: boolean;
|
|
109
|
+
};
|
|
110
|
+
export type Dispatch = (event: Events) => void;
|
|
111
|
+
/**
|
|
112
|
+
* Custom Media Event
|
|
113
|
+
* @beta
|
|
114
|
+
*/
|
|
115
|
+
export type MediaEvent = CustomEvent<Events>;
|
|
116
|
+
export declare const eventEmitter: () => {
|
|
117
|
+
dispatch(event: Events): void;
|
|
118
|
+
subscriber(listener: (event: MediaEvent) => void, onUnsubscribe: () => void): () => void;
|
|
119
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MediaStreamTrack Events
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* See MDN {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack#Events | Events}
|
|
6
|
+
*
|
|
7
|
+
* @beta
|
|
8
|
+
*/
|
|
9
|
+
export var MediaEventType;
|
|
10
|
+
(function (MediaEventType) {
|
|
11
|
+
/**
|
|
12
|
+
* Sent to the MediaStreamTrack when the value of the muted property is
|
|
13
|
+
* changed to true, indicating that the track is unable to provide data
|
|
14
|
+
* temporarily (such as when the network is experiencing a service
|
|
15
|
+
* malfunction).
|
|
16
|
+
*/
|
|
17
|
+
MediaEventType["Mute"] = "mute";
|
|
18
|
+
/**
|
|
19
|
+
* Sent to the track when data becomes available again, ending the muted state.
|
|
20
|
+
*/
|
|
21
|
+
MediaEventType["Unmute"] = "unmute";
|
|
22
|
+
/**
|
|
23
|
+
* Sent when playback of the track ends (when the value readyState changes to
|
|
24
|
+
* ended).
|
|
25
|
+
*/
|
|
26
|
+
MediaEventType["Ended"] = "ended";
|
|
27
|
+
/**
|
|
28
|
+
* Fired when a media input or output device is attached to or removed from
|
|
29
|
+
* the user's computer.
|
|
30
|
+
*
|
|
31
|
+
* @remarks
|
|
32
|
+
* See MDN {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices#Events | Events}
|
|
33
|
+
*/
|
|
34
|
+
MediaEventType["DevicesChanged"] = "devices:changed";
|
|
35
|
+
/**
|
|
36
|
+
* Found new devices from authorized device list
|
|
37
|
+
*/
|
|
38
|
+
MediaEventType["DevicesFound"] = "devices:found";
|
|
39
|
+
/**
|
|
40
|
+
* Lost devices from authorized device list
|
|
41
|
+
*/
|
|
42
|
+
MediaEventType["DevicesLost"] = "devices:lost";
|
|
43
|
+
/**
|
|
44
|
+
* Lost device from authorized device list
|
|
45
|
+
*/
|
|
46
|
+
MediaEventType["DeviceLost"] = "device:lost";
|
|
47
|
+
/**
|
|
48
|
+
* Unauthorized devices
|
|
49
|
+
*/
|
|
50
|
+
MediaEventType["DevicesUnauthorized"] = "devices:unauthorized";
|
|
51
|
+
/**
|
|
52
|
+
* No Input Devices, and no further device events will be emitted
|
|
53
|
+
*/
|
|
54
|
+
MediaEventType["NoInputDevices"] = "devices:noinput";
|
|
55
|
+
/**
|
|
56
|
+
* Other errors
|
|
57
|
+
*/
|
|
58
|
+
MediaEventType["Error"] = "error";
|
|
59
|
+
/**
|
|
60
|
+
* When stream
|
|
61
|
+
*/
|
|
62
|
+
MediaEventType["Stream"] = "stream";
|
|
63
|
+
})(MediaEventType || (MediaEventType = {}));
|
|
64
|
+
export const eventEmitter = () => {
|
|
65
|
+
const element = document.createElement('a');
|
|
66
|
+
const createEvent = (data) => {
|
|
67
|
+
return new CustomEvent('data', { detail: data });
|
|
68
|
+
};
|
|
69
|
+
return {
|
|
70
|
+
dispatch(event) {
|
|
71
|
+
element.dispatchEvent(createEvent(event));
|
|
72
|
+
},
|
|
73
|
+
subscriber(listener, onUnsubscribe) {
|
|
74
|
+
element.addEventListener('data', listener, false);
|
|
75
|
+
return () => {
|
|
76
|
+
element.removeEventListener('data', listener, false);
|
|
77
|
+
onUnsubscribe();
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MediaDeviceRequest } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Get MediaStream with provided input constraints
|
|
4
|
+
*
|
|
5
|
+
* @returns MediaStream
|
|
6
|
+
*
|
|
7
|
+
* @beta
|
|
8
|
+
*/
|
|
9
|
+
export declare const getMediaStream: (request: MediaDeviceRequest & {
|
|
10
|
+
getDefaultConstraints: () => MediaStreamConstraints;
|
|
11
|
+
}) => Promise<MediaStream>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { MediaDeviceFailure } from './types';
|
|
2
|
+
import { getDevices } from './devices';
|
|
3
|
+
import { getMediaConstraints, relaxInputConstraint } from './constraints';
|
|
4
|
+
import { normalizeGetUserMediaError } from './errors';
|
|
5
|
+
import { logger } from './logger';
|
|
6
|
+
/**
|
|
7
|
+
* Get MediaStream with provided input constraints
|
|
8
|
+
*
|
|
9
|
+
* @returns MediaStream
|
|
10
|
+
*
|
|
11
|
+
* @beta
|
|
12
|
+
*/
|
|
13
|
+
export const getMediaStream = async (request) => {
|
|
14
|
+
if (!request.audio && !request.video) {
|
|
15
|
+
throw new Error(MediaDeviceFailure.MissingConstraintsError);
|
|
16
|
+
}
|
|
17
|
+
const devices = await getDevices();
|
|
18
|
+
const audio = relaxInputConstraint(request.audio, devices);
|
|
19
|
+
const video = relaxInputConstraint(request.video, devices);
|
|
20
|
+
const constraints = getMediaConstraints({
|
|
21
|
+
audio,
|
|
22
|
+
video,
|
|
23
|
+
defaultConstraints: request.getDefaultConstraints(),
|
|
24
|
+
});
|
|
25
|
+
logger.debug({ request, constraints, devices }, 'Constraints used for getting media');
|
|
26
|
+
try {
|
|
27
|
+
// Track device changes before and after the getUserMedia call to keep
|
|
28
|
+
// track of authorized/unauthorized devices
|
|
29
|
+
navigator.mediaDevices.dispatchEvent(new Event('devicechange'));
|
|
30
|
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
31
|
+
navigator.mediaDevices.dispatchEvent(new Event('devicechange'));
|
|
32
|
+
return stream;
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error instanceof Error) {
|
|
36
|
+
const devices = await getDevices();
|
|
37
|
+
throw new Error(normalizeGetUserMediaError(error, constraints, devices));
|
|
38
|
+
}
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
};
|