@exode-team/react-recorder 1.1.9 → 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.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 +116 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +116 -1
- 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 +2 -0
- 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
package/dist/index.js
CHANGED
|
@@ -76,6 +76,61 @@ const stopStream = (stream) => {
|
|
|
76
76
|
*
|
|
77
77
|
* @author: exode <hello@exode.ru>
|
|
78
78
|
*/
|
|
79
|
+
const SEEK_OFFSET = 5;
|
|
80
|
+
const setupMediaSession = (audio, callbacks) => {
|
|
81
|
+
if (!('mediaSession' in navigator)) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
navigator.mediaSession.setActionHandler('play', () => {
|
|
85
|
+
audio.play().catch(() => { });
|
|
86
|
+
});
|
|
87
|
+
navigator.mediaSession.setActionHandler('pause', () => {
|
|
88
|
+
audio.pause();
|
|
89
|
+
});
|
|
90
|
+
navigator.mediaSession.setActionHandler('stop', () => {
|
|
91
|
+
var _a;
|
|
92
|
+
audio.pause();
|
|
93
|
+
audio.currentTime = 0;
|
|
94
|
+
(_a = callbacks.onStop) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
95
|
+
});
|
|
96
|
+
navigator.mediaSession.setActionHandler('seekbackward', () => {
|
|
97
|
+
var _a;
|
|
98
|
+
audio.currentTime = Math.max(0, audio.currentTime - SEEK_OFFSET);
|
|
99
|
+
(_a = callbacks.onSeekBackward) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
100
|
+
});
|
|
101
|
+
navigator.mediaSession.setActionHandler('seekforward', () => {
|
|
102
|
+
var _a;
|
|
103
|
+
audio.currentTime = Math.min(audio.duration, audio.currentTime + SEEK_OFFSET);
|
|
104
|
+
(_a = callbacks.onSeekForward) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
105
|
+
});
|
|
106
|
+
navigator.mediaSession.setActionHandler('seekto', (details) => {
|
|
107
|
+
if (details.seekTime != null && isFinite(audio.duration)) {
|
|
108
|
+
audio.currentTime = details.seekTime;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
navigator.mediaSession.setActionHandler('previoustrack', () => {
|
|
112
|
+
var _a;
|
|
113
|
+
(_a = callbacks.onPreviousTrack) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
114
|
+
});
|
|
115
|
+
navigator.mediaSession.setActionHandler('nexttrack', () => {
|
|
116
|
+
var _a;
|
|
117
|
+
(_a = callbacks.onNextTrack) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
const clearMediaSession = () => {
|
|
121
|
+
if (!('mediaSession' in navigator)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const actions = [
|
|
125
|
+
'play', 'pause', 'stop',
|
|
126
|
+
'seekbackward', 'seekforward', 'seekto',
|
|
127
|
+
'previoustrack', 'nexttrack',
|
|
128
|
+
];
|
|
129
|
+
actions.forEach((action) => {
|
|
130
|
+
navigator.mediaSession.setActionHandler(action, null);
|
|
131
|
+
});
|
|
132
|
+
navigator.mediaSession.playbackState = 'none';
|
|
133
|
+
};
|
|
79
134
|
const createAudioPlayback = (url, callbacks) => {
|
|
80
135
|
const audio = new Audio(url);
|
|
81
136
|
audio.onloadedmetadata = () => {
|
|
@@ -87,6 +142,21 @@ const createAudioPlayback = (url, callbacks) => {
|
|
|
87
142
|
audio.onended = () => {
|
|
88
143
|
callbacks.onEnded();
|
|
89
144
|
};
|
|
145
|
+
audio.onplay = () => {
|
|
146
|
+
var _a;
|
|
147
|
+
setupMediaSession(audio, callbacks);
|
|
148
|
+
if ('mediaSession' in navigator) {
|
|
149
|
+
navigator.mediaSession.playbackState = 'playing';
|
|
150
|
+
}
|
|
151
|
+
(_a = callbacks.onPlay) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
152
|
+
};
|
|
153
|
+
audio.onpause = () => {
|
|
154
|
+
var _a;
|
|
155
|
+
if ('mediaSession' in navigator) {
|
|
156
|
+
navigator.mediaSession.playbackState = 'paused';
|
|
157
|
+
}
|
|
158
|
+
(_a = callbacks.onPause) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
159
|
+
};
|
|
90
160
|
return { audio, url };
|
|
91
161
|
};
|
|
92
162
|
const cleanupAudio = (audio) => {
|
|
@@ -95,6 +165,9 @@ const cleanupAudio = (audio) => {
|
|
|
95
165
|
audio.onended = null;
|
|
96
166
|
audio.ontimeupdate = null;
|
|
97
167
|
audio.onloadedmetadata = null;
|
|
168
|
+
audio.onplay = null;
|
|
169
|
+
audio.onpause = null;
|
|
170
|
+
clearMediaSession();
|
|
98
171
|
};
|
|
99
172
|
const createObjectURL = (blob) => {
|
|
100
173
|
return URL.createObjectURL(blob);
|
|
@@ -364,6 +437,8 @@ const useAudioPlayback = () => {
|
|
|
364
437
|
setIsPlaying(false);
|
|
365
438
|
setPlaybackTime(0);
|
|
366
439
|
},
|
|
440
|
+
onPlay: () => setIsPlaying(true),
|
|
441
|
+
onPause: () => setIsPlaying(false),
|
|
367
442
|
});
|
|
368
443
|
audioRef.current = audio;
|
|
369
444
|
setPlaybackTime(0);
|
|
@@ -383,6 +458,8 @@ const useAudioPlayback = () => {
|
|
|
383
458
|
setIsPlaying(false);
|
|
384
459
|
setPlaybackTime(0);
|
|
385
460
|
},
|
|
461
|
+
onPlay: () => setIsPlaying(true),
|
|
462
|
+
onPause: () => setIsPlaying(false),
|
|
386
463
|
});
|
|
387
464
|
audioRef.current = audio;
|
|
388
465
|
}
|
|
@@ -823,6 +900,13 @@ const useAudioBlobLoader = (options) => {
|
|
|
823
900
|
onLoadedMetadata: (dur) => callbacksRef.current.onLoadedMetadata(dur),
|
|
824
901
|
onTimeUpdate: (time) => callbacksRef.current.onTimeUpdate(time),
|
|
825
902
|
onEnded: () => callbacksRef.current.onEnded(),
|
|
903
|
+
onPlay: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onPlay) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
904
|
+
onPause: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onPause) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
905
|
+
onStop: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onStop) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
906
|
+
onSeekBackward: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onSeekBackward) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
907
|
+
onSeekForward: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onSeekForward) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
908
|
+
onPreviousTrack: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onPreviousTrack) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
909
|
+
onNextTrack: () => { var _a, _b; return (_b = (_a = callbacksRef.current).onNextTrack) === null || _b === void 0 ? void 0 : _b.call(_a); },
|
|
826
910
|
});
|
|
827
911
|
audioRef.current = audio;
|
|
828
912
|
setIsLoaded(true);
|
|
@@ -953,9 +1037,13 @@ const audioPlaybackManager = {
|
|
|
953
1037
|
* @author: exode <hello@exode.ru>
|
|
954
1038
|
*/
|
|
955
1039
|
const useVoiceMessagePlayer = (options) => {
|
|
956
|
-
const { src, onEnded, waveformData, preloadedBlob, duration: externalDuration, } = options;
|
|
1040
|
+
const { src, onEnded, onPreviousTrack, onNextTrack, waveformData, preloadedBlob, duration: externalDuration, } = options;
|
|
957
1041
|
const onEndedRef = useRef(onEnded);
|
|
1042
|
+
const onPreviousTrackRef = useRef(onPreviousTrack);
|
|
1043
|
+
const onNextTrackRef = useRef(onNextTrack);
|
|
958
1044
|
onEndedRef.current = onEnded;
|
|
1045
|
+
onPreviousTrackRef.current = onPreviousTrack;
|
|
1046
|
+
onNextTrackRef.current = onNextTrack;
|
|
959
1047
|
const [isPlaying, setIsPlaying] = useState(false);
|
|
960
1048
|
const [currentTime, setCurrentTime] = useState(0);
|
|
961
1049
|
const [duration, setDuration] = useState(externalDuration || 0);
|
|
@@ -989,6 +1077,14 @@ const useVoiceMessagePlayer = (options) => {
|
|
|
989
1077
|
setCurrentTime(0);
|
|
990
1078
|
(_a = onEndedRef.current) === null || _a === void 0 ? void 0 : _a.call(onEndedRef);
|
|
991
1079
|
},
|
|
1080
|
+
onPlay: () => setIsPlaying(true),
|
|
1081
|
+
onPause: () => setIsPlaying(false),
|
|
1082
|
+
onStop: () => {
|
|
1083
|
+
setIsPlaying(false);
|
|
1084
|
+
setCurrentTime(0);
|
|
1085
|
+
},
|
|
1086
|
+
onPreviousTrack: () => { var _a; return (_a = onPreviousTrackRef.current) === null || _a === void 0 ? void 0 : _a.call(onPreviousTrackRef); },
|
|
1087
|
+
onNextTrack: () => { var _a; return (_a = onNextTrackRef.current) === null || _a === void 0 ? void 0 : _a.call(onNextTrackRef); },
|
|
992
1088
|
},
|
|
993
1089
|
});
|
|
994
1090
|
/** Pre-fetch audio without playing (for viewport preloading) */
|
|
@@ -2136,6 +2232,13 @@ class VoicePlaybackChainClass {
|
|
|
2136
2232
|
this.entries[idx + 1].play();
|
|
2137
2233
|
}
|
|
2138
2234
|
};
|
|
2235
|
+
/** Play the previous voice message before the given media ID */
|
|
2236
|
+
this.playPrevious = (currentId) => {
|
|
2237
|
+
const idx = this.entries.findIndex((e) => e.id === currentId);
|
|
2238
|
+
if (idx > 0) {
|
|
2239
|
+
this.entries[idx - 1].play();
|
|
2240
|
+
}
|
|
2241
|
+
};
|
|
2139
2242
|
}
|
|
2140
2243
|
}
|
|
2141
2244
|
const VoicePlaybackChain = new VoicePlaybackChainClass();
|
|
@@ -2243,12 +2346,24 @@ const VoiceMessagePlayer = React.forwardRef((props, ref) => {
|
|
|
2243
2346
|
VoicePlaybackChain.playNext(chainId);
|
|
2244
2347
|
}
|
|
2245
2348
|
}, [onEnded, chainId]);
|
|
2349
|
+
const handleNextTrack = useCallback(() => {
|
|
2350
|
+
if (chainId != null) {
|
|
2351
|
+
VoicePlaybackChain.playNext(chainId);
|
|
2352
|
+
}
|
|
2353
|
+
}, [chainId]);
|
|
2354
|
+
const handlePreviousTrack = useCallback(() => {
|
|
2355
|
+
if (chainId != null) {
|
|
2356
|
+
VoicePlaybackChain.playPrevious(chainId);
|
|
2357
|
+
}
|
|
2358
|
+
}, [chainId]);
|
|
2246
2359
|
const { play, progress, isLoaded, isPlaying, isLoading, currentTime, waveformLevels, seekTo, seekToTime, prefetch, preload, formatTime, togglePlayback, duration: resolvedDuration, } = useVoiceMessagePlayer({
|
|
2247
2360
|
src,
|
|
2248
2361
|
duration,
|
|
2249
2362
|
waveformData,
|
|
2250
2363
|
preloadedBlob: props.preloadedBlob,
|
|
2251
2364
|
onEnded: handleEnded,
|
|
2365
|
+
onNextTrack: handleNextTrack,
|
|
2366
|
+
onPreviousTrack: handlePreviousTrack,
|
|
2252
2367
|
});
|
|
2253
2368
|
useImperativeHandle(ref, () => ({ play, prefetch, seekToTime }), [
|
|
2254
2369
|
play,
|