在网页中播放分成多个文件的音频

Playing audio broken into multiple files in webpage

我想在我的网页上播放有声读物。有声读物是一个 .zip 文件,其中包含多个 .mp3 文件,书中的每一章都有一个。所有文件的运行时间都是几个小时,它们的累计大小是60MB。 .zip 存储在服务器端 (Express.js)

如何在客户端连续播放每个文件(例如在<audio>元素中),使有声书播放流畅,就像1个文件一样?

我需要使用 MediaStream 对象吗?如果可以,怎么做?

-谢谢

也许这会对你有所帮助

<audio controls="controls">
  <source src="track.ogg" type="audio/ogg" />
  <source src="track.mp3" type="audio/mpeg" />
Your browser does not support the audio element.
</audio>

我能想到的唯一选择是使用 javascript mp3 解码器(或将 C 解码器编译为 asm.js/wasm)并使用音频 API。或者使用 mux.js 之类的东西将 mp3 包装在 mp4 中,并使用媒体源扩展来播放。

我会在另一个 上看一下这个答案,但是我做了一些修改以匹配您的问题:

var audioFileURLs= [];

function preloadAudio(url) {
    var audio = new Audio();
    // once this file loads, it will call loadedAudio()
    // the file will be kept by the browser as cache
    audio.addEventListener('canplaythrough', loadedAudio, false);
    audio.src = url;
}

var loaded = 0;
function loadedAudio() {
    // this will be called every time an audio file is loaded
    // we keep track of the loaded files vs the requested files
    loaded++;
    if (loaded == audioFileURLs.length){
        // all have loaded
        init();
    }
}

var player = document.getElementById('player');
function play(index) {
    player.src = audioFiles[index];
    player.play();
}

function init() {
    // do your stuff here, audio has been loaded
    // for example, play all files one after the other
    var i = 0;
    // once the player ends, play the next one
    player.onended = function() {
        i++;
        if (i >= audioFiles.length) {
            // end 
            return;
        }
        play(i);
    };
    // play the first file
    play(i);
}

// call node/express server to get a list of links we can hit to retrieve each audio file
fetch('/getAudioUrls/#BookNameOrIdHere#')
.then(r => r.json())
.then(arrayOfURLs => {
    audioFileURLs = arrayOfURLs
    arrayOfURLs.map(url => preloadAudio(URL))
})

然后在屏幕上显示一个 ID 为 "player" 的音频元素,例如 <audio id="player"></audio>

虽然有了这个答案,arrayOfURLs 数组必须包含 URL 到您服务器上的 API,它将打开 zip 文件和 return 指定的 mp3数据。您可能还只想将此答案作为一般参考,而不是完整的解决方案,因为需要进行优化。您可能应该首先加载第一个音频文件,在第一个文件结束前 5 分钟左右,您可能想要开始预加载下一个文件,然后对整个过程重复此过程......这一切都取决于你,但这应该有望让你站起来。

你也可能 运行 遇到音频元素的问题,因为它只会显示它所在的当前音频片段的长度,而不是有声读物的完整长度。我会选择相信这个 zip 文件中有按章节分隔的书吗?如果是这样,您可以创建一个章节选择器,这几乎可以让您跳转到特定的章节,也就是 getAudioUrls URL。

希望对您有所帮助!


给你的另一条注意事项......阅读你对下面潜在答案的评论,你可以使用某种节点模块将所有音频文件组合成一个(audioconcat 是我在快速 google 搜索)和 return 将一个文件发送给客户端。但是,我个人不会选择这条路线,因为整本有声读物在将它们组合在一起时将存储在服务器的内存中,直到 return 将其发送给客户端。这可能会导致一些内存问题,所以如果可以的话我会避免它。但是,我承认这个选项可能会很好,因为有声读物的全长将显示在音频元素时间轴中。


最好的选择可能是将书籍的全长和章节长度存储在 zip 文件中的 details.json 文件中,并在第一个 API 调用中将其连同 URLs 到每个音频文件。这将使您能够构建一个不错的 UI.