转码和streamaudio – 如何发送内容范围标题

快速版本:当不知道身体长度时如何发送正确的Content-Range标题?

我有一个FLAC文件。 我想将其转码成MP3并立即将其stream式传输给用户。 到目前为止,我有这样的事情:

 function transcode(file) { var spawn = require('child_process').spawn var decode = spawn('flac', [ '--decode', '--stdout', file ]) var encode = spawn('lame', [ '-V0', '-', '-' ]) decode.stdout.pipe(encode.stdin) return encode } var express = require('express') var app = express() app.get('/somefile.mp3', function (req, res) { res.setHeader('Accept-Ranges', 'bytes') res.setHeader('Content-Range', 'bytes') res.setHeader('Content-Type', 'audio/mpeg') transcode(file).stdout.pipe(res) }) 

这按预期工作,但它是“stream”,所以我不能跳过。 显然我需要做Content-Range东西。 使用: https : //github.com/visionmedia/node-range-parser

 function sliceStream(start, writeStream, readStream) { var length = 0 var passed = false readStream.on('data', function (buf) { if (passed) return writeStream.write(buf); length += buf.length if (length < start) return; passed = true writeStream.write(buf.slice(length - start)) }) readStream.on('end', function () { writeStream.end() }) } var parseRange = require('range-parser') app.get('/somefile.mp3', function (req, res) { var ranges = parseRange(Infinity, req.headers['range']) if (ranges === -1 || ranges === -2) return res.send(400); var start = ranges[0].start res.setHeader('Accept-Ranges', 'bytes') res.setHeader('Content-Type', 'audio/mpeg') if (!start) { res.setHeader('Content-Range', 'bytes') transcode(file).stdout.pipe(res) return } res.setHeader('Content-Range', 'bytes ' + start + '-') sliceStream(start, transcode(file).stdout, res) }) 

这是我卡住的地方。 由于我没有等到整首歌被编码,我不知道这首歌的大小。 由于我刚刚在Chrome中取消了“已取消”,因此我假定Content-Range标头的格式不正确。

另外,我目前只是在浏览器中打开歌曲,所以我假设它使用<audio>元素。

build议?

是的,您的Content-Range标题格式不正确。 但是,您可以尝试发送服务器已经转码的当前大小。 尽pipe我怀疑Chrome能够优雅地处理尺寸的变化,

有很多事情你没有处理 :

  1. 您似乎没有发送206 Partial Content状态(也许这是由图书馆处理,不知道)。
  2. 它看起来不像你甚至检查范围请求的结束部分。 铬通常不会发送任何东西,但0- ,但其他浏览器会。 事实上,有些人可能会在一个请求中发送多个范围(皇家疼痛屁股支持)。
  3. 您没有发送适当的Content-Range响应标题,因为您也未能包含您发送的内容的结束索引。 它应该是这样的:
    Content-Range: bytes 0-2048/3980841
  4. 最后,如果客户端发出的范围请求超出范围,也就是说,范围值中没有一个与资源的范围重叠,则服务应该以416 Requested Range Not Satisfiable状态进行响应。

编辑:我还没有testing过这个特殊的情况,但是如果你从FLAC转换到192kbps的CBR MP3,我会想象如果你发送一个稍微不准确的内容长度(closures小于1000位):

  • audio的最后会被播放器截断。 〜1000位可以剪辑大约5ms的audio(对人不明显)。
  • 浏览器会忽略最终索引或内容长度,只是保持接受和/或请求范围以外的原始响应的Content-Range ,直到您closures连接或发送416状态。
  • audio的缺失/错误结束可能会导致<audio>引发MEDIA_ERR_NETWORKMEDIA_ERR_DECODE错误,您只需要优雅地处理。 (在这种情况下audio仍然会被剪辑。)