Skip to content

Instantly share code, notes, and snippets.

@Thisisjuke
Created July 10, 2023 10:30
Show Gist options
  • Save Thisisjuke/e9d156c1b5fddddbb8983d43da55e529 to your computer and use it in GitHub Desktop.
Save Thisisjuke/e9d156c1b5fddddbb8983d43da55e529 to your computer and use it in GitHub Desktop.
Simple useAudioPlayer hook 🎵 to create a Music player from a Blob ⏯️
import { useEffect, useRef, useState } from 'react'
function useAudioPlayer() {
const audioContextRef = useRef<AudioContext | null>(null)
const sourceRef = useRef<AudioBufferSourceNode | null>(null)
const [isPlaying, setIsPlaying] = useState<boolean>(false)
const [audioBlob, setAudioBlob] = useState<Blob | null>(null)
const [totalTime, setTotalTime] = useState<number>(0)
const createAudioSource = (): void => {
if (audioBlob && audioContextRef.current) {
const fileReader = new FileReader()
fileReader.onload = (): void => {
audioContextRef.current!.decodeAudioData(
fileReader.result as ArrayBuffer,
(buffer: AudioBuffer) => {
sourceRef.current = audioContextRef.current!.createBufferSource()
sourceRef.current.buffer = buffer
sourceRef.current.connect(audioContextRef.current!.destination)
sourceRef.current.onended = (): void => {
setIsPlaying(false)
}
setTotalTime(buffer.duration)
sourceRef.current.start()
},
)
}
fileReader.readAsArrayBuffer(audioBlob)
}
}
const playAudio = (): void => {
if (!isPlaying) {
if (sourceRef.current && audioContextRef.current?.state === 'suspended') {
audioContextRef.current.resume().then(() => {
setIsPlaying(true)
})
}
else {
if (audioContextRef.current?.state === 'suspended') {
audioContextRef.current.resume().then(() => {
createAudioSource()
setIsPlaying(true)
})
}
else {
audioContextRef.current = new AudioContext()
createAudioSource()
setIsPlaying(true)
}
}
}
}
const pauseAudio = (): void => {
if (isPlaying && sourceRef.current) {
sourceRef.current.stop()
setIsPlaying(false)
}
}
const reset = (): void => {
if (sourceRef.current) {
sourceRef.current.stop()
sourceRef.current.disconnect()
sourceRef.current = null
}
if (audioContextRef.current) {
audioContextRef.current.close()
audioContextRef.current = null
}
setIsPlaying(false)
}
const setAudio = (audio: Blob | null): void => {
setAudioBlob(audio)
}
const getTotalTime = (): number => {
return totalTime
}
useEffect(() => {
if (!audioContextRef.current) {
audioContextRef.current = new AudioContext()
}
return reset
}, [])
return { playAudio, pauseAudio, isPlaying, setAudio, reset, getTotalTime }
}
export default useAudioPlayer
@Thisisjuke
Copy link
Author

Thisisjuke commented Jul 10, 2023

React Audio Player Hook

This is a React hook that enables audio playback from a Blob. It provides functions to play, pause, set audio, and retrieve the total duration of the audio.

Installation

  1. Copy the code snippet provided into a file named useAudioPlayer.js or any other preferred name.
  2. Place the file in your React project's source folder.

Usage

  1. Import the hook in your component file:
import useAudioPlayer from './useAudioPlayer';

Note: Make sure to adjust the file path in the import statement according to the location of the useAudioPlayer.js file in your project.

  1. Invoke the hook inside your functional component:
const MyComponent = () => {
  const { playAudio, pauseAudio, isPlaying, setAudio, reset, getTotalTime } = useAudioPlayer();

  // Your component logic here
};
  1. Use the hook's functions to control audio playback:
  • `playAudio: Starts playing the audio.
  • `pauseAudio: Pauses the audio if it is playing.
  • `setAudio: Sets the audio to be played by providing a Blob object.
  • `reset: Stops and disconnects the audio, and resets the player state.
  • `getTotalTime: Retrieves the total duration of the audio in seconds.

Example:

const MyComponent = () => {
  const { playAudio, pauseAudio, isPlaying, setAudio, reset, getTotalTime } = useAudioPlayer();

  const handlePlay = () => {
    playAudio();
  };

  const handlePause = () => {
    pauseAudio();
  };

  const handleFileChange = (event) => {
    const file = event.target.files[0];
    setAudio(file);
  };

  const handleReset = () => {
    reset();
  };

  const audioDuration = getTotalTime();

  return (
    <div>
      <input type="file" onChange={handleFileChange} />
      <button onClick={handlePlay}>Play</button>
      <button onClick={handlePause}>Pause</button>
      <button onClick={handleReset}>Reset</button>
      <p>Duration: {audioDuration} seconds</p>
    </div>
  );
};

How to send this file to my backend ?

You should use a Form Data that you will include in your Payload Body.

export const blobToFile = (blob: Blob, uniqueString: string): FormData => {
    const uniqueFileName = `${uniqueString}_${Date.now()}.${blob.type.split('/')[1]}`
    const formData = new FormData()
    formData.append('audio', blob, uniqueFileName)
    return formData
}

Dependencies

This hook requires React to be installed as a dependency in your project.

License

This code is provided under the MIT License. Feel free to modify and use it in your projects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment