@banou/media-player 0.10.20 → 0.10.22
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/README.md +34 -22
- package/dist/audio/loudness-analysis.d.ts +38 -0
- package/dist/audio/playback-tap.d.ts +11 -0
- package/dist/audio/volume-normalizer.d.ts +4 -2
- package/dist/engine/index.d.ts +1 -1
- package/dist/engine/index.js +1 -1
- package/dist/engine/playback.d.ts +21 -0
- package/dist/{engine-C4Gj_4zs.js → engine-Cr_7OImR.js} +120 -103
- package/dist/index.d.ts +1 -1
- package/dist/index.js +929 -651
- package/dist/react/hooks/use-playback.d.ts +2 -1
- package/dist/react/hooks/use-volume-normalizer.d.ts +9 -1
- package/dist/react/video-player.d.ts +19 -7
- package/dist/utils/source.d.ts +6 -1
- package/dist/volume-normalizer-worklet.js +1200 -78
- package/package.json +3 -3
- package/src/lib/audio/loudness-analysis.ts +307 -0
- package/src/lib/audio/playback-tap.ts +37 -0
- package/src/lib/audio/volume-normalizer-worklet.d.ts +49 -0
- package/src/lib/audio/volume-normalizer-worklet.js +1200 -78
- package/src/lib/audio/volume-normalizer.ts +5 -3
- package/src/lib/engine/index.ts +1 -1
- package/src/lib/engine/playback.ts +21 -1
- package/src/lib/index.tsx +1 -0
- package/src/lib/react/hooks/use-playback.ts +5 -1
- package/src/lib/react/hooks/use-volume-normalizer.ts +40 -2
- package/src/lib/react/video-player.tsx +55 -15
- package/src/lib/utils/source.ts +6 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PlaybackOutput } from '../../engine';
|
|
1
2
|
import type { MediaPlayerLocalOptions } from '../video-player';
|
|
2
3
|
/**
|
|
3
4
|
* Owns the engine for the life of a source: start, teardown, and every piece of state the pipeline
|
|
@@ -5,4 +6,4 @@ import type { MediaPlayerLocalOptions } from '../video-player';
|
|
|
5
6
|
*/
|
|
6
7
|
export declare const usePlayback: (video: HTMLVideoElement | null, subtitles: HTMLElement | null,
|
|
7
8
|
/** null when the media is remote: there are no bytes, so there is no pipeline to run. */
|
|
8
|
-
options: MediaPlayerLocalOptions | null) => void;
|
|
9
|
+
options: MediaPlayerLocalOptions | null, onOutput?: (output: PlaybackOutput) => void) => void;
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
+
import type { LoudnessSource } from '../../audio/loudness-analysis';
|
|
2
|
+
import type { PlaybackTap } from '../../audio/playback-tap';
|
|
1
3
|
/**
|
|
2
4
|
* Normalizes the element's volume while `enabled`. Nothing is built until it first is, and turning it off
|
|
3
5
|
* afterwards bypasses rather than unroutes, since an element cannot be handed back. `refused` is true once the
|
|
4
6
|
* engine turned the element down, which leaves it playing exactly as before.
|
|
7
|
+
*
|
|
8
|
+
* With a `source`, the file is also analysed ahead of the playhead while it is on, reading only the byte `ranges`
|
|
9
|
+
* given (all of them when undefined), or with a `tap`, from the audio playback remuxed.
|
|
5
10
|
*/
|
|
6
|
-
export declare const useVolumeNormalizer: (video: HTMLVideoElement | null, workletUrl: string | undefined, enabled: boolean
|
|
11
|
+
export declare const useVolumeNormalizer: (video: HTMLVideoElement | null, workletUrl: string | undefined, enabled: boolean, source?: LoudnessSource | {
|
|
12
|
+
tap: PlaybackTap;
|
|
13
|
+
audioStreamIndex: number;
|
|
14
|
+
}, ranges?: [number, number][]) => {
|
|
7
15
|
refused: boolean;
|
|
8
16
|
};
|
|
@@ -6,13 +6,19 @@ import type { ExposePlayerOptions } from '../remote';
|
|
|
6
6
|
/**
|
|
7
7
|
* The source, read a range at a time: the player never downloads the whole file. Both fields travel
|
|
8
8
|
* together, so passing one without the other is a type error.
|
|
9
|
+
*
|
|
10
|
+
* `readsDownload` marks a source each read of which is a download, a file over HTTP, so the volume normalizer
|
|
11
|
+
* analyses the audio playback fetched instead of reading the file again. Without it, and with no
|
|
12
|
+
* `downloadedRanges`, every byte is taken to be readable for free, as a local file's are.
|
|
9
13
|
*/
|
|
10
14
|
export type MediaPlayerSource = {
|
|
11
15
|
read: (offset: number, size: number) => Promise<ArrayBuffer>;
|
|
12
16
|
size: number;
|
|
17
|
+
readsDownload?: boolean;
|
|
13
18
|
} | {
|
|
14
19
|
read?: undefined;
|
|
15
20
|
size?: undefined;
|
|
21
|
+
readsDownload?: undefined;
|
|
16
22
|
};
|
|
17
23
|
/** Shared by both arms: nothing here depends on who owns the media. */
|
|
18
24
|
type CommonOptions = {
|
|
@@ -134,11 +140,13 @@ export type MediaPlayerLocalOptions = CommonOptions & MediaPlayerSource & {
|
|
|
134
140
|
/** Byte spans available, painted on the seekbar and informing the thumbnail generator. */
|
|
135
141
|
downloadedRanges?: DownloadedRange[];
|
|
136
142
|
/**
|
|
137
|
-
* Reader for the thumbnail engine, when it should differ from playback's.
|
|
143
|
+
* Reader for the thumbnail engine and the volume normalizer's analysis, when it should differ from playback's.
|
|
138
144
|
*
|
|
139
145
|
* They are the same by default so generation shares playback's fetch order. A consumer whose
|
|
140
146
|
* reads are not free wants them apart: a torrent hands this a non-prioritising, fail-fast reader
|
|
141
|
-
* so generating previews cannot steal download order from the bytes playback is blocked on.
|
|
147
|
+
* so generating previews cannot steal download order from the bytes playback is blocked on. The
|
|
148
|
+
* analysis asks it only for bytes inside `downloadedRanges`, with none given for the whole file, and for
|
|
149
|
+
* nothing when the source `readsDownload`.
|
|
142
150
|
*/
|
|
143
151
|
thumbnailRead?: (offset: number, size: number) => Promise<ArrayBuffer>;
|
|
144
152
|
/** Off entirely. A second wasm worker during pipeline boot is worth avoiding on a slow source. */
|
|
@@ -153,10 +161,14 @@ export type MediaPlayerLocalOptions = CommonOptions & MediaPlayerSource & {
|
|
|
153
161
|
*/
|
|
154
162
|
normalizerWorkletUrl?: string;
|
|
155
163
|
/**
|
|
156
|
-
* The settings menu's "Normalize volume" switch:
|
|
157
|
-
*
|
|
158
|
-
* clicks; nothing is saved, so an app that wants it to stick saves what
|
|
159
|
-
* passes it back.
|
|
164
|
+
* The settings menu's "Normalize volume" switch: keeps the file's normal level and turns down what goes well
|
|
165
|
+
* over it, a loud burst before it starts. On by default; pass false for off. The player keeps the switch's
|
|
166
|
+
* state from here and from the viewer's clicks; nothing is saved, so an app that wants it to stick saves what
|
|
167
|
+
* `onNormalizeVolumeChange` reports and passes it back.
|
|
168
|
+
*
|
|
169
|
+
* While it is on the file is read a second time, in a worker, as far as `downloadedRanges` allows, to find the
|
|
170
|
+
* loud parts ahead of the playhead; a source that `readsDownload` is not read again, and its loud parts are found
|
|
171
|
+
* in what playback fetched. The sound plays 10 ms behind its input, on or off, once routed.
|
|
160
172
|
*
|
|
161
173
|
* The first time it is on, the element is routed through Web Audio for the rest of its life (off then
|
|
162
174
|
* bypasses). If autoplay rules hold the audio back, that waits for the page's next click, tap or key press, and
|
|
@@ -165,7 +177,7 @@ export type MediaPlayerLocalOptions = CommonOptions & MediaPlayerSource & {
|
|
|
165
177
|
* the element is never routed.
|
|
166
178
|
*/
|
|
167
179
|
normalizeVolume?: boolean;
|
|
168
|
-
/** The viewer flipped the switch
|
|
180
|
+
/** The viewer flipped the switch, to `normalizeVolume`: what an app saves to pass back as `normalizeVolume`. */
|
|
169
181
|
onNormalizeVolumeChange?: (normalizeVolume: boolean) => void;
|
|
170
182
|
};
|
|
171
183
|
/**
|
package/dist/utils/source.d.ts
CHANGED
|
@@ -15,12 +15,17 @@ declare const fromUrl: ({ url, length: _length, name, credentials }: {
|
|
|
15
15
|
length: number;
|
|
16
16
|
name: string | undefined;
|
|
17
17
|
read: (offset: number, size: number) => Promise<ArrayBuffer>;
|
|
18
|
+
readsDownload: boolean;
|
|
18
19
|
}>;
|
|
19
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* A source resolved down to what the remuxer needs: a total length and a byte-range reader, and whether each read
|
|
22
|
+
* is a download, which the player's `readsDownload` takes.
|
|
23
|
+
*/
|
|
20
24
|
export type RemuxerInput = {
|
|
21
25
|
length: number;
|
|
22
26
|
name?: string;
|
|
23
27
|
read: (offset: number, size: number) => Promise<ArrayBuffer>;
|
|
28
|
+
readsDownload?: boolean;
|
|
24
29
|
};
|
|
25
30
|
export declare const inputToRemuxerInput: (params: Parameters<typeof fromBlob | typeof fromUrl>[0] | {
|
|
26
31
|
length: number;
|