diff --git a/src/components/nowPlayingBar/nowPlayingBar.js b/src/components/nowPlayingBar/nowPlayingBar.js
index 2bf29a2a9c..b25097e325 100644
--- a/src/components/nowPlayingBar/nowPlayingBar.js
+++ b/src/components/nowPlayingBar/nowPlayingBar.js
@@ -32,6 +32,7 @@ import { appRouter } from '../appRouter';
let volumeSliderContainer;
let playPauseButtons;
let positionSlider;
+ let toggleAirPlayButton;
let toggleRepeatButton;
let toggleRepeatButtonIcon;
@@ -80,6 +81,8 @@ import { appRouter } from '../appRouter';
html += '';
html += '';
+ html += '';
+
html += '';
html += '';
@@ -190,6 +193,13 @@ import { appRouter } from '../appRouter';
}
});
+ toggleAirPlayButton = elem.querySelector('.btnAirPlay');
+ toggleAirPlayButton.addEventListener('click', function () {
+ if (currentPlayer) {
+ playbackManager.toggleAirPlay(currentPlayer);
+ }
+ });
+
elem.querySelector('.btnShuffleQueue').addEventListener('click', function () {
if (currentPlayer) {
playbackManager.toggleQueueShuffleMode();
@@ -326,6 +336,12 @@ import { appRouter } from '../appRouter';
toggleRepeatButton.classList.remove('hide');
}
+ if (supportedCommands.indexOf('AirPlay') === -1) {
+ toggleAirPlayButton.classList.add('hide');
+ } else {
+ toggleAirPlayButton.classList.remove('hide');
+ }
+
updateRepeatModeDisplay(playbackManager.getRepeatMode());
onQueueShuffleModeChange();
diff --git a/src/plugins/htmlAudioPlayer/plugin.js b/src/plugins/htmlAudioPlayer/plugin.js
index 585d935f05..30e1cb4880 100644
--- a/src/plugins/htmlAudioPlayer/plugin.js
+++ b/src/plugins/htmlAudioPlayer/plugin.js
@@ -347,6 +347,10 @@ class HtmlAudioPlayer {
return getDefaultProfile();
}
+ toggleAirPlay() {
+ return this.setAirPlayEnabled(!this.isAirPlayEnabled());
+ }
+
// Save this for when playback stops, because querying the time at that point might return 0
currentTime(val) {
const mediaElement = this._mediaElement;
@@ -488,6 +492,33 @@ class HtmlAudioPlayer {
return false;
}
+ isAirPlayEnabled() {
+ if (document.AirPlayEnabled) {
+ return !!document.AirplayElement;
+ }
+ return false;
+ }
+
+ setAirPlayEnabled(isEnabled) {
+ const mediaElement = this._mediaElement;
+
+ if (document.AirPlayEnabled) {
+ if (mediaElement) {
+ if (isEnabled) {
+ mediaElement.requestAirPlay().catch(function(err) {
+ console.error('Error requesting AirPlay', err);
+ });
+ } else {
+ document.exitAirPLay().catch(function(err) {
+ console.error('Error exiting AirPlay', err);
+ });
+ }
+ }
+ } else {
+ mediaElement.webkitShowPlaybackTargetPicker();
+ }
+ }
+
supports(feature) {
if (!supportedFeatures) {
supportedFeatures = getSupportedFeatures();
@@ -507,6 +538,10 @@ function getSupportedFeatures() {
list.push('PlaybackRate');
}
+ if (browser.safari || browser.iOS || browser.iPad) {
+ list.push('AirPlay');
+ }
+
return list;
}