A React hooks library for managing audio playback with advanced controls and features.
npm install audio-hooks
- Multiple playback modes: Shuffle, Single Once/Loop, Sequential Once/Loop
- Advanced controls: Volume, playback rate, seeking, fast forward/rewind
- Track navigation: Previous/Next with smart mode handling
- Web Audio API: High-quality audio processing with gain control
- TypeScript support: Full type definitions included
- Flexible playlist management: Dynamic audio list updates
import { useAudioList, AudioProvider } from 'audio-hooks/react'
function AudioPlayer() {
const { state, controls } = useAudioList([
'audio1.mp3',
'audio2.mp3',
'audio3.mp3'
])
return (
<AudioProvider>
<div>
<h3>Now Playing: Track {state.playingIndex + 1}</h3>
<p>{Math.floor(state.currentTime)}s / {Math.floor(state.duration)}s</p>
<div>
<button onClick={controls.prev}>⏮️</button>
<button onClick={controls.togglePlay}>
{state.playing ? '⏸️' : '▶️'}
</button>
<button onClick={controls.next}>⏭️</button>
</div>
<div>
<button onClick={() => controls.rewind()}>⏪ 5s</button>
<button onClick={() => controls.fastForward()}>⏩ 5s</button>
</div>
<input
type="range"
min="0"
max="1"
step="0.01"
value={state.volume}
onChange={(e) => controls.setVolume(Number(e.target.value))}
/>
</div>
</AudioProvider>
)
}
// hooks/usePlayList.ts
import { useAudioList, AudioProvider } from 'audio-hooks/react'
export interface PlayList {
id: string
name: string
owner?: string
cover?: string
description?: string
tracks: Track[]
createdAt?: string
updatedAt?: string
duration?: number
isPublic?: boolean
tags?: string[]
}
type Track = {
name: string
artist: string
album: string
cover?: string
url: string
}
export const usePlayList = ({ tracks = [] }: PlayList) => {
const {
state,
controls,
} = useAudioList(tracks.map(({ url }) => url), {
onEnded: () => {
console.log('Track ended')
}
})
return {
state,
controls,
playingTrack: tracks[state.playingIndex],
totalTracks: tracks.length,
}
}
// components/AudioPlayer.tsx
import { usePlayList } from 'hooks/usePlayList'
const playList = {
name: 'My Playlist',
tracks: [
{ name: 'Song 1', artist: 'Artist 1', album: 'Album 1', url: 'song1.mp3' },
{ name: 'Song 2', artist: 'Artist 2', album: 'Album 2', url: 'song2.mp3' },
],
}
const AudioPlayer = () => {
const {
state,
controls,
playingTrack,
totalTracks,
} = usePlayList(playList)
return (
<AudioProvider>
<div className="audio-player">
<div className="track-info">
<h3>{playingTrack?.name || 'No track selected'}</h3>
<p>{playingTrack?.artist} - {playingTrack?.album}</p>
<span>Track {state.playingIndex + 1} of {totalTracks}</span>
</div>
<div className="playback-controls">
<button onClick={controls.prev}>⏮️</button>
<button onClick={controls.togglePlay}>
{state.playing ? '⏸️' : '▶️'}
</button>
<button onClick={controls.next}>⏭️</button>
<button onClick={() => controls.nextPlayMode()}>
Mode: {state.playMode}
</button>
</div>
<div className="seek-controls">
<button onClick={() => controls.rewind(10000)}>⏪ 10s</button>
<input
type="range"
min="0"
max={state.duration}
value={state.currentTime}
onChange={(e) => controls.seek(Number(e.target.value))}
/>
<button onClick={() => controls.fastForward(10000)}>⏩ 10s</button>
</div>
<div className="audio-settings">
<label>
Volume: {Math.round(state.volume * 100)}%
<input
type="range"
min="0"
max="1"
step="0.01"
value={state.volume}
onChange={(e) => controls.setVolume(Number(e.target.value))}
/>
</label>
<label>
Speed: {state.playbackRate}x
<input
type="range"
min="0.5"
max="3"
step="0.1"
value={state.playbackRate}
onChange={(e) => controls.setPlaybackRate(Number(e.target.value))}
/>
</label>
</div>
</div>
</AudioProvider>
)
}
Parameters:
-
urls: string[]
- Array of audio URLs -
options?: AudioOptions
- Optional configuration object-
onEnded?: () => void
- Callback fired when a track ends
-
Returns: UseAudioListReturn
-
state: AudioState
- Current playback state -
controls: AudioControls
- Playback control methods
Property | Type | Description |
---|---|---|
audios |
string[] |
Array of audio URLs |
playing |
boolean |
Whether audio is currently playing |
playingIndex |
number |
Index of currently playing track (-1 if none) |
currentTime |
number |
Current playback position in seconds |
duration |
number |
Total duration of current track in seconds |
volume |
number |
Current volume level (0-1) |
playbackRate |
number |
Current playback speed (0.5-3.0) |
playMode |
PlayMode |
Current playback mode |
Method | Parameters | Description |
---|---|---|
play() |
- | Start playing the current audio track |
pause() |
- | Pause the current audio track |
togglePlay() |
- | Toggle between play and pause |
next() |
- | Skip to next track based on current play mode |
prev() |
- | Go to previous track based on current play mode |
seek(time) |
time: number |
Seek to specific time in seconds |
fastForward(ms?) |
ms?: number |
Fast forward by milliseconds (default: 5000) |
rewind(ms?) |
ms?: number |
Rewind by milliseconds (default: 5000) |
setVolume(volume) |
volume: number |
Set volume (0-1) |
nextPlayMode(mode?) |
mode?: PlayMode |
Cycle through or set specific play mode |
playTrack(index) |
index: number |
Play specific track by index |
setPlaybackRate(rate) |
rate: number |
Set playback speed (0.5-3.0) |
setAudioList(urls) |
urls: string[] |
Update the audio URL list |
switchAudio(index) |
index: number |
Switch to track without playing |
type PlayMode =
| 'Shuffle' // Random track order
| 'SingleOnce' // Play current track once, then stop
| 'SingleLoop' // Repeat current track infinitely
| 'SequentialOnce' // Play all tracks once, then stop
| 'SequentialLoop' // Repeat entire playlist infinitely
- Shuffle: Plays tracks in random order, continues infinitely
- SingleOnce: Plays the current track once and stops
- SingleLoop: Repeats the current track indefinitely
- SequentialOnce: Plays all tracks in order once, then stops
- SequentialLoop: Plays all tracks in order, then repeats from the beginning
The hook automatically manages audio resources and cleans up when components unmount. Audio elements are pooled for efficient reuse.
const { state, controls } = useAudioList(urls, {
onEnded: () => console.log('Track finished'),
})
// Handle play errors
const handlePlay = async () => {
try {
await controls.play()
} catch (error) {
console.error('Playback failed:', error)
}
}
- Use stable URL arrays to prevent unnecessary re-initializations
- Implement virtualization for large playlists
- Consider lazy loading for audio metadata
MIT © Lee
Contributions are welcome! Please feel free to submit a Pull Request.
git clone https://github.com/hey-lee/audio-hooks
cd audio-hooks
npm install
npm run dev