@pexip/media 22.0.0 → 22.2.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/api-docs/README.mdx +0 -1
  3. package/api-docs/functions/applyContentHint.mdx +1 -1
  4. package/api-docs/functions/createAudioMixingProcess.mdx +1 -1
  5. package/api-docs/functions/createGetDisplayMedia.mdx +3 -3
  6. package/api-docs/functions/createMediaSignal.mdx +2 -2
  7. package/api-docs/functions/createMediaSignals.mdx +5 -3
  8. package/api-docs/functions/deriveInitialPermissionStatus.mdx +4 -2
  9. package/api-docs/functions/getPermissionStatus.mdx +31 -11
  10. package/api-docs/functions/toDeniedDevices.mdx +3 -1
  11. package/api-docs/interfaces/AudioDetectionSignals.mdx +2 -2
  12. package/api-docs/interfaces/AudioSignalDetectionOptions.mdx +1 -1
  13. package/api-docs/interfaces/ExtendedMediaTrackSettings.mdx +3 -3
  14. package/api-docs/interfaces/Media.mdx +4 -4
  15. package/api-docs/interfaces/MediaAttributes.mdx +2 -2
  16. package/api-docs/interfaces/MediaChangesSignals.mdx +5 -5
  17. package/api-docs/interfaces/MediaController.mdx +3 -3
  18. package/api-docs/interfaces/MediaInit.mdx +1 -1
  19. package/api-docs/interfaces/MediaOptions.mdx +3 -3
  20. package/api-docs/interfaces/MediaTrack.mdx +3 -3
  21. package/api-docs/interfaces/MediaTrackInit.mdx +12 -10
  22. package/api-docs/interfaces/PreviewEventHandler.mdx +7 -7
  23. package/api-docs/interfaces/PreviewStreamController.mdx +10 -10
  24. package/api-docs/interfaces/PreviewStreamParams.mdx +7 -7
  25. package/api-docs/interfaces/VoiceActivityDetectionOptions.mdx +1 -1
  26. package/api-docs/type-aliases/GetUserMediaProcess.mdx +4 -2
  27. package/api-docs/type-aliases/Process.mdx +3 -1
  28. package/api-docs/variables/internalSignals.mdx +1 -1
  29. package/dist/audioMixingProcessor.d.ts +15 -0
  30. package/dist/audioMixingProcessor.js +44 -19
  31. package/dist/audioProcessor.js +13 -3
  32. package/dist/index.d.ts +1 -1
  33. package/dist/index.js +1 -1
  34. package/dist/logger.d.ts +0 -2
  35. package/dist/logger.js +0 -24
  36. package/dist/previewController.js +19 -1
  37. package/dist/utils.js +11 -2
  38. package/dist/videoProcessor.d.ts +1 -0
  39. package/dist/videoProcessor.js +48 -12
  40. package/package.json +7 -12
  41. package/api-docs/functions/proxyWithLog.mdx +0 -33
package/CHANGELOG.md CHANGED
@@ -1,5 +1,57 @@
1
1
  # @pexip/media
2
2
 
3
+ ## 22.2.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 72f8dde: Temporarily remove updating the backend in the pipeline
8
+ - 746f6b6: Add Canvas2d rendering backend support: alpha mask converter,
9
+ Canvas2d mask renderer, canvas dimension-aware rendering, and proper backend
10
+ propagation through the video processor pipeline.
11
+ - 265c898: Migrate test runner from Jest to Vitest.
12
+ - a5e8026: Fix "We can't find your microphone" error when changing the
13
+ microphone while sharing content without audio. The audio mixing processor no
14
+ longer tries to create an audio source node from a presentation stream that
15
+ has no audio track, and audio nodes belonging to a stale `AudioContext` are
16
+ recreated instead of being reused.
17
+ - 0878b3b: Fix race conditions in the video processing pipeline so effect
18
+ changes made during processor startup are correctly applied and worker option
19
+ diffs are computed against the previous state.
20
+ - Updated dependencies [5a17991]
21
+ - Updated dependencies [f4af45a]
22
+ - Updated dependencies [746f6b6]
23
+ - Updated dependencies [c101d02]
24
+ - Updated dependencies [476acbf]
25
+ - Updated dependencies [7c99e29]
26
+ - Updated dependencies [1b82fd5]
27
+ - Updated dependencies [265c898]
28
+ - Updated dependencies [a5e8026]
29
+ - Updated dependencies [0878b3b]
30
+ - @pexip/utils@17.4.1
31
+ - @pexip/media-processor@22.2.0
32
+ - @pexip/media-control@22.2.0
33
+ - @pexip/signal@16.9.6
34
+
35
+ ## 22.1.0
36
+
37
+ ### Minor Changes
38
+
39
+ - 44ad859: Move proxyWithLog to utils
40
+
41
+ ### Patch Changes
42
+
43
+ - 588b6e1: Fix process stopped track
44
+ - 49e9299: Fix process stopped track issue
45
+ - 136aa70: Fix race on close
46
+ - Updated dependencies [a9456de]
47
+ - Updated dependencies [44ad859]
48
+ - Updated dependencies [136aa70]
49
+ - Updated dependencies [ad47e6a]
50
+ - Updated dependencies [514c523]
51
+ - @pexip/media-control@22.1.0
52
+ - @pexip/utils@17.4.0
53
+ - @pexip/media-processor@22.1.0
54
+
3
55
  ## 22.0.0
4
56
 
5
57
  ### Major Changes
@@ -372,7 +372,6 @@ await mediaController.media.applyConstraints({
372
372
  | [createAudioStreamProcess](functions/createAudioStreamProcess.mdx) | Create an Audio Stream Processor and will own the stream passed-in |
373
373
  | [createGetDisplayMedia](functions/createGetDisplayMedia.mdx) | - |
374
374
  | [setLogger](functions/setLogger.mdx) | - |
375
- | [proxyWithLog](functions/proxyWithLog.mdx) | - |
376
375
  | [createMedia](functions/createMedia.mdx) | Create an object to interact with the media scream, which is usually used for our main stream. |
377
376
  | [createPreviewStreamController](functions/createPreviewStreamController.mdx) | - |
378
377
  | [createMediaSignal](functions/createMediaSignal.mdx) | Create a general signal with consistent scoped name |
@@ -8,7 +8,7 @@ Apply the content hint to the track
8
8
 
9
9
  | Type Parameter |
10
10
  | ------ |
11
- | `T` *extends* \| `""` \| `"speech"` \| `"speech-recognition"` \| `"music"` \| `"motion"` \| `"detail"` \| `"text"` |
11
+ | `T extends \| "" \| "speech" \| "speech-recognition" \| "music" \| "motion" \| "detail" \| "text"` |
12
12
 
13
13
  ## Parameters
14
14
 
@@ -11,7 +11,7 @@ Create an Audio Mixing Processor and will own the stream passed-in
11
11
 
12
12
  | Parameter | Type | Default value |
13
13
  | ------ | ------ | ------ |
14
- | `getCurrentMedia` | () => `MediaStream` \| `undefined` | `undefined` |
14
+ | `getCurrentMedia` | `() => MediaStream \| undefined` | `undefined` |
15
15
  | `signals?` | [`MediaSignals`](../type-aliases/MediaSignals.mdx) | `undefined` |
16
16
  | `label?` | `"AudioMixingProcessor"` | `PROCESSOR_LABELS.AudioMixingProcessor` |
17
17
 
@@ -6,8 +6,8 @@ function createGetDisplayMedia(getDefaultConstraints, getDisplayMedia): (constra
6
6
 
7
7
  | Parameter | Type |
8
8
  | ------ | ------ |
9
- | `getDefaultConstraints` | () => `DisplayMediaOptions` |
10
- | `getDisplayMedia` | (`options?`) => `Promise`\<`MediaStream`\> |
9
+ | `getDefaultConstraints` | `() => DisplayMediaOptions` |
10
+ | `getDisplayMedia` | `(options?) => Promise<MediaStream>` |
11
11
 
12
12
  ## Returns
13
13
 
@@ -23,4 +23,4 @@ function createGetDisplayMedia(getDefaultConstraints, getDisplayMedia): (constra
23
23
 
24
24
  ### Returns
25
25
 
26
- `Promise`\<`MediaStream` \| `undefined`\>
26
+ `Promise<MediaStream | undefined>`
@@ -19,11 +19,11 @@ Create a general signal with consistent scoped name
19
19
  | ------ | ------ | ------ | ------ |
20
20
  | `name` | `string` | `undefined` | Signal name |
21
21
  | `crucial` | `boolean` | `true` | Signify if the signal is unmissable. |
22
- | `variant` | `"generic"` \| `"behavior"` \| `"replay"` | `'generic'` | The variant of the signal |
22
+ | `variant` | `"generic" \| "behavior" \| "replay"` | `'generic'` | The variant of the signal |
23
23
 
24
24
  ## Returns
25
25
 
26
- `Signal`\<`T`, `T`\>
26
+ `Signal<T, T>`
27
27
 
28
28
  ## Default Value
29
29
 
@@ -9,18 +9,20 @@ signals for media to work
9
9
 
10
10
  | Type Parameter |
11
11
  | ------ |
12
- | `K` *extends* \| `"onAddTrack"` \| `"onDevicesChanged"` \| `"onMediaTrackMuted"` \| `"onMediaTrackResumed"` \| `"onMediaTrackStopped"` \| `"onMediaTrackSuspended"` \| `"onRemoveTrack"` \| `"onStatusChanged"` \| `"onUpdatingAudio"` \| `"onUpdatingVideo"` |
12
+ | `K extends \| "onAddTrack" \| "onDevicesChanged" \| "onMediaTrackMuted" \| "onMediaTrackResumed" \| "onMediaTrackStopped" \| "onMediaTrackSuspended" \| "onRemoveTrack" \| "onStatusChanged" \| "onUpdatingAudio" \| "onUpdatingVideo"` |
13
13
 
14
14
  ## Parameters
15
15
 
16
16
  | Parameter | Type | Default value | Description |
17
17
  | ------ | ------ | ------ | ------ |
18
- | `more` | `K`[] | `undefined` | Keys from `MediaSignalsOptional`, |
18
+ | `more` | `K[]` | `undefined` | Keys from `MediaSignalsOptional`, |
19
19
  | `scope` | `string` | `''` | any scope prefix for the generated signal name, |
20
20
 
21
21
  ## Returns
22
22
 
23
- `Pick`\<`Required`\<[`MediaSignals`](../type-aliases/MediaSignals.mdx)\>, `SignalKeys`\>
23
+ ```ts
24
+ Pick<Required<MediaSignals>, SignalKeys>
25
+ ```
24
26
 
25
27
  ## See
26
28
 
@@ -7,8 +7,10 @@ function deriveInitialPermissionStatus(prevStatus, getPermissionState): Promise<
7
7
  | Parameter | Type | Default value |
8
8
  | ------ | ------ | ------ |
9
9
  | `prevStatus` | [`UserMediaStatus`](../enumerations/UserMediaStatus.mdx) | `undefined` |
10
- | `getPermissionState` | (`anyActiveAudioTrack?`, `anyActiveVideoTrack?`, `getDevices?`) => `Promise`\<`InputDevicePermission`\> | `getInputDevicePermissionState` |
10
+ | `getPermissionState` | `(anyActiveAudioTrack?, anyActiveVideoTrack?, getDevices?) => Promise<InputDevicePermission>` | `getInputDevicePermissionState` |
11
11
 
12
12
  ## Returns
13
13
 
14
- `Promise`\<[`UserMediaStatus`](../enumerations/UserMediaStatus.mdx)\>
14
+ ```ts
15
+ Promise<UserMediaStatus>
16
+ ```
@@ -16,19 +16,39 @@ function getPermissionStatus(__namedParameters):
16
16
 
17
17
  | Parameter | Type |
18
18
  | ------ | ------ |
19
- | `__namedParameters` | \{ `audio`: `PermissionState`; `video`: `PermissionState`; \} |
19
+ | `__namedParameters` | `{ audio: PermissionState; video: PermissionState; }` |
20
20
  | `__namedParameters.audio` | `PermissionState` |
21
21
  | `__namedParameters.video` | `PermissionState` |
22
22
 
23
23
  ## Returns
24
24
 
25
- \| [`Initial`](../enumerations/UserMediaStatus.mdx#initial)
26
- \| [`InitialPermissionsGranted`](../enumerations/UserMediaStatus.mdx#initialpermissionsgranted)
27
- \| [`InitialPermissionsNotGranted`](../enumerations/UserMediaStatus.mdx#initialpermissionsnotgranted)
28
- \| [`InitialPermissionsVideoInputDenied`](../enumerations/UserMediaStatus.mdx#initialpermissionsvideoinputdenied)
29
- \| [`InitialPermissionsAudioInputDenied`](../enumerations/UserMediaStatus.mdx#initialpermissionsaudioinputdenied)
30
- \| [`InitialPermissionsVideoInputGranted`](../enumerations/UserMediaStatus.mdx#initialpermissionsvideoinputgranted)
31
- \| [`InitialPermissionsAudioInputGranted`](../enumerations/UserMediaStatus.mdx#initialpermissionsaudioinputgranted)
32
- \| [`InitialPermissionsGrantedVideoInputDenied`](../enumerations/UserMediaStatus.mdx#initialpermissionsgrantedvideoinputdenied)
33
- \| [`InitialPermissionsGrantedAudioInputDenied`](../enumerations/UserMediaStatus.mdx#initialpermissionsgrantedaudioinputdenied)
34
- \| [`PermissionsRejected`](../enumerations/UserMediaStatus.mdx#permissionsrejected)
25
+ ```ts
26
+ | Initial
27
+ ```
28
+ ```ts
29
+ | InitialPermissionsGranted
30
+ ```
31
+ ```ts
32
+ | InitialPermissionsNotGranted
33
+ ```
34
+ ```ts
35
+ | InitialPermissionsVideoInputDenied
36
+ ```
37
+ ```ts
38
+ | InitialPermissionsAudioInputDenied
39
+ ```
40
+ ```ts
41
+ | InitialPermissionsVideoInputGranted
42
+ ```
43
+ ```ts
44
+ | InitialPermissionsAudioInputGranted
45
+ ```
46
+ ```ts
47
+ | InitialPermissionsGrantedVideoInputDenied
48
+ ```
49
+ ```ts
50
+ | InitialPermissionsGrantedAudioInputDenied
51
+ ```
52
+ ```ts
53
+ | PermissionsRejected
54
+ ```
@@ -10,4 +10,6 @@ function toDeniedDevices(status?): DeniedDevices | undefined;
10
10
 
11
11
  ## Returns
12
12
 
13
- [`DeniedDevices`](../enumerations/DeniedDevices.mdx) \| `undefined`
13
+ ```ts
14
+ DeniedDevices | undefined
15
+ ```
@@ -2,5 +2,5 @@
2
2
 
3
3
  | Property | Type |
4
4
  | ------ | ------ |
5
- | <a id="onvad"></a> `onVAD` | `Signal`\<`undefined`\> |
6
- | <a id="onsilentdetected"></a> `onSilentDetected` | `Signal`\<`boolean`\> |
5
+ | <a id="onvad"></a> `onVAD` | `Signal<undefined>` |
6
+ | <a id="onsilentdetected"></a> `onSilentDetected` | `Signal<boolean>` |
@@ -3,4 +3,4 @@
3
3
  | Property | Type | Description |
4
4
  | ------ | ------ | ------ |
5
5
  | <a id="audiosignaldetectionduration"></a> `audioSignalDetectionDuration?` | `number` | Audio Signal Detection Duration in second |
6
- | <a id="shoulddetectaudio"></a> `shouldDetectAudio` | () => `boolean` | Whether or not to detect audio signal for malfunctioning device |
6
+ | <a id="shoulddetectaudio"></a> `shouldDetectAudio` | `() => boolean` | Whether or not to detect audio signal for malfunctioning device |
@@ -16,20 +16,20 @@
16
16
  | <a id="edgebluramount"></a> `edgeBlurAmount?` | `number` | - | - |
17
17
  | <a id="maskcombineratio"></a> `maskCombineRatio?` | `number` | - | - |
18
18
  | <a id="foregroundthreshold"></a> `foregroundThreshold?` | `number` | - | - |
19
- | <a id="videosegmentation"></a> `videoSegmentation?` | `"none"` \| `"blur"` \| `"overlay"` | - | - |
19
+ | <a id="videosegmentation"></a> `videoSegmentation?` | `"none" \| "blur" \| "overlay"` | - | - |
20
20
  | <a id="panenabled"></a> `panEnabled?` | `boolean` | - | - |
21
21
  | <a id="tiltenabled"></a> `tiltEnabled?` | `boolean` | - | - |
22
22
  | <a id="zoomenabled"></a> `zoomEnabled?` | `boolean` | - | - |
23
23
  | <a id="pan"></a> `pan?` | `number` | - | - |
24
24
  | <a id="tilt"></a> `tilt?` | `number` | - | - |
25
25
  | <a id="zoom"></a> `zoom?` | `number` | `MediaTrackSettings.zoom` | - |
26
- | <a id="contenthint"></a> `contentHint?` | \| `""` \| `"speech"` \| `"speech-recognition"` \| `"music"` \| `"motion"` \| `"detail"` \| `"text"` | - | - |
26
+ | <a id="contenthint"></a> `contentHint?` | `\| "" \| "speech" \| "speech-recognition" \| "music" \| "motion" \| "detail" \| "text"` | - | - |
27
27
  | <a id="aspectratio"></a> `aspectRatio?` | `number` | - | `MediaTrackSettings.aspectRatio` |
28
28
  | <a id="autogaincontrol"></a> `autoGainControl?` | `boolean` | - | `MediaTrackSettings.autoGainControl` |
29
29
  | <a id="backgroundblur"></a> `backgroundBlur?` | `boolean` | - | `MediaTrackSettings.backgroundBlur` |
30
30
  | <a id="deviceid"></a> `deviceId?` | `string` | - | `MediaTrackSettings.deviceId` |
31
31
  | <a id="displaysurface"></a> `displaySurface?` | `string` | - | `MediaTrackSettings.displaySurface` |
32
- | <a id="echocancellation"></a> `echoCancellation?` | `string` \| `boolean` | - | `MediaTrackSettings.echoCancellation` |
32
+ | <a id="echocancellation"></a> `echoCancellation?` | `string \| boolean` | - | `MediaTrackSettings.echoCancellation` |
33
33
  | <a id="facingmode"></a> `facingMode?` | `string` | - | `MediaTrackSettings.facingMode` |
34
34
  | <a id="framerate"></a> `frameRate?` | `number` | - | `MediaTrackSettings.frameRate` |
35
35
  | <a id="groupid"></a> `groupId?` | `string` | - | `MediaTrackSettings.groupId` |
@@ -13,8 +13,8 @@
13
13
  | <a id="expectedaudioinput"></a> `expectedAudioInput?` | `public` | `MediaDeviceInfoLike` | The audio input device which is expected to be used for the current stream based on the provided constraints | [`MediaAttributes`](MediaAttributes.mdx).[`expectedAudioInput`](MediaAttributes.mdx#expectedaudioinput) |
14
14
  | <a id="expectedvideoinput"></a> `expectedVideoInput?` | `public` | `MediaDeviceInfoLike` | The video input device which is expected to be used for the current stream based on the provided constraints | [`MediaAttributes`](MediaAttributes.mdx).[`expectedVideoInput`](MediaAttributes.mdx#expectedvideoinput) |
15
15
  | <a id="status"></a> `status` | `public` | [`UserMediaStatus`](../enumerations/UserMediaStatus.mdx) | The status of the media | [`MediaAttributes`](MediaAttributes.mdx).[`status`](MediaAttributes.mdx#status) |
16
- | <a id="audiomuted"></a> `audioMuted` | `public` | `boolean` \| `undefined` | Current mute state of audio track `undefined` means there is no such track from the stream | [`MediaAttributes`](MediaAttributes.mdx).[`audioMuted`](MediaAttributes.mdx#audiomuted) |
17
- | <a id="videomuted"></a> `videoMuted` | `public` | `boolean` \| `undefined` | Current mute state of video track `undefined` means there is no such track from the stream | [`MediaAttributes`](MediaAttributes.mdx).[`videoMuted`](MediaAttributes.mdx#videomuted) |
16
+ | <a id="audiomuted"></a> `audioMuted` | `public` | `boolean \| undefined` | Current mute state of audio track `undefined` means there is no such track from the stream | [`MediaAttributes`](MediaAttributes.mdx).[`audioMuted`](MediaAttributes.mdx#audiomuted) |
17
+ | <a id="videomuted"></a> `videoMuted` | `public` | `boolean \| undefined` | Current mute state of video track `undefined` means there is no such track from the stream | [`MediaAttributes`](MediaAttributes.mdx).[`videoMuted`](MediaAttributes.mdx#videomuted) |
18
18
  | <a id="audioinput"></a> `audioInput?` | `public` | `MediaDeviceInfoLike` | Audio input device is used for the audio track from the current stream | [`MediaAttributes`](MediaAttributes.mdx).[`audioInput`](MediaAttributes.mdx#audioinput) |
19
19
  | <a id="videoinput"></a> `videoInput?` | `public` | `MediaDeviceInfoLike` | Video input device is used for the video track from the current stream | [`MediaAttributes`](MediaAttributes.mdx).[`videoInput`](MediaAttributes.mdx#videoinput) |
20
20
 
@@ -76,7 +76,7 @@ Apply the constraints to the current media
76
76
 
77
77
  #### Returns
78
78
 
79
- `Promise`\<`void`\>
79
+ `Promise<void>`
80
80
 
81
81
  ***
82
82
 
@@ -90,7 +90,7 @@ Release the media resources, e.g. camera/microphone
90
90
 
91
91
  #### Returns
92
92
 
93
- `Promise`\<`void`\>
93
+ `Promise<void>`
94
94
 
95
95
  ***
96
96
 
@@ -13,7 +13,7 @@
13
13
  | <a id="expectedaudioinput"></a> `expectedAudioInput?` | `public` | `MediaDeviceInfoLike` | The audio input device which is expected to be used for the current stream based on the provided constraints |
14
14
  | <a id="expectedvideoinput"></a> `expectedVideoInput?` | `public` | `MediaDeviceInfoLike` | The video input device which is expected to be used for the current stream based on the provided constraints |
15
15
  | <a id="status"></a> `status` | `public` | [`UserMediaStatus`](../enumerations/UserMediaStatus.mdx) | The status of the media |
16
- | <a id="audiomuted"></a> `audioMuted` | `public` | `boolean` \| `undefined` | Current mute state of audio track `undefined` means there is no such track from the stream |
17
- | <a id="videomuted"></a> `videoMuted` | `public` | `boolean` \| `undefined` | Current mute state of video track `undefined` means there is no such track from the stream |
16
+ | <a id="audiomuted"></a> `audioMuted` | `public` | `boolean \| undefined` | Current mute state of audio track `undefined` means there is no such track from the stream |
17
+ | <a id="videomuted"></a> `videoMuted` | `public` | `boolean \| undefined` | Current mute state of video track `undefined` means there is no such track from the stream |
18
18
  | <a id="audioinput"></a> `audioInput?` | `public` | `MediaDeviceInfoLike` | Audio input device is used for the audio track from the current stream |
19
19
  | <a id="videoinput"></a> `videoInput?` | `public` | `MediaDeviceInfoLike` | Video input device is used for the video track from the current stream |
@@ -2,14 +2,14 @@
2
2
 
3
3
  | Property | Type |
4
4
  | ------ | ------ |
5
- | <a id="onaddtrack"></a> `onAddTrack` | `Signal`\<`MediaStreamTrack`\> |
6
- | <a id="ondeviceschanged"></a> `onDevicesChanged` | `Signal`\<`IndexedDevices`\> |
5
+ | <a id="onaddtrack"></a> `onAddTrack` | `Signal<MediaStreamTrack>` |
6
+ | <a id="ondeviceschanged"></a> `onDevicesChanged` | `Signal<IndexedDevices>` |
7
7
  | <a id="onmediachanged"></a> `onMediaChanged` | `Signal`\<[`Media`](Media.mdx) \| `undefined`\> |
8
8
  | <a id="onmediatrackmuted"></a> `onMediaTrackMuted` | `Signal`\<[`MediaTrack`](MediaTrack.mdx)\> |
9
9
  | <a id="onmediatrackresumed"></a> `onMediaTrackResumed` | `Signal`\<[`MediaTrack`](MediaTrack.mdx)\> |
10
10
  | <a id="onmediatrackstopped"></a> `onMediaTrackStopped` | `Signal`\<[`MediaTrack`](MediaTrack.mdx)\> |
11
11
  | <a id="onmediatracksuspended"></a> `onMediaTrackSuspended` | `Signal`\<[`MediaTrack`](MediaTrack.mdx)\> |
12
- | <a id="onremovetrack"></a> `onRemoveTrack` | `Signal`\<`MediaStreamTrack`\> |
12
+ | <a id="onremovetrack"></a> `onRemoveTrack` | `Signal<MediaStreamTrack>` |
13
13
  | <a id="onstatuschanged"></a> `onStatusChanged` | `Signal`\<[`UserMediaStatus`](../enumerations/UserMediaStatus.mdx)\> |
14
- | <a id="onupdatingaudio"></a> `onUpdatingAudio` | `Signal`\<`boolean`\> |
15
- | <a id="onupdatingvideo"></a> `onUpdatingVideo` | `Signal`\<`boolean`\> |
14
+ | <a id="onupdatingaudio"></a> `onUpdatingAudio` | `Signal<boolean>` |
15
+ | <a id="onupdatingvideo"></a> `onUpdatingVideo` | `Signal<boolean>` |
@@ -6,6 +6,6 @@
6
6
  | <a id="updatingvideo"></a> `updatingVideo` | `readonly` | `boolean` | - |
7
7
  | <a id="media"></a> `media?` | `readonly` | [`Media`](Media.mdx) | Current Media |
8
8
  | <a id="devices"></a> `devices` | `readonly` | `IndexedDevices` | Current device list |
9
- | <a id="getusermedia"></a> `getUserMedia` | `public` | (`constraints`) => `void` | Execute the media pipeline immediately with provided constraints **See** MediaDeviceRequest |
10
- | <a id="getusermediaasync"></a> `getUserMediaAsync` | `public` | (`constraints`) => `Promise`\<`void`\> | Execute the media pipeline immediately with provided constraints. An explicit version of `getUserMedia` to make it possible to chain other async actions **See** MediaDeviceRequest |
11
- | <a id="tryandgetusermedia"></a> `tryAndGetUserMedia` | `public` | (`constraints`) => `void` | Cross-check PermissionState and available devices before requesting user media, the request will be skipped if there is no granted device. |
9
+ | <a id="getusermedia"></a> `getUserMedia` | `public` | `(constraints) => void` | Execute the media pipeline immediately with provided constraints **See** MediaDeviceRequest |
10
+ | <a id="getusermediaasync"></a> `getUserMediaAsync` | `public` | `(constraints) => Promise<void>` | Execute the media pipeline immediately with provided constraints. An explicit version of `getUserMedia` to make it possible to chain other async actions **See** MediaDeviceRequest |
11
+ | <a id="tryandgetusermedia"></a> `tryAndGetUserMedia` | `public` | `(constraints) => void` | Cross-check PermissionState and available devices before requesting user media, the request will be skipped if there is no granted device. |
@@ -10,5 +10,5 @@
10
10
  | <a id="tracks"></a> `tracks` | [`MediaTrack`](MediaTrack.mdx)[] |
11
11
  | <a id="devices"></a> `devices` | `IndexedDevices` |
12
12
  | <a id="status"></a> `status` | [`UserMediaStatus`](../enumerations/UserMediaStatus.mdx) |
13
- | <a id="stream"></a> `stream` | `MediaStream` \| `undefined` |
13
+ | <a id="stream"></a> `stream` | `MediaStream \| undefined` |
14
14
  | <a id="signals"></a> `signals?` | [`MediaSignals`](../type-aliases/MediaSignals.mdx) |
@@ -5,6 +5,6 @@
5
5
  | <a id="signals"></a> `signals` | [`MediaSignals`](../type-aliases/MediaSignals.mdx) | Media signals to be used for the module **See** MediaSignals |
6
6
  | <a id="audioprocessors"></a> `audioProcessors` | [`TrackProcessor`](../type-aliases/TrackProcessor.mdx)[] | Media Processors |
7
7
  | <a id="videoprocessors"></a> `videoProcessors` | [`TrackProcessor`](../type-aliases/TrackProcessor.mdx)[] | - |
8
- | <a id="stopvideotrackasmute"></a> `stopVideoTrackAsMute?` | () => `boolean` | - |
9
- | <a id="getmutestate"></a> `getMuteState` | () => `DeviceMuteState` | A function to get the devices' mute state |
10
- | <a id="getdefaultconstraints"></a> `getDefaultConstraints?` | () => `object` | Pass default constraints to use with get media wrappers |
8
+ | <a id="stopvideotrackasmute"></a> `stopVideoTrackAsMute?` | `() => boolean` | - |
9
+ | <a id="getmutestate"></a> `getMuteState` | `() => DeviceMuteState` | A function to get the devices' mute state |
10
+ | <a id="getdefaultconstraints"></a> `getDefaultConstraints?` | `() => object` | Pass default constraints to use with get media wrappers |
@@ -5,7 +5,7 @@
5
5
  | <a id="id"></a> `id` | `readonly` | `string` | A unique identifier for the track same as `MediaStreamTrack.id` if `track` is available otherwise it uses the `id` from the construction or the `kind`. **See** MediaTrackInit |
6
6
  | <a id="stopped"></a> `stopped?` | `readonly` | `boolean` | It maps to MediaStreamTrack['readyState'] When `true` the track's `readyState` is `ended`, `false` means `live` otherwise the track is not available |
7
7
  | <a id="suspended"></a> `suspended?` | `readonly` | `boolean` | Indicate that the media has been suspended by the User Agent, and it could happen at any time. `undefined` means the track is not available |
8
- | <a id="kind"></a> `kind` | `readonly` | `"audioinput"` \| `"videoinput"` | - |
8
+ | <a id="kind"></a> `kind` | `readonly` | `"audioinput" \| "videoinput"` | - |
9
9
  | <a id="label"></a> `label?` | `readonly` | `string` | - |
10
10
  | <a id="previousmediatrack"></a> `previousMediaTrack?` | `readonly` | `MediaTrack` | - |
11
11
  | <a id="track"></a> `track?` | `readonly` | `MediaStreamTrack` | The MediaStreamTrack object representing the track **See** https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack |
@@ -75,7 +75,7 @@ applyConstraints(constraints): Promise<void>;
75
75
 
76
76
  #### Returns
77
77
 
78
- `Promise`\<`void`\>
78
+ `Promise<void>`
79
79
 
80
80
  ***
81
81
 
@@ -87,7 +87,7 @@ release(): Promise<void>;
87
87
 
88
88
  #### Returns
89
89
 
90
- `Promise`\<`void`\>
90
+ `Promise<void>`
91
91
 
92
92
  ***
93
93
 
@@ -1,6 +1,8 @@
1
1
  ## Extends
2
2
 
3
- - `Partial`\<`Omit`\<[`MediaTrack`](MediaTrack.mdx), `"mute"`\>\>
3
+ ```ts
4
+ - Partial<Omit<MediaTrack, "mute">>
5
+ ```
4
6
 
5
7
  ## Properties
6
8
 
@@ -14,16 +16,16 @@
14
16
  | <a id="track"></a> `track?` | `readonly` | `MediaStreamTrack` | The MediaStreamTrack object representing the track **See** https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack | - | [`MediaTrack`](MediaTrack.mdx).[`track`](MediaTrack.mdx#track) |
15
17
  | <a id="muted"></a> `muted?` | `public` | `boolean` | The current mute state of the track. `undefined` means the track is not available | - | [`MediaTrack`](MediaTrack.mdx).[`muted`](MediaTrack.mdx#muted) |
16
18
  | <a id="source"></a> `source?` | `readonly` | [`MediaTrack`](MediaTrack.mdx) | The source track that it is originated from | - | [`MediaTrack`](MediaTrack.mdx).[`source`](MediaTrack.mdx#source) |
17
- | <a id="getsettings"></a> `getSettings?` | `public` | () => [`ExtendedMediaTrackSettings`](ExtendedMediaTrackSettings.mdx) | - | - | [`MediaTrack`](MediaTrack.mdx).[`getSettings`](MediaTrack.mdx#getsettings) |
18
- | <a id="getconstraints"></a> `getConstraints?` | `public` | () => `InputDeviceConstraint` | - | - | [`MediaTrack`](MediaTrack.mdx).[`getConstraints`](MediaTrack.mdx#getconstraints) |
19
- | <a id="applyconstraints"></a> `applyConstraints?` | `public` | (`constraints`) => `Promise`\<`void`\> | - | - | [`MediaTrack`](MediaTrack.mdx).[`applyConstraints`](MediaTrack.mdx#applyconstraints) |
20
- | <a id="release"></a> `release?` | `public` | () => `Promise`\<`void`\> | - | - | [`MediaTrack`](MediaTrack.mdx).[`release`](MediaTrack.mdx#release) |
21
- | <a id="clone"></a> `clone?` | `public` | (`signals?`, `label?`) => [`MediaTrack`](MediaTrack.mdx) | - | - | [`MediaTrack`](MediaTrack.mdx).[`clone`](MediaTrack.mdx#clone) |
22
- | <a id="tojson"></a> `toJSON?` | `public` | () => `unknown` | - | - | [`MediaTrack`](MediaTrack.mdx).[`toJSON`](MediaTrack.mdx#tojson) |
23
- | <a id="kind"></a> `kind` | `public` | `"audioinput"` \| `"videoinput"` | - | [`MediaTrack`](MediaTrack.mdx).[`kind`](MediaTrack.mdx#kind) | - |
24
- | <a id="input"></a> `input` | `public` | `MediaDeviceInfoLike` \| `undefined` | The `MediaDeviceInfo` object representing the device that the track is connected to. **See** https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo | [`MediaTrack`](MediaTrack.mdx).[`input`](MediaTrack.mdx#input) | - |
19
+ | <a id="getsettings"></a> `getSettings?` | `public` | () =\> [`ExtendedMediaTrackSettings`](ExtendedMediaTrackSettings.mdx) | - | - | [`MediaTrack`](MediaTrack.mdx).[`getSettings`](MediaTrack.mdx#getsettings) |
20
+ | <a id="getconstraints"></a> `getConstraints?` | `public` | `() => InputDeviceConstraint` | - | - | [`MediaTrack`](MediaTrack.mdx).[`getConstraints`](MediaTrack.mdx#getconstraints) |
21
+ | <a id="applyconstraints"></a> `applyConstraints?` | `public` | `(constraints) => Promise<void>` | - | - | [`MediaTrack`](MediaTrack.mdx).[`applyConstraints`](MediaTrack.mdx#applyconstraints) |
22
+ | <a id="release"></a> `release?` | `public` | `() => Promise<void>` | - | - | [`MediaTrack`](MediaTrack.mdx).[`release`](MediaTrack.mdx#release) |
23
+ | <a id="clone"></a> `clone?` | `public` | (`signals?`, `label?`) =\> [`MediaTrack`](MediaTrack.mdx) | - | - | [`MediaTrack`](MediaTrack.mdx).[`clone`](MediaTrack.mdx#clone) |
24
+ | <a id="tojson"></a> `toJSON?` | `public` | `() => unknown` | - | - | [`MediaTrack`](MediaTrack.mdx).[`toJSON`](MediaTrack.mdx#tojson) |
25
+ | <a id="kind"></a> `kind` | `public` | `"audioinput" \| "videoinput"` | - | [`MediaTrack`](MediaTrack.mdx).[`kind`](MediaTrack.mdx#kind) | - |
26
+ | <a id="input"></a> `input` | `public` | `MediaDeviceInfoLike \| undefined` | The `MediaDeviceInfo` object representing the device that the track is connected to. **See** https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo | [`MediaTrack`](MediaTrack.mdx).[`input`](MediaTrack.mdx#input) | - |
25
27
  | <a id="expectedinput"></a> `expectedInput?` | `public` | `MediaDeviceInfoLike` | The `MediaDeviceInfo` object representing the device that the track is expected to be connected to. **See** https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo | [`MediaTrack`](MediaTrack.mdx).[`expectedInput`](MediaTrack.mdx#expectedinput) | - |
26
28
  | <a id="constraints"></a> `constraints` | `public` | `InputDeviceConstraint` | - | - | - |
27
29
  | <a id="overridemute"></a> `overrideMute?` | `public` | `boolean` | - | - | - |
28
30
  | <a id="signals"></a> `signals?` | `public` | [`MediaSignals`](../type-aliases/MediaSignals.mdx) | - | - | - |
29
- | <a id="mute"></a> `mute?` | `public` | (`toMute`, `self`, `soft?`) => `void` | Overriding Mute the track | - | - |
31
+ | <a id="mute"></a> `mute?` | `public` | `(toMute, self, soft?) => void` | Overriding Mute the track | - | - |
@@ -9,11 +9,11 @@
9
9
  | <a id="audioinputerror"></a> `audioInputError?` | `EventErrorCallback` |
10
10
  | <a id="applychangeserror"></a> `applyChangesError?` | `EventErrorCallback` |
11
11
  | <a id="revertchangeserror"></a> `revertChangesError?` | `EventErrorCallback` |
12
- | <a id="audiomuted"></a> `audioMuted?` | `EventCallback`\<`boolean` \| `undefined`\> |
13
- | <a id="audiosuspended"></a> `audioSuspended?` | `EventCallback`\<`boolean` \| `undefined`\> |
14
- | <a id="updatingmain"></a> `updatingMain?` | `EventCallback`\<`boolean`\> |
15
- | <a id="updatingpreviewaudio"></a> `updatingPreviewAudio?` | `EventCallback`\<`boolean`\> |
16
- | <a id="updatingpreviewvideo"></a> `updatingPreviewVideo?` | `EventCallback`\<`boolean`\> |
17
- | <a id="videomuted"></a> `videoMuted?` | `EventCallback`\<`boolean` \| `undefined`\> |
18
- | <a id="videosuspended"></a> `videoSuspended?` | `EventCallback`\<`boolean` \| `undefined`\> |
12
+ | <a id="audiomuted"></a> `audioMuted?` | `EventCallback<boolean \| undefined>` |
13
+ | <a id="audiosuspended"></a> `audioSuspended?` | `EventCallback<boolean \| undefined>` |
14
+ | <a id="updatingmain"></a> `updatingMain?` | `EventCallback<boolean>` |
15
+ | <a id="updatingpreviewaudio"></a> `updatingPreviewAudio?` | `EventCallback<boolean>` |
16
+ | <a id="updatingpreviewvideo"></a> `updatingPreviewVideo?` | `EventCallback<boolean>` |
17
+ | <a id="videomuted"></a> `videoMuted?` | `EventCallback<boolean \| undefined>` |
18
+ | <a id="videosuspended"></a> `videoSuspended?` | `EventCallback<boolean \| undefined>` |
19
19
  | <a id="unsubscribemain"></a> `unsubscribeMain?` | [`Unsubscribe`](../type-aliases/Unsubscribe.mdx) |
@@ -11,7 +11,7 @@
11
11
  | <a id="updatingmain"></a> `updatingMain` | `boolean` |
12
12
  | <a id="updatingpreviewaudio"></a> `updatingPreviewAudio` | `boolean` |
13
13
  | <a id="updatingpreviewvideo"></a> `updatingPreviewVideo` | `boolean` |
14
- | <a id="cleanup"></a> `cleanup` | () => `Promise`\<`void`\> |
14
+ | <a id="cleanup"></a> `cleanup` | `() => Promise<void>` |
15
15
 
16
16
  ## Methods
17
17
 
@@ -83,7 +83,7 @@ applyChanges(force?): Promise<void>;
83
83
 
84
84
  #### Returns
85
85
 
86
- `Promise`\<`void`\>
86
+ `Promise<void>`
87
87
 
88
88
  ***
89
89
 
@@ -95,7 +95,7 @@ revertChanges(): Promise<void>;
95
95
 
96
96
  #### Returns
97
97
 
98
- `Promise`\<`void`\>
98
+ `Promise<void>`
99
99
 
100
100
  ***
101
101
 
@@ -163,7 +163,7 @@ onUpdatingPreviewAudio(callback): Unsubscribe;
163
163
 
164
164
  | Parameter | Type |
165
165
  | ------ | ------ |
166
- | `callback` | `EventCallback`\<`boolean`\> |
166
+ | `callback` | `EventCallback<boolean>` |
167
167
 
168
168
  #### Returns
169
169
 
@@ -181,7 +181,7 @@ onUpdatingPreviewVideo(callback): Unsubscribe;
181
181
 
182
182
  | Parameter | Type |
183
183
  | ------ | ------ |
184
- | `callback` | `EventCallback`\<`boolean`\> |
184
+ | `callback` | `EventCallback<boolean>` |
185
185
 
186
186
  #### Returns
187
187
 
@@ -199,7 +199,7 @@ onUpdatingMain(callback): Unsubscribe;
199
199
 
200
200
  | Parameter | Type |
201
201
  | ------ | ------ |
202
- | `callback` | `EventCallback`\<`boolean`\> |
202
+ | `callback` | `EventCallback<boolean>` |
203
203
 
204
204
  #### Returns
205
205
 
@@ -289,7 +289,7 @@ onAudioMuted(callback): Unsubscribe;
289
289
 
290
290
  | Parameter | Type |
291
291
  | ------ | ------ |
292
- | `callback` | `EventCallback`\<`boolean` \| `undefined`\> |
292
+ | `callback` | `EventCallback<boolean \| undefined>` |
293
293
 
294
294
  #### Returns
295
295
 
@@ -307,7 +307,7 @@ onAudioSuspended(callback): Unsubscribe;
307
307
 
308
308
  | Parameter | Type |
309
309
  | ------ | ------ |
310
- | `callback` | `EventCallback`\<`boolean` \| `undefined`\> |
310
+ | `callback` | `EventCallback<boolean \| undefined>` |
311
311
 
312
312
  #### Returns
313
313
 
@@ -325,7 +325,7 @@ onVideoMuted(callback): Unsubscribe;
325
325
 
326
326
  | Parameter | Type |
327
327
  | ------ | ------ |
328
- | `callback` | `EventCallback`\<`boolean` \| `undefined`\> |
328
+ | `callback` | `EventCallback<boolean \| undefined>` |
329
329
 
330
330
  #### Returns
331
331
 
@@ -343,7 +343,7 @@ onVideoSuspended(callback): Unsubscribe;
343
343
 
344
344
  | Parameter | Type |
345
345
  | ------ | ------ |
346
- | `callback` | `EventCallback`\<`boolean` \| `undefined`\> |
346
+ | `callback` | `EventCallback<boolean \| undefined>` |
347
347
 
348
348
  #### Returns
349
349
 
@@ -2,15 +2,15 @@
2
2
 
3
3
  | Property | Type | Description |
4
4
  | ------ | ------ | ------ |
5
- | <a id="getcurrentdevices"></a> `getCurrentDevices` | () => `IndexedDevices` | - |
6
- | <a id="getcurrentmedia"></a> `getCurrentMedia` | () => [`Media`](Media.mdx) \| `undefined` | - |
7
- | <a id="updatemainstream"></a> `updateMainStream` | (`request`) => `Promise`\<`void`\> | - |
5
+ | <a id="getcurrentdevices"></a> `getCurrentDevices` | `() => IndexedDevices` | - |
6
+ | <a id="getcurrentmedia"></a> `getCurrentMedia` | () =\> [`Media`](Media.mdx) \| `undefined` | - |
7
+ | <a id="updatemainstream"></a> `updateMainStream` | `(request) => Promise<void>` | - |
8
8
  | <a id="mainmediasignal"></a> `mainMediaSignal` | `Signal`\<[`Media`](Media.mdx) \| `undefined`, [`Media`](Media.mdx) \| `undefined`\> | - |
9
9
  | <a id="signals"></a> `signals` | [`MediaSignals`](../type-aliases/MediaSignals.mdx) | - |
10
- | <a id="onended"></a> `onEnded?` | () => `void` | - |
10
+ | <a id="onended"></a> `onEnded?` | `() => void` | - |
11
11
  | <a id="fftsize"></a> `fftSize?` | `number` | - |
12
- | <a id="queueoptions"></a> `queueOptions?` | `Partial`\<`AsyncQueueOptions`\> | - |
12
+ | <a id="queueoptions"></a> `queueOptions?` | `Partial<AsyncQueueOptions>` | - |
13
13
  | <a id="audioprocessors"></a> `audioProcessors` | [`TrackProcessor`](../type-aliases/TrackProcessor.mdx)[] | - |
14
14
  | <a id="videoprocessors"></a> `videoProcessors` | [`TrackProcessor`](../type-aliases/TrackProcessor.mdx)[] | - |
15
- | <a id="getdefaultconstraints"></a> `getDefaultConstraints?` | () => `object` | Pass default constraints to use with get media wrappers |
16
- | <a id="stopvideotrackasmute"></a> `stopVideoTrackAsMute?` | () => `boolean` | - |
15
+ | <a id="getdefaultconstraints"></a> `getDefaultConstraints?` | `() => object` | Pass default constraints to use with get media wrappers |
16
+ | <a id="stopvideotrackasmute"></a> `stopVideoTrackAsMute?` | `() => boolean` | - |
@@ -3,4 +3,4 @@
3
3
  | Property | Type | Description |
4
4
  | ------ | ------ | ------ |
5
5
  | <a id="vadthrottlems"></a> `vadThrottleMS?` | `number` | Voice Activity Detection in millisecond |
6
- | <a id="shoulddetectvoiceactivity"></a> `shouldDetectVoiceActivity` | () => `boolean` | Whether or not to detect voice activity |
6
+ | <a id="shoulddetectvoiceactivity"></a> `shouldDetectVoiceActivity` | `() => boolean` | Whether or not to detect voice activity |
@@ -9,11 +9,13 @@ type GetUserMediaProcess = (request) => Promise<Media>;
9
9
  | `request` | \{ `constraints`: `MediaDeviceRequest`; `originalConstraints`: `MediaDeviceRequest`; `permission`: \{ `audio`: `PermissionState`; `video`: `PermissionState`; \}; `currentMedia`: [`Media`](../interfaces/Media.mdx) \| `undefined`; \} |
10
10
  | `request.constraints` | `MediaDeviceRequest` |
11
11
  | `request.originalConstraints` | `MediaDeviceRequest` |
12
- | `request.permission` | \{ `audio`: `PermissionState`; `video`: `PermissionState`; \} |
12
+ | `request.permission` | `{ audio: PermissionState; video: PermissionState; }` |
13
13
  | `request.permission.audio` | `PermissionState` |
14
14
  | `request.permission.video` | `PermissionState` |
15
15
  | `request.currentMedia` | [`Media`](../interfaces/Media.mdx) \| `undefined` |
16
16
 
17
17
  ## Returns
18
18
 
19
- `Promise`\<[`Media`](../interfaces/Media.mdx)\>
19
+ ```ts
20
+ Promise<Media>
21
+ ```
@@ -16,4 +16,6 @@ type Process<T> = (a) => Promise<MediaTrack>;
16
16
 
17
17
  ## Returns
18
18
 
19
- `Promise`\<[`MediaTrack`](../interfaces/MediaTrack.mdx)\>
19
+ ```ts
20
+ Promise<MediaTrack>
21
+ ```
@@ -10,4 +10,4 @@ Internal signals
10
10
 
11
11
  | Name | Type |
12
12
  | ------ | ------ |
13
- | <a id="ondeviceschanged"></a> `onDevicesChanged` | `Signal`\<`IndexedDevices`, `IndexedDevices`\> |
13
+ | <a id="ondeviceschanged"></a> `onDevicesChanged` | `Signal<IndexedDevices, IndexedDevices>` |
@@ -5,6 +5,7 @@ interface AudioStreamProcessorProps {
5
5
  mixWithAdditionalMedia?: boolean;
6
6
  merger?: AudioNodeInit<ChannelMergerNode, ChannelMergerNode>;
7
7
  displaySource?: AudioNodeInit<MediaStreamAudioSourceNode, MediaStreamAudioSourceNode>;
8
+ displayStream?: MediaStream;
8
9
  audioGraph?: AudioGraph;
9
10
  }
10
11
  declare const FEATURE_KEYS: {
@@ -13,6 +14,20 @@ declare const FEATURE_KEYS: {
13
14
  type FeaturePropKeys = keyof typeof FEATURE_KEYS;
14
15
  type FeatureProps = Pick<AudioStreamProcessorProps, FeaturePropKeys>;
15
16
  export declare const updateFeatureProps: (constraints: MediaDeviceRequest["audio"], props: FeatureProps) => FeatureProps;
17
+ /**
18
+ * Extract a `MediaStream` containing only the audio tracks of the provided
19
+ * stream, or `undefined` when there is no audio track to mix, e.g. sharing a
20
+ * screen without audio.
21
+ *
22
+ * @param stream - The stream to extract the audio tracks from
23
+ *
24
+ * @example
25
+ *
26
+ * ```typescript
27
+ * const audioOnly = toAudioOnlyStream(displayStream);
28
+ * ```
29
+ */
30
+ export declare const toAudioOnlyStream: (stream?: MediaStream) => MediaStream | undefined;
16
31
  /**
17
32
  * Create an Audio Mixing Processor and will own the stream passed-in
18
33
  */
@@ -28,6 +28,26 @@ export const updateFeatureProps = (constraints, props) => {
28
28
  }
29
29
  return features;
30
30
  };
31
+ /**
32
+ * Extract a `MediaStream` containing only the audio tracks of the provided
33
+ * stream, or `undefined` when there is no audio track to mix, e.g. sharing a
34
+ * screen without audio.
35
+ *
36
+ * @param stream - The stream to extract the audio tracks from
37
+ *
38
+ * @example
39
+ *
40
+ * ```typescript
41
+ * const audioOnly = toAudioOnlyStream(displayStream);
42
+ * ```
43
+ */
44
+ export const toAudioOnlyStream = (stream) => {
45
+ const audioTracks = stream?.getAudioTracks?.() ?? [];
46
+ if (audioTracks.length === 0) {
47
+ return undefined;
48
+ }
49
+ return new MediaStream(audioTracks);
50
+ };
31
51
  /**
32
52
  * Create an Audio Mixing Processor and will own the stream passed-in
33
53
  */
@@ -36,7 +56,8 @@ export const createAudioMixingProcess = (getCurrentMedia, signals, label = PROCE
36
56
  return async (prevMediaTrack) => {
37
57
  updateFeatureProps(prevMediaTrack.getConstraints(), props);
38
58
  const displayStream = getCurrentMedia();
39
- const displayTrack = displayStream?.getAudioTracks?.().at(0);
59
+ const displayAudioStream = toAudioOnlyStream(displayStream);
60
+ const displayTrack = displayAudioStream?.getAudioTracks().at(0);
40
61
  const applyConstraints = async (constraints) => {
41
62
  if (isEmpty(constraints)) {
42
63
  return;
@@ -50,8 +71,8 @@ export const createAudioMixingProcess = (getCurrentMedia, signals, label = PROCE
50
71
  }
51
72
  if (features.mixWithAdditionalMedia) {
52
73
  const newStream = getCurrentMedia();
53
- const [newTrack] = getCurrentMedia()?.getAudioTracks() ?? [];
54
- if (!newTrack) {
74
+ const newAudioStream = toAudioOnlyStream(newStream);
75
+ if (!newAudioStream) {
55
76
  return;
56
77
  }
57
78
  if (!props.audioGraph || !props.merger) {
@@ -59,8 +80,7 @@ export const createAudioMixingProcess = (getCurrentMedia, signals, label = PROCE
59
80
  return;
60
81
  }
61
82
  if (props.displaySource && props.merger) {
62
- if (newStream ===
63
- props.displaySource.audioNode?.mediaStream) {
83
+ if (newStream === props.displayStream) {
64
84
  return;
65
85
  }
66
86
  props.audioGraph.disconnect([
@@ -68,14 +88,13 @@ export const createAudioMixingProcess = (getCurrentMedia, signals, label = PROCE
68
88
  props.merger,
69
89
  ]);
70
90
  }
71
- if (newStream) {
72
- props.displaySource =
73
- createStreamSourceGraphNode(newStream);
74
- props.audioGraph.connect([
75
- props.displaySource,
76
- props.merger,
77
- ]);
78
- }
91
+ props.displayStream = newStream;
92
+ props.displaySource =
93
+ createStreamSourceGraphNode(newAudioStream);
94
+ props.audioGraph.connect([
95
+ props.displaySource,
96
+ props.merger,
97
+ ]);
79
98
  }
80
99
  else if (features.mixWithAdditionalMedia === false) {
81
100
  // Unmixing
@@ -83,6 +102,7 @@ export const createAudioMixingProcess = (getCurrentMedia, signals, label = PROCE
83
102
  props.displaySource.release();
84
103
  props.audioGraph?.disconnect([props.displaySource]);
85
104
  props.displaySource = undefined;
105
+ props.displayStream = undefined;
86
106
  }
87
107
  }
88
108
  return Promise.resolve();
@@ -118,8 +138,10 @@ export const createAudioMixingProcess = (getCurrentMedia, signals, label = PROCE
118
138
  }
119
139
  assert(prevMediaTrack.track, 'Main track should be available');
120
140
  const mainSource = createStreamSourceGraphNode(new MediaStream([prevMediaTrack.track]));
121
- props.displaySource =
122
- displayStream && createStreamSourceGraphNode(displayStream);
141
+ props.displaySource = displayAudioStream
142
+ ? createStreamSourceGraphNode(displayAudioStream)
143
+ : undefined;
144
+ props.displayStream = displayAudioStream ? displayStream : undefined;
123
145
  props.merger = createChannelMergerGraphNode();
124
146
  const destination = createStreamDestinationGraphNode({
125
147
  channelCount: 1,
@@ -151,10 +173,13 @@ export const createAudioMixingProcess = (getCurrentMedia, signals, label = PROCE
151
173
  logger.debug({ label }, 'Release Media');
152
174
  unsubscribe();
153
175
  // Release Props
154
- await props.audioGraph?.release();
155
- props.audioGraph = undefined;
156
- props.merger = undefined;
157
- props.displaySource = undefined;
176
+ await audioGraph.release();
177
+ if (props.audioGraph === audioGraph) {
178
+ props.audioGraph = undefined;
179
+ props.merger = undefined;
180
+ props.displaySource = undefined;
181
+ props.displayStream = undefined;
182
+ }
158
183
  };
159
184
  return Promise.resolve(createMediaTrack({
160
185
  label,
@@ -173,6 +173,14 @@ label = PROCESSOR_LABELS.AudioProcessor, }) => {
173
173
  [source, analyzer],
174
174
  ];
175
175
  logger.debug({ initialAudioNodeConnection, label }, 'Initial AudioNodeConnection');
176
+ if (props.denoiseNode) {
177
+ props.denoiseNode.release();
178
+ props.denoiseNode = undefined;
179
+ }
180
+ if (props.analyzer) {
181
+ props.analyzer.release();
182
+ props.analyzer = undefined;
183
+ }
176
184
  const audioGraph = createAudioGraphProxy(createAudioGraph(initialAudioNodeConnection, props.audioGraphOptions), {
177
185
  connect: (target, args) => {
178
186
  logger.debug({ label, target, args }, 'connect nodes');
@@ -199,9 +207,11 @@ label = PROCESSOR_LABELS.AudioProcessor, }) => {
199
207
  track.stop();
200
208
  // Release Props
201
209
  await audioGraph.release();
202
- props.denoiseNode = undefined;
203
- props.analyzer = undefined;
204
- props.audioGraph = undefined;
210
+ if (props.audioGraph === audioGraph) {
211
+ props.denoiseNode = undefined;
212
+ props.analyzer = undefined;
213
+ props.audioGraph = undefined;
214
+ }
205
215
  };
206
216
  return createMediaTrack({
207
217
  label,
package/dist/index.d.ts CHANGED
@@ -9,4 +9,4 @@ export { createAudioMixingProcess } from './audioMixingProcessor';
9
9
  export { createAudioStreamProcess } from './audioProcessor';
10
10
  export { createMedia } from './media';
11
11
  export { createVideoStreamProcess } from './videoProcessor';
12
- export { setLogger, proxyWithLog } from './logger';
12
+ export { setLogger } from './logger';
package/dist/index.js CHANGED
@@ -9,4 +9,4 @@ export { createAudioMixingProcess } from './audioMixingProcessor';
9
9
  export { createAudioStreamProcess } from './audioProcessor';
10
10
  export { createMedia } from './media';
11
11
  export { createVideoStreamProcess } from './videoProcessor';
12
- export { setLogger, proxyWithLog } from './logger';
12
+ export { setLogger } from './logger';
package/dist/logger.d.ts CHANGED
@@ -7,5 +7,3 @@ export declare function setLogger(newLogger: Logger): void;
7
7
  * @param metaBase - The meta data which will always be included into the log
8
8
  */
9
9
  export declare const createModuleLogger: (metaBase: unknown) => Logger;
10
- export declare const createLogProxyHandler: <T extends object>(logger: Logger, name: string, scope: string) => ProxyHandler<T>;
11
- export declare const proxyWithLog: (logger: Logger, scope: string) => <T extends object>(obj: T, name: string) => T;
package/dist/logger.js CHANGED
@@ -23,27 +23,3 @@ export const createModuleLogger = (metaBase) => {
23
23
  return log;
24
24
  }, {});
25
25
  };
26
- export const createLogProxyHandler = (logger, name, scope) => {
27
- return {
28
- get: (target, p, receiver) => {
29
- const value = Reflect.get(target, p, receiver);
30
- logger.debug({ scope, name, prop: p, value }, `called get ${name}[${String(p)}]`);
31
- if (typeof value === 'function') {
32
- return new Proxy(value, {
33
- apply: (fn, thisArg, args) => {
34
- logger.debug({ scope, name, method: String(p), args }, `called ${name}.${String(p)}(...)`);
35
- return Reflect.apply(fn, thisArg, args);
36
- },
37
- });
38
- }
39
- return value;
40
- },
41
- set: (target, p, value, receiver) => {
42
- logger.info({ scope, name, prop: p, value }, `called set ${name}[${String(p)}]`);
43
- return Reflect.set(target, p, value, receiver);
44
- },
45
- };
46
- };
47
- export const proxyWithLog = (logger, scope) => (obj, name) => {
48
- return new Proxy(obj, createLogProxyHandler(logger, name, scope));
49
- };
@@ -365,7 +365,25 @@ export const createPreviewStreamController = ({ getCurrentDevices, getCurrentMed
365
365
  };
366
366
  const cleanup = async () => {
367
367
  logger.debug('Cleanup preview controller');
368
- await props.media?.release();
368
+ // Drop pending jobs, then enqueue release so it runs after any
369
+ // in-flight `processAndUpdateMedia`. Releasing concurrently with an
370
+ // in-flight `videoProcessor.process()` would tear down the worker
371
+ // pipeline mid-flight.
372
+ queue.empty();
373
+ const media = props.media;
374
+ if (media) {
375
+ await new Promise((resolve, reject) => {
376
+ queue.enqueue(async () => {
377
+ try {
378
+ await media.release();
379
+ resolve();
380
+ }
381
+ catch (error) {
382
+ reject(error);
383
+ }
384
+ });
385
+ });
386
+ }
369
387
  cleanUpMainSubscription();
370
388
  for (const unsub of subscriptions) {
371
389
  unsub?.();
package/dist/utils.js CHANGED
@@ -182,9 +182,9 @@ export const createMediaTrack = (trackInit) => {
182
182
  },
183
183
  async release() {
184
184
  trackUnsubscribe?.();
185
- trackInit.track?.stop();
186
185
  await trackInit.release?.();
187
186
  await trackInit.previousMediaTrack?.release();
187
+ trackInit.track?.stop();
188
188
  trackInit.signals?.onMediaTrackStopped?.emit(this);
189
189
  },
190
190
  toJSON() {
@@ -783,12 +783,21 @@ export const createMediaProcessor = ({ audioProcessors, videoProcessors, onProce
783
783
  }
784
784
  catch (error) {
785
785
  if (error instanceof Error) {
786
+ if (track.stopped) {
787
+ // Ignore the error as track stopped
788
+ return track;
789
+ }
786
790
  onProcessingError?.(error, track);
787
791
  }
788
792
  return track;
789
793
  }
790
794
  };
791
795
  return async (newTracks) => {
792
- return await Promise.all(newTracks.map(track => processTrack(track)));
796
+ return await Promise.all(newTracks.flatMap(track => {
797
+ if (track.stopped === undefined || track.stopped) {
798
+ return [];
799
+ }
800
+ return [processTrack(track)];
801
+ }));
793
802
  };
794
803
  };
@@ -22,6 +22,7 @@ interface VideoStreamProcessProps extends Partial<VideoRenderParams> {
22
22
  contentHint?: VideoContentHint;
23
23
  }
24
24
  declare const FEATURE_KEYS: {
25
+ readonly backend: "string";
25
26
  readonly backgroundBlurAmount: "number";
26
27
  readonly backgroundImageUrl: "string";
27
28
  readonly backgroundThreshold: "number";
@@ -1,11 +1,12 @@
1
1
  import { isRenderEffects } from '@pexip/media-processor';
2
2
  import { extractConstraints, getValueFromConstrainNumber, } from '@pexip/media-control';
3
- import { hasOwn, isEmpty } from '@pexip/utils';
3
+ import { hasOwn, isEmpty, proxyWithLog } from '@pexip/utils';
4
4
  import { createMediaTrack, getBlurKernelSize, getTentBlurSize } from './utils';
5
- import { logger, proxyWithLog } from './logger';
5
+ import { logger } from './logger';
6
6
  import { isVideoContentHint } from './typeGuard';
7
7
  import { PROCESSOR_LABELS } from './constants';
8
8
  const FEATURE_KEYS = {
9
+ backend: 'string',
9
10
  backgroundBlurAmount: 'number',
10
11
  backgroundImageUrl: 'string',
11
12
  backgroundThreshold: 'number',
@@ -217,21 +218,26 @@ const applyFeatures = async (processor, features, referenceProcessingHeight) =>
217
218
  case 'downSampleFactor':
218
219
  case 'backgroundThreshold': {
219
220
  const value = features[k];
220
- if (value !== undefined) {
221
+ if (value !== undefined &&
222
+ value !== processor.renderOptions[k]) {
221
223
  renderOptions[k] = value;
222
224
  }
223
225
  break;
224
226
  }
225
227
  case 'excludeBystanders': {
226
228
  const value = features[k];
227
- if (value !== undefined) {
229
+ if (value !== undefined &&
230
+ value !== processor.renderOptions[k]) {
228
231
  renderOptions[k] = value;
229
232
  }
230
233
  break;
231
234
  }
232
235
  case 'personCenterX': {
233
236
  const value = features[k];
234
- if (value !== undefined) {
237
+ if (value !== undefined &&
238
+ value !== processor.renderOptions.personCenter[0]) {
239
+ // Keep the other coordinate from the local draft or existing
240
+ // processor state so X/Y single-field updates stay paired.
235
241
  renderOptions.personCenter = [
236
242
  value,
237
243
  renderOptions.personCenter?.[1] ??
@@ -242,7 +248,10 @@ const applyFeatures = async (processor, features, referenceProcessingHeight) =>
242
248
  }
243
249
  case 'personCenterY': {
244
250
  const value = features[k];
245
- if (value !== undefined) {
251
+ if (value !== undefined &&
252
+ value !== processor.renderOptions.personCenter[1]) {
253
+ // Keep the other coordinate from the local draft or existing
254
+ // processor state so X/Y single-field updates stay paired.
246
255
  renderOptions.personCenter = [
247
256
  renderOptions.personCenter?.[0] ??
248
257
  processor.renderOptions.personCenter[0],
@@ -255,14 +264,20 @@ const applyFeatures = async (processor, features, referenceProcessingHeight) =>
255
264
  case 'backgroundBlurAmount': {
256
265
  const value = features[k];
257
266
  if (value !== undefined) {
258
- renderOptions[k] = getBlurKernelSize(value, referenceProcessingHeight ?? processor.processingHeight, processor.processingHeight);
267
+ const actualValue = getBlurKernelSize(value, referenceProcessingHeight ?? processor.processingHeight, processor.processingHeight);
268
+ if (actualValue !== processor.renderOptions[k]) {
269
+ renderOptions[k] = actualValue;
270
+ }
259
271
  }
260
272
  break;
261
273
  }
262
274
  case 'edgeBlurAmount': {
263
275
  const value = features[k];
264
276
  if (value !== undefined) {
265
- renderOptions[k] = getTentBlurSize(value, referenceProcessingHeight ?? processor.processingHeight, processor.processingHeight);
277
+ const actualValue = getTentBlurSize(value, referenceProcessingHeight ?? processor.processingHeight, processor.processingHeight);
278
+ if (actualValue !== processor.renderOptions[k]) {
279
+ renderOptions[k] = actualValue;
280
+ }
266
281
  }
267
282
  break;
268
283
  }
@@ -273,6 +288,13 @@ const applyFeatures = async (processor, features, referenceProcessingHeight) =>
273
288
  }
274
289
  break;
275
290
  }
291
+ case 'backend': {
292
+ const value = features[k];
293
+ if (value && value !== processor.renderOptions.backend) {
294
+ renderOptions.backend = value;
295
+ }
296
+ break;
297
+ }
276
298
  case 'backgroundImageUrl': {
277
299
  const value = features[k];
278
300
  if (value &&
@@ -324,7 +346,7 @@ label = PROCESSOR_LABELS.VideoProcessor, referenceProcessingHeight, maskCombineR
324
346
  return async (prevMediaTrack) => {
325
347
  const features = updateFeatureProps(prevMediaTrack.getConstraints(), props);
326
348
  const shouldEnabled = shouldEnable();
327
- if (!shouldEnabled || !prevMediaTrack.track) {
349
+ if (!shouldEnabled || !prevMediaTrack.track || prevMediaTrack.stopped) {
328
350
  logger.debug({
329
351
  label,
330
352
  features,
@@ -356,9 +378,23 @@ label = PROCESSOR_LABELS.VideoProcessor, referenceProcessingHeight, maskCombineR
356
378
  });
357
379
  }
358
380
  else {
359
- await applyFeatures(videoProcessor, { ...features, videoSegmentation }, referenceProcessingHeight);
381
+ await applyFeatures(videoProcessor, {
382
+ backend: gpuAPI(),
383
+ ...renderOptions,
384
+ videoSegmentation,
385
+ }, referenceProcessingHeight);
360
386
  }
361
387
  const track = await videoProcessor.process(prevMediaTrack.track);
388
+ // The source track constraints may have changed while `process()` was
389
+ // awaiting the segmentation model to load (e.g. the user toggled blur
390
+ // in pre-flight before the processor was ready). The features computed
391
+ // above are already baked into the freshly opened processor, so
392
+ // re-apply anything that changed in the meantime to avoid silently
393
+ // dropping the effect.
394
+ const latestFeatures = updateFeatureProps(prevMediaTrack.getConstraints(), props);
395
+ if (!isEmpty(latestFeatures)) {
396
+ await applyFeatures(videoProcessor, latestFeatures, referenceProcessingHeight);
397
+ }
362
398
  // Inherit contentHint from previous track
363
399
  track.contentHint = prevMediaTrack.track.contentHint;
364
400
  let trackReleaseTimeoutID = 0;
@@ -391,7 +427,7 @@ label = PROCESSOR_LABELS.VideoProcessor, referenceProcessingHeight, maskCombineR
391
427
  // the last frame is black to avoid frozen frame in a gateway call
392
428
  trackReleaseTimeoutID = window.setTimeout(() => {
393
429
  track.stop();
394
- videoProcessor.close();
430
+ void videoProcessor.close();
395
431
  void this?.release?.();
396
432
  trackReleaseTimeoutID = 0;
397
433
  }, 500);
@@ -407,7 +443,7 @@ label = PROCESSOR_LABELS.VideoProcessor, referenceProcessingHeight, maskCombineR
407
443
  },
408
444
  signals,
409
445
  async release() {
410
- videoProcessor.close();
446
+ await videoProcessor.close();
411
447
  await this.previousMediaTrack?.release();
412
448
  },
413
449
  async applyConstraints(constraints) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pexip/media",
3
- "version": "22.0.0",
3
+ "version": "22.2.0",
4
4
  "description": "Home for media related stuff",
5
5
  "homepage": "https://developer.pexip.com",
6
6
  "bugs": "https://gitlab.com/pexip/zoo/issues",
@@ -39,7 +39,7 @@
39
39
  "clean": "rm -fr dist api-docs",
40
40
  "dev": "pexip-bundler dev",
41
41
  "prepack": "yarn clean && yarn build && yarn docs",
42
- "test": "jest",
42
+ "test": "pexip-bundler test",
43
43
  "check-format": "prettier --ignore-path=../../.prettierignore --check .",
44
44
  "format": "prettier --ignore-path=../../.prettierignore --write .",
45
45
  "lint": "yarn run -T biome lint",
@@ -47,18 +47,13 @@
47
47
  "docs": "typedoc"
48
48
  },
49
49
  "dependencies": {
50
- "@pexip/media-control": "22.0.0",
51
- "@pexip/media-processor": "22.0.0",
52
- "@pexip/signal": "16.9.5",
53
- "@pexip/utils": "17.3.0"
50
+ "@pexip/media-control": "22.2.0",
51
+ "@pexip/media-processor": "22.2.0",
52
+ "@pexip/signal": "16.9.6",
53
+ "@pexip/utils": "17.4.1"
54
54
  },
55
55
  "devDependencies": {
56
- "@jest/globals": "^29.5.12",
57
- "@pexip/bundler": "18.2.1",
58
- "@swc/core": "^1.10.12",
59
- "@swc/jest": "^0.2.39",
60
- "jest": "^29.5.12",
61
- "jest-junit": "^16.0.0",
56
+ "@pexip/bundler": "18.3.0",
62
57
  "prettier": "^3.2.5",
63
58
  "typedoc": "^0.28.18",
64
59
  "typedoc-plugin-markdown": "^4.11.0",
@@ -1,33 +0,0 @@
1
- ```ts
2
- function proxyWithLog(logger, scope): <T>(obj, name) => T;
3
- ```
4
-
5
- ## Parameters
6
-
7
- | Parameter | Type |
8
- | ------ | ------ |
9
- | `logger` | `Logger` |
10
- | `scope` | `string` |
11
-
12
- ## Returns
13
-
14
- ```ts
15
- <T>(obj, name): T;
16
- ```
17
-
18
- ### Type Parameters
19
-
20
- | Type Parameter |
21
- | ------ |
22
- | `T` *extends* `object` |
23
-
24
- ### Parameters
25
-
26
- | Parameter | Type |
27
- | ------ | ------ |
28
- | `obj` | `T` |
29
- | `name` | `string` |
30
-
31
- ### Returns
32
-
33
- `T`