我正在使用Ionic 3框架开发互联网广播应用程序。我想出了这个使用HTML5音频元素的简单代码。许多人认为这种方法比使用@ ionic-native / streaming-media插件更好。
以下是我的实施:
HTML
<audio id="audioStream" src="http://icecastserverIP:8000/icecastchannel" autoplay></audio>
<a href="#" id="player">
<div class="btn-play" id="con-btn-play">
<img src="assets/img/btn-play.png" alt="Play">
</div>
</a>
JS
$(document).ready(function(){
var audio = $('#audioStream')[0]
// Preloader animation
audio.addEventListener('waiting', function () {
$('#con-btn-play').html('<img src="assets/img/preloader.gif">');
}, false);
audio.addEventListener('playing', function () {
$('#con-btn-play').html('<img src="assets/img/btn-pause.png">');
}, false);
// Play button behaviour
$('#player').click(function(){
if (audio.paused){
audio.play();
$('#con-btn-play').html('<img src="assets/img/btn-pause.png" alt="Pause">');
}else {
audio.pause();
$('#con-btn-play').html('<img src="assets/imgs/btn-play.png" alt="Play">');
}
});
});
该流在Android和iOS中播放得很好。但是,在最轻微的连接丢失时,音频将停止并且不会重新连接。更不用说如果我按暂停,流将继续使用后台数据。
我的问题是:有没有更好的方法来处理Icecast流?您建议使用第三方插件以获得更好的缓冲管理和播放体验?
但是,在最轻微的连接丢失时,音频将停止并且不会重新连接。
您可以通过处理Audio元素上的error
事件来重新连接您自己的代码。 https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/onerror
更不用说如果我按暂停,流将继续使用后台数据。
是的,您需要创建自己的UI来控制此元素。当有人停下来时,你会想要打电话给.stop()
。默认情况下,音频元素采用常规音频文件,该文件在某个时刻结束。
第三方插件......
不需要插件。
...更好的缓冲管理和游戏体验?
根据我在这个答案中提出的两条建议,您可以为用户提供有用的体验。但是,您可能遇到的其他两个问题尚未涉及。
第一个是不请求常规ICY元数据,也不由浏览器解码。
第二个问题是,由于浏览器将流视为常规音频文件,因此它还将所有音频数据缓冲到内存中。这对于您将永远不会返回并播放以前播放的音频的直播流来说并不是非常有用。 (这很少是您遇到的问题,因为音频数据需要相对较少的内存,但问题确实存在。)
这两个都是通过使用MediaSource Extensions解决的。使用MSE,您可以直接控制检索数据,对元数据进行解复用,以及将数据推送到要播放的缓冲区。由于您的代码处于控制之中,因此您可以无限期地流式传输而不会泄漏内存。
我建议的第一件事是在你的Icecast服务器设置中增加<queue-size>
和<burst-size>
的值。
默认情况下,服务器只会在连接时将64kb的音频流作为缓冲区发送,对于320kbps的mp3流,小于2秒。
将<audio>
元素的preload标记设置为none或元数据可以防止暂停时无限数据流,或者您可以将playbackRate
参数设置为0.0或将src
更改为空值,然后在audio元素上调用.load()
以断开客户端与流暂停。
通过在连接时添加额外的请求标头,您的Icecast服务器可以将元数据直接编码到音频流中。优点是,将元数据更新与音频同步变得简单。
我编写了一个基本的服务工作者脚本来处理该过程,它为请求添加了必要的头,然后解析返回的流以提取元数据并创建一个可读的流,其中只包含传递给音频元素的音频数据。
如果你想尝试一下,代码在Github here上。