feat: 处理暂停
This commit is contained in:
parent
c173f83301
commit
d89dd55a51
|
@ -90,7 +90,7 @@ class WebAudioPlayer {
|
|||
})
|
||||
navigator.mediaSession.setActionHandler('stop', () => {
|
||||
console.log('Media session: stop requested')
|
||||
this.stop()
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -111,29 +111,20 @@ class WebAudioPlayer {
|
|||
this.nextSource?.stop()
|
||||
}
|
||||
|
||||
// 将音频 buffer 加载到缓存空间
|
||||
const loadBuffer = async (track: QueueItem) => {
|
||||
if (this.audioBuffer[track.song.cid]) return // 已经缓存了,直接跳
|
||||
const response = await fetch(track.sourceUrl ?? "")
|
||||
const arrayBuffer = await response.arrayBuffer()
|
||||
const audioBuffer = await this.context.decodeAudioData(arrayBuffer)
|
||||
this.audioBuffer[track.song.cid] = audioBuffer
|
||||
}
|
||||
|
||||
if (playQueue.currentTrack) {
|
||||
await loadBuffer(playQueue.currentTrack)
|
||||
await this.loadBuffer(playQueue.currentTrack)
|
||||
this.play()
|
||||
}
|
||||
|
||||
if (playQueue.nextTrack) {
|
||||
await loadBuffer(playQueue.nextTrack)
|
||||
await this.loadBuffer(playQueue.nextTrack)
|
||||
if (playState.isPlaying) this.scheduleNextTrack()
|
||||
} else {
|
||||
this.nextSource = null
|
||||
}
|
||||
|
||||
if (playQueue.previousTrack)
|
||||
await loadBuffer(playQueue.previousTrack)
|
||||
await this.loadBuffer(playQueue.previousTrack)
|
||||
|
||||
debugPlayer("缓存完成")
|
||||
} catch (error) {
|
||||
|
@ -141,9 +132,21 @@ class WebAudioPlayer {
|
|||
}
|
||||
}
|
||||
|
||||
// 将音频 buffer 加载到缓存空间
|
||||
loadBuffer = async (track: QueueItem) => {
|
||||
if (this.audioBuffer[track.song.cid]) return // 已经缓存了,直接跳
|
||||
const response = await fetch(track.sourceUrl ?? "")
|
||||
const arrayBuffer = await response.arrayBuffer()
|
||||
const audioBuffer = await this.context.decodeAudioData(arrayBuffer)
|
||||
this.audioBuffer[track.song.cid] = audioBuffer
|
||||
}
|
||||
|
||||
// 播放
|
||||
play() {
|
||||
if (!playQueue.currentTrack) return
|
||||
|
||||
if (!playState.actualPlaying) {
|
||||
// 如果实际正在播放,那么跳过音轨初始化阶段
|
||||
debugPlayer("开始播放")
|
||||
if (playState.playProgress !== 0) debugPlayer(`已经有所进度!${playState.playProgress}`)
|
||||
this.currentSource = this.context.createBufferSource()
|
||||
|
@ -152,14 +155,33 @@ class WebAudioPlayer {
|
|||
this.currentSource.start(this.context.currentTime, playState.playProgress)
|
||||
playState.reportActualPlaying(true)
|
||||
this.reportProgress()
|
||||
}
|
||||
// 开始预先准备无缝播放下一首
|
||||
// 获取下一首歌接入的时间点
|
||||
this.currentTrackStartTime = this.context.currentTime - playState.playProgress
|
||||
if (this.audioBuffer[playQueue.nextTrack.song.cid]) this.scheduleNextTrack()
|
||||
if (playQueue.nextTrack && this.audioBuffer[playQueue.nextTrack.song.cid]) this.scheduleNextTrack()
|
||||
|
||||
// 写入当前曲目播放完成后的钩子
|
||||
if (this.currentSource) this.currentSource.onended = () => {
|
||||
debugPlayer("当前歌曲播放结束")
|
||||
if (!!this.reportInterval) {
|
||||
// 页面依然正在回报播放进度,因此为歌曲自然结束
|
||||
debugPlayer("歌曲自然结束")
|
||||
this.onTrackEnded()
|
||||
} else {
|
||||
debugPlayer("用户暂停")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 安排下一首歌
|
||||
scheduleNextTrack() {
|
||||
if (this.nextSource !== null) {
|
||||
debugPlayer("下一首已经调度,跳过重复调度")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: 处理不同循环逻辑
|
||||
if (!playQueue.nextTrack) return
|
||||
this.nextSource = null
|
||||
const nextTrackStartTime = this.currentTrackStartTime
|
||||
|
@ -184,7 +206,9 @@ class WebAudioPlayer {
|
|||
|
||||
// 停止回报
|
||||
stopReportProgress() {
|
||||
if (this.reportInterval) clearInterval(this.reportInterval)
|
||||
this.reportInterval = null
|
||||
debugPlayer(this.reportInterval)
|
||||
}
|
||||
|
||||
pause() {
|
||||
|
@ -192,33 +216,43 @@ class WebAudioPlayer {
|
|||
debugPlayer(this.currentSource)
|
||||
this.currentSource?.stop()
|
||||
this.nextSource?.stop()
|
||||
this.nextSource = null
|
||||
playState.reportActualPlaying(false)
|
||||
this.stopReportProgress()
|
||||
}
|
||||
|
||||
stop() {
|
||||
async onTrackEnded() {
|
||||
// 1. 清理当前状态
|
||||
this.stopReportProgress()
|
||||
playState.reportPlayProgress(0)
|
||||
|
||||
// 2. 检查是否还有下一首
|
||||
if (!this.nextSource) {
|
||||
// 播放结束
|
||||
playState.reportActualPlaying(false)
|
||||
playState.togglePlay(false)
|
||||
return
|
||||
}
|
||||
|
||||
togglePlay() {
|
||||
// 3. 切换到下一首
|
||||
playQueue.continueToNext()
|
||||
this.currentSource = this.nextSource
|
||||
this.nextSource = null
|
||||
|
||||
// 4. 重新计算时间轴并启动进度报告
|
||||
this.currentTrackStartTime = this.context.currentTime
|
||||
this.reportProgress()
|
||||
|
||||
// 5. 处理下下首
|
||||
if (playQueue.nextTrack) {
|
||||
debugPlayer("处理下下一首歌")
|
||||
if (this.audioBuffer[playQueue.nextTrack.song.cid]) {
|
||||
this.scheduleNextTrack()
|
||||
} else {
|
||||
await this.loadBuffer(playQueue.nextTrack)
|
||||
if (playState.actualPlaying) this.scheduleNextTrack()
|
||||
}
|
||||
|
||||
getCurrentTime() {
|
||||
|
||||
}
|
||||
|
||||
updateMediaSessionState() {
|
||||
|
||||
}
|
||||
|
||||
// 定期更新播放位置
|
||||
startPositionUpdates() {
|
||||
|
||||
}
|
||||
|
||||
// 清理资源
|
||||
destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,5 +31,6 @@ async function pauseOrResume() {
|
|||
<button class="bg-white/20 px-2 py-1" @click="playTheList">开始播放</button>
|
||||
<div>当前播放队列里有 {{ playQueue.queue.length }} 首歌</div>
|
||||
<button class="bg-white/20 px-2 py-1" @click="pauseOrResume">播放/暂停</button>
|
||||
<div>播放进度:{{ Math.floor(playState.playProgress) }} / {{ Math.floor(playState.trackDuration) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -102,16 +102,10 @@ export const usePlayQueueStore = defineStore('queue', () => {
|
|||
currentPlaying.value = turnTo
|
||||
}
|
||||
|
||||
// 跳至下一首(通常为用户点按下一首按钮)
|
||||
const skipToNext = () => {
|
||||
currentPlaying.value = currentPlaying.value + 1
|
||||
}
|
||||
|
||||
// 继续播放接下来的曲目
|
||||
// 通常为当前曲目播放完毕,需要通过循环模式判断应该重置进度或队列指针 +1
|
||||
const continueToNext = () => {
|
||||
debugStore(loopingMode.value)
|
||||
// 注意:单曲循环时的进度重置需要在播放状态管理中处理
|
||||
if (loopingMode.value !== 'single') {
|
||||
currentPlaying.value = currentPlaying.value + 1
|
||||
}
|
||||
|
@ -202,7 +196,6 @@ export const usePlayQueueStore = defineStore('queue', () => {
|
|||
toggleShuffle,
|
||||
toggleLoop,
|
||||
toggleQueuePlay,
|
||||
skipToNext,
|
||||
continueToNext,
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue
Block a user