@pexip/media 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 +39 -0
- package/dist/audioMixingProcessor.d.ts +18 -0
- package/dist/audioMixingProcessor.js +173 -0
- package/dist/audioProcessor.d.ts +86 -0
- package/dist/audioProcessor.js +310 -0
- package/dist/baseLogger.d.ts +37 -0
- package/dist/baseLogger.js +29 -0
- package/dist/displayMedia.d.ts +3 -0
- package/dist/displayMedia.js +31 -0
- package/dist/index.d.ts +11 -837
- package/dist/index.js +11 -0
- package/dist/logger.d.ts +11 -0
- package/dist/logger.js +44 -0
- package/dist/media.d.ts +8 -0
- package/dist/media.js +296 -0
- package/dist/previewController.d.ts +64 -0
- package/dist/previewController.js +375 -0
- package/dist/signals.d.ts +25 -0
- package/dist/signals.js +38 -0
- package/dist/status.d.ts +35 -0
- package/dist/status.js +199 -0
- package/dist/typeGuard.d.ts +9 -0
- package/dist/typeGuard.js +40 -0
- package/dist/types.d.ts +559 -0
- package/dist/types.js +278 -0
- package/dist/userMedia.d.ts +38 -0
- package/dist/userMedia.js +333 -0
- package/dist/utils.d.ts +108 -0
- package/dist/utils.js +360 -0
- package/dist/videoProcessor.d.ts +56 -0
- package/dist/videoProcessor.js +349 -0
- package/package.json +10 -10
- package/dist/index.mjs +0 -2900
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { MediaDeviceRequest, MediaDeviceInfoLike } from '@pexip/media-control';
|
|
2
|
+
import { UserMediaStatus } from './types';
|
|
3
|
+
import type { Media, MediaAttributes, Pipeline, Process, ProcessMedia, ExtendedMediaTrackSettingsKey, ExtendedMediaTrackSettings } from './types';
|
|
4
|
+
export declare const makeDeriveDeviceStatus: (constraints: MediaDeviceRequest) => (audio: UserMediaStatus, video: UserMediaStatus, both: UserMediaStatus) => UserMediaStatus;
|
|
5
|
+
export declare const createMediaProcess: (process: ProcessMedia) => Process<Promise<Media>>;
|
|
6
|
+
export declare const createMediaPipeline: <T = MediaDeviceRequest>(init: Pipeline<T> | (() => Pipeline<T>)) => {
|
|
7
|
+
pipe: (process: Process<Promise<Media>>) => void;
|
|
8
|
+
execute: (m: T) => Promise<Media>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Interpret provided input to resolve to a MediaDeviceInfoLike when possible
|
|
12
|
+
* otherwise `undefined`
|
|
13
|
+
*/
|
|
14
|
+
export declare const interpretInput: (input: boolean | MediaDeviceInfoLike | undefined, getCurrentInput: () => MediaDeviceInfoLike | undefined) => MediaDeviceInfoLike | undefined;
|
|
15
|
+
type InputConstraints = MediaDeviceRequest['audio'];
|
|
16
|
+
interface MediaInputInfo {
|
|
17
|
+
devices: MediaDeviceInfoLike[];
|
|
18
|
+
input: MediaDeviceInfoLike | undefined;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Memorized Expected Input
|
|
22
|
+
*/
|
|
23
|
+
export declare const createMemorizedGetExpectedInput: () => (constraints: InputConstraints, getInfo: () => MediaInputInfo) => ExpectedInput;
|
|
24
|
+
/**
|
|
25
|
+
* A utility function to check if the provided track is muted. There are
|
|
26
|
+
* 2 factors to be considered: `MediaStreamTrack['muted']` and `MediaStreamTrack['enabled']`.
|
|
27
|
+
*
|
|
28
|
+
* ```
|
|
29
|
+
* | muted \ enabled | true | false |
|
|
30
|
+
* |-----------------| ----- | ----- |
|
|
31
|
+
* | true | true | true |
|
|
32
|
+
* | false | false | true |
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @param tracks - The tracks can be got from `MediaStream['getAudioStats']` or
|
|
36
|
+
* `MediaStream['getVideoTracks']`
|
|
37
|
+
*
|
|
38
|
+
* @returns `true` means muted, `false` means not muted and `undefined` means
|
|
39
|
+
* there is no track to check
|
|
40
|
+
*/
|
|
41
|
+
export declare const isMuted: (tracks: MediaStreamTrack[] | undefined) => boolean | undefined;
|
|
42
|
+
type ExpectedInput = MediaDeviceInfoLike | undefined;
|
|
43
|
+
export declare const buildMedia: (getMedia: () => Partial<Media>, onSetStatus?: ((status: UserMediaStatus) => void) | undefined) => Media;
|
|
44
|
+
/**
|
|
45
|
+
* Clone the media from the rawStream (if any), otherwise, stream
|
|
46
|
+
*/
|
|
47
|
+
export declare const cloneMedia: (media: Media) => Promise<Media>;
|
|
48
|
+
/**
|
|
49
|
+
* Shallow copy the provided object and override with provided overriding
|
|
50
|
+
*
|
|
51
|
+
* @param original - Original object
|
|
52
|
+
* @param overriding - Object of the same type to override the original
|
|
53
|
+
*
|
|
54
|
+
* @returns a shallow copied object
|
|
55
|
+
*/
|
|
56
|
+
export declare const shallowCopy: <T>(original: T, overriding: Partial<T>) => T;
|
|
57
|
+
export declare const getDevicesChanges: (prev: MediaDeviceInfoLike[], next: MediaDeviceInfoLike[]) => {
|
|
58
|
+
unauthorized: MediaDeviceInfoLike[];
|
|
59
|
+
authorized: MediaDeviceInfoLike[];
|
|
60
|
+
found: MediaDeviceInfoLike[];
|
|
61
|
+
lost: MediaDeviceInfoLike[];
|
|
62
|
+
devices: MediaDeviceInfoLike[];
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Apply Extended constraints on top of the original
|
|
66
|
+
*
|
|
67
|
+
* @param media - The media from the media pipeline
|
|
68
|
+
* @param applyExtended - The function to be called when the previous
|
|
69
|
+
* `applyConstraints` is done
|
|
70
|
+
*/
|
|
71
|
+
export declare const applyExtendedConstraints: (media: Media, applyExtended: (constraints: MediaDeviceRequest) => Promise<void>) => (constraints: MediaDeviceRequest) => Promise<void>;
|
|
72
|
+
export declare const AUDIO_SETTINGS_KEYS: ExtendedMediaTrackSettingsKey[];
|
|
73
|
+
export declare const VIDEO_SETTINGS_KEYS: ExtendedMediaTrackSettingsKey[];
|
|
74
|
+
export declare const MIXING_SETTINGS_KEYS: ExtendedMediaTrackSettingsKey[];
|
|
75
|
+
export declare const hasSettingsChanged: (keysToLookFor: ExtendedMediaTrackSettingsKey[]) => (settingsA: ExtendedMediaTrackSettings | undefined, settingsB: ExtendedMediaTrackSettings | undefined) => boolean;
|
|
76
|
+
export declare const toJSON: (media: Partial<MediaAttributes>) => {
|
|
77
|
+
constraints: MediaDeviceRequest | undefined;
|
|
78
|
+
devices: MediaDeviceInfoLike[] | undefined;
|
|
79
|
+
stream: MediaStream | undefined;
|
|
80
|
+
rawStream: MediaStream | undefined;
|
|
81
|
+
audioInput: MediaDeviceInfoLike | undefined;
|
|
82
|
+
videoInput: MediaDeviceInfoLike | undefined;
|
|
83
|
+
expectedAudioInput: MediaDeviceInfoLike | undefined;
|
|
84
|
+
expectedVideoInput: MediaDeviceInfoLike | undefined;
|
|
85
|
+
status: UserMediaStatus | undefined;
|
|
86
|
+
audioMuted: boolean | undefined;
|
|
87
|
+
videoMuted: boolean | undefined;
|
|
88
|
+
};
|
|
89
|
+
export declare const wrapToJSON: (media: Media) => Media;
|
|
90
|
+
/**
|
|
91
|
+
* A function to get the blur kernel size of image height
|
|
92
|
+
*
|
|
93
|
+
* @param percentage - The percentage of image height to calculate the blur
|
|
94
|
+
* kernel size
|
|
95
|
+
* @param height - The image height
|
|
96
|
+
* @param max - The max kernel size
|
|
97
|
+
*
|
|
98
|
+
* @returns blur kernel size
|
|
99
|
+
*/
|
|
100
|
+
export declare const getBlurKernelSize: (percentage: number, height: number, max?: number) => number;
|
|
101
|
+
/**
|
|
102
|
+
* Apply the content hint to the track
|
|
103
|
+
*
|
|
104
|
+
* @param hint - Content hint
|
|
105
|
+
* @param track - The track to be applied
|
|
106
|
+
*/
|
|
107
|
+
export declare const applyContentHint: <T extends "" | "speech" | "speech-recognition" | "music" | "motion" | "detail" | "text">(hint?: T | undefined) => (track: MediaStreamTrack) => void;
|
|
108
|
+
export {};
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import { applyConstraints, createTrackDevicesChanges, extractConstraintsWithKeys, findDeviceFromConstraints, muteStreamTrack, relaxInputConstraint, stopMediaStream, isAudioInput, isVideoInput, } from '@pexip/media-control';
|
|
2
|
+
import { UserMediaStatus } from './types';
|
|
3
|
+
import { isOverConstrained } from './status';
|
|
4
|
+
import { isMedia } from './typeGuard';
|
|
5
|
+
export const makeDeriveDeviceStatus = (constraints) => (audio, video, both) => {
|
|
6
|
+
if (!constraints.audio && constraints.video) {
|
|
7
|
+
return video;
|
|
8
|
+
}
|
|
9
|
+
if (!constraints.video && constraints.audio) {
|
|
10
|
+
return audio;
|
|
11
|
+
}
|
|
12
|
+
return both;
|
|
13
|
+
};
|
|
14
|
+
export const createMediaProcess = (process) => async (mediaP) => {
|
|
15
|
+
const media = await mediaP;
|
|
16
|
+
return process(media) ?? media;
|
|
17
|
+
};
|
|
18
|
+
export const createMediaPipeline = (init) => {
|
|
19
|
+
const getPipeline = () => (typeof init === 'function' ? init() : init);
|
|
20
|
+
return {
|
|
21
|
+
pipe: (process) => {
|
|
22
|
+
getPipeline().push(process);
|
|
23
|
+
},
|
|
24
|
+
execute: async (m) => {
|
|
25
|
+
const [first, ...processes] = getPipeline();
|
|
26
|
+
if (first) {
|
|
27
|
+
const piped = processes.reduce((prev, next) => next(prev), first(m));
|
|
28
|
+
return piped;
|
|
29
|
+
}
|
|
30
|
+
const media = m instanceof Promise ? (await m) : m;
|
|
31
|
+
if (isMedia(media)) {
|
|
32
|
+
return Promise.resolve(media);
|
|
33
|
+
}
|
|
34
|
+
throw new Error('Expect a media input or a processor');
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Interpret provided input to resolve to a MediaDeviceInfoLike when possible
|
|
40
|
+
* otherwise `undefined`
|
|
41
|
+
*/
|
|
42
|
+
export const interpretInput = (input, getCurrentInput) => {
|
|
43
|
+
if (input === true || input === undefined) {
|
|
44
|
+
return getCurrentInput();
|
|
45
|
+
}
|
|
46
|
+
if (input === false) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
return input;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Memorized Expected Input
|
|
53
|
+
*/
|
|
54
|
+
export const createMemorizedGetExpectedInput = () => {
|
|
55
|
+
const props = {
|
|
56
|
+
cachedExpectedInputs: new Map(),
|
|
57
|
+
};
|
|
58
|
+
return (constraints, getInfo) => {
|
|
59
|
+
if (props.cachedExpectedInputs.has(constraints)) {
|
|
60
|
+
return props.cachedExpectedInputs.get(constraints);
|
|
61
|
+
}
|
|
62
|
+
const { devices, input } = getInfo();
|
|
63
|
+
// Update cache
|
|
64
|
+
const relaxedConstraints = relaxInputConstraint(constraints, devices);
|
|
65
|
+
const { device: [[device] = []], } = extractConstraintsWithKeys(['device'])(relaxedConstraints);
|
|
66
|
+
// The result from `findDeviceFromConstraints` has more restrictive
|
|
67
|
+
// result since it also consider if the device can be found from the
|
|
68
|
+
// device list
|
|
69
|
+
const found = device ?? findDeviceFromConstraints(constraints, devices);
|
|
70
|
+
const expectedInput = interpretInput(found, () => input);
|
|
71
|
+
props.cachedExpectedInputs.clear();
|
|
72
|
+
props.cachedExpectedInputs.set(constraints, expectedInput);
|
|
73
|
+
return expectedInput;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* A utility function to check if the provided track is muted. There are
|
|
78
|
+
* 2 factors to be considered: `MediaStreamTrack['muted']` and `MediaStreamTrack['enabled']`.
|
|
79
|
+
*
|
|
80
|
+
* ```
|
|
81
|
+
* | muted \ enabled | true | false |
|
|
82
|
+
* |-----------------| ----- | ----- |
|
|
83
|
+
* | true | true | true |
|
|
84
|
+
* | false | false | true |
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* @param tracks - The tracks can be got from `MediaStream['getAudioStats']` or
|
|
88
|
+
* `MediaStream['getVideoTracks']`
|
|
89
|
+
*
|
|
90
|
+
* @returns `true` means muted, `false` means not muted and `undefined` means
|
|
91
|
+
* there is no track to check
|
|
92
|
+
*/
|
|
93
|
+
export const isMuted = (tracks) => {
|
|
94
|
+
if (!tracks?.length) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
return !tracks.some(track => !track.muted && track.enabled);
|
|
98
|
+
};
|
|
99
|
+
export const buildMedia = (getMedia, onSetStatus) => {
|
|
100
|
+
const props = {
|
|
101
|
+
status: getMedia().status ?? UserMediaStatus.Initial,
|
|
102
|
+
devices: getMedia().devices ?? [],
|
|
103
|
+
constraints: getMedia().constraints,
|
|
104
|
+
};
|
|
105
|
+
const getExpectedAudioInput = createMemorizedGetExpectedInput();
|
|
106
|
+
const getExpectedVideoInput = createMemorizedGetExpectedInput();
|
|
107
|
+
const muteTrack = (kind) => (muted) => {
|
|
108
|
+
const { muteAudio, muteVideo, stream } = getMedia();
|
|
109
|
+
const mute = kind === 'audio' ? muteAudio : muteVideo;
|
|
110
|
+
if (mute) {
|
|
111
|
+
return mute(muted);
|
|
112
|
+
}
|
|
113
|
+
return muteStreamTrack(stream)(muted, kind);
|
|
114
|
+
};
|
|
115
|
+
const release = () => {
|
|
116
|
+
const { release, stream } = getMedia();
|
|
117
|
+
if (release) {
|
|
118
|
+
return release();
|
|
119
|
+
}
|
|
120
|
+
return new Promise(resolve => {
|
|
121
|
+
stopMediaStream(stream);
|
|
122
|
+
resolve();
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
return {
|
|
126
|
+
get constraints() {
|
|
127
|
+
return props.constraints;
|
|
128
|
+
},
|
|
129
|
+
get devices() {
|
|
130
|
+
return props.devices;
|
|
131
|
+
},
|
|
132
|
+
set devices(newDevices) {
|
|
133
|
+
props.devices = newDevices;
|
|
134
|
+
},
|
|
135
|
+
get stream() {
|
|
136
|
+
return getMedia().stream;
|
|
137
|
+
},
|
|
138
|
+
get expectedAudioInput() {
|
|
139
|
+
const media = getMedia();
|
|
140
|
+
return getExpectedAudioInput(props.constraints?.audio, () => ({
|
|
141
|
+
devices: media.devices?.filter(isAudioInput) ?? [],
|
|
142
|
+
input: media.audioInput,
|
|
143
|
+
}));
|
|
144
|
+
},
|
|
145
|
+
get expectedVideoInput() {
|
|
146
|
+
const media = getMedia();
|
|
147
|
+
return getExpectedVideoInput(props.constraints?.video, () => ({
|
|
148
|
+
devices: media.devices?.filter(isVideoInput) ?? [],
|
|
149
|
+
input: media.videoInput,
|
|
150
|
+
}));
|
|
151
|
+
},
|
|
152
|
+
get rawStream() {
|
|
153
|
+
const { rawStream, stream } = getMedia();
|
|
154
|
+
return rawStream ?? stream;
|
|
155
|
+
},
|
|
156
|
+
get audioInput() {
|
|
157
|
+
return getMedia().audioInput;
|
|
158
|
+
},
|
|
159
|
+
get videoInput() {
|
|
160
|
+
return getMedia().videoInput;
|
|
161
|
+
},
|
|
162
|
+
get status() {
|
|
163
|
+
return props.status;
|
|
164
|
+
},
|
|
165
|
+
set status(status) {
|
|
166
|
+
props.status = status;
|
|
167
|
+
onSetStatus?.(status);
|
|
168
|
+
},
|
|
169
|
+
set constraints(value) {
|
|
170
|
+
props.constraints = value;
|
|
171
|
+
},
|
|
172
|
+
get audioMuted() {
|
|
173
|
+
return isMuted(getMedia().stream?.getAudioTracks());
|
|
174
|
+
},
|
|
175
|
+
get videoMuted() {
|
|
176
|
+
return isMuted(getMedia().stream?.getVideoTracks());
|
|
177
|
+
},
|
|
178
|
+
muteAudio: muteTrack('audio'),
|
|
179
|
+
muteVideo: muteTrack('video'),
|
|
180
|
+
applyConstraints: async (constraints) => {
|
|
181
|
+
const { stream, applyConstraints: prevApplyConstraints } = getMedia();
|
|
182
|
+
if (prevApplyConstraints) {
|
|
183
|
+
return await prevApplyConstraints(constraints);
|
|
184
|
+
}
|
|
185
|
+
return await applyConstraints(stream?.getTracks(), constraints);
|
|
186
|
+
},
|
|
187
|
+
release,
|
|
188
|
+
getSettings: () => {
|
|
189
|
+
const { getSettings, stream } = getMedia();
|
|
190
|
+
if (!stream) {
|
|
191
|
+
return {
|
|
192
|
+
audio: [],
|
|
193
|
+
video: [],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
if (getSettings) {
|
|
197
|
+
return getSettings();
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
audio: stream
|
|
201
|
+
.getAudioTracks()
|
|
202
|
+
.map(track => track.getSettings()),
|
|
203
|
+
video: stream
|
|
204
|
+
.getVideoTracks()
|
|
205
|
+
.map(track => track.getSettings()),
|
|
206
|
+
};
|
|
207
|
+
},
|
|
208
|
+
toJSON: () => toJSON(getMedia()),
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* Clone the media from the rawStream (if any), otherwise, stream
|
|
213
|
+
*/
|
|
214
|
+
export const cloneMedia = async (media) => {
|
|
215
|
+
const stream = (media.rawStream ?? media.stream)?.clone();
|
|
216
|
+
// Restore the enabled state for all cloned track
|
|
217
|
+
stream?.getTracks().forEach(track => (track.enabled = true));
|
|
218
|
+
const { audio, video } = media.getSettings();
|
|
219
|
+
const clonedMedia = buildMedia(() => ({
|
|
220
|
+
stream,
|
|
221
|
+
constraints: media?.constraints,
|
|
222
|
+
devices: media?.devices,
|
|
223
|
+
status: media?.status,
|
|
224
|
+
rawStream: stream,
|
|
225
|
+
audioInput: media?.audioInput,
|
|
226
|
+
videoInput: media?.videoInput,
|
|
227
|
+
getSettings: () => ({ audio, video }),
|
|
228
|
+
}));
|
|
229
|
+
return Promise.resolve(clonedMedia);
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Shallow copy the provided object and override with provided overriding
|
|
233
|
+
*
|
|
234
|
+
* @param original - Original object
|
|
235
|
+
* @param overriding - Object of the same type to override the original
|
|
236
|
+
*
|
|
237
|
+
* @returns a shallow copied object
|
|
238
|
+
*/
|
|
239
|
+
export const shallowCopy = (original, overriding) => {
|
|
240
|
+
const copy = Object.create(Object.getPrototypeOf(original), Object.getOwnPropertyDescriptors(original));
|
|
241
|
+
return Object.defineProperties(copy, Object.getOwnPropertyDescriptors(overriding));
|
|
242
|
+
};
|
|
243
|
+
export const getDevicesChanges = (prev, next) => {
|
|
244
|
+
const trackChanges = createTrackDevicesChanges(prev);
|
|
245
|
+
return trackChanges(next);
|
|
246
|
+
};
|
|
247
|
+
/**
|
|
248
|
+
* Apply Extended constraints on top of the original
|
|
249
|
+
*
|
|
250
|
+
* @param media - The media from the media pipeline
|
|
251
|
+
* @param applyExtended - The function to be called when the previous
|
|
252
|
+
* `applyConstraints` is done
|
|
253
|
+
*/
|
|
254
|
+
export const applyExtendedConstraints = (media, applyExtended) =>
|
|
255
|
+
/**
|
|
256
|
+
* Apply constraints
|
|
257
|
+
* @param constraints - The constraints to be applied to the media
|
|
258
|
+
*/
|
|
259
|
+
async (constraints) => {
|
|
260
|
+
await media.applyConstraints(constraints);
|
|
261
|
+
if (!isOverConstrained(media.status)) {
|
|
262
|
+
await applyExtended(constraints);
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
export const AUDIO_SETTINGS_KEYS = [
|
|
266
|
+
'denoise',
|
|
267
|
+
'vad',
|
|
268
|
+
'asd',
|
|
269
|
+
'contentHint',
|
|
270
|
+
];
|
|
271
|
+
export const VIDEO_SETTINGS_KEYS = [
|
|
272
|
+
'frameRate',
|
|
273
|
+
'videoSegmentation',
|
|
274
|
+
'videoSegmentationModel',
|
|
275
|
+
'foregroundThreshold',
|
|
276
|
+
'backgroundBlurAmount',
|
|
277
|
+
'edgeBlurAmount',
|
|
278
|
+
'flipHorizontal',
|
|
279
|
+
'bgImageUrl',
|
|
280
|
+
'width',
|
|
281
|
+
'height',
|
|
282
|
+
'contentHint',
|
|
283
|
+
];
|
|
284
|
+
export const MIXING_SETTINGS_KEYS = [
|
|
285
|
+
'mixWithAdditionalMedia',
|
|
286
|
+
];
|
|
287
|
+
export const hasSettingsChanged = (keysToLookFor) => {
|
|
288
|
+
const cache = {};
|
|
289
|
+
return (settingsA, settingsB) => {
|
|
290
|
+
if (cache.result !== undefined &&
|
|
291
|
+
cache.settingsA === settingsA &&
|
|
292
|
+
cache.settingsB === settingsB) {
|
|
293
|
+
return cache.result;
|
|
294
|
+
}
|
|
295
|
+
cache.settingsA = settingsA;
|
|
296
|
+
cache.settingsB = settingsB;
|
|
297
|
+
for (const key of keysToLookFor) {
|
|
298
|
+
if (settingsA === settingsB) {
|
|
299
|
+
cache.result = false;
|
|
300
|
+
return cache.result;
|
|
301
|
+
}
|
|
302
|
+
if (settingsA === undefined || settingsB === undefined) {
|
|
303
|
+
cache.result = true;
|
|
304
|
+
return cache.result;
|
|
305
|
+
}
|
|
306
|
+
if (settingsA[key] !== settingsB[key]) {
|
|
307
|
+
cache.result = true;
|
|
308
|
+
return cache.result;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
cache.result = false;
|
|
312
|
+
return cache.result;
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
export const toJSON = (media) => {
|
|
316
|
+
return {
|
|
317
|
+
constraints: media.constraints,
|
|
318
|
+
devices: media.devices,
|
|
319
|
+
stream: media.stream,
|
|
320
|
+
rawStream: media.rawStream,
|
|
321
|
+
audioInput: media.audioInput,
|
|
322
|
+
videoInput: media.videoInput,
|
|
323
|
+
expectedAudioInput: media.expectedAudioInput,
|
|
324
|
+
expectedVideoInput: media.expectedVideoInput,
|
|
325
|
+
status: media.status,
|
|
326
|
+
audioMuted: media.audioMuted,
|
|
327
|
+
videoMuted: media.videoMuted,
|
|
328
|
+
};
|
|
329
|
+
};
|
|
330
|
+
export const wrapToJSON = (media) => {
|
|
331
|
+
media.toJSON = () => toJSON(media);
|
|
332
|
+
return media;
|
|
333
|
+
};
|
|
334
|
+
/**
|
|
335
|
+
* A function to get the blur kernel size of image height
|
|
336
|
+
*
|
|
337
|
+
* @param percentage - The percentage of image height to calculate the blur
|
|
338
|
+
* kernel size
|
|
339
|
+
* @param height - The image height
|
|
340
|
+
* @param max - The max kernel size
|
|
341
|
+
*
|
|
342
|
+
* @returns blur kernel size
|
|
343
|
+
*/
|
|
344
|
+
export const getBlurKernelSize = (percentage, height, max = 20) => {
|
|
345
|
+
if (height <= 0 || percentage <= 0 || max <= 0) {
|
|
346
|
+
return 0;
|
|
347
|
+
}
|
|
348
|
+
return Math.min(Math.ceil(percentage * 0.001 * height), max);
|
|
349
|
+
};
|
|
350
|
+
/**
|
|
351
|
+
* Apply the content hint to the track
|
|
352
|
+
*
|
|
353
|
+
* @param hint - Content hint
|
|
354
|
+
* @param track - The track to be applied
|
|
355
|
+
*/
|
|
356
|
+
export const applyContentHint = (hint) => (track) => {
|
|
357
|
+
if (hint !== undefined && hint !== track.contentHint) {
|
|
358
|
+
track.contentHint = hint;
|
|
359
|
+
}
|
|
360
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { VideoProcessor, SegmentationModel, SegmentationTransform } from '@pexip/media-processor';
|
|
2
|
+
import type { MediaDeviceRequest } from '@pexip/media-control';
|
|
3
|
+
import type { Process, Media, VideoRenderParams, Segmenters, VideoStreamTrackProcessorAPIs, VideoContentHint } from './types';
|
|
4
|
+
interface ProcessorDeps {
|
|
5
|
+
videoProcessor?: () => VideoProcessor;
|
|
6
|
+
transformer?: SegmentationTransform;
|
|
7
|
+
segmenters: Segmenters;
|
|
8
|
+
videoSegmentationModel?: SegmentationModel;
|
|
9
|
+
}
|
|
10
|
+
interface VideoStreamProcessOptions extends Partial<VideoRenderParams>, Omit<ProcessorDeps, 'videoProcessor'> {
|
|
11
|
+
/**
|
|
12
|
+
* What API to use for processing the MediaStreamTrack
|
|
13
|
+
* `stream` - Use MediaStreamTrackProcessor, when available
|
|
14
|
+
* `canvas` - Use Canvas
|
|
15
|
+
*/
|
|
16
|
+
trackProcessorAPI?: () => VideoStreamTrackProcessorAPIs;
|
|
17
|
+
/**
|
|
18
|
+
* Whether or to enable this processor
|
|
19
|
+
*/
|
|
20
|
+
shouldEnable: () => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Callback when error occurs
|
|
23
|
+
*/
|
|
24
|
+
onError?: (error: Error) => void;
|
|
25
|
+
processingWidth: number;
|
|
26
|
+
processingHeight: number;
|
|
27
|
+
hasInitializedDeps?: boolean;
|
|
28
|
+
width?: number;
|
|
29
|
+
height?: number;
|
|
30
|
+
scope?: string;
|
|
31
|
+
}
|
|
32
|
+
interface VideoStreamProcessProps extends Partial<VideoRenderParams>, Required<ProcessorDeps> {
|
|
33
|
+
hasInitialized: boolean;
|
|
34
|
+
contentHint?: VideoContentHint;
|
|
35
|
+
}
|
|
36
|
+
declare const FEATURE_KEYS: [
|
|
37
|
+
'backgroundBlurAmount',
|
|
38
|
+
'bgImageUrl',
|
|
39
|
+
'edgeBlurAmount',
|
|
40
|
+
'flipHorizontal',
|
|
41
|
+
'foregroundThreshold',
|
|
42
|
+
'frameRate',
|
|
43
|
+
'videoSegmentation',
|
|
44
|
+
'videoSegmentationModel',
|
|
45
|
+
'width',
|
|
46
|
+
'height',
|
|
47
|
+
'pan',
|
|
48
|
+
'tilt',
|
|
49
|
+
'zoom',
|
|
50
|
+
'contentHint'
|
|
51
|
+
];
|
|
52
|
+
type FeaturePropKeys = (typeof FEATURE_KEYS)[number];
|
|
53
|
+
type FeatureProps = Pick<Partial<VideoStreamProcessProps>, FeaturePropKeys>;
|
|
54
|
+
export declare const updateFeatureProps: (constraints: MediaDeviceRequest['video'], props: FeatureProps) => FeatureProps;
|
|
55
|
+
export declare const createVideoStreamProcess: ({ trackProcessorAPI, processingWidth, processingHeight, shouldEnable, frameRate, videoSegmentation, foregroundThreshold, bgImageUrl, flipHorizontal, edgeBlurAmount, scope, ...options }: VideoStreamProcessOptions) => Process<Promise<Media>>;
|
|
56
|
+
export {};
|