原理介绍:
项目需求 Web端播放实时音频流,折腾了两天后问题得以解决。记录下开发调试过程,方便后来者。首次想到是利用Audio标签,Audio标签可以直接播放MP3格式,服务端将实时音频流编码成WAV格式通过Http方式传给Web端即可。采用Audio Web API方式播放实时流会出现卡顿现象,以上方法一次性解码的数据可以连续播放,每次解码后要重新创建BufferSource,显而易见这种播放模式播放实时流效率很低,查阅了Audio Web API 文档 播放网络流似乎要利用,基于AudioWorkletProcessor的自定义节点,文档也给了一个简单的例子。另外一种可行的方法是服务端输出Rtmp音频流 通过video.js播放实际应该是用了flash。项目开始已经想到了这个方案可行只是觉得有些绕(需要将音频流封装后推送到rtmp server)。另外一个可行的方案就是利用H5 MSE实现,这个方案也有开源的库可以用,例如video.js 或flv.js这需要服务端将音频打包成flv格式,推送给Web前端,Web端接收到音频数据后调用flv.js进行播放。
前端代码如下所示:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>Web Audio API 测试</title>
<script src="../static/js/reconnectingwebsocket.js"
th:href=@{/js/reconnectingwebsocket.js}></script>
</head>
<body>
<table>
<tr>
<td>参数:</td>
<td><input style="width: 390px;" type="text" name="type"
id="type"></td>
<td>
<button onclick="onSendMessage()">发送消息</button>
</td>
<td>
<button onclick="onCloseMessage()">断开连接</button>
</td>
</tr>
</table>
</body>
<script>
//Web Audio API
var nextStartTime = 0;
var context = null;
try {
context = new (window.AudioContext || window.webkitAudioContext)();
} catch (e) {
alert('您当前的浏览器不支持Web Audio API ');
}
var objSocket = null;
var wsUrl = 'ws://localhost:8080/Audiowebsocket';
if ('WebSocket' in window) {
//objSocket = new ReconnectingWebSocket(wsUrl);
objSocket = new WebSocket(wsUrl);
} else {
alert('Not support websocket')
}
/**
WebSocket服务连接
*/
objSocket.onopen = function(evt) {
onOpen(evt)
};
objSocket.onclose = function(evt) {
onClose(evt)
};
objSocket.onmessage = function(evt) {
onMessage(evt)
};
objSocket.onerror = function(evt) {
onError(evt)
};
function onOpen(evt) {
console.log("Connected to WebSocket server.");
}
function onClose(evt) {
console.log("Disconnected");
}
function onError(evt) {
console.log('Error occured: ' + evt.data);
}
function onMessage(evt) { //websocket返回数据信息处理
//console.log('Retrieved data from server: ' + evt.data);
var reader = new FileReader(); //文件阅读器
reader.readAsArrayBuffer(evt.data); //读取成ArrayBuffer对象
reader.onload = function() { //读取完毕
//解码
context.decodeAudioData(this.result, function(buffer) {
console.log("decode success");
playSound(buffer);
}, function(e) {
console.log("decode failed");
"Error with decoding audio data" + e.