给定 <audio> 元素源通过 HTTP 进行流式传输会导致延迟(缓冲)?

问题描述 投票:0回答:1

我在 FastAPI 中有一个简单的 API 流生成器,由于整个数据的处理成本高昂,它可以动态传输音频块(即 wav)。但是,音频不会立即开始,除非传输一些较大的块(即超过 5-10 秒)或通过停止服务器来关闭连接。

<audio
    ref={audioRef}
    controls={true}
    autoPlay={true}
    onCanPlayThrough={() => {
        console.log("Can play through.");
        setIsLoaded(true);
    }}
    onError={(err) => {
        console.log("Error loading.");
        console.error(err);
    }}
    onLoadedData={(event) => {
        console.log("Loaded data.");
        console.log(event);
    }}
    onLoadedMetadata={(event) => {
        console.log("Loaded metadata.");
        console.log(event);
    }}
    onWaiting={(event) => {
        console.log("Audio is waiting for more data.");
        console.log(event);
    }}
>
    <source id="source" src="/audio" type="audio/wav"/>
    Your browser does not support the audio element.
</audio>

这是生成第一个块时的响应:

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: *
Access-Control-Allow-Headers: *
date: Fri, 05 Jan 2024 20:04:48 GMT
server: uvicorn
content-type: audio/wave
connection: close
transfer-encoding: chunked

此外,标签的 HTMLMediaElement 不会触发任何事件,除非如上所述流式传输一些较大的块或通过停止服务器关闭连接,然后才开始实际播放。

还测试了:

curl -m 15 -o output.wav http://localhost:5000/audio
效果符合预期。

在自动播放启动之前需要多少缓冲是否有任何限制,或者是否需要做一些特定的事情?流式传输的块长度为 3-4 秒,当然第一帧包含用于解码的元数据。我想要立即刷新第一个块并立即播放。然而,情况并非如此,我可能不得不依赖一些较低级别的接口来手动播放每个块,因为它们是连续音频数据的完全实时播放。

http audio html5-audio audio-streaming
1个回答
0
投票

是的,浏览器将进行缓冲,直到确信可以播放流而不会丢失。这可能有点过时,但在 Chromium 中曾经是:

  • 用于嗅探的固定大小缓冲区 - 在发送大约 8 KB 的数据之前,浏览器甚至不会尝试解码,因为它需要“嗅探”类型,并且为此需要一些数据。显然,如果您使用直接 PCM,您将很快填充该缓冲区,但这里可能存在另一个问题,因为浏览器不知道您正在发送的编解码器。 WAVE 文件可以包含许多编解码器。尽管它几乎总是 LPCM,但也可能是其他东西,所以也许您遇到了问题。

  • “网络”缓冲——这是更实用的缓冲区,以确保流畅的流。填充此缓冲区的速度越快,播放就会越早开始。如果连接时,您的服务器闲置并且不立即发送任何数据,那么浏览器可能会认为它需要缓冲更长时间。你提到你正在 3-4 秒的时间内做事......这实际上可能是你的问题。如果您发送了几秒钟,然后停止发送数据直到另外 3-4 秒,浏览器在收到数据之前并不知道它可以期待该数据。

您应该在可能的情况下进行预缓冲,并在连接后立即将数据刷新到客户端,并在获取数据时以流式传输方式(而不是分块)继续向其发送数据。您始终可以稍后通过将播放速率提高一小部分来降低预缓冲的延迟,直到实时播放头赶上缓冲的数据。请注意,浏览器缓冲是有原因的......并且您不想在高延迟连接上中断用户,所以不要将其推得太远。

我可能必须依赖一些较低级别的接口来手动播放每个块,因为它们是连续音频数据的完全实时播放

不,浏览器本质上是为你做这件事的。无论如何,您绝对不想尝试手动逐个播放块。你永远无法让它们对齐。它们最少需要缓冲并作为一个大流播放。即使你可以对齐它们,你也会有省电设备启动并停止播放,因为到处都没有播放任何内容。最坏的情况是,您可以使用 MediaSource 扩展(带有一些编解码器/容器)来获得更多控制,但您的用例实际上并不需要它。

© www.soinside.com 2019 - 2024. All rights reserved.