I'm trying to make an autoplay of audio files from an array, using the react-audio-player. I want to play each audio twice, and then automatically move to the next one.
I found a way to automatically play all the audios, but when I want to play the same audio second time, the player stops. So it plays the first audio, stops, then I click play again and it plays the first audio again and advances to the second, and then stops again.
I think the problem is that since the audio URL doesn't change, the player doesn't recognize it as a new audio.
I can't find almost any threads related to this issue, as it's quite specific. I will appreciate any help.
const userItems = [{ "MP3": "https://www2.cs.uic.edu/~i101/SoundFiles/CantinaBand3.wav" }, { "MP3": "https://www2.cs.uic.edu/~i101/SoundFiles/CantinaBand3.wav" }, { "MP3": "https://www2.cs.uic.edu/~i101/SoundFiles/Fanfare60.wav" }]
const [repeatAudio, setRepeatAudio] = useState(true); // Determine if the audio has been played already
const [currentAudioIndex, setCurrentAudioIndex] = useState(0);
const audioSrc = userItems[currentAudioIndex].MP3
function setNextAudio() {
if (repeatAudio) { // If the audio hasn't been played, keep same audio index
setCurrentAudioIndex(i => i + 0)
setRepeatAudio(false)
} else { // If it has been played, jump to the next index
setCurrentAudioIndex(i => i + 1)
setRepeatAudio(true)
}
}
return (
<div>
<ReactAudioPlayer
src={audioSrc}
autoPlay
controls
onEnded={() => setNextAudio()}
/>
</div>
)
}
I've cleaned this up a bit to make it easier to understand, but yes the key bit is the "replay" doesn't involve a URL change, and so autoPlay
doesn't kick in. You have to manage that yourself by getting a reference to the audio element and prodding it directly.
import React, { useState, useRef } from "react";
import ReactAudioPlayer from "react-audio-player";
const userItems = [
{ MP3: "https://www2.cs.uic.edu/~i101/SoundFiles/CantinaBand3.wav" },
{ MP3: "https://www2.cs.uic.edu/~i101/SoundFiles/Fanfare60.wav" }
];
const PlayTwicePlayer = () => {
const [audioPointer, setAudioPointer] = useState({
index: 0,
playedOnce: false
});
const audioPlayerRef = useRef(null);
const audioSrc = userItems[audioPointer.index].MP3;
function handleAudioEnded() {
// Dont proceed to next track if already at the end of the array
if (audioPointer.index >= userItems.length - 1) return;
if (audioPointer.playedOnce) {
// If they already played it, that means we just finished playing it a second time, and need to move to the next track.
setAudioPointer((prev) => ({
index: prev.index + 1,
playedOnce: false
}));
return;
} else {
// If they hadn't already played it, we just finished the first run so we can set playedOnce to true now.
// We must additionally seek back to 0 and play manually using a reference to the player because autoPlay does not
// trigger since the URL didn't change.
setAudioPointer((prev) => ({ ...prev, playedOnce: true }));
audioPlayerRef.current.currentTime = 0;
audioPlayerRef.current.play();
return;
}
}
return (
<div>
<ReactAudioPlayer
src={audioSrc}
autoPlay
controls
onEnded={handleAudioEnded}
ref={(ref) => {
if (!ref) return;
audioPlayerRef.current = ref.audioEl.current;
}}
/>
</div>
);
};
Note this won't give you seamless transitions. To do that you'd need the WebAudio API. Easy library wrappers for it exist like https://github.com/t-mullen/video-stream-merger and https://github.com/jaggad/crunker.