feat: fix ios lockscreen controls
This commit is contained in:
parent
a7d0099c96
commit
523aa2d710
1 changed files with 62 additions and 51 deletions
113
js/player.js
113
js/player.js
|
|
@ -256,70 +256,81 @@ export class Player {
|
||||||
setupMediaSession() {
|
setupMediaSession() {
|
||||||
if (!('mediaSession' in navigator)) return;
|
if (!('mediaSession' in navigator)) return;
|
||||||
|
|
||||||
navigator.mediaSession.setActionHandler('play', async () => {
|
const setHandlers = () => {
|
||||||
|
navigator.mediaSession.setActionHandler('play', async () => {
|
||||||
// Initialize and resume audio context first (required for iOS lock screen)
|
// Initialize and resume audio context first (required for iOS lock screen)
|
||||||
// Must happen before audio.play() or audio won't route through Web Audio
|
// Must happen before audio.play() or audio won't route through Web Audio
|
||||||
if (!audioContextManager.isReady()) {
|
if (!audioContextManager.isReady()) {
|
||||||
audioContextManager.init(this.audio);
|
audioContextManager.init(this.audio);
|
||||||
this.applyReplayGain();
|
this.applyReplayGain();
|
||||||
}
|
}
|
||||||
await audioContextManager.resume();
|
await audioContextManager.resume();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.audio.play();
|
await this.audio.play();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('MediaSession play failed:', e);
|
console.error('MediaSession play failed:', e);
|
||||||
// If play fails, try to handle it like a regular play/pause
|
// If play fails, try to handle it like a regular play/pause
|
||||||
this.handlePlayPause();
|
this.handlePlayPause();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
navigator.mediaSession.setActionHandler('pause', () => {
|
navigator.mediaSession.setActionHandler('pause', () => {
|
||||||
this.audio.pause();
|
this.audio.pause();
|
||||||
});
|
});
|
||||||
|
|
||||||
navigator.mediaSession.setActionHandler('previoustrack', async () => {
|
navigator.mediaSession.setActionHandler('previoustrack', async () => {
|
||||||
// Ensure audio context is active for iOS lock screen controls
|
// Ensure audio context is active for iOS lock screen controls
|
||||||
if (!audioContextManager.isReady()) {
|
if (!audioContextManager.isReady()) {
|
||||||
audioContextManager.init(this.audio);
|
audioContextManager.init(this.audio);
|
||||||
this.applyReplayGain();
|
this.applyReplayGain();
|
||||||
}
|
}
|
||||||
await audioContextManager.resume();
|
await audioContextManager.resume();
|
||||||
this.playPrev();
|
this.playPrev();
|
||||||
});
|
});
|
||||||
|
|
||||||
navigator.mediaSession.setActionHandler('nexttrack', async () => {
|
navigator.mediaSession.setActionHandler('nexttrack', async () => {
|
||||||
// Ensure audio context is active for iOS lock screen controls
|
// Ensure audio context is active for iOS lock screen controls
|
||||||
if (!audioContextManager.isReady()) {
|
if (!audioContextManager.isReady()) {
|
||||||
audioContextManager.init(this.audio);
|
audioContextManager.init(this.audio);
|
||||||
this.applyReplayGain();
|
this.applyReplayGain();
|
||||||
|
}
|
||||||
|
await audioContextManager.resume();
|
||||||
|
this.playNext();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!this.isIOS) {
|
||||||
|
navigator.mediaSession.setActionHandler('seekbackward', (details) => {
|
||||||
|
const skipTime = details.seekOffset || 10;
|
||||||
|
this.seekBackward(skipTime);
|
||||||
|
});
|
||||||
|
navigator.mediaSession.setActionHandler('seekforward', (details) => {
|
||||||
|
const skipTime = details.seekOffset || 10;
|
||||||
|
this.seekForward(skipTime);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
await audioContextManager.resume();
|
|
||||||
this.playNext();
|
|
||||||
});
|
|
||||||
|
|
||||||
navigator.mediaSession.setActionHandler('seekbackward', (details) => {
|
navigator.mediaSession.setActionHandler('seekto', (details) => {
|
||||||
const skipTime = details.seekOffset || 10;
|
if (details.seekTime !== undefined) {
|
||||||
this.seekBackward(skipTime);
|
this.audio.currentTime = Math.max(0, details.seekTime);
|
||||||
});
|
this.updateMediaSessionPositionState();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
navigator.mediaSession.setActionHandler('seekforward', (details) => {
|
navigator.mediaSession.setActionHandler('stop', () => {
|
||||||
const skipTime = details.seekOffset || 10;
|
this.audio.pause();
|
||||||
this.seekForward(skipTime);
|
this.audio.currentTime = 0;
|
||||||
});
|
this.updateMediaSessionPlaybackState();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
navigator.mediaSession.setActionHandler('seekto', (details) => {
|
if (this.isIOS) {
|
||||||
if (details.seekTime !== undefined) {
|
// iOS: set handlers only when playback starts. Setting them in the constructor makes
|
||||||
this.audio.currentTime = Math.max(0, details.seekTime);
|
// the lock screen show +10/-10. Registering on first 'playing' gives next/previous track
|
||||||
this.updateMediaSessionPositionState();
|
this.audio.addEventListener('playing', () => setHandlers(), { once: true });
|
||||||
}
|
} else {
|
||||||
});
|
setHandlers();
|
||||||
|
}
|
||||||
navigator.mediaSession.setActionHandler('stop', () => {
|
|
||||||
this.audio.pause();
|
|
||||||
this.audio.currentTime = 0;
|
|
||||||
this.updateMediaSessionPlaybackState();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setQuality(quality) {
|
setQuality(quality) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue