\n
import React, { useState, useEffect, useRef } from "react";\nimport "./AudioPlayer.css";\nimport Navbar from "../../components/Navbar/Navbar";\nimport { useParams } from "react-router-dom";\nimport axios from "axios";\nimport Slider from "../../components/Slider/Slider";\nimport ControlPanel from "../../components/Controls/ControlPanel";\nimport * as RiIcons from "react-icons/ri";\n\nfunction AudioPlayer() {\n const [episodeData, setEpisodeData] = useState([]);\n const [percentage, setPercentage] = useState();\n const [isPlaying, setIsPlaying] = useState(false);\n const [duration, setDuration] = useState(0);\n const [currentTime, setCurrentTime] = useState();\n const [speed, setSpeed] = useState(1);\n\n const audioRef = useRef();\n\n const onChange = (e) => {\n const audio = audioRef.current;\n audio.currentTime = (audio.duration / 100) * e.target.value;\n setPercentage(e.target.value);\n };\n\n const play = () => {\n const audio = audioRef.current;\n // audio.playbackRate = speed;\n audio.volume = 0.1;\n\n if (!isPlaying) {\n setIsPlaying(true);\n audio.play();\n }\n\n if (isPlaying) {\n setIsPlaying(false);\n audio.pause();\n }\n };\n\n const getCurrDuration = (e) => {\n const percent = (\n (e.currentTarget.currentTime / e.currentTarget.duration) *\n 100\n ).toFixed(2);\n\n const time = e.currentTarget.currentTime;\n\n setPercentage(+percent);\n setCurrentTime(time.toFixed(2));\n };\n\n const changeSpeed = () => {\n if (speed >= 2) {\n setSpeed(0.5);\n } else setSpeed(speed + 0.5);\n };\n\n const skip = (time) => {\n const audio = audioRef.current;\n\n if (time == "back") {\n console.log("15");\n setCurrentTime(audio.currentTime - 15);\n } else if (time == "fwd") {\n console.log("15");\n setCurrentTime(audio.currentTime + 15);\n }\n };\n\n const { id } = useParams();\n\n const headers = { jwt_token: localStorage.token };\n\n useEffect(() => {\n axios\n .get(`/api/get/episodes/${id}`, { headers })\n .then((res) => setEpisodeData(res.data));\n }, []);\n\n useEffect(() => {\n const audio = audioRef.current;\n audio.playbackRate = speed;\n }, [speed]);\n\n return (\n <div>\n <Navbar />\n <div>\n <div style={{ width: "60%", margin: "0 auto", paddingTop: "10rem" }}>\n <div className="app-container">\n <h3 style={{ color: "#fff" }}>{episodeData.podcast_title}</h3>\n <h3 style={{ color: "#fff" }}>{episodeData.episode_title}</h3>\n\n <Slider percentage={percentage} onChange={onChange} />\n <audio\n ref={audioRef}\n onTimeUpdate={getCurrDuration}\n onLoadedData={(e) => {\n setDuration(e.currentTarget.duration.toFixed(2));\n }}\n src={episodeData.episode_audio}\n ></audio>\n <ControlPanel\n play={play}\n isPlaying={isPlaying}\n duration={duration}\n currentTime={currentTime}\n />\n <button className="speed-button" onClick={() => changeSpeed()}>\n {speed}x\n </button>\n <button onClick={() => skip("back")}>\n BACK 15 SECONDS\n <RiIcons.RiArrowGoBackLine color={"white"} size={16} />\n </button>\n <button onClick={() => skip("fwd")}>\n <RiIcons.RiArrowGoForwardLine color={"white"} size={16} />\n FORWARD 15 SECONDS\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nexport default AudioPlayer;\n
\n","author":{"@type":"Person","name":"Tosh Velaga"},"upvoteCount":0,"answerCount":1,"acceptedAnswer":{"@type":"Answer","text":"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.
\nThe currentTime property sets or returns the current position (in seconds) of the audio/video playback.
\nWhen setting this property, the playback will jump to the specified position.
\nconst skip = (time) => {\n const audio = audioRef.current;\n\n if (time == 'back') {\n // changes\n audio.currentTime = audio.currentTime - 15;\n } else if (time == 'fwd') {\n // changes\n audio.currentTime = audio.currentTime + 15;\n }\n};\n
\nBy 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.
\n","author":{"@type":"Person","name":"Akshay Pagare"},"upvoteCount":3}}}Reputation: 155
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
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
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