78 lines
1.8 KiB
TypeScript
78 lines
1.8 KiB
TypeScript
import { useState, useRef, useCallback, useEffect } from 'react'
|
|
|
|
export interface UseAudioPlayerReturn {
|
|
currentlyPlaying: string | null
|
|
isPlaying: (id: string) => boolean
|
|
play: (id: string, audioUrl: string) => Promise<void>
|
|
stop: () => void
|
|
}
|
|
|
|
export function useAudioPlayer(): UseAudioPlayerReturn {
|
|
const [currentlyPlaying, setCurrentlyPlaying] = useState<string | null>(null)
|
|
const audioRef = useRef<HTMLAudioElement | null>(null)
|
|
|
|
const stop = useCallback(() => {
|
|
if (audioRef.current) {
|
|
audioRef.current.pause()
|
|
audioRef.current.currentTime = 0
|
|
}
|
|
setCurrentlyPlaying(null)
|
|
}, [])
|
|
|
|
const play = useCallback(async (id: string, audioUrl: string) => {
|
|
// 如果已经在播放相同的音频,则停止
|
|
if (currentlyPlaying === id) {
|
|
stop()
|
|
return
|
|
}
|
|
|
|
// 停止当前播放的音频
|
|
if (audioRef.current) {
|
|
audioRef.current.pause()
|
|
}
|
|
|
|
try {
|
|
// 创建新的音频实例
|
|
const audio = new Audio(audioUrl)
|
|
audioRef.current = audio
|
|
|
|
// 设置音频事件监听
|
|
audio.addEventListener('ended', () => {
|
|
setCurrentlyPlaying(null)
|
|
})
|
|
|
|
audio.addEventListener('error', (e) => {
|
|
console.error('Audio playback error:', e)
|
|
setCurrentlyPlaying(null)
|
|
})
|
|
|
|
// 开始播放
|
|
setCurrentlyPlaying(id)
|
|
await audio.play()
|
|
} catch (error) {
|
|
console.error('Failed to play audio:', error)
|
|
setCurrentlyPlaying(null)
|
|
}
|
|
}, [currentlyPlaying, stop])
|
|
|
|
const isPlaying = useCallback((id: string) => {
|
|
return currentlyPlaying === id
|
|
}, [currentlyPlaying])
|
|
|
|
// 清理函数
|
|
useEffect(() => {
|
|
return () => {
|
|
if (audioRef.current) {
|
|
audioRef.current.pause()
|
|
audioRef.current = null
|
|
}
|
|
}
|
|
}, [])
|
|
|
|
return {
|
|
currentlyPlaying,
|
|
isPlaying,
|
|
play,
|
|
stop,
|
|
}
|
|
}
|