Home > Enterprise >  AudioPlayer does not play after changing track
AudioPlayer does not play after changing track

Time:01-16

I want to create an audioplayer on React Nextjs, with some dots, each one corresponding to an audio track. When I click on a dot, it pause the track that currently is playing, if there is one, and play the new one instead.

I have some playing problems. When I arrive on the page and click on a dots, I need to click it 3 times to play the track. If I click on a new one, I need to click 2 times to play the new one.

Here is the code :

AudioPlayer.js

import React, { useState, useRef, useEffect } from 'react';

const AudioPlayer = () => {
    // state
    const [isPlaying, setIsPLaying] = useState(false);
    const [duration, setDuration] = useState(0);
    const [currentTime, setCurrentTime] = useState(0);
    const [currentTrack, setCurrentTrack] = useState(null)

    // references
    const audioPlayer = useRef(); //reference to our audioplayer
    const progressBar = useRef(); //reference to our progressBar
    const animationRef = useRef() //reference the animation

    useEffect(() => {
        const seconds = Math.floor(audioPlayer.current.duration)
        setDuration(seconds);
        progressBar.current.max = seconds;
    }, [audioPlayer?.current?.loadmetadata, audioPlayer?.current?.readyState])

    const togglePlayPause = () => {
        const prevValue = isPlaying;
        setIsPLaying(!prevValue);
        if (!prevValue) {
            audioPlayer.current.play();
            animationRef.current = requestAnimationFrame(whilePlaying);
        } else {
            audioPlayer.current.pause();
            cancelAnimationFrame(animationRef.current);
        }
    }

    const whilePlaying = () => {
        progressBar.current.value = audioPlayer.current.currentTime;
        setCurrentTime(progressBar.current.value);
        animationRef.current = requestAnimationFrame(whilePlaying);
    }

    const calculateTime = (secs) => {
        const minutes = Math.floor(secs / 60);
        const returnedMinutes = minutes < 10 ? `0${minutes}` : `${minutes}`;
        const seconds = Math.floor(secs % 60);
        const returnedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
        return `${returnedMinutes} : ${returnedSeconds}`
    }

    const changeRange = () => {
        audioPlayer.current.currentTime = progressBar.current.value;
        setCurrentTime(progressBar.current.value);
    }

    const changeTrack = (e) => {
        if (isPlaying) {}
            setCurrentTrack(e.target.value)
            console.log(e.target.value)
            togglePlayPause();
    }

    return (
        <>
            <input ref={audioPlayer} className='dots' value='/piste1.mp3' onClick={e => changeTrack(e)}></input>
            <input ref={audioPlayer} className='dots left-8' value='/piste2.mp3' onClick={e => changeTrack(e)}></input>
            <div>
                <audio ref={audioPlayer} src={currentTrack} preload='metadata'></audio>
                <button className="mx-5" onClick={togglePlayPause}>
                    {isPlaying ? "Pause" : "Play"}
                </button>

                {/* Current time */}
                <div>{calculateTime(currentTime)}</div>

                {/* progress bar */}
                <div>
                    <input type='range' defaultValue="0" ref={progressBar} onChange={changeRange} />
                </div>

                {/* duration */}
                <div>{(duration && !isNaN(duration)) && calculateTime(duration)}</div>
            </div>
        </>

    )
}

export default AudioPlayer

CodePudding user response:

Why is the audioPlayer being passed as a ref to 3 different elements. That looks like it will produce issues. Only your audio element should have audioPlayer as a ref.

No need for togglePlayPause function in changeTrack. That code looks like it's causing quite some issues as well. Anyways, your chanfeTrack code should look like this:

const changeTrack = (evt) => {
    setCurrentTrack(evt.target.value)
};

If the audio doesn't immediately start playing, make sure the onCanPlay event is set to play the audio using something like evt.target.play()

  • Related