2020-08-16 20:24:45 +02:00
|
|
|
import browser from '../../scripts/browser';
|
|
|
|
import { appHost } from '../../components/apphost';
|
|
|
|
import * as htmlMediaHelper from '../../components/htmlMediaHelper';
|
2020-10-18 13:53:12 +01:00
|
|
|
import profileBuilder from '../../scripts/browserDeviceProfile';
|
2020-11-30 14:38:03 -05:00
|
|
|
import { getIncludeCorsCredentials } from '../../scripts/settings/webSettings';
|
2023-03-08 11:03:48 -05:00
|
|
|
import { PluginType } from '../../types/plugin.ts';
|
2022-10-14 10:53:16 -04:00
|
|
|
import Events from '../../utils/events.ts';
|
2020-08-03 20:57:54 +01:00
|
|
|
|
|
|
|
function getDefaultProfile() {
|
2020-10-18 13:53:12 +01:00
|
|
|
return profileBuilder({});
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
let fadeTimeout;
|
|
|
|
function fade(instance, elem, startingVolume) {
|
|
|
|
instance._isFadingOut = true;
|
|
|
|
|
|
|
|
// Need to record the starting volume on each pass rather than querying elem.volume
|
|
|
|
// This is due to iOS safari not allowing volume changes and always returning the system volume value
|
|
|
|
const newVolume = Math.max(0, startingVolume - 0.15);
|
|
|
|
console.debug('fading volume to ' + newVolume);
|
|
|
|
elem.volume = newVolume;
|
|
|
|
|
|
|
|
if (newVolume <= 0) {
|
|
|
|
instance._isFadingOut = false;
|
|
|
|
return Promise.resolve();
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
return new Promise(function (resolve, reject) {
|
|
|
|
cancelFadeTimeout();
|
|
|
|
fadeTimeout = setTimeout(function () {
|
|
|
|
fade(instance, elem, newVolume).then(resolve, reject);
|
|
|
|
}, 100);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function cancelFadeTimeout() {
|
|
|
|
const timeout = fadeTimeout;
|
|
|
|
if (timeout) {
|
|
|
|
clearTimeout(timeout);
|
|
|
|
fadeTimeout = null;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
function supportsFade() {
|
2022-10-06 01:13:06 -04:00
|
|
|
// Not working on tizen.
|
|
|
|
// We could possibly enable on other tv's, but all smart tv browsers tend to be pretty primitive
|
|
|
|
return !browser.tv;
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
function requireHlsPlayer(callback) {
|
2023-04-19 10:47:02 -04:00
|
|
|
import('hls.js/dist/hls.js').then(({ default: hls }) => {
|
2023-03-06 10:02:38 +01:00
|
|
|
hls.DefaultConfig.lowLatencyMode = false;
|
|
|
|
hls.DefaultConfig.backBufferLength = Infinity;
|
|
|
|
hls.DefaultConfig.liveBackBufferLength = 90;
|
2020-08-03 20:57:54 +01:00
|
|
|
window.Hls = hls;
|
|
|
|
callback();
|
|
|
|
});
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
function enableHlsPlayer(url, item, mediaSource, mediaType) {
|
|
|
|
if (!htmlMediaHelper.enableHlsJsPlayer(mediaSource.RunTimeTicks, mediaType)) {
|
|
|
|
return Promise.reject();
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
if (url.indexOf('.m3u8') !== -1) {
|
|
|
|
return Promise.resolve();
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
// issue head request to get content type
|
|
|
|
return new Promise(function (resolve, reject) {
|
2020-08-16 20:24:45 +02:00
|
|
|
import('../../components/fetchhelper').then((fetchHelper) => {
|
2020-08-03 20:57:54 +01:00
|
|
|
fetchHelper.ajax({
|
|
|
|
url: url,
|
|
|
|
type: 'HEAD'
|
|
|
|
}).then(function (response) {
|
|
|
|
const contentType = (response.headers.get('Content-Type') || '').toLowerCase();
|
2022-06-17 10:05:22 -04:00
|
|
|
if (contentType === 'application/vnd.apple.mpegurl' || contentType === 'application/x-mpegurl') {
|
2020-08-03 20:57:54 +01:00
|
|
|
resolve();
|
|
|
|
} else {
|
|
|
|
reject();
|
|
|
|
}
|
|
|
|
}, reject);
|
2019-01-10 15:39:37 +03:00
|
|
|
});
|
2020-08-03 20:57:54 +01:00
|
|
|
});
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
class HtmlAudioPlayer {
|
|
|
|
constructor() {
|
|
|
|
const self = this;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
self.name = 'Html Audio Player';
|
2023-03-08 11:03:48 -05:00
|
|
|
self.type = PluginType.MediaPlayer;
|
2019-01-10 15:39:37 +03:00
|
|
|
self.id = 'htmlaudioplayer';
|
|
|
|
|
|
|
|
// Let any players created by plugins take priority
|
|
|
|
self.priority = 1;
|
|
|
|
|
|
|
|
self.play = function (options) {
|
|
|
|
self._started = false;
|
|
|
|
self._timeUpdated = false;
|
|
|
|
self._currentTime = null;
|
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
const elem = createMediaElement();
|
2023-01-30 18:47:38 +00:00
|
|
|
|
2019-01-10 15:39:37 +03:00
|
|
|
return setCurrentSrc(elem, options);
|
|
|
|
};
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
function setCurrentSrc(elem, options) {
|
2019-01-10 15:39:37 +03:00
|
|
|
unBindEvents(elem);
|
|
|
|
bindEvents(elem);
|
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
let val = options.url;
|
2020-02-16 03:44:43 +01:00
|
|
|
console.debug('playing url: ' + val);
|
2023-05-24 06:58:28 +01:00
|
|
|
import('../../scripts/settings/userSettings').then((userSettings) => {
|
2023-08-04 18:20:51 +01:00
|
|
|
console.debug(userSettings.selectAudioNormalization());
|
|
|
|
if (userSettings.selectAudioNormalization() == "TrackGain" && options.item.LUFS != null) {
|
2023-01-31 18:27:43 +00:00
|
|
|
const dbGain = -18 - options.item.LUFS;
|
2023-02-01 10:46:08 +00:00
|
|
|
self.gainNode.gain.value = Math.pow(10, (dbGain / 20));
|
2023-08-04 18:20:51 +01:00
|
|
|
console.debug("using trackgain")
|
|
|
|
} else if (userSettings.selectAudioNormalization() == "AlbumGain" && options.item.LUFSAlbum != null) {
|
2023-08-04 17:45:59 +01:00
|
|
|
const dbGain = -18 - options.item.LUFSAlbum;
|
|
|
|
self.gainNode.gain.value = Math.pow(10, (dbGain / 20));
|
2023-08-04 18:20:51 +01:00
|
|
|
console.debug("using albumgain")
|
2023-01-30 20:36:11 +00:00
|
|
|
} else {
|
|
|
|
self.gainNode.gain.value = 1;
|
|
|
|
}
|
2023-05-13 13:44:23 +01:00
|
|
|
console.debug('gain:' + self.gainNode.gain.value);
|
2023-05-24 06:58:36 +01:00
|
|
|
}).catch((err) => {
|
2023-05-17 19:18:58 +01:00
|
|
|
console.error('Failed to add/change gainNode', err);
|
2023-01-30 20:36:11 +00:00
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
// Convert to seconds
|
2020-08-03 20:57:54 +01:00
|
|
|
const seconds = (options.playerStartPositionTicks || 0) / 10000000;
|
2019-01-10 15:39:37 +03:00
|
|
|
if (seconds) {
|
|
|
|
val += '#t=' + seconds;
|
|
|
|
}
|
|
|
|
|
|
|
|
htmlMediaHelper.destroyHlsPlayer(self);
|
|
|
|
|
|
|
|
self._currentPlayOptions = options;
|
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
const crossOrigin = htmlMediaHelper.getCrossOriginValue(options.mediaSource);
|
2019-01-10 15:39:37 +03:00
|
|
|
if (crossOrigin) {
|
|
|
|
elem.crossOrigin = crossOrigin;
|
|
|
|
}
|
|
|
|
|
|
|
|
return enableHlsPlayer(val, options.item, options.mediaSource, 'Audio').then(function () {
|
|
|
|
return new Promise(function (resolve, reject) {
|
2020-11-30 14:38:03 -05:00
|
|
|
requireHlsPlayer(async () => {
|
|
|
|
const includeCorsCredentials = await getIncludeCorsCredentials();
|
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
const hls = new Hls({
|
2020-11-30 13:35:50 -05:00
|
|
|
manifestLoadingTimeOut: 20000,
|
2021-01-26 22:20:12 -05:00
|
|
|
xhrSetup: function (xhr) {
|
2020-11-30 14:38:03 -05:00
|
|
|
xhr.withCredentials = includeCorsCredentials;
|
2020-11-30 13:35:50 -05:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
});
|
2019-01-10 15:39:37 +03:00
|
|
|
hls.loadSource(val);
|
|
|
|
hls.attachMedia(elem);
|
|
|
|
|
|
|
|
htmlMediaHelper.bindEventsToHlsPlayer(self, hls, elem, onError, resolve, reject);
|
|
|
|
|
|
|
|
self._hlsPlayer = hls;
|
|
|
|
|
|
|
|
self._currentSrc = val;
|
|
|
|
});
|
|
|
|
});
|
2020-11-30 14:38:03 -05:00
|
|
|
}, async () => {
|
2019-01-10 15:39:37 +03:00
|
|
|
elem.autoplay = true;
|
|
|
|
|
2020-11-30 14:38:03 -05:00
|
|
|
const includeCorsCredentials = await getIncludeCorsCredentials();
|
|
|
|
if (includeCorsCredentials) {
|
|
|
|
// Safari will not send cookies without this
|
|
|
|
elem.crossOrigin = 'use-credentials';
|
|
|
|
}
|
2020-05-07 21:04:26 -07:00
|
|
|
|
2019-01-10 15:39:37 +03:00
|
|
|
return htmlMediaHelper.applySrc(elem, val, options).then(function () {
|
|
|
|
self._currentSrc = val;
|
|
|
|
|
|
|
|
return htmlMediaHelper.playWithPromise(elem, onError);
|
|
|
|
});
|
|
|
|
});
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function bindEvents(elem) {
|
2019-01-10 15:39:37 +03:00
|
|
|
elem.addEventListener('timeupdate', onTimeUpdate);
|
|
|
|
elem.addEventListener('ended', onEnded);
|
|
|
|
elem.addEventListener('volumechange', onVolumeChange);
|
|
|
|
elem.addEventListener('pause', onPause);
|
|
|
|
elem.addEventListener('playing', onPlaying);
|
|
|
|
elem.addEventListener('play', onPlay);
|
2020-04-01 17:53:14 +02:00
|
|
|
elem.addEventListener('waiting', onWaiting);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function unBindEvents(elem) {
|
2019-01-10 15:39:37 +03:00
|
|
|
elem.removeEventListener('timeupdate', onTimeUpdate);
|
|
|
|
elem.removeEventListener('ended', onEnded);
|
|
|
|
elem.removeEventListener('volumechange', onVolumeChange);
|
|
|
|
elem.removeEventListener('pause', onPause);
|
|
|
|
elem.removeEventListener('playing', onPlaying);
|
|
|
|
elem.removeEventListener('play', onPlay);
|
2020-04-01 17:53:14 +02:00
|
|
|
elem.removeEventListener('waiting', onWaiting);
|
2021-09-12 01:28:56 +03:00
|
|
|
elem.removeEventListener('error', onError); // bound in htmlMediaHelper
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2019-01-10 15:39:37 +03:00
|
|
|
self.stop = function (destroyPlayer) {
|
|
|
|
cancelFadeTimeout();
|
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
const elem = self._mediaElement;
|
|
|
|
const src = self._currentSrc;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
if (elem && src) {
|
|
|
|
if (!destroyPlayer || !supportsFade()) {
|
|
|
|
elem.pause();
|
|
|
|
|
|
|
|
htmlMediaHelper.onEndedInternal(self, elem, onError);
|
|
|
|
|
|
|
|
if (destroyPlayer) {
|
|
|
|
self.destroy();
|
|
|
|
}
|
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
const originalVolume = elem.volume;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
return fade(self, elem, elem.volume).then(function () {
|
|
|
|
elem.pause();
|
|
|
|
elem.volume = originalVolume;
|
|
|
|
|
|
|
|
htmlMediaHelper.onEndedInternal(self, elem, onError);
|
|
|
|
|
|
|
|
if (destroyPlayer) {
|
|
|
|
self.destroy();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return Promise.resolve();
|
|
|
|
};
|
|
|
|
|
|
|
|
self.destroy = function () {
|
|
|
|
unBindEvents(self._mediaElement);
|
2021-09-17 01:20:58 +03:00
|
|
|
htmlMediaHelper.resetSrc(self._mediaElement);
|
2019-01-10 15:39:37 +03:00
|
|
|
};
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
function createMediaElement() {
|
2020-08-03 20:57:54 +01:00
|
|
|
let elem = self._mediaElement;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
if (elem) {
|
|
|
|
return elem;
|
|
|
|
}
|
|
|
|
|
|
|
|
elem = document.querySelector('.mediaPlayerAudio');
|
|
|
|
|
|
|
|
if (!elem) {
|
|
|
|
elem = document.createElement('audio');
|
|
|
|
elem.classList.add('mediaPlayerAudio');
|
|
|
|
elem.classList.add('hide');
|
|
|
|
|
|
|
|
document.body.appendChild(elem);
|
|
|
|
}
|
|
|
|
|
|
|
|
elem.volume = htmlMediaHelper.getSavedVolume();
|
|
|
|
|
|
|
|
self._mediaElement = elem;
|
|
|
|
|
2023-01-30 18:47:38 +00:00
|
|
|
addGainElement(elem);
|
|
|
|
|
2019-01-10 15:39:37 +03:00
|
|
|
return elem;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2023-01-30 18:47:38 +00:00
|
|
|
function addGainElement(elem) {
|
2023-05-17 19:18:58 +01:00
|
|
|
try {
|
2023-05-23 20:17:33 +01:00
|
|
|
const AudioContext = window.AudioContext || window.webkitAudioContext; /* eslint-disable-line compat/compat */
|
|
|
|
|
|
|
|
const audioCtx = new AudioContext();
|
2023-05-17 19:18:58 +01:00
|
|
|
const source = audioCtx.createMediaElementSource(elem);
|
2023-01-30 18:47:38 +00:00
|
|
|
|
2023-05-17 19:18:58 +01:00
|
|
|
const gainNode = audioCtx.createGain();
|
2023-01-30 18:47:38 +00:00
|
|
|
|
2023-05-17 19:18:58 +01:00
|
|
|
source.connect(gainNode);
|
|
|
|
gainNode.connect(audioCtx.destination);
|
2023-01-30 18:47:38 +00:00
|
|
|
|
2023-05-17 19:18:58 +01:00
|
|
|
self.gainNode = gainNode;
|
|
|
|
} catch (e) {
|
|
|
|
console.error('Web Audio API is not supported in this browser', e);
|
|
|
|
}
|
2023-01-30 18:47:38 +00:00
|
|
|
}
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
function onEnded() {
|
2019-01-10 15:39:37 +03:00
|
|
|
htmlMediaHelper.onEndedInternal(self, this, onError);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function onTimeUpdate() {
|
2019-01-10 15:39:37 +03:00
|
|
|
// Get the player position + the transcoding offset
|
2020-08-03 20:57:54 +01:00
|
|
|
const time = this.currentTime;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
// Don't trigger events after user stop
|
|
|
|
if (!self._isFadingOut) {
|
|
|
|
self._currentTime = time;
|
2020-09-08 02:05:02 -04:00
|
|
|
Events.trigger(self, 'timeupdate');
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function onVolumeChange() {
|
2019-01-10 15:39:37 +03:00
|
|
|
if (!self._isFadingOut) {
|
|
|
|
htmlMediaHelper.saveVolume(this.volume);
|
2020-09-08 02:05:02 -04:00
|
|
|
Events.trigger(self, 'volumechange');
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function onPlaying(e) {
|
2019-01-10 15:39:37 +03:00
|
|
|
if (!self._started) {
|
|
|
|
self._started = true;
|
|
|
|
this.removeAttribute('controls');
|
|
|
|
|
|
|
|
htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks);
|
|
|
|
}
|
2020-09-08 02:05:02 -04:00
|
|
|
Events.trigger(self, 'playing');
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2021-01-26 22:20:12 -05:00
|
|
|
function onPlay() {
|
2020-09-08 02:05:02 -04:00
|
|
|
Events.trigger(self, 'unpause');
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function onPause() {
|
2020-09-08 02:05:02 -04:00
|
|
|
Events.trigger(self, 'pause');
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
|
2020-04-01 17:53:14 +02:00
|
|
|
function onWaiting() {
|
2020-09-08 02:05:02 -04:00
|
|
|
Events.trigger(self, 'waiting');
|
2020-04-01 17:53:14 +02:00
|
|
|
}
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
function onError() {
|
2020-08-03 20:57:54 +01:00
|
|
|
const errorCode = this.error ? (this.error.code || 0) : 0;
|
|
|
|
const errorMessage = this.error ? (this.error.message || '') : '';
|
2020-02-17 20:41:04 +01:00
|
|
|
console.error('media element error: ' + errorCode.toString() + ' ' + errorMessage);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
let type;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
switch (errorCode) {
|
|
|
|
case 1:
|
2019-01-10 15:39:37 +03:00
|
|
|
// MEDIA_ERR_ABORTED
|
|
|
|
// This will trigger when changing media while something is playing
|
2018-10-23 01:05:09 +03:00
|
|
|
return;
|
|
|
|
case 2:
|
2019-01-10 15:39:37 +03:00
|
|
|
// MEDIA_ERR_NETWORK
|
|
|
|
type = 'network';
|
2018-10-23 01:05:09 +03:00
|
|
|
break;
|
|
|
|
case 3:
|
2019-01-10 15:39:37 +03:00
|
|
|
// MEDIA_ERR_DECODE
|
|
|
|
if (self._hlsPlayer) {
|
|
|
|
htmlMediaHelper.handleHlsJsMediaError(self);
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
type = 'mediadecodeerror';
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
break;
|
|
|
|
case 4:
|
2019-01-10 15:39:37 +03:00
|
|
|
// MEDIA_ERR_SRC_NOT_SUPPORTED
|
|
|
|
type = 'medianotsupported';
|
2018-10-23 01:05:09 +03:00
|
|
|
break;
|
|
|
|
default:
|
2019-01-10 15:39:37 +03:00
|
|
|
// seeing cases where Edge is firing error events with no error code
|
|
|
|
// example is start playing something, then immediately change src to something else
|
|
|
|
return;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
htmlMediaHelper.onErrorInternal(self, type);
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
currentSrc() {
|
2019-01-10 15:39:37 +03:00
|
|
|
return this._currentSrc;
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
canPlayMediaType(mediaType) {
|
2019-01-10 15:39:37 +03:00
|
|
|
return (mediaType || '').toLowerCase() === 'audio';
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
getDeviceProfile(item) {
|
2019-01-10 15:39:37 +03:00
|
|
|
if (appHost.getDeviceProfile) {
|
|
|
|
return appHost.getDeviceProfile(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
return getDefaultProfile();
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2023-04-10 12:06:00 +03:00
|
|
|
toggleAirPlay() {
|
|
|
|
return this.setAirPlayEnabled(!this.isAirPlayEnabled());
|
|
|
|
}
|
|
|
|
|
2019-01-10 15:39:37 +03:00
|
|
|
// Save this for when playback stops, because querying the time at that point might return 0
|
2020-08-03 20:57:54 +01:00
|
|
|
currentTime(val) {
|
|
|
|
const mediaElement = this._mediaElement;
|
2018-10-23 01:05:09 +03:00
|
|
|
if (mediaElement) {
|
2019-01-10 15:39:37 +03:00
|
|
|
if (val != null) {
|
|
|
|
mediaElement.currentTime = val / 1000;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
const currentTime = this._currentTime;
|
2019-01-10 15:39:37 +03:00
|
|
|
if (currentTime) {
|
|
|
|
return currentTime * 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (mediaElement.currentTime || 0) * 1000;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2021-01-26 22:20:12 -05:00
|
|
|
duration() {
|
2020-08-03 20:57:54 +01:00
|
|
|
const mediaElement = this._mediaElement;
|
2018-10-23 01:05:09 +03:00
|
|
|
if (mediaElement) {
|
2020-08-03 20:57:54 +01:00
|
|
|
const duration = mediaElement.duration;
|
2019-01-10 15:39:37 +03:00
|
|
|
if (htmlMediaHelper.isValidDuration(duration)) {
|
|
|
|
return duration * 1000;
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
return null;
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
seekable() {
|
|
|
|
const mediaElement = this._mediaElement;
|
2018-10-23 01:05:09 +03:00
|
|
|
if (mediaElement) {
|
2020-08-03 20:57:54 +01:00
|
|
|
const seekable = mediaElement.seekable;
|
2023-07-06 13:39:48 -04:00
|
|
|
if (seekable?.length) {
|
2020-08-03 20:57:54 +01:00
|
|
|
let start = seekable.start(0);
|
|
|
|
let end = seekable.end(0);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
if (!htmlMediaHelper.isValidDuration(start)) {
|
|
|
|
start = 0;
|
|
|
|
}
|
|
|
|
if (!htmlMediaHelper.isValidDuration(end)) {
|
|
|
|
end = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (end - start) > 0;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
return false;
|
2018-10-23 01:05:09 +03:00
|
|
|
}
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
getBufferedRanges() {
|
|
|
|
const mediaElement = this._mediaElement;
|
2019-01-10 15:39:37 +03:00
|
|
|
if (mediaElement) {
|
|
|
|
return htmlMediaHelper.getBufferedRanges(this, mediaElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
return [];
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
pause() {
|
|
|
|
const mediaElement = this._mediaElement;
|
2019-01-10 15:39:37 +03:00
|
|
|
if (mediaElement) {
|
|
|
|
mediaElement.pause();
|
|
|
|
}
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
// This is a retry after error
|
2020-08-03 20:57:54 +01:00
|
|
|
resume() {
|
2022-10-05 15:31:15 -04:00
|
|
|
this.unpause();
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
unpause() {
|
|
|
|
const mediaElement = this._mediaElement;
|
2019-01-10 15:39:37 +03:00
|
|
|
if (mediaElement) {
|
|
|
|
mediaElement.play();
|
|
|
|
}
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
paused() {
|
|
|
|
const mediaElement = this._mediaElement;
|
2019-01-10 15:39:37 +03:00
|
|
|
if (mediaElement) {
|
|
|
|
return mediaElement.paused;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
setPlaybackRate(value) {
|
|
|
|
const mediaElement = this._mediaElement;
|
2020-04-01 17:53:14 +02:00
|
|
|
if (mediaElement) {
|
|
|
|
mediaElement.playbackRate = value;
|
|
|
|
}
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2020-04-01 17:53:14 +02:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
getPlaybackRate() {
|
|
|
|
const mediaElement = this._mediaElement;
|
2020-04-01 17:53:14 +02:00
|
|
|
if (mediaElement) {
|
|
|
|
return mediaElement.playbackRate;
|
|
|
|
}
|
|
|
|
return null;
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2020-04-01 17:53:14 +02:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
setVolume(val) {
|
|
|
|
const mediaElement = this._mediaElement;
|
2019-01-10 15:39:37 +03:00
|
|
|
if (mediaElement) {
|
2021-08-10 16:16:52 -07:00
|
|
|
mediaElement.volume = Math.pow(val / 100, 3);
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
getVolume() {
|
|
|
|
const mediaElement = this._mediaElement;
|
2019-01-10 15:39:37 +03:00
|
|
|
if (mediaElement) {
|
2021-08-10 16:16:52 -07:00
|
|
|
return Math.min(Math.round(Math.pow(mediaElement.volume, 1 / 3) * 100), 100);
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
volumeUp() {
|
2019-01-10 15:39:37 +03:00
|
|
|
this.setVolume(Math.min(this.getVolume() + 2, 100));
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
volumeDown() {
|
2019-01-10 15:39:37 +03:00
|
|
|
this.setVolume(Math.max(this.getVolume() - 2, 0));
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
setMute(mute) {
|
|
|
|
const mediaElement = this._mediaElement;
|
2019-01-10 15:39:37 +03:00
|
|
|
if (mediaElement) {
|
|
|
|
mediaElement.muted = mute;
|
|
|
|
}
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
isMuted() {
|
|
|
|
const mediaElement = this._mediaElement;
|
2019-01-10 15:39:37 +03:00
|
|
|
if (mediaElement) {
|
|
|
|
return mediaElement.muted;
|
|
|
|
}
|
|
|
|
return false;
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
2020-04-01 17:53:14 +02:00
|
|
|
|
2023-04-10 12:06:00 +03:00
|
|
|
isAirPlayEnabled() {
|
|
|
|
if (document.AirPlayEnabled) {
|
|
|
|
return !!document.AirplayElement;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
setAirPlayEnabled(isEnabled) {
|
|
|
|
const mediaElement = this._mediaElement;
|
|
|
|
|
2023-06-17 13:18:13 +03:00
|
|
|
if (mediaElement) {
|
|
|
|
if (document.AirPlayEnabled) {
|
2023-04-10 12:06:00 +03:00
|
|
|
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);
|
|
|
|
});
|
|
|
|
}
|
2023-06-17 13:18:13 +03:00
|
|
|
} else {
|
|
|
|
mediaElement.webkitShowPlaybackTargetPicker();
|
2023-04-10 12:06:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
supports(feature) {
|
2020-04-01 17:53:14 +02:00
|
|
|
if (!supportedFeatures) {
|
|
|
|
supportedFeatures = getSupportedFeatures();
|
|
|
|
}
|
|
|
|
|
|
|
|
return supportedFeatures.indexOf(feature) !== -1;
|
2020-08-03 20:57:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let supportedFeatures;
|
|
|
|
|
|
|
|
function getSupportedFeatures() {
|
|
|
|
const list = [];
|
|
|
|
const audio = document.createElement('audio');
|
|
|
|
|
|
|
|
if (typeof audio.playbackRate === 'number') {
|
|
|
|
list.push('PlaybackRate');
|
|
|
|
}
|
|
|
|
|
2023-05-11 22:27:57 +03:00
|
|
|
if (browser.safari) {
|
2023-04-10 12:06:00 +03:00
|
|
|
list.push('AirPlay');
|
|
|
|
}
|
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
return list;
|
|
|
|
}
|
2020-04-01 17:53:14 +02:00
|
|
|
|
2020-08-03 20:57:54 +01:00
|
|
|
export default HtmlAudioPlayer;
|