react-native-waveform-player 0.0.1 → 1.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/AudioWaveform.podspec +29 -0
- package/LICENSE +20 -0
- package/README.md +296 -0
- package/android/build.gradle +67 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/audiowaveform/AudioPlayerEngine.kt +353 -0
- package/android/src/main/java/com/audiowaveform/AudioWaveformEvent.kt +22 -0
- package/android/src/main/java/com/audiowaveform/AudioWaveformPackage.kt +17 -0
- package/android/src/main/java/com/audiowaveform/AudioWaveformView.kt +715 -0
- package/android/src/main/java/com/audiowaveform/AudioWaveformViewManager.kt +234 -0
- package/android/src/main/java/com/audiowaveform/PlayPauseButton.kt +106 -0
- package/android/src/main/java/com/audiowaveform/SpeedPillView.kt +70 -0
- package/android/src/main/java/com/audiowaveform/WaveformBarsView.kt +358 -0
- package/android/src/main/java/com/audiowaveform/WaveformDecoder.kt +240 -0
- package/android/src/main/res/drawable/pause_fill.xml +15 -0
- package/android/src/main/res/drawable/play_fill.xml +15 -0
- package/ios/AudioPlayerEngine.swift +281 -0
- package/ios/AudioWaveformView.h +14 -0
- package/ios/AudioWaveformView.mm +307 -0
- package/ios/AudioWaveformViewImpl.swift +835 -0
- package/ios/PlayPauseButton.swift +118 -0
- package/ios/SpeedPillView.swift +70 -0
- package/ios/WaveformBarsView.swift +327 -0
- package/ios/WaveformDecoder.swift +332 -0
- package/lib/module/AudioWaveformView.js +8 -0
- package/lib/module/AudioWaveformView.js.map +1 -0
- package/lib/module/AudioWaveformView.native.js +79 -0
- package/lib/module/AudioWaveformView.native.js.map +1 -0
- package/lib/module/AudioWaveformViewNativeComponent.ts +95 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/AudioWaveformView.d.ts +233 -0
- package/lib/typescript/src/AudioWaveformView.d.ts.map +1 -0
- package/lib/typescript/src/AudioWaveformView.native.d.ts +335 -0
- package/lib/typescript/src/AudioWaveformView.native.d.ts.map +1 -0
- package/lib/typescript/src/AudioWaveformViewNativeComponent.d.ts +71 -0
- package/lib/typescript/src/AudioWaveformViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +138 -7
- package/src/AudioWaveformView.native.tsx +281 -0
- package/src/AudioWaveformView.tsx +96 -0
- package/src/AudioWaveformViewNativeComponent.ts +95 -0
- package/src/index.tsx +13 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useImperativeHandle,
|
|
4
|
+
useMemo,
|
|
5
|
+
useRef,
|
|
6
|
+
type ForwardedRef,
|
|
7
|
+
} from 'react';
|
|
8
|
+
import {
|
|
9
|
+
type ColorValue,
|
|
10
|
+
type NativeSyntheticEvent,
|
|
11
|
+
type ViewProps,
|
|
12
|
+
} from 'react-native';
|
|
13
|
+
import NativeAudioWaveformView, {
|
|
14
|
+
Commands,
|
|
15
|
+
} from './AudioWaveformViewNativeComponent';
|
|
16
|
+
|
|
17
|
+
export type AudioWaveformPlayerState =
|
|
18
|
+
| 'idle'
|
|
19
|
+
| 'loading'
|
|
20
|
+
| 'ready'
|
|
21
|
+
| 'ended'
|
|
22
|
+
| 'error';
|
|
23
|
+
|
|
24
|
+
export type AudioWaveformTimeMode = 'count-up' | 'count-down';
|
|
25
|
+
|
|
26
|
+
export type AudioWaveformSource = { uri: string };
|
|
27
|
+
|
|
28
|
+
export type AudioWaveformPlayerStateEvent = {
|
|
29
|
+
state: AudioWaveformPlayerState;
|
|
30
|
+
isPlaying: boolean;
|
|
31
|
+
speed: number;
|
|
32
|
+
error?: string;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type AudioWaveformTimeUpdateEvent = {
|
|
36
|
+
currentTimeMs: number;
|
|
37
|
+
durationMs: number;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type AudioWaveformSeekEvent = {
|
|
41
|
+
positionMs: number;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type AudioWaveformLoadEvent = {
|
|
45
|
+
durationMs: number;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type AudioWaveformLoadErrorEvent = {
|
|
49
|
+
message: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type AudioWaveformViewProps = Omit<ViewProps, 'children'> & {
|
|
53
|
+
source: AudioWaveformSource;
|
|
54
|
+
|
|
55
|
+
/** Pre-computed amplitudes in [0, 1]. When provided, native decode is skipped. */
|
|
56
|
+
samples?: ReadonlyArray<number>;
|
|
57
|
+
|
|
58
|
+
/** Highlighted bar color (the "played" portion). */
|
|
59
|
+
playedBarColor?: ColorValue;
|
|
60
|
+
/** Bar color for the not-yet-played portion. */
|
|
61
|
+
unplayedBarColor?: ColorValue;
|
|
62
|
+
|
|
63
|
+
/** Bar thickness (default 3). */
|
|
64
|
+
barWidth?: number;
|
|
65
|
+
/** Gap between bars (default 2). */
|
|
66
|
+
barGap?: number;
|
|
67
|
+
/** Bar corner radius (default = barWidth / 2). */
|
|
68
|
+
barRadius?: number;
|
|
69
|
+
/** Force a specific number of bars; default auto from view width. */
|
|
70
|
+
barCount?: number;
|
|
71
|
+
|
|
72
|
+
/** Background of the rounded container (default light blue). Has no effect when showBackground={false}. */
|
|
73
|
+
containerBackgroundColor?: ColorValue;
|
|
74
|
+
/** Container corner radius (default 16). Has no effect when showBackground={false}. */
|
|
75
|
+
containerBorderRadius?: number;
|
|
76
|
+
/** Whether to draw the rounded container background. Default true. */
|
|
77
|
+
showBackground?: boolean;
|
|
78
|
+
|
|
79
|
+
/** Show the play/pause button. Default true. */
|
|
80
|
+
showPlayButton?: boolean;
|
|
81
|
+
playButtonColor?: ColorValue;
|
|
82
|
+
|
|
83
|
+
/** Show the time label. Default true. */
|
|
84
|
+
showTime?: boolean;
|
|
85
|
+
timeColor?: ColorValue;
|
|
86
|
+
/** count-up: 0:00 -> duration. count-down: duration -> 0:00. Default count-up. */
|
|
87
|
+
timeMode?: AudioWaveformTimeMode;
|
|
88
|
+
|
|
89
|
+
/** Show the playback-speed pill. Default true. */
|
|
90
|
+
showSpeedControl?: boolean;
|
|
91
|
+
speedColor?: ColorValue;
|
|
92
|
+
speedBackgroundColor?: ColorValue;
|
|
93
|
+
/** Available speeds the pill cycles through (default [0.5, 1, 1.5, 2]). */
|
|
94
|
+
speeds?: ReadonlyArray<number>;
|
|
95
|
+
/** Initial speed when the component mounts. Default 1. */
|
|
96
|
+
defaultSpeed?: number;
|
|
97
|
+
|
|
98
|
+
/** Begin playback as soon as the source is ready. Default false. */
|
|
99
|
+
autoPlay?: boolean;
|
|
100
|
+
/** Seek to this position immediately on load (milliseconds). Default 0. */
|
|
101
|
+
initialPositionMs?: number;
|
|
102
|
+
/** Restart from the beginning when playback ends. Default false. */
|
|
103
|
+
loop?: boolean;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Allow audio to keep playing when the host app is backgrounded.
|
|
107
|
+
* Default `false` — playback is paused on `didEnterBackground` (iOS) /
|
|
108
|
+
* `onHostPause` (Android).
|
|
109
|
+
*
|
|
110
|
+
* When `true`:
|
|
111
|
+
* - **iOS**: the host app must enable the "Audio, AirPlay, and Picture in
|
|
112
|
+
* Picture" Background Mode (Xcode → Signing & Capabilities → +Capability
|
|
113
|
+
* → Background Modes, or add `UIBackgroundModes: [audio]` to
|
|
114
|
+
* `Info.plist`). The library will configure `AVAudioSession` to
|
|
115
|
+
* `.playback` and activate it when the source is set.
|
|
116
|
+
* - **Android**: no host configuration is required for typical use.
|
|
117
|
+
* `MediaPlayer` keeps playing through `Activity.onPause` already.
|
|
118
|
+
* Optionally add `<uses-permission android:name="android.permission.WAKE_LOCK"/>`
|
|
119
|
+
* to your app manifest if you need playback to survive device sleep —
|
|
120
|
+
* the library will then call `MediaPlayer.setWakeMode` automatically.
|
|
121
|
+
*/
|
|
122
|
+
playInBackground?: boolean;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* When the app is backgrounded, skip the cheap-but-pointless waveform /
|
|
126
|
+
* time-label refreshes that would otherwise piggy-back on every 30 Hz
|
|
127
|
+
* progress tick (the OS already skips the actual GPU painting).
|
|
128
|
+
*
|
|
129
|
+
* Default `true` — there is no visible effect since the view is
|
|
130
|
+
* offscreen, and we save a small amount of CPU per tick. The
|
|
131
|
+
* `onTimeUpdate` JS event keeps firing regardless so you can still
|
|
132
|
+
* drive Now Playing / Lock Screen / analytics from background.
|
|
133
|
+
*
|
|
134
|
+
* Set to `false` if you want the bars + time label to stay refreshed in
|
|
135
|
+
* background for some reason (rare).
|
|
136
|
+
*/
|
|
137
|
+
pauseUiUpdatesInBackground?: boolean;
|
|
138
|
+
|
|
139
|
+
/** When defined, the component is fully controlled — internal taps fire onPlayerStateChange but do not toggle play state. */
|
|
140
|
+
playing?: boolean;
|
|
141
|
+
/** When defined, the component is fully controlled — speed pill taps fire onPlayerStateChange but do not change speed. */
|
|
142
|
+
speed?: number;
|
|
143
|
+
|
|
144
|
+
onLoad?: (event: AudioWaveformLoadEvent) => void;
|
|
145
|
+
onLoadError?: (event: AudioWaveformLoadErrorEvent) => void;
|
|
146
|
+
onPlayerStateChange?: (event: AudioWaveformPlayerStateEvent) => void;
|
|
147
|
+
onTimeUpdate?: (event: AudioWaveformTimeUpdateEvent) => void;
|
|
148
|
+
onSeek?: (event: AudioWaveformSeekEvent) => void;
|
|
149
|
+
onEnd?: () => void;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export type AudioWaveformViewRef = {
|
|
153
|
+
play: () => void;
|
|
154
|
+
pause: () => void;
|
|
155
|
+
toggle: () => void;
|
|
156
|
+
seekTo: (positionMs: number) => void;
|
|
157
|
+
setSpeed: (speed: number) => void;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
function AudioWaveformViewInner(
|
|
161
|
+
props: AudioWaveformViewProps,
|
|
162
|
+
ref: ForwardedRef<AudioWaveformViewRef>
|
|
163
|
+
) {
|
|
164
|
+
const nativeRef = useRef<React.ComponentRef<
|
|
165
|
+
typeof NativeAudioWaveformView
|
|
166
|
+
> | null>(null);
|
|
167
|
+
|
|
168
|
+
const {
|
|
169
|
+
playing,
|
|
170
|
+
speed,
|
|
171
|
+
onLoad,
|
|
172
|
+
onLoadError,
|
|
173
|
+
onPlayerStateChange,
|
|
174
|
+
onTimeUpdate,
|
|
175
|
+
onSeek,
|
|
176
|
+
onEnd,
|
|
177
|
+
...rest
|
|
178
|
+
} = props;
|
|
179
|
+
|
|
180
|
+
// Translate the React-style controlled props (boolean/number/undefined) into
|
|
181
|
+
// the Fabric-friendly Int32/Float sentinels: -1 = uncontrolled.
|
|
182
|
+
const controlledPlaying = useMemo(() => {
|
|
183
|
+
if (playing === undefined) return -1;
|
|
184
|
+
return playing ? 1 : 0;
|
|
185
|
+
}, [playing]);
|
|
186
|
+
|
|
187
|
+
const controlledSpeed = useMemo(() => {
|
|
188
|
+
if (speed === undefined || !Number.isFinite(speed) || speed < 0) {
|
|
189
|
+
return -1;
|
|
190
|
+
}
|
|
191
|
+
return speed;
|
|
192
|
+
}, [speed]);
|
|
193
|
+
|
|
194
|
+
useImperativeHandle(
|
|
195
|
+
ref,
|
|
196
|
+
() => ({
|
|
197
|
+
play: () => {
|
|
198
|
+
if (nativeRef.current) Commands.play(nativeRef.current);
|
|
199
|
+
},
|
|
200
|
+
pause: () => {
|
|
201
|
+
if (nativeRef.current) Commands.pause(nativeRef.current);
|
|
202
|
+
},
|
|
203
|
+
toggle: () => {
|
|
204
|
+
if (nativeRef.current) Commands.toggle(nativeRef.current);
|
|
205
|
+
},
|
|
206
|
+
seekTo: (positionMs: number) => {
|
|
207
|
+
if (nativeRef.current) {
|
|
208
|
+
Commands.seekTo(
|
|
209
|
+
nativeRef.current,
|
|
210
|
+
Math.max(0, Math.round(positionMs))
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
setSpeed: (s: number) => {
|
|
215
|
+
if (nativeRef.current) Commands.setSpeed(nativeRef.current, s);
|
|
216
|
+
},
|
|
217
|
+
}),
|
|
218
|
+
[]
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<NativeAudioWaveformView
|
|
223
|
+
ref={nativeRef}
|
|
224
|
+
{...rest}
|
|
225
|
+
controlledPlaying={controlledPlaying}
|
|
226
|
+
controlledSpeed={controlledSpeed}
|
|
227
|
+
onLoad={
|
|
228
|
+
onLoad
|
|
229
|
+
? (e: NativeSyntheticEvent<AudioWaveformLoadEvent>) =>
|
|
230
|
+
onLoad(e.nativeEvent)
|
|
231
|
+
: undefined
|
|
232
|
+
}
|
|
233
|
+
onLoadError={
|
|
234
|
+
onLoadError
|
|
235
|
+
? (e: NativeSyntheticEvent<AudioWaveformLoadErrorEvent>) =>
|
|
236
|
+
onLoadError(e.nativeEvent)
|
|
237
|
+
: undefined
|
|
238
|
+
}
|
|
239
|
+
onPlayerStateChange={
|
|
240
|
+
onPlayerStateChange
|
|
241
|
+
? (
|
|
242
|
+
e: NativeSyntheticEvent<{
|
|
243
|
+
state: string;
|
|
244
|
+
isPlaying: boolean;
|
|
245
|
+
speed: number;
|
|
246
|
+
error: string;
|
|
247
|
+
}>
|
|
248
|
+
) => {
|
|
249
|
+
const { state, isPlaying, speed: spd, error } = e.nativeEvent;
|
|
250
|
+
onPlayerStateChange({
|
|
251
|
+
state: state as AudioWaveformPlayerState,
|
|
252
|
+
isPlaying,
|
|
253
|
+
speed: spd,
|
|
254
|
+
error: error && error.length > 0 ? error : undefined,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
: undefined
|
|
258
|
+
}
|
|
259
|
+
onTimeUpdate={
|
|
260
|
+
onTimeUpdate
|
|
261
|
+
? (e: NativeSyntheticEvent<AudioWaveformTimeUpdateEvent>) =>
|
|
262
|
+
onTimeUpdate(e.nativeEvent)
|
|
263
|
+
: undefined
|
|
264
|
+
}
|
|
265
|
+
onSeek={
|
|
266
|
+
onSeek
|
|
267
|
+
? (e: NativeSyntheticEvent<AudioWaveformSeekEvent>) =>
|
|
268
|
+
onSeek(e.nativeEvent)
|
|
269
|
+
: undefined
|
|
270
|
+
}
|
|
271
|
+
onEnd={onEnd ? () => onEnd() : undefined}
|
|
272
|
+
/>
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export const AudioWaveformView = forwardRef<
|
|
277
|
+
AudioWaveformViewRef,
|
|
278
|
+
AudioWaveformViewProps
|
|
279
|
+
>(AudioWaveformViewInner);
|
|
280
|
+
|
|
281
|
+
AudioWaveformView.displayName = 'AudioWaveformView';
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { forwardRef, type ForwardedRef } from 'react';
|
|
2
|
+
import type { ViewProps, ColorValue } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export type AudioWaveformPlayerState =
|
|
5
|
+
| 'idle'
|
|
6
|
+
| 'loading'
|
|
7
|
+
| 'ready'
|
|
8
|
+
| 'ended'
|
|
9
|
+
| 'error';
|
|
10
|
+
|
|
11
|
+
export type AudioWaveformTimeMode = 'count-up' | 'count-down';
|
|
12
|
+
|
|
13
|
+
export type AudioWaveformSource = { uri: string };
|
|
14
|
+
|
|
15
|
+
export type AudioWaveformPlayerStateEvent = {
|
|
16
|
+
state: AudioWaveformPlayerState;
|
|
17
|
+
isPlaying: boolean;
|
|
18
|
+
speed: number;
|
|
19
|
+
error?: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type AudioWaveformTimeUpdateEvent = {
|
|
23
|
+
currentTimeMs: number;
|
|
24
|
+
durationMs: number;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type AudioWaveformSeekEvent = {
|
|
28
|
+
positionMs: number;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type AudioWaveformLoadEvent = {
|
|
32
|
+
durationMs: number;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type AudioWaveformLoadErrorEvent = {
|
|
36
|
+
message: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type AudioWaveformViewProps = Omit<ViewProps, 'children'> & {
|
|
40
|
+
source: AudioWaveformSource;
|
|
41
|
+
samples?: ReadonlyArray<number>;
|
|
42
|
+
playedBarColor?: ColorValue;
|
|
43
|
+
unplayedBarColor?: ColorValue;
|
|
44
|
+
barWidth?: number;
|
|
45
|
+
barGap?: number;
|
|
46
|
+
barRadius?: number;
|
|
47
|
+
barCount?: number;
|
|
48
|
+
containerBackgroundColor?: ColorValue;
|
|
49
|
+
containerBorderRadius?: number;
|
|
50
|
+
showBackground?: boolean;
|
|
51
|
+
showPlayButton?: boolean;
|
|
52
|
+
playButtonColor?: ColorValue;
|
|
53
|
+
showTime?: boolean;
|
|
54
|
+
timeColor?: ColorValue;
|
|
55
|
+
timeMode?: AudioWaveformTimeMode;
|
|
56
|
+
showSpeedControl?: boolean;
|
|
57
|
+
speedColor?: ColorValue;
|
|
58
|
+
speedBackgroundColor?: ColorValue;
|
|
59
|
+
speeds?: ReadonlyArray<number>;
|
|
60
|
+
defaultSpeed?: number;
|
|
61
|
+
autoPlay?: boolean;
|
|
62
|
+
initialPositionMs?: number;
|
|
63
|
+
loop?: boolean;
|
|
64
|
+
playInBackground?: boolean;
|
|
65
|
+
pauseUiUpdatesInBackground?: boolean;
|
|
66
|
+
playing?: boolean;
|
|
67
|
+
speed?: number;
|
|
68
|
+
onLoad?: (event: AudioWaveformLoadEvent) => void;
|
|
69
|
+
onLoadError?: (event: AudioWaveformLoadErrorEvent) => void;
|
|
70
|
+
onPlayerStateChange?: (event: AudioWaveformPlayerStateEvent) => void;
|
|
71
|
+
onTimeUpdate?: (event: AudioWaveformTimeUpdateEvent) => void;
|
|
72
|
+
onSeek?: (event: AudioWaveformSeekEvent) => void;
|
|
73
|
+
onEnd?: () => void;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export type AudioWaveformViewRef = {
|
|
77
|
+
play: () => void;
|
|
78
|
+
pause: () => void;
|
|
79
|
+
toggle: () => void;
|
|
80
|
+
seekTo: (positionMs: number) => void;
|
|
81
|
+
setSpeed: (speed: number) => void;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
function AudioWaveformViewInner(
|
|
85
|
+
_props: AudioWaveformViewProps,
|
|
86
|
+
_ref: ForwardedRef<AudioWaveformViewRef>
|
|
87
|
+
): never {
|
|
88
|
+
throw new Error(
|
|
89
|
+
"'react-native-waveform-player' is only supported on native platforms."
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const AudioWaveformView = forwardRef<
|
|
94
|
+
AudioWaveformViewRef,
|
|
95
|
+
AudioWaveformViewProps
|
|
96
|
+
>(AudioWaveformViewInner);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
codegenNativeComponent,
|
|
3
|
+
codegenNativeCommands,
|
|
4
|
+
type CodegenTypes,
|
|
5
|
+
type ColorValue,
|
|
6
|
+
type HostComponent,
|
|
7
|
+
type ViewProps,
|
|
8
|
+
} from 'react-native';
|
|
9
|
+
|
|
10
|
+
type Source = Readonly<{ uri: string }>;
|
|
11
|
+
|
|
12
|
+
type OnLoadEvent = Readonly<{ durationMs: CodegenTypes.Int32 }>;
|
|
13
|
+
type OnLoadErrorEvent = Readonly<{ message: string }>;
|
|
14
|
+
type OnPlayerStateChangeEvent = Readonly<{
|
|
15
|
+
state: string;
|
|
16
|
+
isPlaying: boolean;
|
|
17
|
+
speed: CodegenTypes.Float;
|
|
18
|
+
error: string;
|
|
19
|
+
}>;
|
|
20
|
+
type OnTimeUpdateEvent = Readonly<{
|
|
21
|
+
currentTimeMs: CodegenTypes.Int32;
|
|
22
|
+
durationMs: CodegenTypes.Int32;
|
|
23
|
+
}>;
|
|
24
|
+
type OnSeekEvent = Readonly<{ positionMs: CodegenTypes.Int32 }>;
|
|
25
|
+
type OnEndEvent = Readonly<{}>;
|
|
26
|
+
|
|
27
|
+
export interface NativeProps extends ViewProps {
|
|
28
|
+
source: Source;
|
|
29
|
+
samples?: ReadonlyArray<CodegenTypes.Float>;
|
|
30
|
+
|
|
31
|
+
playedBarColor?: ColorValue;
|
|
32
|
+
unplayedBarColor?: ColorValue;
|
|
33
|
+
|
|
34
|
+
barWidth?: CodegenTypes.WithDefault<CodegenTypes.Float, 3.0>;
|
|
35
|
+
barGap?: CodegenTypes.WithDefault<CodegenTypes.Float, 2.0>;
|
|
36
|
+
// -1 sentinel = "auto" (barWidth / 2)
|
|
37
|
+
barRadius?: CodegenTypes.WithDefault<CodegenTypes.Float, -1.0>;
|
|
38
|
+
// 0 sentinel = "auto from width"
|
|
39
|
+
barCount?: CodegenTypes.WithDefault<CodegenTypes.Int32, 0>;
|
|
40
|
+
|
|
41
|
+
containerBackgroundColor?: ColorValue;
|
|
42
|
+
containerBorderRadius?: CodegenTypes.WithDefault<CodegenTypes.Float, 16.0>;
|
|
43
|
+
showBackground?: CodegenTypes.WithDefault<boolean, true>;
|
|
44
|
+
|
|
45
|
+
showPlayButton?: CodegenTypes.WithDefault<boolean, true>;
|
|
46
|
+
playButtonColor?: ColorValue;
|
|
47
|
+
|
|
48
|
+
showTime?: CodegenTypes.WithDefault<boolean, true>;
|
|
49
|
+
timeColor?: ColorValue;
|
|
50
|
+
timeMode?: CodegenTypes.WithDefault<'count-up' | 'count-down', 'count-up'>;
|
|
51
|
+
|
|
52
|
+
showSpeedControl?: CodegenTypes.WithDefault<boolean, true>;
|
|
53
|
+
speedColor?: ColorValue;
|
|
54
|
+
speedBackgroundColor?: ColorValue;
|
|
55
|
+
speeds?: ReadonlyArray<CodegenTypes.Float>;
|
|
56
|
+
defaultSpeed?: CodegenTypes.WithDefault<CodegenTypes.Float, 1.0>;
|
|
57
|
+
|
|
58
|
+
autoPlay?: CodegenTypes.WithDefault<boolean, false>;
|
|
59
|
+
initialPositionMs?: CodegenTypes.WithDefault<CodegenTypes.Int32, 0>;
|
|
60
|
+
loop?: CodegenTypes.WithDefault<boolean, false>;
|
|
61
|
+
playInBackground?: CodegenTypes.WithDefault<boolean, false>;
|
|
62
|
+
pauseUiUpdatesInBackground?: CodegenTypes.WithDefault<boolean, true>;
|
|
63
|
+
|
|
64
|
+
// -1 sentinel = "uncontrolled" — internal state drives playback.
|
|
65
|
+
controlledPlaying?: CodegenTypes.WithDefault<CodegenTypes.Int32, -1>;
|
|
66
|
+
// -1 sentinel = "uncontrolled" — internal state drives speed.
|
|
67
|
+
controlledSpeed?: CodegenTypes.WithDefault<CodegenTypes.Float, -1.0>;
|
|
68
|
+
|
|
69
|
+
onLoad?: CodegenTypes.DirectEventHandler<OnLoadEvent>;
|
|
70
|
+
onLoadError?: CodegenTypes.DirectEventHandler<OnLoadErrorEvent>;
|
|
71
|
+
onPlayerStateChange?: CodegenTypes.DirectEventHandler<OnPlayerStateChangeEvent>;
|
|
72
|
+
onTimeUpdate?: CodegenTypes.DirectEventHandler<OnTimeUpdateEvent>;
|
|
73
|
+
onSeek?: CodegenTypes.DirectEventHandler<OnSeekEvent>;
|
|
74
|
+
onEnd?: CodegenTypes.DirectEventHandler<OnEndEvent>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface NativeCommands {
|
|
78
|
+
play: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
79
|
+
pause: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
80
|
+
toggle: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
81
|
+
seekTo: (
|
|
82
|
+
viewRef: React.ElementRef<HostComponent<NativeProps>>,
|
|
83
|
+
positionMs: CodegenTypes.Int32
|
|
84
|
+
) => void;
|
|
85
|
+
setSpeed: (
|
|
86
|
+
viewRef: React.ElementRef<HostComponent<NativeProps>>,
|
|
87
|
+
speed: CodegenTypes.Float
|
|
88
|
+
) => void;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
|
|
92
|
+
supportedCommands: ['play', 'pause', 'toggle', 'seekTo', 'setSpeed'],
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
export default codegenNativeComponent<NativeProps>('AudioWaveformView');
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { AudioWaveformView } from './AudioWaveformView';
|
|
2
|
+
export type {
|
|
3
|
+
AudioWaveformViewProps,
|
|
4
|
+
AudioWaveformViewRef,
|
|
5
|
+
AudioWaveformPlayerState,
|
|
6
|
+
AudioWaveformPlayerStateEvent,
|
|
7
|
+
AudioWaveformTimeUpdateEvent,
|
|
8
|
+
AudioWaveformSeekEvent,
|
|
9
|
+
AudioWaveformLoadEvent,
|
|
10
|
+
AudioWaveformLoadErrorEvent,
|
|
11
|
+
AudioWaveformTimeMode,
|
|
12
|
+
AudioWaveformSource,
|
|
13
|
+
} from './AudioWaveformView';
|