2013-01-13 42 views
4

快速版本:如何发送正确的Content-Range标题时不知道身长?转码和流音频 - 如何发送内容范围标头

我有一个FLAC文件。我想将其转码为MP3并立即将其流式传输给用户。 我有这样的事情至今:

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) 
}) 

这按预期工作,但它的“流媒体”,所以我不能跳过左右。 显然我需要做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>元素。

对此提出建议?

回答

6

是的,你的Content-Range标题格式不正确,没有大小。但是,您可能会尝试发送您的服务器已经转码的当前大小。虽然我很怀疑,铬会处理不断变化的大小优雅...

There are a number of things you're not handling

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

编辑:我没有测试过这种特殊情况下,但如果你是从FLAC转码为192kbps的MP3 CBR,我会想象还有如果你发送时会出现设置的可能性只有一个极限一个稍微不准确的内容长度(关闭的不到1000位):

  • 音频的最后会得到在玩家结束修剪掉。 〜1000位将会剪辑大约5ms的音频(对人不明显)。
  • 浏览器会忽略最终索引或内容长度,并且只是保持接受和/或请求您最初回复的Content-Range以外的范围,直到您关闭连接或发送416状态。
  • 音频的丢失/错误结束可能会导致<audio>抛出一个MEDIA_ERR_NETWORKMEDIA_ERR_DECODE错误,您只需简单地处理。 (在这种情况下,音频仍然会被剪辑。)
+0

所以基本上这意味着我必须事先知道长度? –

+0

基本上是。但是,如果您进行了CBR编码,则可以轻松估计长度。你会知道代码转换后文件的长度(以毫秒为单位)和恒定比特率。 – idbehold

+0

如果不是确切的,该怎么办?有关系吗? –