java - 流式音频不会使用音频标签播放
问题描述
我正在尝试制作音频流服务,为此我创建了一个服务器来处理音频标签的请求并使用请求的适当块进行响应。但是,当我尝试在浏览器中播放它时,虽然我可以看到浏览器发出的请求,但我仍然无法播放它。知道有什么问题吗?
提供块的服务器代码
@GetOperation(endpoint = "/stream/song")
public HttpResponse getChunkAudioTag(@RequestHeader(RANGE_HEADER_KEY) String range, @QueryParameter("id") String songId) throws Exception {
JSONObject songInfo = fakeDbDAO.getSongById(songId);
String fileName = (String) songInfo.get("filename");
try (FileInputStream fileInputStream = new FileInputStream(
new File(String.format(RESOURCES_FOLDER_PATH_TEMPLATE, fileName, FileFormat.MP3.getExtension()))
)) {
Headers headers = new Headers(
ACCEPT_RANGES_HEADER_KEY, BYTES,
Headers.CONTENT_TYPE, "audio/mpeg",
Headers.CONNECTION, ConnectionType.KEEP_ALIVE.getValue()
);
int fileSize = fileInputStream.available();
if (range == null) {
return HttpResponse
.builder()
.headers(headers)
.requestStatus(RequestStatus.OK)
.build();
}
String rangeString = range.split(AUDIO_TAG_RANGE_SEPARATOR)[1]; // Splits "bytes=x-y" and returns the actual range
ChunkRange chunkRange = new ChunkRange(rangeString, fileSize);
byte[] audioChunk = getAudioChunk(fileInputStream, chunkRange);
headers.addHeader(CONTENT_RANGE_HEADER_KEY, String.format(CONTENT_RANGE_TEMPLATE, chunkRange.getFrom(), chunkRange.getTo() - 1, fileSize));
headers.addHeader(Headers.CONTENT_LENGTH, String.valueOf(audioChunk.length));
return HttpResponse
.builder()
.requestStatus(RequestStatus.PARTIAL_CONTENT)
.headers(headers)
.body(convertByteArrayToString(audioChunk))
.build();
}
}
private byte[] getAudioChunk(FileInputStream fileInputStream, ChunkRange chunkRange) throws IOException {
byte[] result = new byte[chunkRange.getLength()];
fileInputStream.skip(chunkRange.getFrom());
fileInputStream.read(result);
return result;
}
private String convertByteArrayToString(byte[] chunkByteArray) {
return Base64
.getEncoder()
.encodeToString(chunkByteArray);
}
音频标签(我正在使用 React)
<audio src={`http://localhost:6543/stream/song?id=${currentSong.id}`} controls ref={audioRef} />
示例 HTTP 请求
GET /stream/song?id=1 HTTP/1.1
Host: localhost:6543
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
sec-ch-ua: "Google Chrome";v="95", "Chromium";v="95", ";Not A Brand";v="99"
Accept-Encoding: identity;q=1, *;q=0
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
sec-ch-ua-platform: "macOS"
Accept: */*
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: audio
Referer: http://localhost:3000/
Accept-Language: en-US,en;q=0.9
Range: bytes=0-
示例 HTTP 响应
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Type: audio/mpeg
Content-Range: bytes 0-99999/4127452
Content-Length: 100000
*/ base64 encoded chunk /*
解决方案
推荐阅读
- ruby-on-rails - PG::UndefinedTable:错误:关系“用户”不存在 - Azure 数据库
- javascript - 书架解决了承诺,但不保存到数据库中
- java - 带有 @MappingTarget 的 Mapstruct 不要调用 lombok Builder build()
- html - 文本未居中对齐
- openlayers - 如何将视图位置与动画结合起来?
- r - 排斥网络边缘的文本
- sql - 如何使用分隔符分隔视图中的列元素?
- vim - 突出显示一些文本并替换为剪贴板中的内容
- javascript - 正则表达式 - 捕获标记的模板文字
- c++ - 菜单驱动程序搜索功能