【问题标题】:How to stream consecutive DYNAMIC audio files from NodeJS to HTML5 audio tag- as one stream如何将连续的动态音频文件从 NodeJS 流式传输到 HTML5 音频标签 - 作为一个流
【发布时间】:2021-04-15 23:46:43
【问题描述】:

从安卓设备,节点服务器正在接收 arrayBuffer 格式的原始数据文件块。 服务器将它们单独转换(比如说 10 秒的可播放音频)转换为 WAV 格式,以便流式传输到 HTML5 音频文件。 这个想法是,只要 android 按下“发送”,浏览器就可以立即开始听到流式音频文件。

如何将这些文件连续流式传输到 HTML 音频标签,使其听起来像一个大文件?

目前我可以将一个 10 秒的文件流式传输到标签并播放。我还尝试了音频标签“onended”属性来尝试获取下一个 10 秒的文件,但您可以听到它没有作为一个文件连接。

   const audioStream = fs.createReadStream(audioPath);

   audioStream.pipe(res);

理想情况下,我需要在所有文件从 android 客户端传入时连续通过管道传输它们,这意味着我不能首先将它们连接到一个文件中,因为服务器仅在浏览器播放它们时才接收它们(延迟最多几秒钟就可以了)。

可以做什么?

编辑:

这是我尝试过的:

  var audio = document.getElementById('my');
  var mediaSource = new MediaSource();
  var SEGMENTS = 5;
  var oReq = new XMLHttpRequest();

  mediaSource.addEventListener('sourceopen', function() {

    var sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');

    sourceBuffer.addEventListener('updateend', function() {
        //GET('6.mp3', function(data) { onAudioLoaded(data, index); });
      oReq.open("GET", '6.mp3');
      oReq.responseType = "arraybuffer";
        oReq.send();
    });

    function onAudioLoaded(data, index) {

      sourceBuffer.appendBuffer(data);
    }

    function h(){
      var arraybuffer = oReq.response; // not responseText
      onAudioLoaded(arraybuffer, 0)
     // console.log(arraybuffer);
    }

目前,我正在从服务器获取相同的 mp3 文件,并希望将它们串在一起以查看它是否有效。 正如我在下面提到的,我收到“源缓冲区已满”错误。

从长远来看,我会将其移至 websocket,因此每次服务器接收到一个块时,它都会发送到这里,从而将结果串成一个“实时流”。 有什么想法吗? 谢谢

编辑:

事实证明,我的整个方法都是错误的; 因为我将每个接收到的原始音频块转换为一个唯一的 mp3 文件(它不能是 WAV,因为没有“媒体源扩展”支持)——即使我能够使用 MSE 将它们串在一起,每个文件之间的间隔是听到。我假设这是因为每个 mp3 文件中都有“填充”。

有没有人可以在浏览器中无缝播放我的原始音频块?除非我在这个“实现”中遗漏了一些东西。 谢谢。

【问题讨论】:

  • 尝试使用媒体源扩展。谷歌搜索 Media Source Extensions play mp3 并经过研究,在这里询问您尝试的任何方法(您自己的代码)是否不起作用,我们会尝试帮助您修复它。
  • 试用后,似乎有潜力,但是,sourceBuffer 对它可以容纳的数量有限制,然后我收到此错误:(index):118 Uncaught DOMException: Failed to在 'SourceBuffer' 上执行 'appendBuffer':SourceBuffer 已满,无法释放空间来附加额外的缓冲区。似乎有一种从缓冲区中删除的方法,但只有在缓冲区没有更新时才能这样做。你能帮忙吗?
  • 我以前见过这个错误,但我不记得原因了。我认为我的 mime 字符串格式错误。给我看一些可测试的代码......你如何加载数据并追加?使用edit mode 选项更新您的帖子,使用一些我们可以检查问题的代码。
  • 我添加了代码,谢谢。
  • 你也可以在这个例子中看到,从你提到我的地方,在检查器中抛出了同样的异常:72lions.github.io/PlayingChunkedMP3MediaSourceAPI

标签: node.js html5-audio fs audio-streaming


【解决方案1】:

关于“如何将连续的动态音频文件作为一个流播放”的问题...

尝试如下所示的代码设置。在 Chrome 上测试。
(某些名称已更改,例如您的 var arraybuffer 现在是 input_MP3_Bytes):

<!DOCTYPE html>
<html>
<body>

<audio id="audioMSE" controls></audio>

<script>

var input_MP3_Bytes = []; var mediaSource; var sourceBuffer;
var is_FirstAppend = true; //# for setting up MSE if first append.

var mimeCodec = 'audio/mpeg;'; //# tested on Chrome browser only
//var mimeCodec = 'audio/mpeg; codecs="mp3"';  //# untested.. maybe needed by other browsers?

//# for audio tag reference
var myAudio = document.getElementById('audioMSE'); 
myAudio.play(); //# start conveyor belt (to receive incoming bytes)

//# load some input MP3 bytes for MSE
var fileURL = "file_01.mp3"; //"6.mp3"
load_MP3( fileURL ); 

function load_MP3( filename ) 
{
    var oReq = new XMLHttpRequest();
    oReq.open("GET", filename, true);
    oReq.responseType = "arraybuffer";
    oReq.addEventListener('loadend', on_MP3isLoaded  ); 
    oReq.send(null);
}

function on_MP3isLoaded() 
{
    input_MP3_Bytes = new Uint8Array( this.response ); //# fill the byte array
    
    if (is_FirstAppend == true) 
    {
        console.log( "MSE support : " + MediaSource.isTypeSupported(mimeCodec) );
        makeMSE(); is_FirstAppend = false;
    }
    else { sourceBuffer.appendBuffer( input_MP3_Bytes ); }
 
}

function makeMSE ( ) 
{
    if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec) ) 
    {
        mediaSource = new MediaSource;
        myAudio.src = URL.createObjectURL( mediaSource );
        mediaSource.addEventListener( "sourceopen", mse_sourceOpen );
    } 
    else { console.log("## Unsupported MIME type or codec: " + mimeCodec); }
}

function mse_sourceOpen() 
{
    sourceBuffer = mediaSource.addSourceBuffer( mimeCodec );
    sourceBuffer.addEventListener( "updateend", mse_updateEnd );
    
    //sourceBuffer.mode = "sequence";
    sourceBuffer.appendBuffer( input_MP3_Bytes );
    
};

function mse_updateEnd() 
{
    //# what to do after feeding-in the bytes...?
    //# 1) Here you could update (overwrite) same "input_MP3_Bytes" array with new GET request 
    //# 2) Or below is just a quick test... endless looping
    
    //# 1) load another MP3 file 
    fileURL = "file_25.mp3";
    load_MP3( fileURL ); 
    
    //# 2) re-feed same bytes for endless looping
    //sourceBuffer.appendBuffer( input_MP3_Bytes );
    
    //mediaSource.endOfStream(); //# close stream to close audio
    //console.log("mediaSource.readyState : " + mediaSource.readyState); //# is ended
}

</script>

</body>
</html>

【讨论】:

  • 感谢您的回复。与我尝试过的类似,在测试您的代码时,我也收到“SourceBuffer is full”错误,因此它停止附加到缓冲区。有什么办法可以解决这个问题?
  • 澄清一下,这适用于前 12mb 左右的数据。之后就不能再追加了。
猜你喜欢
  • 1970-01-01
  • 2019-10-29
  • 2011-04-18
  • 2011-04-26
  • 2012-06-11
  • 1970-01-01
  • 2014-11-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多