我有一个 Angular 客户端和一个 SpringBoot 服务器。在服务器上,我有一个端点,可以从文本生成音频文件。音频文件的生成依赖于另一个需要太长时间(5 秒以上)的 API,我不想让用户等待超过 5 秒才能开始音频。
为了解决时间问题,我在从 API 接收字节时返回一个 Flux(支持流式传输)。到这里为止,一切都很好。端点代码:
@PostMapping(value = "/speech")
public Flux<DataBuffer> generateSpeechAudio(@RequestBody @Valid SpeechRequest speechRequest) {
return audioService.generateSpeech(speechRequest);
}
在客户端(Angular),我想在字节下载完成之前调用 API 并启动音频。为此,我正在使用 reportProgress 并观察客户端调用中的事件:
transcribeTextToAudio(toAudio: ITranscript): Observable<HttpEvent<string>> {
return this.httpClient.post<string>(`${this.transcriptionLink}/speech`, toAudio, {
observe: 'events',
responseType: 'arrayBuffer' as 'json',
reportProgress: true,
});
}
我不确定如何获取字节并“播放它们”,或者即使这样的事情是可能的。使用 MediaSource 可以,但只有我等待整个文件下载。
使用 MediaSource 是一种方法,但它仅适用于几个编解码器和容器,并且可能很棘手。
更好的方法是让浏览器处理播放和流式传输。 为此,请不要发出 POST 请求,而是发出 GET 请求。 尝试这样的事情:
const audioUrl = new URL('speech', this.transcriptionLink);
audioUrl.searchParams.set('text', 'text to speak goes here');
const audio = new Audio(audioUrl);
audio.play(); // Do this on-click or some similar user action, at least at first to avoid autoplay policy issues.
在这种情况下,浏览器通过音频元素为您发出 GET 请求。 一旦它认为有足够的缓冲,它就会开始播放。