audio 标签 加载url 音频总时长及拖动条不能拖动 问题
H5的audio标签,在使用过程中,出现有些情况出现总时长,有些时候没有总时长的情况。有总时长:src是本地文件时,及使用云存储url地址时,显示总时长。<div id="audioDiv"><audio id="aud" controls preload><source src="a.wav" type="audio/wav"></audio>&l
·
浏览器:Chrome
H5的audio标签,在使用过程中,出现有些情况出现总时长,有些时候没有总时长的情况,并且拖动条也不可拖动(自定义资源接口情况)。
有总时长:src是本地文件时,及使用云存储url地址时,显示总时长。
<div id="audioDiv">
<audio id="aud" controls preload>
<source src="a.wav" type="audio/wav">
</audio>
</div>
无总时长:src地址是后台服务器读取音频文件后,回写的数据流并且响应头不包含Content-Length。
<div id="audioDiv">
<audio id="aud" controls preload>
<source src="http://localhost:12386/audio" type="audio/wav">
</audio>
</div>
后台服务器代码:audio标签获取不到总时长的缘故是当后台写回数据流,响应头没有Content-Length时,无法获取到总时长,只有加上该响应头,audio标签才能正确的获取总时长。
@RequestMapping("audio")
public void audio(HttpServletResponse response) throws IOException {
File f = new ClassPathResource("a.wav").getFile();
FileInputStream fis = new FileInputStream(f);
// 无所谓,application/octet-stream也可以,不写也可以
response.setHeader("Content-Type", "audio/wav");
// 关键所在,如果后台直接读取文件流写回客户端,无Content-Length,则audio标签无法获取总时长
response.setHeader("Content-Length", f.length() + "");
byte[] buf = new byte[4096];
int len;
while ((len = fis.read(buf)) != -1) {
response.getOutputStream().write(buf, 0, len);
}
response.getOutputStream().flush();
}
拖动条不能拖动问题:后端需要继续增加响应头 Content-Range, Accept-Ranges
@GetMapping("audio/{fileName}")
public void audio(HttpServletResponse response, HttpServletRequest request, @PathVariable("fileName") String fileName) throws IOException {
File f = new ClassPathResource(fileName).getFile();
FileInputStream fis = new FileInputStream(f);
// audio / video 标签拖动时发送的请求, 第一次:bytes=0-, 后续:bytes=startPos-endPos
String rangeString = request.getHeader("Range");
// range 值
long rangeStart = Long.parseLong(rangeString.substring(rangeString.indexOf("=") + 1, rangeString.indexOf("-")));
// range范围是从0个字节开始,所以结束位置下标是文件长度-1
long rangeEnd = f.length() - 1;
// 解析请求Range头信息,bytes=xxx-xxx, (存在0-0,-1这种情况,暂不考虑)
if (rangeString.indexOf("-") < rangeString.length() - 1) {
rangeEnd = Long.parseLong(rangeString.substring(rangeString.indexOf("-") + 1));
}
// chrome浏览器第一次发送请求,range开始为0
if (rangeStart == 0) {
// 没有这个header,audio没有总时长,第一次请求返回总长度
response.setHeader("Content-Length", f.length() + "");
} else {
// 配合content-range头使用,后续Content-Length代表分段大小
response.setStatus(HttpStatus.PARTIAL_CONTENT.value());
response.setHeader("Content-Length", (rangeEnd - rangeStart + 1) + "");
}
// 不太重要
response.setHeader("Content-Type", fileName.endsWith("wav") ? "audio/wav" : "audio/mp3");
// range范围 start-end/total, 这个头可以不要,但是如果不要(content-length必须为文件总大小),每次拖拽,浏览器请求的文件都是全量大小的文件, 浪费带宽
response.setHeader("Content-Range", "bytes " + rangeStart + "-" + rangeEnd + "/" + f.length());
// 告知video / audio标签可以接受范围单位,这个头必须传递
response.setHeader("Accept-Ranges", "bytes");
// 不重要
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
// skip bytes
if (rangeStart > 0) {
long skipped = fis.skip(rangeStart);
System.out.println(fileName + ", skipped: " + skipped + ", total: " + f.length());
}
byte[] buf = new byte[4096];
int len;
long total = 0L;
while ((len = fis.read(buf)) != -1) {
total += len;
response.getOutputStream().write(buf, 0, len);
}
System.out.println(fileName + ", write: " + total + ", range: " + (rangeEnd - rangeStart));
response.getOutputStream().flush();
}
更多推荐
已为社区贡献6条内容
所有评论(0)