diff --git a/README.md b/README.md index 8ff19ce..f8c2b21 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ webrtc 实现的 p2p 信道 - [x] 响应列表时不再广播 - [x] 对方退出时清除其列表 - [x] 稳定通信 - - [ ] 分片请求时立即播放 + - [x] 分片请求时立即播放 - [ ] 上锁防止连续重复加载同一个造成分片混乱 - [ ] 集群分发 - [ ] 下载加速 diff --git a/public/index.html b/public/index.html index a565725..6bdcfc1 100644 --- a/public/index.html +++ b/public/index.html @@ -107,15 +107,39 @@ onerror: error => { console.log('音乐列表错误', error) }, - onload: async item => { + onload: async (item, sourceBuffer) => { console.log('加载音乐', item) return await new Promise((resolve) => { - var buffer = new ArrayBuffer(0) - var count = 0 + 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.src === '') { + console.log('音乐数据加载中, 但是音频已经停止播放') + break + } + 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) => { - buffer = appendBuffer(buffer, event.data) console.log('收到音乐数据 chunk', count, buffer.byteLength) + buffer = appendBuffer(buffer, event.data) count++ if (buffer.byteLength >= item.size) { console.log('音乐数据接收完毕') diff --git a/public/music.js b/public/music.js index ad309fd..6573e29 100644 --- a/public/music.js +++ b/public/music.js @@ -134,14 +134,26 @@ export default class MusicList { } async play(item) { if (!item.arrayBuffer) { - await this.load(item) + // 边加载边播放 + const mediaSource = new MediaSource() + this.audio.src = URL.createObjectURL(mediaSource) + mediaSource.addEventListener('sourceopen', async () => { + const sourceBuffer = mediaSource.addSourceBuffer(item.type) + this.event.onload(item, sourceBuffer) + this.audio.play() + }) + } else { + // 本地缓存直接播放 + this.audio.src = URL.createObjectURL(new Blob([item.arrayBuffer], { type: item.type })) + this.audio.play() } this.playing = item - this.audio.src = URL.createObjectURL(new Blob([item.arrayBuffer], { type: item.type })) - this.audio.play() this.event.onplay(item) } async stop() { + //if (!this.audio.paused) { + // this.audio.pause() + //} this.audio.pause() this.audio.src = '' this.event.onstop(this.playing)