@pexip/media 20.3.5 → 22.0.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 +106 -0
- package/README.md +20 -32
- package/api-docs/README.mdx +23 -35
- package/api-docs/functions/getBlurKernelSize.mdx +25 -0
- package/api-docs/functions/getTentBlurSize.mdx +24 -0
- package/api-docs/functions/proxyWithLog.mdx +33 -0
- package/api-docs/interfaces/ExtendedMediaTrackSettings.mdx +9 -5
- package/api-docs/interfaces/PreviewControllerProps.mdx +1 -0
- package/api-docs/interfaces/PreviewStreamParams.mdx +1 -0
- package/api-docs/type-aliases/VideoRenderParams.mdx +3 -1
- package/dist/audioMixingProcessor.d.ts +4 -2
- package/dist/audioMixingProcessor.js +22 -12
- package/dist/audioProcessor.d.ts +7 -2
- package/dist/audioProcessor.js +25 -20
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/logger.js +8 -0
- package/dist/media.js +5 -5
- package/dist/previewController.d.ts +3 -1
- package/dist/previewController.js +24 -9
- package/dist/typeGuard.d.ts +1 -2
- package/dist/typeGuard.js +0 -3
- package/dist/types.d.ts +10 -15
- package/dist/userMedia.d.ts +4 -1
- package/dist/userMedia.js +15 -11
- package/dist/utils.d.ts +17 -6
- package/dist/utils.js +31 -16
- package/dist/videoProcessor.d.ts +41 -23
- package/dist/videoProcessor.js +315 -193
- package/package.json +14 -14
- package/api-docs/functions/isVideoStreamTrackProcessorAPIs.mdx +0 -13
- package/api-docs/type-aliases/Segmenters.mdx +0 -3
- package/api-docs/type-aliases/VideoStreamTrackProcessorAPIs.mdx +0 -7
package/dist/media.js
CHANGED
|
@@ -7,7 +7,7 @@ import { createGetUserMediaProcess, requestUserMediaWithRetry, } from './userMed
|
|
|
7
7
|
import { AUDIO_SETTINGS_KEYS, MIXING_SETTINGS_KEYS, PAN_TILT_ZOOM_SETTINGS_KEYS, VIDEO_SETTINGS_KEYS, buildMedia, createMediaProcessor, diffSettings, getDevicesChanges, getSettingsFromKeys, hasPtzFeature, isApplyingRenderEffect, mergeSettings, refineMediaConstraints, } from './utils';
|
|
8
8
|
import { getPermissionStatus, isRequestPermissionNeeded } from './status';
|
|
9
9
|
import { isMedia } from './typeGuard';
|
|
10
|
-
import { updateFeatureProps as getVideoFeatures } from './videoProcessor';
|
|
10
|
+
import { updateFeatureProps as getVideoFeatures, mapFeatureToSettings, mapSettingsToFeatures, } from './videoProcessor';
|
|
11
11
|
import { updateFeatureProps as getAudioFeatures } from './audioProcessor';
|
|
12
12
|
import { updateFeatureProps as getMixingFeatures } from './audioMixingProcessor';
|
|
13
13
|
import { GET_USER_MEDIA_TIMEOUT_MS, DEVICE_CHANGE_DEBOUNCE_TIMEOUT_MS, } from './constants';
|
|
@@ -59,7 +59,7 @@ export const createMediaUpdater = ({ getUserMedia, getCurrentDevices, shouldDisc
|
|
|
59
59
|
const defaultVideoSettings = getSettingsFromKeys(VIDEO_SETTINGS_KEYS, getDefaultConstraints?.().video);
|
|
60
60
|
const videoFeaturesChanged = defaultVideoSettings === false
|
|
61
61
|
? undefined
|
|
62
|
-
: diffSettings(VIDEO_SETTINGS_KEYS)(prevVideoSettings ?? defaultVideoSettings, videoFeatures);
|
|
62
|
+
: diffSettings(VIDEO_SETTINGS_KEYS)(prevVideoSettings ?? defaultVideoSettings, mapFeatureToSettings(videoFeatures));
|
|
63
63
|
const defaultMixingSettings = getSettingsFromKeys(MIXING_SETTINGS_KEYS, getDefaultConstraints?.().audio);
|
|
64
64
|
const mixingFeaturesChanged = defaultMixingSettings === false
|
|
65
65
|
? undefined
|
|
@@ -68,7 +68,7 @@ export const createMediaUpdater = ({ getUserMedia, getCurrentDevices, shouldDisc
|
|
|
68
68
|
const ptzFeaturesChanges = defaultPTZSettings === false
|
|
69
69
|
? undefined
|
|
70
70
|
: hasPtzFeature() &&
|
|
71
|
-
diffSettings(PAN_TILT_ZOOM_SETTINGS_KEYS)(prevVideoSettings ?? defaultPTZSettings, videoFeatures);
|
|
71
|
+
diffSettings(PAN_TILT_ZOOM_SETTINGS_KEYS)(prevVideoSettings ?? defaultPTZSettings, mapFeatureToSettings(videoFeatures));
|
|
72
72
|
const audioRequest = refineMediaConstraints({
|
|
73
73
|
kind: 'audioinput',
|
|
74
74
|
request: constraints.audio,
|
|
@@ -154,8 +154,8 @@ export const createMediaUpdater = ({ getUserMedia, getCurrentDevices, shouldDisc
|
|
|
154
154
|
: undefined;
|
|
155
155
|
if (audioDiff || videoDiff) {
|
|
156
156
|
await currentMedia?.applyConstraints({
|
|
157
|
-
audio: audioDiff,
|
|
158
|
-
video: videoDiff,
|
|
157
|
+
audio: audioDiff && mapSettingsToFeatures(audioDiff),
|
|
158
|
+
video: videoDiff && mapSettingsToFeatures(videoDiff),
|
|
159
159
|
});
|
|
160
160
|
}
|
|
161
161
|
};
|
|
@@ -39,6 +39,7 @@ export interface PreviewStreamParams {
|
|
|
39
39
|
audio?: InputConstraintSet | false;
|
|
40
40
|
video?: InputConstraintSet | false;
|
|
41
41
|
};
|
|
42
|
+
stopVideoTrackAsMute?: () => boolean;
|
|
42
43
|
}
|
|
43
44
|
export interface PreviewControllerProps {
|
|
44
45
|
media: Media | undefined;
|
|
@@ -51,6 +52,7 @@ export interface PreviewControllerProps {
|
|
|
51
52
|
discardMedia: boolean;
|
|
52
53
|
initialized: boolean;
|
|
53
54
|
signals: MediaSignals;
|
|
55
|
+
keepVideoMuted: boolean;
|
|
54
56
|
}
|
|
55
57
|
export interface PreviewStreamController {
|
|
56
58
|
media: Media | undefined;
|
|
@@ -83,6 +85,6 @@ export interface PreviewStreamController {
|
|
|
83
85
|
onVideoMuted(callback: EventCallback<boolean | undefined>): Unsubscribe;
|
|
84
86
|
onVideoSuspended(callback: EventCallback<boolean | undefined>): Unsubscribe;
|
|
85
87
|
}
|
|
86
|
-
export declare const createPreviewStreamController: ({ getCurrentDevices, getCurrentMedia, updateMainStream, onEnded, mainMediaSignal, queueOptions, audioProcessors, videoProcessors, getDefaultConstraints, signals, }: PreviewStreamParams) => PreviewStreamController;
|
|
88
|
+
export declare const createPreviewStreamController: ({ getCurrentDevices, getCurrentMedia, updateMainStream, onEnded, mainMediaSignal, queueOptions, audioProcessors, videoProcessors, getDefaultConstraints, signals, stopVideoTrackAsMute, }: PreviewStreamParams) => PreviewStreamController;
|
|
87
89
|
export type CreatePreviewStreamController = typeof createPreviewStreamController;
|
|
88
90
|
export {};
|
|
@@ -51,7 +51,7 @@ export const createPreviewStreamController = ({ getCurrentDevices, getCurrentMed
|
|
|
51
51
|
throttleInMS: DEFAULT_QUEUE_THROTTLE_MS,
|
|
52
52
|
delayInMS: DEFAULT_QUEUE_DELAY_MS,
|
|
53
53
|
dropLast: DEFAULT_QUEUE_DROP_LAST,
|
|
54
|
-
}, audioProcessors, videoProcessors, getDefaultConstraints = () => ({}), signals, }) => {
|
|
54
|
+
}, audioProcessors, videoProcessors, getDefaultConstraints = () => ({}), signals, stopVideoTrackAsMute = () => false, }) => {
|
|
55
55
|
const queue = createAsyncQueue(queueOptions);
|
|
56
56
|
const eventHandlers = {};
|
|
57
57
|
const internalProps = {
|
|
@@ -62,6 +62,7 @@ export const createPreviewStreamController = ({ getCurrentDevices, getCurrentMed
|
|
|
62
62
|
discardMedia: false,
|
|
63
63
|
initialized: false,
|
|
64
64
|
signals,
|
|
65
|
+
keepVideoMuted: false,
|
|
65
66
|
};
|
|
66
67
|
const logger = createModuleLogger({
|
|
67
68
|
module: 'PreviewStreamController',
|
|
@@ -125,7 +126,7 @@ export const createPreviewStreamController = ({ getCurrentDevices, getCurrentMed
|
|
|
125
126
|
eventHandlers.audioMuted?.(track.muted);
|
|
126
127
|
}
|
|
127
128
|
else {
|
|
128
|
-
eventHandlers.videoMuted?.(track.muted);
|
|
129
|
+
eventHandlers.videoMuted?.(props.keepVideoMuted || track.muted);
|
|
129
130
|
}
|
|
130
131
|
}),
|
|
131
132
|
props.signals.onMediaTrackSuspended?.add(track => {
|
|
@@ -151,7 +152,9 @@ export const createPreviewStreamController = ({ getCurrentDevices, getCurrentMed
|
|
|
151
152
|
break;
|
|
152
153
|
}
|
|
153
154
|
case 'video': {
|
|
154
|
-
eventHandlers.videoMuted?.(
|
|
155
|
+
eventHandlers.videoMuted?.(props.keepVideoMuted ||
|
|
156
|
+
isTrackMuted(track) ||
|
|
157
|
+
isTrackEnded(track));
|
|
155
158
|
break;
|
|
156
159
|
}
|
|
157
160
|
}
|
|
@@ -163,7 +166,9 @@ export const createPreviewStreamController = ({ getCurrentDevices, getCurrentMed
|
|
|
163
166
|
break;
|
|
164
167
|
}
|
|
165
168
|
case 'video': {
|
|
166
|
-
eventHandlers.videoMuted?.(
|
|
169
|
+
eventHandlers.videoMuted?.(props.keepVideoMuted ||
|
|
170
|
+
isTrackMuted(track) ||
|
|
171
|
+
isTrackEnded(track));
|
|
167
172
|
break;
|
|
168
173
|
}
|
|
169
174
|
}
|
|
@@ -173,7 +178,7 @@ export const createPreviewStreamController = ({ getCurrentDevices, getCurrentMed
|
|
|
173
178
|
getUserMedia: requestUserMediaWithRetry(() => Promise.resolve(getCurrentDevices())),
|
|
174
179
|
signals: props.signals,
|
|
175
180
|
getCurrentDevices: () => Promise.resolve(getCurrentDevices()),
|
|
176
|
-
stopVideoTrackAsMute
|
|
181
|
+
stopVideoTrackAsMute,
|
|
177
182
|
updateMedia: constraints => updateMedia(constraints),
|
|
178
183
|
});
|
|
179
184
|
const mergeMediaConstraints = (constraints) => {
|
|
@@ -223,6 +228,14 @@ export const createPreviewStreamController = ({ getCurrentDevices, getCurrentMed
|
|
|
223
228
|
getCurrentDevices: () => Promise.resolve(getCurrentDevices()),
|
|
224
229
|
shouldDiscardMedia: () => props.discardMedia,
|
|
225
230
|
onMediaTracksChanged: (media, tracks) => {
|
|
231
|
+
if (props.keepVideoMuted) {
|
|
232
|
+
for (const track of tracks) {
|
|
233
|
+
if (track.kind === 'videoinput') {
|
|
234
|
+
track.mute(true);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
props.keepVideoMuted = false;
|
|
238
|
+
}
|
|
226
239
|
props.media = media;
|
|
227
240
|
queue.enqueue(async () => {
|
|
228
241
|
await processAndUpdateMedia(media, tracks, false);
|
|
@@ -328,14 +341,16 @@ export const createPreviewStreamController = ({ getCurrentDevices, getCurrentMed
|
|
|
328
341
|
props.updatingPreviewAudio = false;
|
|
329
342
|
}
|
|
330
343
|
};
|
|
331
|
-
const updateVideoInput = async (input) => {
|
|
344
|
+
const updateVideoInput = async (input, syncMuteState = true) => {
|
|
332
345
|
try {
|
|
333
346
|
props.videoInput = input;
|
|
334
347
|
props.updatingPreviewVideo = true;
|
|
335
348
|
if (input === undefined) {
|
|
336
349
|
return await releaseVideo();
|
|
337
350
|
}
|
|
338
|
-
|
|
351
|
+
props.keepVideoMuted = syncMuteState && !!props.media?.videoMuted;
|
|
352
|
+
await updatePreviewMedia({ video: { device: { exact: input } } });
|
|
353
|
+
return;
|
|
339
354
|
}
|
|
340
355
|
catch (error) {
|
|
341
356
|
if (error instanceof Error) {
|
|
@@ -373,7 +388,7 @@ export const createPreviewStreamController = ({ getCurrentDevices, getCurrentMed
|
|
|
373
388
|
const audioSettings = extractFeaturesToConstraints(AUDIO_SETTINGS_KEYS, previewAudio);
|
|
374
389
|
// Omit the width & height settings from the preview so that the one
|
|
375
390
|
// from the main can be applied
|
|
376
|
-
const { width: _width, height: _height, ...videoSettings } = extractFeaturesToConstraints(VIDEO_SETTINGS_KEYS, previewVideo);
|
|
391
|
+
const { width: _width, height: _height, edgeBlurAmount: _edgeBlurAmount, lightWrapBlurAmount: _lightWrapBlurAmount, backgroundBlurAmount: _backgroundBlurAmount, ...videoSettings } = extractFeaturesToConstraints(VIDEO_SETTINGS_KEYS, previewVideo);
|
|
377
392
|
logger.info({ audioInput, videoInput, audioSettings, videoSettings }, 'Apply changes to main');
|
|
378
393
|
try {
|
|
379
394
|
await replaceMainStream({
|
|
@@ -475,7 +490,7 @@ export const createPreviewStreamController = ({ getCurrentDevices, getCurrentMed
|
|
|
475
490
|
return updateAudioInput(input);
|
|
476
491
|
}
|
|
477
492
|
case 'videoinput': {
|
|
478
|
-
return updateVideoInput(input);
|
|
493
|
+
return updateVideoInput(input, false);
|
|
479
494
|
}
|
|
480
495
|
}
|
|
481
496
|
},
|
package/dist/typeGuard.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AnalyzerNodeInit } from '@pexip/media-processor';
|
|
2
|
-
import type { AudioContentHint, Media, VideoContentHint
|
|
2
|
+
import type { AudioContentHint, Media, VideoContentHint } from './types';
|
|
3
3
|
import { UserMediaStatus } from './types';
|
|
4
4
|
export declare const isNonNullObject: (value: unknown) => value is Record<string, unknown>;
|
|
5
5
|
export declare const isUserMediaStatus: (value: unknown) => value is UserMediaStatus;
|
|
@@ -7,4 +7,3 @@ export declare const isMedia: (value: unknown) => value is Media;
|
|
|
7
7
|
export declare const isAnalyzerNodeInitProp: (value: unknown) => value is AnalyzerNodeInit | undefined;
|
|
8
8
|
export declare const isAudioContentHint: (value: unknown) => value is AudioContentHint;
|
|
9
9
|
export declare const isVideoContentHint: (value: unknown) => value is VideoContentHint;
|
|
10
|
-
export declare const isVideoStreamTrackProcessorAPIs: (value: unknown) => value is VideoStreamTrackProcessorAPIs;
|
package/dist/typeGuard.js
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IndexedDevices, InputConstraintSet, InputDeviceConstraint, MediaDeviceInfoLike, MediaDeviceRequest } from '@pexip/media-control';
|
|
2
|
-
import type { RendererOptions, RenderEffects
|
|
2
|
+
import type { RendererOptions, RenderEffects } from '@pexip/media-processor';
|
|
3
3
|
import type { Signal } from '@pexip/signal';
|
|
4
4
|
export type Unsubscribe = () => void;
|
|
5
5
|
export interface ExtendedMediaTrackSettings extends MediaTrackSettings {
|
|
@@ -14,10 +14,12 @@ export interface ExtendedMediaTrackSettings extends MediaTrackSettings {
|
|
|
14
14
|
maskCombineRatio?: number;
|
|
15
15
|
foregroundThreshold?: number;
|
|
16
16
|
videoSegmentation?: RenderEffects;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
panEnabled?: boolean;
|
|
18
|
+
tiltEnabled?: boolean;
|
|
19
|
+
zoomEnabled?: boolean;
|
|
20
|
+
pan?: number;
|
|
21
|
+
tilt?: number;
|
|
22
|
+
zoom?: number;
|
|
21
23
|
contentHint?: AudioContentHint | VideoContentHint;
|
|
22
24
|
}
|
|
23
25
|
export type ExtendedMediaTrackSettingsKey = keyof ExtendedMediaTrackSettings;
|
|
@@ -230,12 +232,6 @@ export type GetUserMediaProcess = (request: {
|
|
|
230
232
|
};
|
|
231
233
|
currentMedia: Media | undefined;
|
|
232
234
|
}) => Promise<Media>;
|
|
233
|
-
/**
|
|
234
|
-
* Use which processor API to process the stream track
|
|
235
|
-
* `stream` - Use `MediaStreamTrackProcessor`, when available
|
|
236
|
-
* `canvas` - Use Canvas
|
|
237
|
-
*/
|
|
238
|
-
export type VideoStreamTrackProcessorAPIs = 'stream' | 'canvas';
|
|
239
235
|
export declare enum UserMediaStatus {
|
|
240
236
|
/**
|
|
241
237
|
* The initial status
|
|
@@ -531,7 +527,7 @@ export interface MediaController {
|
|
|
531
527
|
*/
|
|
532
528
|
tryAndGetUserMedia: (constraints: MediaDeviceRequest) => void;
|
|
533
529
|
}
|
|
534
|
-
export type VideoRenderParams = Omit<RendererOptions, 'effects'> & {
|
|
530
|
+
export type VideoRenderParams = Omit<RendererOptions, 'effects' | 'personCenter'> & {
|
|
535
531
|
/**
|
|
536
532
|
* Target frame rate for the video segmentation
|
|
537
533
|
*/
|
|
@@ -545,6 +541,8 @@ export type VideoRenderParams = Omit<RendererOptions, 'effects'> & {
|
|
|
545
541
|
pan?: boolean;
|
|
546
542
|
tilt?: boolean;
|
|
547
543
|
zoom?: boolean;
|
|
544
|
+
personCenterX?: number;
|
|
545
|
+
personCenterY?: number;
|
|
548
546
|
};
|
|
549
547
|
export interface MediaChangesSignals {
|
|
550
548
|
onAddTrack: Signal<MediaStreamTrack>;
|
|
@@ -571,9 +569,6 @@ export declare enum DeniedDevices {
|
|
|
571
569
|
Camera = "camera",
|
|
572
570
|
Both = "microphone-and-camera"
|
|
573
571
|
}
|
|
574
|
-
export type Segmenters = {
|
|
575
|
-
[Property in SegmentationModel]: Segmenter;
|
|
576
|
-
};
|
|
577
572
|
/**
|
|
578
573
|
* Audio content hints are only applicable when the MediaStreamTrack contains an
|
|
579
574
|
* audio track
|
package/dist/userMedia.d.ts
CHANGED
|
@@ -11,7 +11,10 @@ export declare const toSameDeviceStatus: ({ audio, video, }: {
|
|
|
11
11
|
audio: boolean;
|
|
12
12
|
video: boolean;
|
|
13
13
|
}) => UserMediaStatus.PermissionsGranted | UserMediaStatus.PermissionsGrantedFallback | UserMediaStatus.PermissionsGrantedFallbackAudioinput | UserMediaStatus.PermissionsGrantedFallbackVideoinput;
|
|
14
|
-
export declare const toOnlyDeviceStatus: (kind: "audioinput" | "videoinput",
|
|
14
|
+
export declare const toOnlyDeviceStatus: (kind: "audioinput" | "videoinput", streamedRequestedDevices: {
|
|
15
|
+
audio: boolean;
|
|
16
|
+
video: boolean;
|
|
17
|
+
}, devices: IndexedDevices) => UserMediaStatus.PermissionsRejectedAudioInput | UserMediaStatus.PermissionsRejectedVideoInput | UserMediaStatus.PermissionsOnlyAudioinput | UserMediaStatus.PermissionsOnlyAudioinputNoVideoDevices | UserMediaStatus.PermissionsOnlyAudioinputFallback | UserMediaStatus.PermissionsOnlyAudioinputFallbackNoVideoDevices | UserMediaStatus.PermissionsOnlyVideoinput | UserMediaStatus.PermissionsOnlyVideoinputNoAudioDevices | UserMediaStatus.PermissionsOnlyVideoinputFallback | UserMediaStatus.PermissionsOnlyVideoinputFallbackNoAudioDevices;
|
|
15
18
|
/**
|
|
16
19
|
* Check if there is any track match with the `kind`
|
|
17
20
|
*/
|
package/dist/userMedia.js
CHANGED
|
@@ -71,12 +71,16 @@ export const toSameDeviceStatus = ({ audio, video, }) => {
|
|
|
71
71
|
}
|
|
72
72
|
return UserMediaStatus.PermissionsGrantedFallback;
|
|
73
73
|
};
|
|
74
|
-
export const toOnlyDeviceStatus = (kind,
|
|
75
|
-
const
|
|
76
|
-
const
|
|
74
|
+
export const toOnlyDeviceStatus = (kind, streamedRequestedDevices, devices) => {
|
|
75
|
+
const [self, other] = kind === 'audioinput' ? ['audio', 'video'] : ['video', 'audio'];
|
|
76
|
+
const otherKind = kind === 'audioinput' ? 'videoinput' : 'audioinput';
|
|
77
|
+
const matched = streamedRequestedDevices[self];
|
|
78
|
+
const anotherDeviceRequested = streamedRequestedDevices[other];
|
|
79
|
+
const hasAnotherTypeOfAuthorizedDevice = devices.anyAuthorizedDevice(otherKind);
|
|
80
|
+
const hasAnotherTypeOfDevice = devices.size(otherKind) > 0;
|
|
77
81
|
if (matched) {
|
|
78
82
|
if (hasAnotherTypeOfDevice) {
|
|
79
|
-
if (hasAnotherTypeOfAuthorizedDevice) {
|
|
83
|
+
if (hasAnotherTypeOfAuthorizedDevice || !anotherDeviceRequested) {
|
|
80
84
|
return kind === 'audioinput'
|
|
81
85
|
? UserMediaStatus.PermissionsOnlyAudioinput
|
|
82
86
|
: UserMediaStatus.PermissionsOnlyVideoinput;
|
|
@@ -90,7 +94,7 @@ export const toOnlyDeviceStatus = (kind, matched, devices) => {
|
|
|
90
94
|
: UserMediaStatus.PermissionsOnlyVideoinputNoAudioDevices;
|
|
91
95
|
}
|
|
92
96
|
if (hasAnotherTypeOfDevice) {
|
|
93
|
-
if (hasAnotherTypeOfAuthorizedDevice) {
|
|
97
|
+
if (hasAnotherTypeOfAuthorizedDevice || !anotherDeviceRequested) {
|
|
94
98
|
return kind === 'audioinput'
|
|
95
99
|
? UserMediaStatus.PermissionsOnlyAudioinputFallback
|
|
96
100
|
: UserMediaStatus.PermissionsOnlyVideoinputFallback;
|
|
@@ -421,10 +425,10 @@ export const requestUserMedia = (getCurrentDevices, getMedia = getUserMedia) =>
|
|
|
421
425
|
? constraints.video
|
|
422
426
|
: false,
|
|
423
427
|
});
|
|
424
|
-
const
|
|
425
|
-
const onlyAudioStatus = toOnlyDeviceStatus('audioinput',
|
|
426
|
-
const onlyVideoStatus = toOnlyDeviceStatus('videoinput',
|
|
427
|
-
const status = deriveDeviceStatus(onlyAudioStatus, onlyVideoStatus, toSameDeviceStatus(
|
|
428
|
+
const streamedRequestedDevices = isStreamingRequestedDevices(constraints, stream, devices);
|
|
429
|
+
const onlyAudioStatus = toOnlyDeviceStatus('audioinput', streamedRequestedDevices, devices);
|
|
430
|
+
const onlyVideoStatus = toOnlyDeviceStatus('videoinput', streamedRequestedDevices, devices);
|
|
431
|
+
const status = deriveDeviceStatus(onlyAudioStatus, onlyVideoStatus, toSameDeviceStatus(streamedRequestedDevices));
|
|
428
432
|
return [stream, status];
|
|
429
433
|
}
|
|
430
434
|
catch (error) {
|
|
@@ -521,10 +525,10 @@ export const createGetUserMediaProcess = ({ getCurrentDevices, getUserMedia, sco
|
|
|
521
525
|
}));
|
|
522
526
|
}
|
|
523
527
|
const relaxedConstraints = {};
|
|
524
|
-
if (constraints.audio) {
|
|
528
|
+
if (constraints.audio !== undefined) {
|
|
525
529
|
relaxedConstraints.audio = relaxInputConstraint('audioinput', constraints.audio, currentDevices);
|
|
526
530
|
}
|
|
527
|
-
if (constraints.video) {
|
|
531
|
+
if (constraints.video !== undefined) {
|
|
528
532
|
relaxedConstraints.video = relaxInputConstraint('videoinput', constraints.video, currentDevices);
|
|
529
533
|
}
|
|
530
534
|
const [stream, status] = await getUserMedia(relaxedConstraints);
|
package/dist/utils.d.ts
CHANGED
|
@@ -54,17 +54,28 @@ export declare const getSettingsFromKeys: (keys: ExtendedMediaTrackSettingsKey[]
|
|
|
54
54
|
export declare const diffSettings: (keysToLookFor: ExtendedMediaTrackSettingsKey[]) => (settingsA: ExtendedMediaTrackSettings | undefined, settingsB: ExtendedMediaTrackSettings | undefined) => ExtendedMediaTrackSettings | undefined;
|
|
55
55
|
export declare const mergeSettings: (settingsA: ExtendedMediaTrackSettings | undefined, settingsB: ExtendedMediaTrackSettings | undefined) => ExtendedMediaTrackSettings | undefined;
|
|
56
56
|
/**
|
|
57
|
-
* A function to get the blur kernel size of image height
|
|
57
|
+
* A function to get the blur kernel size of image height based on
|
|
58
|
+
* Kawase blur algorithm
|
|
58
59
|
*
|
|
59
|
-
* @param
|
|
60
|
-
*
|
|
61
|
-
* @param height - The image height
|
|
62
|
-
* @param lowestProcessingHeight - The lowest image height that is processed by the consumer, used to adjust the blur kernel size across different resolutions
|
|
60
|
+
* @param norm - [0-100] The normalized blur amount
|
|
61
|
+
* @param heightRef - The reference image height
|
|
62
|
+
* @param height - The current image height
|
|
63
63
|
* @param max - The upper bound
|
|
64
64
|
*
|
|
65
65
|
* @returns blur kernel size
|
|
66
66
|
*/
|
|
67
|
-
export declare const getBlurKernelSize: (
|
|
67
|
+
export declare const getBlurKernelSize: (norm: number, heightRef: number, height: number, max?: number) => number;
|
|
68
|
+
/**
|
|
69
|
+
* A function to get the Tent blur size of image height
|
|
70
|
+
*
|
|
71
|
+
* @param norm - [0-100] The normalized blur amount
|
|
72
|
+
* @param heightRef - The reference image height
|
|
73
|
+
* @param height - The current image height
|
|
74
|
+
* @param max - The upper bound
|
|
75
|
+
*
|
|
76
|
+
* @returns tent blur size
|
|
77
|
+
*/
|
|
78
|
+
export declare const getTentBlurSize: (norm: number, heightRef: number, height: number, max?: number) => number;
|
|
68
79
|
/**
|
|
69
80
|
* Apply the content hint to the track
|
|
70
81
|
*
|
package/dist/utils.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createStreamTrackEventSubscriptions, createTrackDevicesChanges, extractConstraintsWithKeys, findDeviceFromConstraints, relaxInputConstraint, resolveMediaDeviceConstraints, shouldRequestDevice, toMediaDeviceInputKind, } from '@pexip/media-control';
|
|
2
|
-
import { calculateMaxBlurPass } from '@pexip/media-processor';
|
|
2
|
+
import { calculateMaxBlurPass, clamping, } from '@pexip/media-processor';
|
|
3
3
|
import { hasOwn, assert, isEmpty } from '@pexip/utils';
|
|
4
4
|
import { internalSignals } from './signals';
|
|
5
|
+
import { MAX_TENT_BLUR_SIZE } from './constants';
|
|
6
|
+
import { mapFeatureToSettings } from './videoProcessor';
|
|
5
7
|
export const makeDeriveDeviceStatus = (constraints) => (audio, video, both) => {
|
|
6
8
|
if (constraints.audio) {
|
|
7
9
|
if (constraints.video) {
|
|
@@ -570,7 +572,6 @@ export const AUDIO_SETTINGS_KEYS = [
|
|
|
570
572
|
export const VIDEO_SETTINGS_KEYS = [
|
|
571
573
|
'frameRate',
|
|
572
574
|
'videoSegmentation',
|
|
573
|
-
'videoSegmentationModel',
|
|
574
575
|
'foregroundThreshold',
|
|
575
576
|
'backgroundBlurAmount',
|
|
576
577
|
'edgeBlurAmount',
|
|
@@ -628,10 +629,11 @@ export const getSettingsFromKeys = (keys, settings) => {
|
|
|
628
629
|
return settings;
|
|
629
630
|
}
|
|
630
631
|
const result = {};
|
|
632
|
+
const mapped = mapFeatureToSettings(settings);
|
|
631
633
|
for (const key of keys) {
|
|
632
|
-
if (
|
|
634
|
+
if (mapped[key] !== undefined) {
|
|
633
635
|
// @ts-expect-error --- Type issue and need to be fixed when we have time
|
|
634
|
-
result[key] =
|
|
636
|
+
result[key] = mapped[key];
|
|
635
637
|
}
|
|
636
638
|
}
|
|
637
639
|
return result;
|
|
@@ -684,26 +686,39 @@ export const mergeSettings = (settingsA, settingsB) => {
|
|
|
684
686
|
}
|
|
685
687
|
return { ...settingsA, ...settingsB };
|
|
686
688
|
};
|
|
689
|
+
const clampNorm = clamping(0, 100);
|
|
687
690
|
/**
|
|
688
|
-
* A function to get the blur kernel size of image height
|
|
691
|
+
* A function to get the blur kernel size of image height based on
|
|
692
|
+
* Kawase blur algorithm
|
|
689
693
|
*
|
|
690
|
-
* @param
|
|
691
|
-
*
|
|
692
|
-
* @param height - The image height
|
|
693
|
-
* @param lowestProcessingHeight - The lowest image height that is processed by the consumer, used to adjust the blur kernel size across different resolutions
|
|
694
|
+
* @param norm - [0-100] The normalized blur amount
|
|
695
|
+
* @param heightRef - The reference image height
|
|
696
|
+
* @param height - The current image height
|
|
694
697
|
* @param max - The upper bound
|
|
695
698
|
*
|
|
696
699
|
* @returns blur kernel size
|
|
697
700
|
*/
|
|
698
|
-
export const getBlurKernelSize = (
|
|
699
|
-
if (height <= 0 ||
|
|
701
|
+
export const getBlurKernelSize = (norm, heightRef, height, max = calculateMaxBlurPass(height)) => {
|
|
702
|
+
if (height <= 0 || norm <= 0 || max <= 0 || heightRef <= 0) {
|
|
700
703
|
return 0;
|
|
701
704
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
705
|
+
return clamping(0, max)(Math.round(clampNorm(norm) * 0.01 * max - Math.log2(heightRef / height)));
|
|
706
|
+
};
|
|
707
|
+
/**
|
|
708
|
+
* A function to get the Tent blur size of image height
|
|
709
|
+
*
|
|
710
|
+
* @param norm - [0-100] The normalized blur amount
|
|
711
|
+
* @param heightRef - The reference image height
|
|
712
|
+
* @param height - The current image height
|
|
713
|
+
* @param max - The upper bound
|
|
714
|
+
*
|
|
715
|
+
* @returns tent blur size
|
|
716
|
+
*/
|
|
717
|
+
export const getTentBlurSize = (norm, heightRef, height, max = MAX_TENT_BLUR_SIZE) => {
|
|
718
|
+
if (height <= 0 || norm <= 0 || heightRef <= 0 || max <= 0) {
|
|
719
|
+
return 0;
|
|
720
|
+
}
|
|
721
|
+
return clamping(0, max)(Math.round((norm * 0.01 * max * height) / heightRef));
|
|
707
722
|
};
|
|
708
723
|
/**
|
|
709
724
|
* Apply the content hint to the track
|
package/dist/videoProcessor.d.ts
CHANGED
|
@@ -1,27 +1,15 @@
|
|
|
1
|
-
import type { RenderBackend,
|
|
2
|
-
import type { MediaDeviceRequest } from '@pexip/media-control';
|
|
3
|
-
import type {
|
|
4
|
-
interface
|
|
5
|
-
segmenters: Partial<Segmenters>;
|
|
6
|
-
transformer?: SegmentationTransform;
|
|
7
|
-
videoProcessor?: () => VideoProcessor;
|
|
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;
|
|
1
|
+
import type { RenderBackend, VideoProcessor } from '@pexip/media-processor';
|
|
2
|
+
import type { InputConstraintSet, MediaDeviceRequest } from '@pexip/media-control';
|
|
3
|
+
import type { ExtendedMediaTrackSettings, MediaSignals, TrackProcessor, VideoContentHint, VideoRenderParams } from './types';
|
|
4
|
+
interface VideoStreamProcessOptions extends Partial<VideoRenderParams> {
|
|
17
5
|
/**
|
|
18
6
|
* Whether or to enable this processor
|
|
19
7
|
*/
|
|
20
8
|
shouldEnable: () => boolean;
|
|
21
|
-
|
|
9
|
+
getVideoProcessor: () => VideoProcessor;
|
|
10
|
+
referenceProcessingHeight?: number;
|
|
22
11
|
processingWidth: number;
|
|
23
12
|
processingHeight: number;
|
|
24
|
-
hasInitializedDeps?: boolean;
|
|
25
13
|
width?: number;
|
|
26
14
|
height?: number;
|
|
27
15
|
label?: string;
|
|
@@ -30,13 +18,43 @@ interface VideoStreamProcessOptions extends Partial<VideoRenderParams>, Omit<Pro
|
|
|
30
18
|
gpuAPI?: () => RenderBackend;
|
|
31
19
|
signals?: MediaSignals;
|
|
32
20
|
}
|
|
33
|
-
interface VideoStreamProcessProps extends Partial<VideoRenderParams
|
|
34
|
-
hasInitialized: boolean;
|
|
21
|
+
interface VideoStreamProcessProps extends Partial<VideoRenderParams> {
|
|
35
22
|
contentHint?: VideoContentHint;
|
|
36
23
|
}
|
|
37
|
-
declare const FEATURE_KEYS:
|
|
38
|
-
|
|
24
|
+
declare const FEATURE_KEYS: {
|
|
25
|
+
readonly backgroundBlurAmount: "number";
|
|
26
|
+
readonly backgroundImageUrl: "string";
|
|
27
|
+
readonly backgroundThreshold: "number";
|
|
28
|
+
readonly maskCombineRatio: "number";
|
|
29
|
+
readonly edgeBlurAmount: "number";
|
|
30
|
+
readonly foregroundThreshold: "number";
|
|
31
|
+
readonly frameRate: "number";
|
|
32
|
+
readonly videoSegmentation: "string";
|
|
33
|
+
readonly width: "number";
|
|
34
|
+
readonly height: "number";
|
|
35
|
+
readonly pan: "boolean";
|
|
36
|
+
readonly tilt: "boolean";
|
|
37
|
+
readonly zoom: "boolean";
|
|
38
|
+
readonly contentHint: "string";
|
|
39
|
+
readonly sigmaSpace: "number";
|
|
40
|
+
readonly sigmaRangeLo: "number";
|
|
41
|
+
readonly sigmaRangeHi: "number";
|
|
42
|
+
readonly excludeBystanders: "boolean";
|
|
43
|
+
readonly personCenterX: "number";
|
|
44
|
+
readonly personCenterY: "number";
|
|
45
|
+
readonly morphErodeRadiusPx: "number";
|
|
46
|
+
readonly morphPass: "number";
|
|
47
|
+
readonly morphDilateRadiusPx: "number";
|
|
48
|
+
readonly lightWrapIntensity: "number";
|
|
49
|
+
readonly lightWrapTightness: "number";
|
|
50
|
+
readonly lightWrapEdgeBand: "number";
|
|
51
|
+
readonly lightWrapBlurAmount: "number";
|
|
52
|
+
readonly downSampleFactor: "number";
|
|
53
|
+
};
|
|
54
|
+
type FeaturePropKeys = keyof typeof FEATURE_KEYS;
|
|
39
55
|
type FeatureProps = Pick<Partial<VideoStreamProcessProps>, FeaturePropKeys>;
|
|
40
56
|
export declare const updateFeatureProps: (constraints: MediaDeviceRequest["video"], props: FeatureProps) => FeatureProps;
|
|
41
|
-
export declare const
|
|
57
|
+
export declare const mapFeatureToSettings: (props: InputConstraintSet) => ExtendedMediaTrackSettings;
|
|
58
|
+
export declare const mapSettingsToFeatures: (settings: ExtendedMediaTrackSettings) => InputConstraintSet;
|
|
59
|
+
export declare const createVideoStreamProcess: ({ backgroundImageUrl, dynamicProcessingDimensions, backgroundThreshold, downSampleFactor, foregroundThreshold, lightWrapEdgeBand, lightWrapIntensity, lightWrapTightness, morphDilateRadiusPx, morphErodeRadiusPx, morphPass, personCenterX, personCenterY, sigmaSpace, sigmaRangeHi, sigmaRangeLo, frameRate, gpuAPI, label, referenceProcessingHeight, maskCombineRatio, processingHeight, processingWidth, shouldEnable, stopAsMute, videoSegmentation, signals, getVideoProcessor, ...options }: VideoStreamProcessOptions) => TrackProcessor;
|
|
42
60
|
export {};
|