我在一个目录中有几个mp3文件,我想一个接一个地流式传输,这样浏览器就会(a)立即开始播放音频,并继续播放所有的mp3,直到我关闭响应流。(Intent是一个端点,其功能类似于播放列表mp3流。)
下面是我的代码:
import express from 'express';
const app = express();
function startServer() {
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
}
app.get('/stream', (req, res) => {
const mp3Files = fs.readdirSync('.').filter(file => file.endsWith('.mp3'));
let i = 0;
res.setHeader('Content-Type', 'audio/mpeg');
res.set('Transfer-Encoding', 'chunked');
function sendFile() {
const mp3File = mp3Files[i];
console.log(`processing ${mp3File}`);
const fileStream = fs.createReadStream(mp3File);
fileStream.on('data', (chunk) => {
res.write(chunk);
}).on('end', () => {
i++;
if (i < mp3Files.length) {
sendFile();
} else {
res.end();
}
});
}
sendFile();
});
startServer();
字符串
我可以确认所有的mp3文件都已处理,但浏览器只播放第一个文件的音频。需要说明的是,我并没有在客户端做任何事情--我只是将Chrome指向express API端点。
我希望得到相同的结果,如果我看到Chrome指向任何其他(工作)流音频URL,如https://audio1.maxi80.com。
有没有想过我做错了什么?
1条答案
按热度按时间7eumitmz1#
我让你的代码工作,因为是,它是成功地过渡到下一首歌的整个目录的mp3文件(50 mb的总)。这12个文件都是以同样的方式从CD上撕下来的。但有几件事让我印象深刻。
最重要的。您可能需要一个Content-Length头,它是发送的文件大小的总和。我黑进了这个
字符串
这使得浏览器的简单音频播放器能够更好地估计总的流时间。进度条在一个合理的位置,而不是只保持在最后。
x1c 0d1x的数据
我注意到的第二件事是,当回调调用
res.write
时,没有对读取流进行节流。当客户端连接时,50 MB的数据几乎立即被推入写入流。您可以在console.log语句中破解,在每个data
回调中打印出chunk.length
,以了解我的意思。我想浏览器很快就把它拉下来了,因为我在本地主机上。但是,如果客户端的缓冲区有限,并且与音乐同步,那么这不会给节点进程带来很大的字节背压吗?考虑将
drain
事件挂接到响应对象上,并以所需的速度写入响应流。我可能错了,但是如果客户端本身没有做太多的缓冲,缓冲就没有免费的午餐。最后一件事我不知道你正在处理的文件,但是如果任何ID 3头包含某种长度提示,那可能会让浏览器客户端的播放器感到困惑。因此,上面插入的Content-Length头应该可以解决这个问题。(免责声明:我不认为ID 3头实际上包含长度提示。我可能是错的)。