From 5a723227722b30da2c0023dd9edff4767c91446c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Thomas?= Date: Fri, 24 May 2019 00:35:10 +0200 Subject: [PATCH 1/2] Work around play queue not going to the next song automatically This commit works around a race caused by some of our JS code trying to run play() for the next song while the MEJS player is still cleaning up the last song. MEJS issue: https://github.com/mediaelement/mediaelement/issues/2650 --- .../src/main/webapp/WEB-INF/jsp/playQueue.jsp | 63 ++++++++++++++++--- 1 file changed, 53 insertions(+), 10 deletions(-) diff --git a/airsonic-main/src/main/webapp/WEB-INF/jsp/playQueue.jsp b/airsonic-main/src/main/webapp/WEB-INF/jsp/playQueue.jsp index c9156c42..8426f588 100644 --- a/airsonic-main/src/main/webapp/WEB-INF/jsp/playQueue.jsp +++ b/airsonic-main/src/main/webapp/WEB-INF/jsp/playQueue.jsp @@ -52,7 +52,7 @@ } }}); - createPlayer(); + createMediaElementPlayer(); $("#playlistBody").sortable({ stop: function(event, ui) { @@ -145,8 +145,21 @@ onNext(repeatEnabled); } - function createPlayer() { - $('#audioPlayer').get(0).addEventListener("ended", onEnded); + function createMediaElementPlayer() { + + var player = $('#audioPlayer').get(0); + + // Once playback reaches the end, go to the next song, if any. + player.addEventListener("ended", onEnded); + + // FIXME: Remove once https://github.com/mediaelement/mediaelement/issues/2650 is fixed. + // + // Once a media is loaded, we can start playback, but not before. + // + // Trying to start playback after a song has endred but before the + // 'canplay' event for the next song currently causes a race condition + // in the MediaElement.js player (4.2.10). + player.addEventListener("canplay", function() { player.play(); }); } function getPlayQueue() { @@ -532,6 +545,40 @@ } } + function loadMediaElementPlayer(song, position) { + var player = $('#audioPlayer').get(0); + + // Is this a new song? + if (player.src != song.streamUrl) { + // Stop the current playing song and change the media source. + player.src = song.streamUrl; + // Inform MEJS that we need to load a new media source. The + // 'canplay' event will be fired once playback is possible. + player.load(); + // The 'skip' function takes a 'position' argument. We don't + // usually send it, and in this case it's better to do nothing. + // Otherwise, the 'canplay' event will also be fired after + // setting 'currentTime'. + if (position && position > 0) { + player.currentTime = position; + } + + // Are we seeking on an already-playing song? + } else { + // Seeking also starts playing. The 'canplay' event will be + // fired after setting 'currentTime'. + player.currentTime = position || 0; + } + + // FIXME: Uncomment once https://github.com/mediaelement/mediaelement/issues/2650 is fixed. + // + // Calling 'player.play()' at this point may work by chance, but it's + // not guaranteed in the current MediaElement.js player (4.2.10). See + // the 'createMediaElementPlayer()' function above. + // + // player.play(); + } + function skip(index, position) { if (index < 0 || index >= songs.length) { return; @@ -541,16 +588,12 @@ currentStreamUrl = song.streamUrl; updateCurrentImage(); + // Handle ChromeCast player. if (CastPlayer.castSession) { CastPlayer.loadCastMedia(song, position); + // Handle MediaElement (HTML5) player. } else { - if ($('#audioPlayer').get(0).src != song.streamUrl) { - $('#audioPlayer').get(0).src = song.streamUrl; - $('#audioPlayer').get(0).load(); - console.log(song.streamUrl); - } - $('#audioPlayer').get(0).currentTime = position ? position : 0; - $('#audioPlayer').get(0).play(); + loadMediaElementPlayer(song, position); } updateWindowTitle(song); From 2e0134259d9db9eed5d9630efbf5eb59db51d815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Thomas?= Date: Thu, 6 Jun 2019 22:46:44 +0200 Subject: [PATCH 2/2] Try to show a progress bar in the media player This commit is kind of a hack to force MediaElement.js to show a progress bar when we are loading a song. Normally, in vanilla HTML5 MediaElement, we'd explicitely call 'play()' when loading a song. Here, we cannot ensure playback will work well if we don't wait for the 'canplay' event to be fired, but the progress bar won't show up without 'play()'... This commit emits a fake 'waiting' event to let the MEJS know that it should update the UI. --- airsonic-main/src/main/webapp/WEB-INF/jsp/playQueue.jsp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/airsonic-main/src/main/webapp/WEB-INF/jsp/playQueue.jsp b/airsonic-main/src/main/webapp/WEB-INF/jsp/playQueue.jsp index 8426f588..81c8137a 100644 --- a/airsonic-main/src/main/webapp/WEB-INF/jsp/playQueue.jsp +++ b/airsonic-main/src/main/webapp/WEB-INF/jsp/playQueue.jsp @@ -577,6 +577,12 @@ // the 'createMediaElementPlayer()' function above. // // player.play(); + + // FIXME: Remove once https://github.com/mediaelement/mediaelement/issues/2650 is fixed. + // + // Instead, we're triggering a 'waiting' event so that the player shows + // a progress bar to indicate that it's loading the stream. + player.dispatchEvent(new Event("waiting")); } function skip(index, position) {