@pexip/media 19.0.0 → 20.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 +75 -0
- package/dist/audioMixingProcessor.d.ts +1 -1
- package/dist/audioMixingProcessor.js +5 -5
- package/dist/audioProcessor.d.ts +1 -1
- package/dist/audioProcessor.js +4 -2
- package/dist/baseLogger.d.ts +15 -6
- package/dist/baseLogger.js +13 -7
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/displayMedia.d.ts +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.js +8 -7
- package/dist/logger.js +1 -4
- package/dist/media.d.ts +6 -2
- package/dist/media.js +96 -46
- package/dist/previewController.js +4 -4
- package/dist/signals.d.ts +4 -4
- package/dist/signals.js +8 -5
- package/dist/status.d.ts +2 -1
- package/dist/status.js +8 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/typeGuard.d.ts +2 -1
- package/dist/typeGuard.js +3 -0
- package/dist/types.d.ts +3 -3
- package/dist/userMedia.d.ts +8 -1
- package/dist/userMedia.js +357 -20
- package/dist/utils.d.ts +10 -8
- package/dist/utils.js +84 -39
- package/dist/videoProcessor.d.ts +5 -3
- package/dist/videoProcessor.js +53 -60
- package/package.json +22 -11
package/dist/utils.js
CHANGED
|
@@ -3,22 +3,22 @@ import { calculateMaxBlurPass } from '@pexip/media-processor';
|
|
|
3
3
|
import { hasOwn, assert, isEmpty } from '@pexip/utils';
|
|
4
4
|
import { internalSignals } from './signals';
|
|
5
5
|
export const makeDeriveDeviceStatus = (constraints) => (audio, video, both) => {
|
|
6
|
-
if (constraints.audio
|
|
7
|
-
if (constraints.video
|
|
6
|
+
if (constraints.audio) {
|
|
7
|
+
if (constraints.video) {
|
|
8
8
|
return both;
|
|
9
9
|
}
|
|
10
10
|
return audio;
|
|
11
11
|
}
|
|
12
|
-
if (constraints.video
|
|
12
|
+
if (constraints.video) {
|
|
13
13
|
return video;
|
|
14
14
|
}
|
|
15
15
|
return both;
|
|
16
16
|
};
|
|
17
17
|
export const createMediaTrack = (trackInit) => {
|
|
18
|
-
|
|
18
|
+
const trackConsistency = trackInit.track === undefined ||
|
|
19
19
|
(trackInit.kind === trackInit.input?.kind &&
|
|
20
|
-
trackInit.kind === toMediaDeviceInputKind(trackInit.track)
|
|
21
|
-
|
|
20
|
+
trackInit.kind === toMediaDeviceInputKind(trackInit.track));
|
|
21
|
+
assert(trackConsistency, `Inconsistent track kind: ${trackInit.input?.kind} ${trackInit.track && toMediaDeviceInputKind(trackInit.track)} vs ${trackInit.kind}`);
|
|
22
22
|
const currentConstraints = typeof trackInit.constraints === 'boolean' ? {} : trackInit.constraints;
|
|
23
23
|
// Find the original source track through the linked list
|
|
24
24
|
let sourceMediaTrack = trackInit.previousMediaTrack;
|
|
@@ -41,7 +41,7 @@ export const createMediaTrack = (trackInit) => {
|
|
|
41
41
|
...(trackInit.getSettings?.() ?? {}),
|
|
42
42
|
};
|
|
43
43
|
};
|
|
44
|
-
|
|
44
|
+
const mediaTrack = {
|
|
45
45
|
get kind() {
|
|
46
46
|
return trackInit.kind;
|
|
47
47
|
},
|
|
@@ -52,7 +52,9 @@ export const createMediaTrack = (trackInit) => {
|
|
|
52
52
|
return trackInit.track;
|
|
53
53
|
},
|
|
54
54
|
get input() {
|
|
55
|
-
return trackInit.
|
|
55
|
+
return trackInit.track?.readyState !== 'live'
|
|
56
|
+
? undefined
|
|
57
|
+
: trackInit.input;
|
|
56
58
|
},
|
|
57
59
|
get expectedInput() {
|
|
58
60
|
return trackInit.expectedInput;
|
|
@@ -74,7 +76,7 @@ export const createMediaTrack = (trackInit) => {
|
|
|
74
76
|
isTrackMuted(trackInit.track));
|
|
75
77
|
},
|
|
76
78
|
get source() {
|
|
77
|
-
return sourceMediaTrack ??
|
|
79
|
+
return sourceMediaTrack ?? mediaTrack;
|
|
78
80
|
},
|
|
79
81
|
mute(toMute) {
|
|
80
82
|
if (trackInit.overrideMute) {
|
|
@@ -89,11 +91,12 @@ export const createMediaTrack = (trackInit) => {
|
|
|
89
91
|
getConstraints() {
|
|
90
92
|
return getConstraints();
|
|
91
93
|
},
|
|
92
|
-
clone() {
|
|
94
|
+
clone(signals) {
|
|
93
95
|
return createMediaTrack({
|
|
94
96
|
...trackInit,
|
|
95
97
|
constraints: getConstraints(),
|
|
96
98
|
track: trackInit.track?.clone(),
|
|
99
|
+
signals,
|
|
97
100
|
});
|
|
98
101
|
},
|
|
99
102
|
async applyConstraints(constraints) {
|
|
@@ -152,10 +155,14 @@ export const createMediaTrack = (trackInit) => {
|
|
|
152
155
|
};
|
|
153
156
|
},
|
|
154
157
|
};
|
|
158
|
+
return mediaTrack;
|
|
155
159
|
};
|
|
156
160
|
export const createTrackProcessingPipeline = (processors) => async (track) => {
|
|
157
161
|
let lastTrack = track;
|
|
158
162
|
for (const process of processors) {
|
|
163
|
+
if (lastTrack.track?.readyState !== 'live') {
|
|
164
|
+
return lastTrack;
|
|
165
|
+
}
|
|
159
166
|
lastTrack = await process(lastTrack);
|
|
160
167
|
}
|
|
161
168
|
return lastTrack;
|
|
@@ -187,7 +194,7 @@ export const findExpectedInput = (devices, constraints, input, kind) => {
|
|
|
187
194
|
* A utility function to check if the provided track is muted. There are
|
|
188
195
|
* 2 factors to be considered: `MediaStreamTrack['muted']` and `MediaStreamTrack['enabled']`.
|
|
189
196
|
*
|
|
190
|
-
* ```
|
|
197
|
+
* ```md
|
|
191
198
|
* | muted \ enabled | true | false |
|
|
192
199
|
* |-----------------| ----- | ----- |
|
|
193
200
|
* | true | true | true |
|
|
@@ -334,23 +341,23 @@ export const buildMedia = (mediaInit, onDevicesChanged = internalSignals.onDevic
|
|
|
334
341
|
return props.originalConstraints;
|
|
335
342
|
},
|
|
336
343
|
isAudioInputUnavailable() {
|
|
337
|
-
return
|
|
338
|
-
props.devices.size('audioinput') === 0);
|
|
344
|
+
return !props.devices.anyAuthorizedDevice('audioinput');
|
|
339
345
|
},
|
|
340
346
|
isVideoInputUnavailable() {
|
|
341
|
-
return
|
|
342
|
-
props.devices.size('videoinput') === 0);
|
|
347
|
+
return !props.devices.anyAuthorizedDevice('videoinput');
|
|
343
348
|
},
|
|
344
349
|
setOriginalConstraints(constraints) {
|
|
345
350
|
props.originalConstraints = constraints;
|
|
346
351
|
},
|
|
347
352
|
requestedAudio() {
|
|
348
353
|
return (Boolean(props.audioTrack?.track) ||
|
|
349
|
-
Boolean(props.originalConstraints.audio)
|
|
354
|
+
(Boolean(props.originalConstraints.audio) &&
|
|
355
|
+
props.devices.size('audioinput') > 0));
|
|
350
356
|
},
|
|
351
357
|
requestedVideo() {
|
|
352
358
|
return (Boolean(props.videoTrack?.track) ||
|
|
353
|
-
Boolean(props.originalConstraints.video)
|
|
359
|
+
(Boolean(props.originalConstraints.video) &&
|
|
360
|
+
props.devices.size('videoinput') > 0));
|
|
354
361
|
},
|
|
355
362
|
muteAudio(mute) {
|
|
356
363
|
if (!props.audioTrack) {
|
|
@@ -377,7 +384,9 @@ export const buildMedia = (mediaInit, onDevicesChanged = internalSignals.onDevic
|
|
|
377
384
|
async release() {
|
|
378
385
|
unsubscribe?.();
|
|
379
386
|
unsubscribe = undefined;
|
|
380
|
-
|
|
387
|
+
for (const unsubscribe of trackSubscriptions.values()) {
|
|
388
|
+
unsubscribe();
|
|
389
|
+
}
|
|
381
390
|
trackSubscriptions.clear();
|
|
382
391
|
await Promise.all([
|
|
383
392
|
props.audioTrack?.release(),
|
|
@@ -388,12 +397,12 @@ export const buildMedia = (mediaInit, onDevicesChanged = internalSignals.onDevic
|
|
|
388
397
|
audio: props.audioTrack?.getSettings(),
|
|
389
398
|
video: props.videoTrack?.getSettings(),
|
|
390
399
|
}),
|
|
391
|
-
clone() {
|
|
400
|
+
clone(signals) {
|
|
392
401
|
const tracks = [props.audioTrack, props.videoTrack].flatMap(track => {
|
|
393
402
|
if (!track?.source) {
|
|
394
403
|
return [];
|
|
395
404
|
}
|
|
396
|
-
const cloned = track.source.clone();
|
|
405
|
+
const cloned = track.source.clone(signals);
|
|
397
406
|
// Restore the enabled state for all cloned track
|
|
398
407
|
cloned.mute(false);
|
|
399
408
|
return cloned;
|
|
@@ -516,6 +525,11 @@ export const VIDEO_SETTINGS_KEYS = [
|
|
|
516
525
|
export const MIXING_SETTINGS_KEYS = [
|
|
517
526
|
'mixWithAdditionalMedia',
|
|
518
527
|
];
|
|
528
|
+
export const PAN_TILT_ZOOM_SETTINGS_KEYS = [
|
|
529
|
+
'pan',
|
|
530
|
+
'tilt',
|
|
531
|
+
'zoom',
|
|
532
|
+
];
|
|
519
533
|
export const hasSettingsChanged = (keysToLookFor) => {
|
|
520
534
|
const cache = {};
|
|
521
535
|
return (settingsA, settingsB) => {
|
|
@@ -544,6 +558,28 @@ export const hasSettingsChanged = (keysToLookFor) => {
|
|
|
544
558
|
return cache.result;
|
|
545
559
|
};
|
|
546
560
|
};
|
|
561
|
+
export const isApplyingRenderEffect = (effect) => {
|
|
562
|
+
switch (effect) {
|
|
563
|
+
case 'blur':
|
|
564
|
+
case 'overlay':
|
|
565
|
+
return true;
|
|
566
|
+
default:
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
export const getSettingsFromKeys = (keys, settings) => {
|
|
571
|
+
if (!settings) {
|
|
572
|
+
return settings;
|
|
573
|
+
}
|
|
574
|
+
const result = {};
|
|
575
|
+
for (const key of keys) {
|
|
576
|
+
if (settings[key] !== undefined) {
|
|
577
|
+
// @ts-expect-error --- Type issue and need to be fixed when we have time
|
|
578
|
+
result[key] = settings[key];
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
return result;
|
|
582
|
+
};
|
|
547
583
|
export const diffSettings = (keysToLookFor) => {
|
|
548
584
|
const cache = {};
|
|
549
585
|
return (settingsA, settingsB) => {
|
|
@@ -559,7 +595,16 @@ export const diffSettings = (keysToLookFor) => {
|
|
|
559
595
|
return cache.diff;
|
|
560
596
|
}
|
|
561
597
|
if (settingsA === undefined || settingsB === undefined) {
|
|
562
|
-
|
|
598
|
+
const settings = settingsA ?? settingsB;
|
|
599
|
+
for (const key of keysToLookFor) {
|
|
600
|
+
if (settings?.[key] !== undefined) {
|
|
601
|
+
if (cache.diff === undefined) {
|
|
602
|
+
cache.diff = {};
|
|
603
|
+
}
|
|
604
|
+
// @ts-expect-error --- Type issue and need to be fixed when we have time
|
|
605
|
+
cache.diff[key] = settings[key];
|
|
606
|
+
}
|
|
607
|
+
}
|
|
563
608
|
return cache.diff;
|
|
564
609
|
}
|
|
565
610
|
for (const key of keysToLookFor) {
|
|
@@ -624,6 +669,7 @@ export const refineMediaConstraints = (state) => {
|
|
|
624
669
|
switch (state.permission) {
|
|
625
670
|
case 'denied':
|
|
626
671
|
return false;
|
|
672
|
+
case 'prompt':
|
|
627
673
|
case 'granted': {
|
|
628
674
|
const requestNeeded = shouldRequestDevice({
|
|
629
675
|
kind: state.kind,
|
|
@@ -641,7 +687,6 @@ export const refineMediaConstraints = (state) => {
|
|
|
641
687
|
}
|
|
642
688
|
return state.request;
|
|
643
689
|
}
|
|
644
|
-
case 'prompt':
|
|
645
690
|
default:
|
|
646
691
|
return state.request;
|
|
647
692
|
}
|
|
@@ -649,25 +694,25 @@ export const refineMediaConstraints = (state) => {
|
|
|
649
694
|
export const createMediaProcessor = ({ audioProcessors, videoProcessors, onProcessingError, }) => {
|
|
650
695
|
const processAudioTrack = createTrackProcessingPipeline(audioProcessors);
|
|
651
696
|
const processVideoTrack = createTrackProcessingPipeline(videoProcessors);
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
assert(false, `Unexpected track kind: ${track.kind}`);
|
|
662
|
-
}
|
|
697
|
+
const processTrack = async (track) => {
|
|
698
|
+
try {
|
|
699
|
+
switch (track.kind) {
|
|
700
|
+
case 'audioinput':
|
|
701
|
+
return await processAudioTrack(track);
|
|
702
|
+
case 'videoinput':
|
|
703
|
+
return await processVideoTrack(track);
|
|
704
|
+
default:
|
|
705
|
+
assert(false, `Unexpected track kind: ${track.kind}`);
|
|
663
706
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
return track;
|
|
707
|
+
}
|
|
708
|
+
catch (error) {
|
|
709
|
+
if (error instanceof Error) {
|
|
710
|
+
onProcessingError?.(error, track);
|
|
669
711
|
}
|
|
670
|
-
|
|
712
|
+
return track;
|
|
713
|
+
}
|
|
714
|
+
};
|
|
715
|
+
return async (newTracks) => {
|
|
671
716
|
return await Promise.all(newTracks.map(track => processTrack(track)));
|
|
672
717
|
};
|
|
673
718
|
};
|
package/dist/videoProcessor.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { VideoProcessor, SegmentationTransform, SegmentationModel } from '@pexip/media-processor';
|
|
1
|
+
import type { VideoProcessor, SegmentationTransform, SegmentationModel, RenderBackend } from '@pexip/media-processor';
|
|
2
2
|
import type { MediaDeviceRequest } from '@pexip/media-control';
|
|
3
3
|
import type { TrackProcessor, VideoRenderParams, Segmenters, VideoStreamTrackProcessorAPIs, VideoContentHint } from './types';
|
|
4
4
|
interface ProcessorDeps {
|
|
@@ -24,6 +24,8 @@ interface VideoStreamProcessOptions extends Partial<VideoRenderParams>, Omit<Pro
|
|
|
24
24
|
width?: number;
|
|
25
25
|
height?: number;
|
|
26
26
|
label?: string;
|
|
27
|
+
dynamicProcessingDimensions?: () => boolean;
|
|
28
|
+
gpuAPI?: () => RenderBackend;
|
|
27
29
|
}
|
|
28
30
|
interface VideoStreamProcessProps extends Partial<VideoRenderParams>, Required<ProcessorDeps> {
|
|
29
31
|
hasInitialized: boolean;
|
|
@@ -32,6 +34,6 @@ interface VideoStreamProcessProps extends Partial<VideoRenderParams>, Required<P
|
|
|
32
34
|
declare const FEATURE_KEYS: readonly ["backgroundBlurAmount", "backgroundImageUrl", "maskCombineRatio", "edgeBlurAmount", "foregroundThreshold", "frameRate", "videoSegmentation", "videoSegmentationModel", "width", "height", "pan", "tilt", "zoom", "contentHint"];
|
|
33
35
|
type FeaturePropKeys = (typeof FEATURE_KEYS)[number];
|
|
34
36
|
type FeatureProps = Pick<Partial<VideoStreamProcessProps>, FeaturePropKeys>;
|
|
35
|
-
export declare const updateFeatureProps: (constraints: MediaDeviceRequest[
|
|
36
|
-
export declare const createVideoStreamProcess: ({ trackProcessorAPI, processingWidth, processingHeight, shouldEnable, frameRate, videoSegmentation, foregroundThreshold, backgroundImageUrl, maskCombineRatio, edgeBlurAmount, label, ...options }: VideoStreamProcessOptions) => TrackProcessor;
|
|
37
|
+
export declare const updateFeatureProps: (constraints: MediaDeviceRequest["video"], props: FeatureProps) => FeatureProps;
|
|
38
|
+
export declare const createVideoStreamProcess: ({ trackProcessorAPI, processingWidth, processingHeight, shouldEnable, frameRate, videoSegmentation, foregroundThreshold, backgroundImageUrl, maskCombineRatio, edgeBlurAmount, label, dynamicProcessingDimensions, gpuAPI, ...options }: VideoStreamProcessOptions) => TrackProcessor;
|
|
37
39
|
export {};
|
package/dist/videoProcessor.js
CHANGED
|
@@ -30,7 +30,8 @@ export const updateFeatureProps = (constraints, props) => {
|
|
|
30
30
|
const [[feature = ''] = []] = extracted[key];
|
|
31
31
|
if (isVideoContentHint(feature) && props[key] !== feature) {
|
|
32
32
|
props[key] = feature;
|
|
33
|
-
|
|
33
|
+
accm[key] = feature;
|
|
34
|
+
return accm;
|
|
34
35
|
}
|
|
35
36
|
return accm;
|
|
36
37
|
}
|
|
@@ -38,7 +39,8 @@ export const updateFeatureProps = (constraints, props) => {
|
|
|
38
39
|
const [[feature] = []] = extracted[key];
|
|
39
40
|
if (isRenderEffects(feature) && props[key] !== feature) {
|
|
40
41
|
props[key] = feature;
|
|
41
|
-
|
|
42
|
+
accm[key] = feature;
|
|
43
|
+
return accm;
|
|
42
44
|
}
|
|
43
45
|
return accm;
|
|
44
46
|
}
|
|
@@ -46,7 +48,8 @@ export const updateFeatureProps = (constraints, props) => {
|
|
|
46
48
|
const [[feature] = []] = extracted[key];
|
|
47
49
|
if (isSegmentationModel(feature) && props[key] !== feature) {
|
|
48
50
|
props[key] = feature;
|
|
49
|
-
|
|
51
|
+
accm[key] = feature;
|
|
52
|
+
return accm;
|
|
50
53
|
}
|
|
51
54
|
return accm;
|
|
52
55
|
}
|
|
@@ -54,7 +57,8 @@ export const updateFeatureProps = (constraints, props) => {
|
|
|
54
57
|
const [[feature] = []] = extracted[key];
|
|
55
58
|
if (feature) {
|
|
56
59
|
props[key] = feature;
|
|
57
|
-
|
|
60
|
+
accm[key] = feature;
|
|
61
|
+
return accm;
|
|
58
62
|
}
|
|
59
63
|
return accm;
|
|
60
64
|
}
|
|
@@ -70,10 +74,8 @@ export const updateFeatureProps = (constraints, props) => {
|
|
|
70
74
|
const value = getValueFromConstrainNumber(feature);
|
|
71
75
|
if (props[key] !== value) {
|
|
72
76
|
props[key] = value;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
[key]: value,
|
|
76
|
-
};
|
|
77
|
+
accm[key] = value;
|
|
78
|
+
return accm;
|
|
77
79
|
}
|
|
78
80
|
}
|
|
79
81
|
return accm;
|
|
@@ -84,7 +86,8 @@ export const updateFeatureProps = (constraints, props) => {
|
|
|
84
86
|
const [feature] = extracted[key];
|
|
85
87
|
if (feature !== undefined && props[key] !== feature) {
|
|
86
88
|
props[key] = feature;
|
|
87
|
-
|
|
89
|
+
accm[key] = feature;
|
|
90
|
+
return accm;
|
|
88
91
|
}
|
|
89
92
|
return accm;
|
|
90
93
|
}
|
|
@@ -92,7 +95,7 @@ export const updateFeatureProps = (constraints, props) => {
|
|
|
92
95
|
}, {});
|
|
93
96
|
};
|
|
94
97
|
const applyFeatures = (transformer, features) => {
|
|
95
|
-
|
|
98
|
+
for (const key in features) {
|
|
96
99
|
const k = key;
|
|
97
100
|
switch (k) {
|
|
98
101
|
case 'edgeBlurAmount':
|
|
@@ -102,66 +105,30 @@ const applyFeatures = (transformer, features) => {
|
|
|
102
105
|
if (value !== undefined) {
|
|
103
106
|
transformer[k] = value;
|
|
104
107
|
}
|
|
105
|
-
|
|
108
|
+
break;
|
|
106
109
|
}
|
|
107
110
|
case 'backgroundBlurAmount': {
|
|
108
111
|
const value = features[k];
|
|
109
112
|
if (value !== undefined) {
|
|
110
113
|
transformer[k] = getBlurKernelSize(value, transformer.height);
|
|
111
114
|
}
|
|
112
|
-
|
|
115
|
+
break;
|
|
113
116
|
}
|
|
114
117
|
case 'videoSegmentation': {
|
|
115
118
|
const value = features[k];
|
|
116
119
|
if (value && value !== transformer.effects) {
|
|
117
120
|
transformer.effects = value;
|
|
118
121
|
}
|
|
119
|
-
|
|
122
|
+
break;
|
|
120
123
|
}
|
|
121
124
|
case 'backgroundImageUrl': {
|
|
122
125
|
const value = features[k];
|
|
123
126
|
if (value && value !== transformer.backgroundImageUrl) {
|
|
124
127
|
transformer.backgroundImageUrl = value;
|
|
125
128
|
}
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
default: {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
};
|
|
134
|
-
const adjustResolution = async (track, features, processingSize) => {
|
|
135
|
-
if (features.videoSegmentation) {
|
|
136
|
-
const videoSettings = track.getSettings();
|
|
137
|
-
const constraints = updateFeatureProps(track.getConstraints(), {});
|
|
138
|
-
switch (features.videoSegmentation) {
|
|
139
|
-
case 'blur':
|
|
140
|
-
case 'overlay': {
|
|
141
|
-
if (videoSettings?.height !== processingSize.height) {
|
|
142
|
-
try {
|
|
143
|
-
await track.applyConstraints({
|
|
144
|
-
width: processingSize.width,
|
|
145
|
-
height: processingSize.height,
|
|
146
|
-
});
|
|
147
|
-
const postVideoSettings = track.getSettings();
|
|
148
|
-
if (postVideoSettings?.height !== processingSize.height) {
|
|
149
|
-
// Workaround Firefox 16:9 ratio https://bugzilla.mozilla.org/show_bug.cgi?id=1193640
|
|
150
|
-
await track.applyConstraints({ height: 720 });
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
catch (error) {
|
|
154
|
-
// Workaround Firefox 16:9 ratio https://bugzilla.mozilla.org/show_bug.cgi?id=1193640
|
|
155
|
-
await track.applyConstraints({ height: 720 });
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
129
|
break;
|
|
159
130
|
}
|
|
160
|
-
|
|
161
|
-
if (constraints.height &&
|
|
162
|
-
constraints.height !== videoSettings?.height) {
|
|
163
|
-
await track.applyConstraints({ height: constraints.height });
|
|
164
|
-
}
|
|
131
|
+
default: {
|
|
165
132
|
break;
|
|
166
133
|
}
|
|
167
134
|
}
|
|
@@ -178,7 +145,8 @@ export const createVideoStreamProcess = ({ trackProcessorAPI = () => 'stream', p
|
|
|
178
145
|
//backgroundBlurAmount,
|
|
179
146
|
videoSegmentation,
|
|
180
147
|
//edgeBlurAmount,
|
|
181
|
-
foregroundThreshold, backgroundImageUrl, maskCombineRatio, edgeBlurAmount, label = PROCESSOR_LABELS.VideoProcessor,
|
|
148
|
+
foregroundThreshold, backgroundImageUrl, maskCombineRatio, edgeBlurAmount, label = PROCESSOR_LABELS.VideoProcessor, dynamicProcessingDimensions = () => false, gpuAPI = () => 'webgl', // dynamically changing the config will not be picked up, not a priority for now
|
|
149
|
+
...options }) => {
|
|
182
150
|
const videoSegmentationModel = options.videoSegmentationModel ?? 'selfie';
|
|
183
151
|
const segmenter = options.segmenters[videoSegmentationModel];
|
|
184
152
|
if (!segmenter) {
|
|
@@ -235,14 +203,34 @@ foregroundThreshold, backgroundImageUrl, maskCombineRatio, edgeBlurAmount, label
|
|
|
235
203
|
return prevMediaTrack;
|
|
236
204
|
}
|
|
237
205
|
if (!props.hasInitialized) {
|
|
238
|
-
|
|
206
|
+
if (dynamicProcessingDimensions()) {
|
|
207
|
+
const { width, height } = prevMediaTrack.getSettings();
|
|
208
|
+
/**
|
|
209
|
+
* when the processor is closed, the segmenter is not killed, but the track is released.
|
|
210
|
+
* this means we can't listen on the track settings changes when we change quality
|
|
211
|
+
* we need to update instead of open if the segmenter is already running
|
|
212
|
+
*/
|
|
213
|
+
if (props.transformer.segmenter.status === 'new') {
|
|
214
|
+
await props.videoProcessor().open({
|
|
215
|
+
processingWidth: width,
|
|
216
|
+
processingHeight: height,
|
|
217
|
+
});
|
|
218
|
+
props.transformer.backend = gpuAPI();
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
props.transformer.update({
|
|
222
|
+
processingWidth: width,
|
|
223
|
+
processingHeight: height,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
await props.videoProcessor().open();
|
|
229
|
+
props.transformer.backend = gpuAPI();
|
|
230
|
+
}
|
|
239
231
|
props.hasInitialized = true;
|
|
240
232
|
}
|
|
241
233
|
applyFeatures(props.transformer, features);
|
|
242
|
-
await adjustResolution(prevMediaTrack, features, {
|
|
243
|
-
width: processingWidth,
|
|
244
|
-
height: processingHeight,
|
|
245
|
-
});
|
|
246
234
|
const model = features.videoSegmentationModel &&
|
|
247
235
|
props.segmenters[features.videoSegmentationModel];
|
|
248
236
|
if (features.videoSegmentationModel &&
|
|
@@ -292,10 +280,15 @@ foregroundThreshold, backgroundImageUrl, maskCombineRatio, edgeBlurAmount, label
|
|
|
292
280
|
return;
|
|
293
281
|
}
|
|
294
282
|
applyFeatures(props.transformer, features);
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
height
|
|
298
|
-
|
|
283
|
+
if (dynamicProcessingDimensions()) {
|
|
284
|
+
const acceptedSettings = prevMediaTrack.source.getSettings();
|
|
285
|
+
if (acceptedSettings.width && acceptedSettings.height) {
|
|
286
|
+
props.transformer.update({
|
|
287
|
+
processingHeight: acceptedSettings.height,
|
|
288
|
+
processingWidth: acceptedSettings.width,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
299
292
|
const model = features.videoSegmentationModel &&
|
|
300
293
|
props.segmenters[features.videoSegmentationModel];
|
|
301
294
|
if (model &&
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pexip/media",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "20.0.0",
|
|
4
4
|
"description": "Home for media related stuff",
|
|
5
5
|
"homepage": "https://gitlab.com/pexip/zoo",
|
|
6
6
|
"bugs": "https://gitlab.com/pexip/zoo/issues",
|
|
@@ -14,6 +14,16 @@
|
|
|
14
14
|
"author": "Terrence Lam <terrence@tlam.dev>",
|
|
15
15
|
"module": "dist/index.js",
|
|
16
16
|
"types": "dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./*": {
|
|
23
|
+
"types": "./dist/*.d.ts",
|
|
24
|
+
"import": "./dist/*.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
17
27
|
"directories": {
|
|
18
28
|
"lib": "lib",
|
|
19
29
|
"test": "__tests__"
|
|
@@ -23,30 +33,31 @@
|
|
|
23
33
|
],
|
|
24
34
|
"scripts": {
|
|
25
35
|
"build": "pexip-bundler build",
|
|
36
|
+
"build:sourcemap": "pexip-bundler build --sourcemap",
|
|
26
37
|
"clean": "rm -fr dist",
|
|
27
38
|
"dev": "pexip-bundler dev",
|
|
28
|
-
"prepack": "yarn clean && yarn build
|
|
39
|
+
"prepack": "yarn clean && yarn build",
|
|
29
40
|
"test": "jest",
|
|
30
41
|
"check-format": "prettier --ignore-path=../../.prettierignore --check .",
|
|
31
42
|
"format": "prettier --ignore-path=../../.prettierignore --write .",
|
|
32
|
-
"lint": "yarn run -T
|
|
43
|
+
"lint": "yarn run -T biome lint",
|
|
33
44
|
"typecheck": "yarn tsc --noEmit -p ."
|
|
34
45
|
},
|
|
35
46
|
"dependencies": {
|
|
36
|
-
"@pexip/media-control": "
|
|
37
|
-
"@pexip/media-processor": "
|
|
38
|
-
"@pexip/signal": "16.
|
|
39
|
-
"@pexip/utils": "
|
|
47
|
+
"@pexip/media-control": "20.0.0",
|
|
48
|
+
"@pexip/media-processor": "20.0.0",
|
|
49
|
+
"@pexip/signal": "16.8.0",
|
|
50
|
+
"@pexip/utils": "17.0.0"
|
|
40
51
|
},
|
|
41
52
|
"devDependencies": {
|
|
42
53
|
"@jest/globals": "^29.7.0",
|
|
43
|
-
"@pexip/bundler": "
|
|
44
|
-
"@swc/core": "^1.
|
|
45
|
-
"@swc/jest": "^0.2.
|
|
54
|
+
"@pexip/bundler": "18.0.0",
|
|
55
|
+
"@swc/core": "^1.10.12",
|
|
56
|
+
"@swc/jest": "^0.2.37",
|
|
46
57
|
"jest": "^29.5.12",
|
|
47
58
|
"jest-junit": "^16.0.0",
|
|
48
59
|
"prettier": "^3.2.5",
|
|
49
|
-
"typescript": "~5.3
|
|
60
|
+
"typescript": "~5.7.3"
|
|
50
61
|
},
|
|
51
62
|
"publishConfig": {
|
|
52
63
|
"access": "public",
|