Ein Problem mit dem music-streamer war von Anfang an, dass es gar nicht so einfach war, nach Ende eines Liedes das nächste zu laden. Anfangs lud desöfteren ein gewähltes Lied einfach nicht und ich begann, last-modified Header passend zu setzen und mit dem Caching rumzuspielen, um das wenigstens nicht zu einem dauerhaften nicht ladenden - weil nur als Bruchstück gecachetem - Lied werden zu lassen. Außerdem reduzierte ich die Zahl parallel offener HTTP-Verbindungen zum Server. Trotzdem, manchmal klappte es einfach nicht.
Deswegen dachte ich mir wenig dabei, dass das Problem bestehen blieb. Manchmal lud einfach das nächste Lied nicht. Doch in den letzten Tagen hatte sich irgendwas verändert, ungefähr 50% der Lieder blieben stecken, und sie luden nicht nicht, sie wurden einfach nie ausgewählt - die Playlist blieb beim gerade gespielten Lied stehen. Da sich auf dem Server nichts geändert hatte, musste es am Browser liegen. Gestern konnte ich mir mal die Zeit nehmen und den Javascript-Code des Players vereinfachen und so ausschließen, dass es am Scheitern des Prebuffern des nächsten Liedes scheiterte, denn tatsächlich:
Chromium 28 sendet manchmal das ended-Event nicht, wenn das Lied zuende ist.
Sehr ärgerlich, weil im Code keine Beliebigkeit ist, das Event wird nicht nur manchmal gesetzt und ich sehe auch nichts, was wegen schlechtem Timing den Fehler manchmal auslösen könnte:
var player = document.createElement("audio");
player.id = "player";
player.setAttribute("controls", true);
player.setAttribute("preload", "auto");
var source = document.createElement("source");
player.addEventListener('ended', function() {
removeOldControls();
var newPlayer = createPlayer(index+1, songs);
newPlayer.play();
insertOrReplace('#player', newPlayer);
});
Das wurde mir jetzt zu blöd und ich untersuchte, ob ich das manuell fixen kann. Und ja, das geht, denn obwohl das ended-Event nicht gefeuert wird, die ended-Property wird trotzdem und scheinbar zuverlässig auf true gesetzt. Man kann also alle paar ms das Audio-Element fragen, ob es fertig ist, und wenn es eine Weile fertig ist ohne den nächsten Track auszuwählen, manuell das ended-Event abfeuern:
setInterval(function() {
// occasionally, the end event is not triggered. Detect this and start the next track
var player = document.querySelector('#player');
if (player.ended) {
var event = document.createEvent("HTMLEvents");
event.initEvent("ended", true, true);
player.dispatchEvent(event);
}
}, 200);
Seitdem blieb kein Lied mehr hängen.