From 4f57a19ef60f28e9e0ebc16b56fb5e4a4161d4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A7=89?= Date: Wed, 4 Oct 2023 10:16:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E5=A5=BD=E7=9A=84=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ public/index.html | 53 +++++++++++++++++++++++------------------------ public/music.js | 43 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 69 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index e8c1906..4fa5654 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ webrtc 实现的 p2p 信道 - [x] P2P通信 + - [ ] 分离出主要功能, 作为库或桁架使用 - [x] 音乐播放 - [x] 请求到单个目标防止接收到重复分片数据 - [x] 主机记录各自曲目列表以供查询 @@ -14,6 +15,7 @@ webrtc 实现的 p2p 信道 - [ ] 上锁防止连续重复加载同一个造成分片混乱 - [x] 使用单独的状态标识音乐是否缓存 - [x] 取消本地存储时不直接移除列表 + - [x] 分片下载过程与播放控制分离 - [ ] 取消本地存储时检查是否移除(其它成员可能有同一曲) - [ ] 成员列表刷新时播放被重置BUG - [ ] 集群分发 diff --git a/public/index.html b/public/index.html index 6aa9503..5a9c208 100644 --- a/public/index.html +++ b/public/index.html @@ -109,40 +109,39 @@ onerror: error => { console.log('音乐列表错误', error) }, - onload: async (item, sourceBuffer) => { + onload: async item => { console.log('加载音乐', item) return await new Promise((resolve) => { var buffer = new ArrayBuffer(0) // 接收音乐数据 var count = 0 // 接收分片计数 - var bufferCursor = 0 // 加载进度 - var partlength = 1024 * 64 // 每次加载1MB - - // 指针达到音乐数据大小则结束加载 - const mediaLoader = async () => { - while (bufferCursor !== item.size) { - if (musicList.audio.paused && musicList.audio.currentTime !== 0) { - console.log('音乐暂停') - break - } - console.log('当前播放进度', musicList.audio.currentTime) - const 当前播放进度 = musicList.audio.currentTime - const 当前结束时间 = sourceBuffer.buffered.length && sourceBuffer.buffered.end(0) - const 剩余数据长度 = buffer.byteLength - bufferCursor - const 本次加载长度 = Math.min(partlength, 剩余数据长度) - const 缓冲时间 = 当前结束时间 - 当前播放进度 - if (buffer.byteLength > bufferCursor && !sourceBuffer.updating && 缓冲时间 < 60) { - sourceBuffer.appendBuffer(buffer.slice(bufferCursor, bufferCursor + 本次加载长度)) - bufferCursor += 本次加载长度 - } - await new Promise((resolve) => setTimeout(resolve, 1000)) - } - } - mediaLoader() - + //var bufferCursor = 0 // 加载进度 + //var partlength = 1024 * 64 // 每次加载1MB + //// 指针达到音乐数据大小则结束加载 + //const mediaLoader = async () => { + // while (bufferCursor !== item.size) { + // if (musicList.audio.paused && musicList.audio.currentTime !== 0) { + // console.log('音乐暂停') + // break + // } + // console.log('当前播放进度', musicList.audio.currentTime) + // const 当前播放进度 = musicList.audio.currentTime + // const 当前结束时间 = sourceBuffer.buffered.length && sourceBuffer.buffered.end(0) + // const 剩余数据长度 = buffer.byteLength - bufferCursor + // const 本次加载长度 = Math.min(partlength, 剩余数据长度) + // const 缓冲时间 = 当前结束时间 - 当前播放进度 + // if (buffer.byteLength > bufferCursor && !sourceBuffer.updating && 缓冲时间 < 60) { + // sourceBuffer.appendBuffer(buffer.slice(bufferCursor, bufferCursor + 本次加载长度)) + // bufferCursor += 本次加载长度 + // } + // await new Promise((resolve) => setTimeout(resolve, 1000)) + // } + //} + //mediaLoader() clientList.setChannel(`music-data-${item.id}`, { onmessage: async (event, client) => { console.log('收到音乐数据 chunk', count, buffer.byteLength) - buffer = appendBuffer(buffer, event.data) + buffer = appendBuffer(buffer, event.data) // 合并分片准备存储 + item.arrayBufferChunks.push(event.data) // 保存分片给边下边播 count++ if (buffer.byteLength >= item.size) { console.log('音乐数据接收完毕') diff --git a/public/music.js b/public/music.js index 43b8d17..f84e0ae 100644 --- a/public/music.js +++ b/public/music.js @@ -139,14 +139,53 @@ export default class MusicList { await this.event.onload(item) } async play(item) { - if (!item.save) { + if (!item.arrayBuffer) { // 边加载边播放 const mediaSource = new MediaSource() this.audio.src = URL.createObjectURL(mediaSource) + if (!item.arrayBufferChunks) item.arrayBufferChunks = [] mediaSource.addEventListener('sourceopen', async () => { const sourceBuffer = mediaSource.addSourceBuffer(item.type) - this.event.onload(item, sourceBuffer) + const arrayBufferLoader = async (index = 0) => { + + // 等待 item.arrayBufferChunks 不为空 + while (item.arrayBufferChunks.length === 0) { + await new Promise(resolve => setTimeout(resolve, 100)) + } + + console.log('开始加载====================================') + // 按照数据长度计算出分片应有数量, 如果数量不到且没有停止加载则一直读取 + const chunkNumber = Math.ceil(item.size / 1024 / 64) // 64KB每片 + console.log({ index, chunkNumber, paused: this.audio.paused }) + while (index < chunkNumber && !this.audio.paused) { + console.log('加载中------------------------------------', index) + const 播放状态 = !this.audio.paused && this.playing === item + const 加载状态 = item.arrayBufferChunks.length < chunkNumber + const 播放进度 = this.audio.currentTime / this.audio.duration + const 加载进度 = index / chunkNumber + const 结束时间 = sourceBuffer.buffered.length && sourceBuffer.buffered.end(0) + const 缓冲时间 = 结束时间 - this.audio.currentTime + console.log({ 播放状态, 加载状态, 播放进度, 加载进度, 缓冲时间 }) + if (!播放状态 && !加载状态) break // 播放停止且加载完毕则退出 + if (缓冲时间 > 60) await new Promise(resolve => setTimeout(resolve, 30000)) // 缓冲超过60秒则等待30秒 + if (播放进度 - 加载进度 > 0.5) await new Promise(resolve => setTimeout(resolve, 1000)) // 播放进度超过加载进度0.5则等待1秒 + if (sourceBuffer.updating) { + await new Promise(resolve => sourceBuffer.addEventListener('updateend', resolve)) + } else { + while (item.arrayBufferChunks.length <= index) { + await new Promise(resolve => setTimeout(resolve, 100)) + } + const chunk = item.arrayBufferChunks[index] // 顺序取出一个arrayBuffer分片 + sourceBuffer.appendBuffer(chunk) // 添加到sourceBuffer + index++ + } + } + console.log('加载完毕====================================') + item.arrayBufferChunks = null // 加载完毕释放分片内存 + } + this.event.onload(item) this.audio.play() + arrayBufferLoader() }) } else { // 本地缓存直接播放