I am running an Icecast server and using a custom audio player to receive the stream and display the currently playing title and artist. The method I am using--JavaScript and Json--makes a request to the server every 15 seconds so that the metadada is updated as each new song plays.
Is there a way to send the changed information from the server to the browser without a request? Even 10 listeners sending requests every 15 seconds are a lot or requests if each listens for half an hour.
//Get the stream meta from xml
function ajax_get(url, callback) {
'use strict';
setInterval( function() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
//console.log('responseText:' + xmlhttp.responseText);
try {
var obj = JSON.parse(xmlhttp.responseText);
} catch(err) {
console.log(err.message + " in " + xmlhttp.responseText);
return;
}
callback(obj);
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
}, 15000);
}
ajax_get('https://listen.abengnews.com/status-json.xsl', function(obj) {
document.getElementById("scroll-text").innerHTML = obj.icestats.source.server_name + ", " + obj.icestats.source.genre + ". Now playing: " + obj.icestats.source.title + ". " + obj.icestats.source.server_description;
});
#scroll-container {
/*position: absolute;*/
background-color: #005500;
border: 1px solid black;
border-radius: 5px;
overflow: hidden;
width: 250px;
margin: auto;
font-family: arial,san-serif;
font-size:10px;
font-weight: bold;
font-color: #fff;
}
#scroll-text {
display: block;
height:12px;
white-space: nowrap;
/* animation properties */
-moz-transform: translateX(100%);
-webkit-transform: translateX(100%);
transform: translateX(100%);
-moz-animation: my-animation 15s linear infinite;
-webkit-animation: my-animation 15s linear infinite;
animation: my-animation 15s linear infinite;
}
/* for Firefox */
@-moz-keyframes my-animation {
from { -moz-transform: translateX(100%); }
to { -moz-transform: translateX(-100%); }
}
/* for Chrome */
@-webkit-keyframes my-animation {
from { -webkit-transform: translateX(100%); }
to { -webkit-transform: translateX(-100%); }
}
@keyframes my-animation {
from {
-moz-transform: translateX(100%);
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
to {
-moz-transform: translateX(-100%);
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
<div id="scroll-container">
<span class="scroll-text" id="scroll-text"><span>
</div>
I found the answer to pushing metadata of an Icecast stream to a custom HTML5 audio player by using Server-Sent Events (SSE) as defined by MDN. I learned of this method after searching how to implement websockets as suggested by @Alex Paramonov.
SSE is far simpler to implement and probably the best option for the use case that does not require two-way full duplex communication between the server and the client. All it took were two simple snippets of JavaScript and PHP.
The JavaScript listens for changes sent by the PHP, that has a 10 seconds trigger to provide info on the currently playing audio.
This is the HTML and JavaScript (found here on Stockoverflow in another answer):
<h1>Getting server updates</h1>
<div id="result"></div>
<script>
messages = new Array();
if(typeof(EventSource) !== "undefined") {
var source = new EventSource("demo_sse.php");
source.onmessage = function(event) {
if (messages.length == 10) messages.splice(-1, 1);
messages.splice(0, 0, event.data);
document.getElementById("result").innerHTML = messages.join("<br />");
};
} else {
document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>
And this is the PHP that checks the Icecast meta:
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
// prevent direct access
//if ( ! defined("ABSPATH") ) die("");
$json = file_get_contents('https://listen.example.com:8000/status-json.xsl');
$obj = json_decode($json);
$retry = 10000;
echo "data:{$obj->icestats->source->server_name}.\nretry:{$retry}\n ";
echo "data:{$obj->icestats->source->genre}. Now playing:\nretry:{$retry}\n";
echo "data:{$obj->icestats->source->title}.\nretry:{$retry}\n";
echo "data:{$obj->icestats->source->server_description}\n\nretry:{$retry}\n\n";
flush();
And that is it. I am sure that it can be tidied up.