Tosh Velaga
Tosh Velaga

Reputation: 155

How do I fast-forward the audio in my react component?

I have a react component that display an audio player. I need to implement a feature where you can go back and forward in the audio 15 seconds. I have a function called skip that does this but it only updates the time and is not moving the audio track. What I am doing wrong? Here is an image of my audio player

enter image description here

import React, { useState, useEffect, useRef } from "react";
import "./AudioPlayer.css";
import Navbar from "../../components/Navbar/Navbar";
import { useParams } from "react-router-dom";
import axios from "axios";
import Slider from "../../components/Slider/Slider";
import ControlPanel from "../../components/Controls/ControlPanel";
import * as RiIcons from "react-icons/ri";

function AudioPlayer() {
    const [episodeData, setEpisodeData] = useState([]);
    const [percentage, setPercentage] = useState();
    const [isPlaying, setIsPlaying] = useState(false);
    const [duration, setDuration] = useState(0);
    const [currentTime, setCurrentTime] = useState();
    const [speed, setSpeed] = useState(1);

    const audioRef = useRef();

    const onChange = (e) => {
        const audio = audioRef.current;
        audio.currentTime = (audio.duration / 100) * e.target.value;
        setPercentage(e.target.value);
    };

    const play = () => {
        const audio = audioRef.current;
        // audio.playbackRate = speed;
        audio.volume = 0.1;

        if (!isPlaying) {
            setIsPlaying(true);
            audio.play();
        }

        if (isPlaying) {
            setIsPlaying(false);
            audio.pause();
        }
    };

    const getCurrDuration = (e) => {
        const percent = (
            (e.currentTarget.currentTime / e.currentTarget.duration) *
            100
        ).toFixed(2);

        const time = e.currentTarget.currentTime;

        setPercentage(+percent);
        setCurrentTime(time.toFixed(2));
    };

    const changeSpeed = () => {
        if (speed >= 2) {
            setSpeed(0.5);
        } else setSpeed(speed + 0.5);
    };

    const skip = (time) => {
        const audio = audioRef.current;

        if (time == "back") {
            console.log("15");
            setCurrentTime(audio.currentTime - 15);
        } else if (time == "fwd") {
            console.log("15");
            setCurrentTime(audio.currentTime + 15);
        }
    };

    const { id } = useParams();

    const headers = { jwt_token: localStorage.token };

    useEffect(() => {
        axios
            .get(`/api/get/episodes/${id}`, { headers })
            .then((res) => setEpisodeData(res.data));
    }, []);

    useEffect(() => {
        const audio = audioRef.current;
        audio.playbackRate = speed;
    }, [speed]);

    return (
        <div>
            <Navbar />
            <div>
                <div style={{ width: "60%", margin: "0 auto", paddingTop: "10rem" }}>
                    <div className="app-container">
                        <h3 style={{ color: "#fff" }}>{episodeData.podcast_title}</h3>
                        <h3 style={{ color: "#fff" }}>{episodeData.episode_title}</h3>

                        <Slider percentage={percentage} onChange={onChange} />
                        <audio
                            ref={audioRef}
                            onTimeUpdate={getCurrDuration}
                            onLoadedData={(e) => {
                                setDuration(e.currentTarget.duration.toFixed(2));
                            }}
                            src={episodeData.episode_audio}
                        ></audio>
                        <ControlPanel
                            play={play}
                            isPlaying={isPlaying}
                            duration={duration}
                            currentTime={currentTime}
                        />
                        <button className="speed-button" onClick={() => changeSpeed()}>
                            {speed}x
                        </button>
                        <button onClick={() => skip("back")}>
                            BACK 15 SECONDS
                            <RiIcons.RiArrowGoBackLine color={"white"} size={16} />
                        </button>
                        <button onClick={() => skip("fwd")}>
                            <RiIcons.RiArrowGoForwardLine color={"white"} size={16} />
                            FORWARD 15 SECONDS
                        </button>
                    </div>
                </div>
            </div>
        </div>
    );
}

export default AudioPlayer;

Upvotes: 0

Views: 3374

Answers (1)

Akshay Pagare
Akshay Pagare

Reputation: 154

The problem with your code is, you're trying to change the state of component where as you should be changing the current time of the audio player.

The currentTime property sets or returns the current position (in seconds) of the audio/video playback.

When setting this property, the playback will jump to the specified position.

const skip = (time) => {
  const audio = audioRef.current;

  if (time == 'back') {
    // changes
    audio.currentTime = audio.currentTime - 15;
  } else if (time == 'fwd') {
    // changes
    audio.currentTime = audio.currentTime + 15;
  }
};

By changing the current time of the audio player using ref the audio player jumps to the specified position, so your onchange function will also be called.

Upvotes: 3

Related Questions