@exode-team/react-recorder 1.1.8 → 1.1.10
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/dist/components/VoiceMessagePlayer/VoiceMessagePlayer.d.ts +1 -0
- package/dist/components/VoiceMessagePlayer/VoiceMessagePlayer.d.ts.map +1 -1
- package/dist/hooks/useAudioBlobLoader.d.ts.map +1 -1
- package/dist/hooks/useAudioPlayback.d.ts.map +1 -1
- package/dist/hooks/useVoiceMessagePlayer.d.ts.map +1 -1
- package/dist/index.cjs +154 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +154 -5
- package/dist/index.js.map +1 -1
- package/dist/platform/audio-playback-adapter.d.ts +7 -0
- package/dist/platform/audio-playback-adapter.d.ts.map +1 -1
- package/dist/types/recorder.d.ts +4 -1
- package/dist/types/recorder.d.ts.map +1 -1
- package/dist/utils/voice-playback-chain.d.ts +2 -0
- package/dist/utils/voice-playback-chain.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoiceMessagePlayer.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceMessagePlayer/VoiceMessagePlayer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AA0BH,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,QAAQ,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"VoiceMessagePlayer.d.ts","sourceRoot":"","sources":["../../../src/components/VoiceMessagePlayer/VoiceMessagePlayer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AA0BH,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAeD,QAAA,MAAM,kBAAkB,KAqOtB,CAAC;AAGH,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAudioBlobLoader.d.ts","sourceRoot":"","sources":["../../src/hooks/useAudioBlobLoader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAYrD,UAAU,yBAAyB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC5B,iBAAiB,EAAE,iBAAiB,CAAC;CACxC;AAED,UAAU,wBAAwB;IAC9B,QAAQ,EAAE,KAAK,CAAC,gBAAgB,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC1D,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,QAAA,MAAM,kBAAkB,GAAI,SAAS,yBAAyB,KAAG,
|
|
1
|
+
{"version":3,"file":"useAudioBlobLoader.d.ts","sourceRoot":"","sources":["../../src/hooks/useAudioBlobLoader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAYrD,UAAU,yBAAyB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC5B,iBAAiB,EAAE,iBAAiB,CAAC;CACxC;AAED,UAAU,wBAAwB;IAC9B,QAAQ,EAAE,KAAK,CAAC,gBAAgB,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC1D,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,QAAA,MAAM,kBAAkB,GAAI,SAAS,yBAAyB,KAAG,wBA2IhE,CAAC;AAGF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAudioPlayback.d.ts","sourceRoot":"","sources":["../../src/hooks/useAudioPlayback.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,UAAU,sBAAsB;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC;IAClC,cAAc,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,KAAK,IAAI,CAAC;IAC7D,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,mBAAmB,EAAE,MAAM,IAAI,CAAC;CACnC;AAED,QAAA,MAAM,gBAAgB,QAAO,
|
|
1
|
+
{"version":3,"file":"useAudioPlayback.d.ts","sourceRoot":"","sources":["../../src/hooks/useAudioPlayback.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,UAAU,sBAAsB;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC;IAClC,cAAc,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,KAAK,IAAI,CAAC;IAC7D,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,mBAAmB,EAAE,MAAM,IAAI,CAAC;CACnC;AAED,QAAA,MAAM,gBAAgB,QAAO,sBA+H5B,CAAC;AAGF,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useVoiceMessagePlayer.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoiceMessagePlayer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AAG1F,QAAA,MAAM,qBAAqB,GAAI,SAAS,4BAA4B,KAAG,
|
|
1
|
+
{"version":3,"file":"useVoiceMessagePlayer.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoiceMessagePlayer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AAG1F,QAAA,MAAM,qBAAqB,GAAI,SAAS,4BAA4B,KAAG,2BAmNtE,CAAC;AAGF,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
|
package/dist/index.cjs
CHANGED
|
@@ -78,6 +78,61 @@ const stopStream = (stream) => {
|
|
|
78
78
|
*
|
|
79
79
|
* @author: exode <hello@exode.ru>
|
|
80
80
|
*/
|
|
81
|
+
const SEEK_OFFSET = 5;
|
|
82
|
+
const setupMediaSession = (audio, callbacks) => {
|
|
83
|
+
if (!('mediaSession' in navigator)) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
navigator.mediaSession.setActionHandler('play', () => {
|
|
87
|
+
audio.play().catch(() => { });
|
|
88
|
+
});
|
|
89
|
+
navigator.mediaSession.setActionHandler('pause', () => {
|
|
90
|
+
audio.pause();
|
|
91
|
+
});
|
|
92
|
+
navigator.mediaSession.setActionHandler('stop', () => {
|
|
93
|
+
var _a;
|
|
94
|
+
audio.pause();
|
|
95
|
+
audio.currentTime = 0;
|
|
96
|
+
(_a = callbacks.onStop) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
97
|
+
});
|
|
98
|
+
navigator.mediaSession.setActionHandler('seekbackward', () => {
|
|
99
|
+
var _a;
|
|
100
|
+
audio.currentTime = Math.max(0, audio.currentTime - SEEK_OFFSET);
|
|
101
|
+
(_a = callbacks.onSeekBackward) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
102
|
+
});
|
|
103
|
+
navigator.mediaSession.setActionHandler('seekforward', () => {
|
|
104
|
+
var _a;
|
|
105
|
+
audio.currentTime = Math.min(audio.duration, audio.currentTime + SEEK_OFFSET);
|
|
106
|
+
(_a = callbacks.onSeekForward) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
107
|
+
});
|
|
108
|
+
navigator.mediaSession.setActionHandler('seekto', (details) => {
|
|
109
|
+
if (details.seekTime != null && isFinite(audio.duration)) {
|
|
110
|
+
audio.currentTime = details.seekTime;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
navigator.mediaSession.setActionHandler('previoustrack', () => {
|
|
114
|
+
var _a;
|
|
115
|
+
(_a = callbacks.onPreviousTrack) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
116
|
+
});
|
|
117
|
+
navigator.mediaSession.setActionHandler('nexttrack', () => {
|
|
118
|
+
var _a;
|
|
119
|
+
(_a = callbacks.onNextTrack) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
const clearMediaSession = () => {
|
|
123
|
+
if (!('mediaSession' in navigator)) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const actions = [
|
|
127
|
+
'play', 'pause', 'stop',
|
|
128
|
+
'seekbackward', 'seekforward', 'seekto',
|
|
129
|
+
'previoustrack', 'nexttrack',
|
|
130
|
+
];
|
|
131
|
+
actions.forEach((action) => {
|
|
132
|
+
navigator.mediaSession.setActionHandler(action, null);
|
|
133
|
+
});
|
|
134
|
+
navigator.mediaSession.playbackState = 'none';
|
|
135
|
+
};
|
|
81
136
|
const createAudioPlayback = (url, callbacks) => {
|
|
82
137
|
const audio = new Audio(url);
|
|
83
138
|
audio.onloadedmetadata = () => {
|
|
@@ -89,6 +144,21 @@ const createAudioPlayback = (url, callbacks) => {
|
|
|
89
144
|
audio.onended = () => {
|
|
90
145
|
callbacks.onEnded();
|
|
91
146
|
};
|
|
147
|
+
audio.onplay = () => {
|
|
148
|
+
var _a;
|
|
149
|
+
setupMediaSession(audio, callbacks);
|
|
150
|
+
if ('mediaSession' in navigator) {
|
|
151
|
+
navigator.mediaSession.playbackState = 'playing';
|
|
152
|
+
}
|
|
153
|
+
(_a = callbacks.onPlay) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
154
|
+
};
|
|
155
|
+
audio.onpause = () => {
|
|
156
|
+
var _a;
|
|
157
|
+
if ('mediaSession' in navigator) {
|
|
158
|
+
navigator.mediaSession.playbackState = 'paused';
|
|
159
|
+
}
|
|
160
|
+
(_a = callbacks.onPause) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
161
|
+
};
|
|
92
162
|
return { audio, url };
|
|
93
163
|
};
|
|
94
164
|
const cleanupAudio = (audio) => {
|
|
@@ -97,6 +167,9 @@ const cleanupAudio = (audio) => {
|
|
|
97
167
|
audio.onended = null;
|
|
98
168
|
audio.ontimeupdate = null;
|
|
99
169
|
audio.onloadedmetadata = null;
|
|
170
|
+
audio.onplay = null;
|
|
171
|
+
audio.onpause = null;
|
|
172
|
+
clearMediaSession();
|
|
100
173
|
};
|
|
101
174
|
const createObjectURL = (blob) => {
|
|
102
175
|
return URL.createObjectURL(blob);
|
|
@@ -366,6 +439,8 @@ const useAudioPlayback = () => {
|
|
|
366
439
|
setIsPlaying(false);
|
|
367
440
|
setPlaybackTime(0);
|
|
368
441
|
},
|
|
442
|
+
onPlay: () => setIsPlaying(true),
|
|
443
|
+
onPause: () => setIsPlaying(false),
|
|
369
444
|
});
|
|
370
445
|
audioRef.current = audio;
|
|
371
446
|
setPlaybackTime(0);
|
|
@@ -385,6 +460,8 @@ const useAudioPlayback = () => {
|
|
|
385
460
|
setIsPlaying(false);
|
|
386
461
|
setPlaybackTime(0);
|
|
387
462
|
},
|
|
463
|
+
onPlay: () => setIsPlaying(true),
|
|
464
|
+
onPause: () => setIsPlaying(false),
|
|
388
465
|
});
|
|
389
466
|
audioRef.current = audio;
|
|
390
467
|
}
|
|
@@ -825,6 +902,13 @@ const useAudioBlobLoader = (options) => {
|
|
|
825
902
|
onLoadedMetadata: (dur) => callbacksRef.current.onLoadedMetadata(dur),
|
|
826
903
|
onTimeUpdate: (time) => callbacksRef.current.onTimeUpdate(time),
|
|
827
904
|
onEnded: () => callbacksRef.current.onEnded(),
|
|
905
|
+
onPlay: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onPlay) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
906
|
+
onPause: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onPause) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
907
|
+
onStop: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onStop) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
908
|
+
onSeekBackward: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onSeekBackward) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
909
|
+
onSeekForward: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onSeekForward) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
910
|
+
onPreviousTrack: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onPreviousTrack) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
911
|
+
onNextTrack: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onNextTrack) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
828
912
|
});
|
|
829
913
|
audioRef.current = audio;
|
|
830
914
|
setIsLoaded(true);
|
|
@@ -955,9 +1039,13 @@ const audioPlaybackManager = {
|
|
|
955
1039
|
* @author: exode <hello@exode.ru>
|
|
956
1040
|
*/
|
|
957
1041
|
const useVoiceMessagePlayer = (options) => {
|
|
958
|
-
const { src, onEnded, waveformData, preloadedBlob, duration: externalDuration, } = options;
|
|
1042
|
+
const { src, onEnded, onPreviousTrack, onNextTrack, waveformData, preloadedBlob, duration: externalDuration, } = options;
|
|
959
1043
|
const onEndedRef = React.useRef(onEnded);
|
|
1044
|
+
const onPreviousTrackRef = React.useRef(onPreviousTrack);
|
|
1045
|
+
const onNextTrackRef = React.useRef(onNextTrack);
|
|
960
1046
|
onEndedRef.current = onEnded;
|
|
1047
|
+
onPreviousTrackRef.current = onPreviousTrack;
|
|
1048
|
+
onNextTrackRef.current = onNextTrack;
|
|
961
1049
|
const [isPlaying, setIsPlaying] = React.useState(false);
|
|
962
1050
|
const [currentTime, setCurrentTime] = React.useState(0);
|
|
963
1051
|
const [duration, setDuration] = React.useState(externalDuration || 0);
|
|
@@ -991,6 +1079,14 @@ const useVoiceMessagePlayer = (options) => {
|
|
|
991
1079
|
setCurrentTime(0);
|
|
992
1080
|
(_a = onEndedRef.current) === null || _a === void 0 ? void 0 : _a.call(onEndedRef);
|
|
993
1081
|
},
|
|
1082
|
+
onPlay: () => setIsPlaying(true),
|
|
1083
|
+
onPause: () => setIsPlaying(false),
|
|
1084
|
+
onStop: () => {
|
|
1085
|
+
setIsPlaying(false);
|
|
1086
|
+
setCurrentTime(0);
|
|
1087
|
+
},
|
|
1088
|
+
onPreviousTrack: () => { var _a; return (_a = onPreviousTrackRef.current) === null || _a === void 0 ? void 0 : _a.call(onPreviousTrackRef); },
|
|
1089
|
+
onNextTrack: () => { var _a; return (_a = onNextTrackRef.current) === null || _a === void 0 ? void 0 : _a.call(onNextTrackRef); },
|
|
994
1090
|
},
|
|
995
1091
|
});
|
|
996
1092
|
/** Pre-fetch audio without playing (for viewport preloading) */
|
|
@@ -1045,15 +1141,44 @@ const useVoiceMessagePlayer = (options) => {
|
|
|
1045
1141
|
setIsPlaying(false);
|
|
1046
1142
|
}
|
|
1047
1143
|
}, [isLoading, stopThis, audioRef]);
|
|
1048
|
-
const seekTo = React.useCallback((
|
|
1144
|
+
const seekTo = React.useCallback((seekPercent) => {
|
|
1049
1145
|
const audio = audioRef.current;
|
|
1050
1146
|
if (!audio || !isFinite(audio.duration)) {
|
|
1051
1147
|
return;
|
|
1052
1148
|
}
|
|
1053
|
-
const time =
|
|
1149
|
+
const time = seekPercent * audio.duration;
|
|
1054
1150
|
audio.currentTime = time;
|
|
1055
1151
|
setCurrentTime(time);
|
|
1056
1152
|
}, [audioRef]);
|
|
1153
|
+
/** Seek to a specific time in seconds and start playback */
|
|
1154
|
+
const seekToTime = React.useCallback((seconds) => {
|
|
1155
|
+
const audio = audioRef.current;
|
|
1156
|
+
if (audio && isFinite(audio.duration)) {
|
|
1157
|
+
audioPlaybackManager.stopOthers(stopThis);
|
|
1158
|
+
audio.currentTime = Math.max(0, Math.min(seconds, audio.duration));
|
|
1159
|
+
setCurrentTime(audio.currentTime);
|
|
1160
|
+
audio.play()
|
|
1161
|
+
.then(() => setIsPlaying(true))
|
|
1162
|
+
.catch(() => setIsPlaying(false));
|
|
1163
|
+
}
|
|
1164
|
+
else {
|
|
1165
|
+
void ensureAudioLoaded().then(() => {
|
|
1166
|
+
const loadedAudio = audioRef.current;
|
|
1167
|
+
if (loadedAudio) {
|
|
1168
|
+
audioPlaybackManager.stopOthers(stopThis);
|
|
1169
|
+
loadedAudio.currentTime = Math.max(0, Math.min(seconds, loadedAudio.duration || seconds));
|
|
1170
|
+
setCurrentTime(loadedAudio.currentTime);
|
|
1171
|
+
loadedAudio.play()
|
|
1172
|
+
.then(() => setIsPlaying(true))
|
|
1173
|
+
.catch(() => setIsPlaying(false));
|
|
1174
|
+
}
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
}, [
|
|
1178
|
+
audioRef,
|
|
1179
|
+
stopThis,
|
|
1180
|
+
ensureAudioLoaded,
|
|
1181
|
+
]);
|
|
1057
1182
|
/** Sync external duration */
|
|
1058
1183
|
React.useEffect(() => {
|
|
1059
1184
|
if (externalDuration) {
|
|
@@ -1070,6 +1195,7 @@ const useVoiceMessagePlayer = (options) => {
|
|
|
1070
1195
|
currentTime,
|
|
1071
1196
|
waveformLevels,
|
|
1072
1197
|
seekTo,
|
|
1198
|
+
seekToTime,
|
|
1073
1199
|
prefetch,
|
|
1074
1200
|
preload,
|
|
1075
1201
|
formatTime,
|
|
@@ -2108,6 +2234,13 @@ class VoicePlaybackChainClass {
|
|
|
2108
2234
|
this.entries[idx + 1].play();
|
|
2109
2235
|
}
|
|
2110
2236
|
};
|
|
2237
|
+
/** Play the previous voice message before the given media ID */
|
|
2238
|
+
this.playPrevious = (currentId) => {
|
|
2239
|
+
const idx = this.entries.findIndex((e) => e.id === currentId);
|
|
2240
|
+
if (idx > 0) {
|
|
2241
|
+
this.entries[idx - 1].play();
|
|
2242
|
+
}
|
|
2243
|
+
};
|
|
2111
2244
|
}
|
|
2112
2245
|
}
|
|
2113
2246
|
const VoicePlaybackChain = new VoicePlaybackChainClass();
|
|
@@ -2215,14 +2348,30 @@ const VoiceMessagePlayer = React.forwardRef((props, ref) => {
|
|
|
2215
2348
|
VoicePlaybackChain.playNext(chainId);
|
|
2216
2349
|
}
|
|
2217
2350
|
}, [onEnded, chainId]);
|
|
2218
|
-
const
|
|
2351
|
+
const handleNextTrack = React.useCallback(() => {
|
|
2352
|
+
if (chainId != null) {
|
|
2353
|
+
VoicePlaybackChain.playNext(chainId);
|
|
2354
|
+
}
|
|
2355
|
+
}, [chainId]);
|
|
2356
|
+
const handlePreviousTrack = React.useCallback(() => {
|
|
2357
|
+
if (chainId != null) {
|
|
2358
|
+
VoicePlaybackChain.playPrevious(chainId);
|
|
2359
|
+
}
|
|
2360
|
+
}, [chainId]);
|
|
2361
|
+
const { play, progress, isLoaded, isPlaying, isLoading, currentTime, waveformLevels, seekTo, seekToTime, prefetch, preload, formatTime, togglePlayback, duration: resolvedDuration, } = useVoiceMessagePlayer({
|
|
2219
2362
|
src,
|
|
2220
2363
|
duration,
|
|
2221
2364
|
waveformData,
|
|
2222
2365
|
preloadedBlob: props.preloadedBlob,
|
|
2223
2366
|
onEnded: handleEnded,
|
|
2367
|
+
onNextTrack: handleNextTrack,
|
|
2368
|
+
onPreviousTrack: handlePreviousTrack,
|
|
2224
2369
|
});
|
|
2225
|
-
React.useImperativeHandle(ref, () => ({ play, prefetch }), [
|
|
2370
|
+
React.useImperativeHandle(ref, () => ({ play, prefetch, seekToTime }), [
|
|
2371
|
+
play,
|
|
2372
|
+
prefetch,
|
|
2373
|
+
seekToTime,
|
|
2374
|
+
]);
|
|
2226
2375
|
/** Auto-preload audio when player enters viewport */
|
|
2227
2376
|
React.useEffect(() => {
|
|
2228
2377
|
if (!autoPreload || isLoaded || isLoading) {
|