我有一个 mp3 音频流播放器,可以在每个桌面浏览器中正常运行,使用 MediaSourceExtensions 并为那些不支持 MSE 的浏览器回退到 WebAudioAPI。 iOS Safari 就是这样一种浏览器,理论上应该支持通过 Web Audio API 进行 mp3 解码,不会出现任何问题。
我一直在努力让 iOS Safari 正确播放从流返回的 mp3 音频块。到目前为止,它是唯一一个似乎有问题的浏览器,我一生都无法弄清楚发生了什么。遗憾的是,关于此类极端情况的信息并不多,而且 StackOverflow 上的其他问题也没有任何帮助。
这是我的 js 代码的相关部分,事情被挂断了。它是异步
fetch()
进程的回调函数,该进程从流中获取 mp3 数据。
async function pushStream(value) {
// Web Audio streaming for browsers that don't support MSE
if (usingWebAudio) {
// convert the stream UInt8Array to an ArrayBuffer
var dataBuffer = value.stream.buffer;
// decode the raw mp3 chunks
audCtx.decodeAudioData(dataBuffer, function(newData) {
// add the decoded data to the buffer
console.log("pushing new audio data to buffer");
webAudioBuffer.push(newData);
// if we have audio in the buffer, play it
if (webAudioBuffer.length) {
scheduleWebAudio();
}
}, function(e) {
console.error(e);
});
我看到的是错误回调被触发并打印
null: null
作为其错误消息(非常有帮助)。每隔一段时间,我就会看到控制台打印pushing new audio data to buffer
,但这似乎只在流播放时每隔几分钟发生一次。几乎所有流数据在解码过程中都会出错,并且缺乏有用的错误消息使我无法弄清楚原因。
据我所知,iOS safari 应该支持 mp3 流,没有任何问题。它还应该支持
decodeAudioData()
功能。我能找到的大多数其他答案都与在用户与屏幕交互之前尝试播放音频有关。就我而言,我使用页面上的播放按钮启动音频,所以我也不认为这是问题所在。
最后一件事,我正在 Windows 上进行开发并使用 remotedebug iOS 适配器。这可能是我没有收到有用的调试消息的原因,但是所有其他调试和错误打印似乎都工作正常,所以我不相信情况是这样。
预先感谢您的帮助!
不幸的是,Safari 中有一个错误,导致它以 null 拒绝
decodeAudioData()
承诺。根据我的经验,这种情况发生在它实际上应该用 EncodingError
来拒绝承诺的情况下。
可以通过要求 Safari 解码图像来重现该错误。 https://github.com/chrisguttandin/standardized-audio-context/blob/9c705bd2e5d8a774b93b07c3b203c8f343737988/test/expectation/safari/any/offline-audio-context-constructor.js#L648-L663
一般来说
decodeAudioData()
只能处理完整文件。它无法按块解码文件。 WebCodecs API 旨在解决这个问题,但我想它不会很快在 iOS 上可用。
然而,由于 MP3 的内部结构,有一种技巧适用于 MP3。 MP3 是由块本身构建的,任意数量的这些块就形成了技术上有效的 MP3。这意味着您可以通过确保传递到
decodeAudioData()
的每个缓冲区恰好在这些内部块边界处开始和结束来预处理数据。例如,phonograph 库确实遵循了这一原则。
MediaSourceExtensions 对于那些不支持 MSE 的浏览器可回退到 WebAudioAPI
Web Audio API
decodeAudioData()
并不是 MSE 功能的合适替代品。 你想要做的事情根本不可能通过这种方式实现。
即使您确实对块进行了预处理以将它们对齐为整齐的 MPEG 帧,一旦解码,您将获得在每个帧边界处听起来很奇怪的音频。 (另请参阅:MP3 无缝播放。)
最好的办法就是根本不需要 MSE。 如果您可以通过 HTTP 流式传输内容,请改为这样做,并让浏览器使用
<audio>
或 <video>
等媒体元素来处理它。