@@ -41,6 +41,10 @@ const pendingLanguage = ref<AudioLanguage | ''>('')
|
||||
const activeHostId = ref('')
|
||||
const lastClosedSource = ref<GlobalAudioSource | null>(null)
|
||||
const closeVersion = ref(0)
|
||||
const playbackRate = ref(1)
|
||||
const muted = ref(false)
|
||||
|
||||
const PLAYBACK_RATES = [1, 1.25, 1.5, 2] as const
|
||||
|
||||
let audioElement: HTMLAudioElement | null = null
|
||||
let retryOnError: GlobalAudioRetryHandler | null = null
|
||||
@@ -74,11 +78,17 @@ const syncAudioDuration = () => {
|
||||
: currentAudio.value?.duration || 0
|
||||
}
|
||||
|
||||
const applyAudioPreferences = (audio: HTMLAudioElement) => {
|
||||
audio.playbackRate = playbackRate.value
|
||||
audio.muted = muted.value
|
||||
}
|
||||
|
||||
const ensureAudioElement = () => {
|
||||
if (audioElement || typeof window === 'undefined' || !window.Audio) return audioElement
|
||||
|
||||
const audio = new window.Audio()
|
||||
audio.preload = 'metadata'
|
||||
applyAudioPreferences(audio)
|
||||
audio.addEventListener('loadedmetadata', syncAudioDuration)
|
||||
audio.addEventListener('play', () => {
|
||||
playing.value = true
|
||||
@@ -124,6 +134,11 @@ const resetState = () => {
|
||||
duration.value = 0
|
||||
displayMode.value = 'mini'
|
||||
pendingLanguage.value = ''
|
||||
playbackRate.value = 1
|
||||
muted.value = false
|
||||
if (audioElement) {
|
||||
applyAudioPreferences(audioElement)
|
||||
}
|
||||
retryOnError = null
|
||||
retrying = false
|
||||
retryUsed = false
|
||||
@@ -227,6 +242,7 @@ const play = async (audio: AudioItem, options: GlobalAudioPlayOptions = {}) => {
|
||||
element.src = audio.audioUrl
|
||||
element.load()
|
||||
}
|
||||
applyAudioPreferences(element)
|
||||
|
||||
try {
|
||||
await element.play()
|
||||
@@ -448,6 +464,22 @@ const seekToPercent = (percent: number) => {
|
||||
currentTime.value = targetTime
|
||||
}
|
||||
|
||||
const cyclePlaybackRate = () => {
|
||||
const currentIndex = PLAYBACK_RATES.indexOf(playbackRate.value as typeof PLAYBACK_RATES[number])
|
||||
const nextIndex = currentIndex >= 0 ? (currentIndex + 1) % PLAYBACK_RATES.length : 0
|
||||
playbackRate.value = PLAYBACK_RATES[nextIndex]
|
||||
if (audioElement) {
|
||||
audioElement.playbackRate = playbackRate.value
|
||||
}
|
||||
}
|
||||
|
||||
const toggleMuted = () => {
|
||||
muted.value = !muted.value
|
||||
if (audioElement) {
|
||||
audioElement.muted = muted.value
|
||||
}
|
||||
}
|
||||
|
||||
const registerHost = () => {
|
||||
hostSequence += 1
|
||||
const hostId = `global-audio-host-${hostSequence}`
|
||||
@@ -490,6 +522,8 @@ export const useGlobalAudioPlayer = () => ({
|
||||
activeHostId,
|
||||
lastClosedSource,
|
||||
closeVersion,
|
||||
playbackRate,
|
||||
muted,
|
||||
hasAudio: computed(() => Boolean(currentAudio.value)),
|
||||
play,
|
||||
pause,
|
||||
@@ -502,6 +536,8 @@ export const useGlobalAudioPlayer = () => ({
|
||||
handleEnded,
|
||||
handleError,
|
||||
seekToPercent,
|
||||
cyclePlaybackRate,
|
||||
toggleMuted,
|
||||
registerHost,
|
||||
activateHost,
|
||||
unregisterHost,
|
||||
|
||||
Reference in New Issue
Block a user