A customizable React audio player component with TypeScript support, mobile compatibility, and comprehensive accessibility features
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Media Source Extensions (MSE), Encrypted Media Extensions (EME) support, utility functions, and advanced audio features for streaming and encrypted content.
Support for Media Source Extensions allowing for advanced streaming capabilities and custom media handling.
interface MSEPropsObject {
/** Custom seek handler for MSE streams */
onSeek: OnSeek;
/** Handler for encrypted media events */
onEcrypted?: (e: unknown) => void;
/** Total duration of the source in seconds (required for MSE) */
srcDuration: number;
}
type OnSeek = (audio: HTMLAudioElement, time: number) => Promise<void>;When MSE configuration is provided:
onSeek function handles all seeking operations instead of standard currentTime settingsrcDuration is used to display total duration instead of audio.durationonEcrypted handles Encrypted Media Extensions (EME) eventsAccess to the underlying HTML audio element and component methods for advanced control.
Methods available on the H5AudioPlayer component instance for programmatic control.
class H5AudioPlayer extends Component<PlayerProps> {
/** Toggle between play and pause states */
togglePlay(e: React.SyntheticEvent): void;
/** Safely play audio with promise-based error handling */
playAudioPromise(): void;
/** Check if audio is currently playing */
isPlaying(): boolean;
/** Reference to the underlying HTML audio element */
audio: React.RefObject<HTMLAudioElement>;
/** Reference to the progress bar container */
progressBar: React.RefObject<HTMLDivElement>;
/** Reference to the main player container */
container: React.RefObject<HTMLDivElement>;
}Advanced error handling for playback and seeking operations.
interface ErrorHandlers {
/** Called when audio.play() promise is rejected */
onPlayError?: (err: Error) => void;
/** Called when currentTime change operations fail */
onChangeCurrentTimeError?: (err: Error) => void;
}Common error scenarios:
Fine-tune performance and responsiveness through various timing configurations.
interface PerformanceConfig {
/** Frequency of progress bar updates in milliseconds */
progressUpdateInterval?: number;
/** Frequency of onListen event firing in milliseconds */
listenInterval?: number;
/** Jump distance for keyboard/button controls in milliseconds */
progressJumpStep?: number;
/** Separate jump distances for backward/forward */
progressJumpSteps?: {
backward?: number;
forward?: number;
};
/** Volume increment for volume controls */
volumeJumpStep?: number;
}Performance Recommendations:
progressUpdateInterval (10-50ms) for smoother progress barslistenInterval (500-2000ms) for less frequent position trackingMSE Configuration for Streaming:
import AudioPlayer from 'react-h5-audio-player';
const streamingPlayer = () => {
const handleMSESeek = async (audio: HTMLAudioElement, time: number) => {
// Custom seek implementation for MSE
try {
await myStreamingService.seekTo(time);
// Update UI to reflect new position
console.log(`Seeking to ${time} seconds`);
} catch (error) {
console.error('Seek failed:', error);
}
};
const handleEncrypted = (e: unknown) => {
// Handle EME for encrypted content
console.log('Encrypted media detected', e);
// Setup MediaKeys, licenses, etc.
};
return (
<AudioPlayer
src="blob:https://example.com/stream"
mse={{
onSeek: handleMSESeek,
onEcrypted: handleEncrypted,
srcDuration: 3600 // 1 hour in seconds
}}
onError={(e) => console.error('Streaming error:', e)}
/>
);
};Custom Error Handling:
<AudioPlayer
src="audio.mp3"
onPlayError={(err) => {
console.error('Playback failed:', err);
// Show user-friendly error message
if (err.message.includes('NotAllowedError')) {
alert('Please click play to start audio (browser autoplay policy)');
}
}}
onChangeCurrentTimeError={(err) => {
console.error('Seek failed:', err);
// Handle seek failures gracefully
}}
onError={(e) => {
const audio = e.target as HTMLAudioElement;
if (audio.error) {
switch (audio.error.code) {
case MediaError.MEDIA_ERR_NETWORK:
console.error('Network error loading audio');
break;
case MediaError.MEDIA_ERR_DECODE:
console.error('Audio decoding error');
break;
case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
console.error('Audio format not supported');
break;
default:
console.error('Unknown audio error');
}
}
}}
/>Performance Tuning:
<AudioPlayer
src="audio.mp3"
progressUpdateInterval={20} // Smooth 50fps progress updates
listenInterval={250} // Position tracking 4x per second
progressJumpStep={10000} // 10 second jumps
progressJumpSteps={{
backward: 15000, // 15 second rewind
forward: 30000 // 30 second skip forward
}}
volumeJumpStep={0.1} // 10% volume increments
/>Programmatic Control:
import React, { useRef, useEffect } from 'react';
import AudioPlayer from 'react-h5-audio-player';
const ControlledPlayer = () => {
const playerRef = useRef<AudioPlayer>(null);
useEffect(() => {
// Example: Auto-play after 3 seconds
const timer = setTimeout(() => {
if (playerRef.current) {
playerRef.current.playAudioPromise();
}
}, 3000);
return () => clearTimeout(timer);
}, []);
const handleExternalPlay = () => {
if (playerRef.current) {
playerRef.current.togglePlay({} as React.SyntheticEvent);
}
};
const checkPlayingStatus = () => {
if (playerRef.current) {
const isPlaying = playerRef.current.isPlaying();
console.log('Currently playing:', isPlaying);
}
};
return (
<div>
<AudioPlayer
ref={playerRef}
src="audio.mp3"
/>
<button onClick={handleExternalPlay}>
External Play/Pause
</button>
<button onClick={checkPlayingStatus}>
Check Status
</button>
</div>
);
};Custom Time Display:
// The utility functions are internal to the component and not exported
// Time formatting is handled automatically by the component based on timeFormat prop
<AudioPlayer
src="audio.mp3"
timeFormat="mm:ss" // or "hh:mm:ss" or "auto"
onListen={(e) => {
const audio = e.target as HTMLAudioElement;
console.log('Position update:', audio.currentTime);
// Custom logic for position tracking
}}
/>Advanced Accessibility:
<AudioPlayer
src="podcast.mp3"
i18nAriaLabels={{
player: 'Podcast Player',
progressControl: 'Playback progress, use arrow keys to seek',
volumeControl: 'Volume control, use arrow keys to adjust',
play: 'Play podcast',
pause: 'Pause podcast',
rewind: 'Rewind 15 seconds',
forward: 'Skip forward 30 seconds'
}}
progressJumpSteps={{
backward: 15000, // 15s rewind for podcasts
forward: 30000 // 30s skip for podcasts
}}
/>Install with Tessl CLI
npx tessl i tessl/npm-react-h5-audio-player