HTML5 <audio> 直播流的糟糕选择?

标签 html audio mp3 live-streaming lame

previous question 中所述,我构建了一个原型(prototype)(使用 MVC Web API、NAudio 和 NAudio.Lame),在将其转换为 mp3 后流式传输实时低质量音频。源流是 PCM:8K、16 位、单声道,我正在使用 html5 的音频标签。

Chrome 和 IE11 上,在从浏览器听到音频之前会有 15-34 秒 延迟(高延迟),据我所知,是我们的最终用户无法接受。理想情况下,延迟不会超过 5 秒。即使在我的音频标签中使用 preload="none"属性时也会发生延迟。

仔细观察这个问题,似乎两个浏览器都在收到约 32K 的音频数据之前不会开始播放音频。考虑到这一点,我可以通过更改 Lame 的 MP3“比特率”设置来影响延迟。但是,如果我减少延迟(通过为相同长度的音频向浏览器发送更多数据),我将在稍后引入音频丢失。

例子:

  • 如果我使用 Lame 的 V0 编码,延迟将近 34 秒,这需要将近 0.5 MB 的源音频。
  • 如果我使用 Lame 的 ABR_32 编码,我可以将延迟减少到 10-15 秒,但我会在整个聆听过程中遇到停顿和中断。

问题:

  1. 有什么办法可以最大限度地减少启动延迟(延迟)吗?
  2. 我是否应该继续研究各种 Lame“预设”以期选择“正确”的?
  3. MP3 会不会不是直播流媒体的最佳格式?
  4. 改用 Ogg/Vorbis(或 Ogg/OPUS)会有帮助吗?
  5. 我们是否需要放弃 HTML5 的音频标签并使用 Flash 或 java applet?

谢谢。

最佳答案

您无法减少延迟,因为您无法控制浏览器代码和缓冲大小。 HTML5 规范不强制执行任何约束,因此我看不出有任何改进的理由。

不过,您可以使用 webaudio API 实现一个解决方案(非常简单),您可以在其中自行处理流式传输。

如果您可以将 MP3 的 block 拆分为固定大小(以便事先知道每个 MP3 block 的大小,或者至少在接收时知道),那么您可以使用 20 行代码进行直播。 block 大小将是您的延迟。

关键是使用 AudioContext::decodeAudioData。

// Fix up prefixing
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
var offset = 0;
var byteOffset = 0;
var minDecodeSize = 16384; // This is your chunk size

var request = new XMLHttpRequest();
request.onprogress = function(evt)
{
   if (request.response)
   {
       var size = request.response.length - byteOffset;
       if (size < minDecodeSize) return;
       // In Chrome, XHR stream mode gives text, not ArrayBuffer.
       // If in Firefox, you can get an ArrayBuffer as is
       var buf;
       if (request.response instanceof ArrayBuffer)
           buf = request.response;
       else
       { 
           ab = new ArrayBuffer(size);
           buf = new Uint8Array(ab);
           for (var i = 0; i < size; i++) 
               buf[i] = request.response.charCodeAt(i + byteOffset) & 0xff;
       }
       byteOffset = request.response.length;
       context.decodeAudioData(ab, function(buffer) {
           playSound(buffer);
       }, onError);
   }
};
request.open('GET', url, true);
request.responseType = expectedType; // 'stream' in chrome, 'moz-chunked-arraybuffer' in firefox, 'ms-stream' in IE
request.overrideMimeType('text/plain; charset=x-user-defined');
request.send(null);

function playSound(buffer) {
    var source = context.createBufferSource(); // creates a sound source
    source.buffer = buffer;                    // tell the source which sound to play
    source.connect(context.destination);       // connect the source to the context's destination (the speakers)
    source.start(offset);                           // play the source now
                                           // note: on older systems, may have to use deprecated noteOn(time);
    offset += buffer.duration;
}

关于HTML5 <audio> 直播流的糟糕选择?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20663149/

相关文章:

ios - fatal error : unexpectedly found nil while unwrapping an Optional value using AVAudio

c# - 如何在桌面 WPF 应用程序中播放 OGG 声音文件?

ios - 如何使用 Swift 在 iOS 中将音频格式从 mp3 转换为 wav?

java - 服务器端mp3编码

JAVA - Xuggler - 组合 MP3 音频文件和 MP4 电影时播放视频

javascript - selectize - Uncaught TypeError : $(. ..).selectize 不是函数

HTML 选择下拉箭头样式

c# - 无法在Chrome中使用接受范围:字节复制Ogg音频

css - 将按钮和链接放在 particles.js 脚本(Z-index)上

html - 粘贴后如何检查输入值长度?