Merge pull request #260 from itsgareth/gareth/fix-ios-lockscreen-controls

feat: fix ios lockscreen controls
This commit is contained in:
edidealt 2026-03-01 12:23:08 +02:00 committed by GitHub
commit eb61e87980
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -256,70 +256,81 @@ export class Player {
setupMediaSession() {
if (!('mediaSession' in navigator)) return;
navigator.mediaSession.setActionHandler('play', async () => {
// Initialize and resume audio context first (required for iOS lock screen)
// Must happen before audio.play() or audio won't route through Web Audio
if (!audioContextManager.isReady()) {
audioContextManager.init(this.audio);
this.applyReplayGain();
const setHandlers = () => {
navigator.mediaSession.setActionHandler('play', async () => {
// Initialize and resume audio context first (required for iOS lock screen)
// Must happen before audio.play() or audio won't route through Web Audio
if (!audioContextManager.isReady()) {
audioContextManager.init(this.audio);
this.applyReplayGain();
}
await audioContextManager.resume();
try {
await this.audio.play();
} catch (e) {
console.error('MediaSession play failed:', e);
// If play fails, try to handle it like a regular play/pause
this.handlePlayPause();
}
});
navigator.mediaSession.setActionHandler('pause', () => {
this.audio.pause();
});
navigator.mediaSession.setActionHandler('previoustrack', async () => {
// Ensure audio context is active for iOS lock screen controls
if (!audioContextManager.isReady()) {
audioContextManager.init(this.audio);
this.applyReplayGain();
}
await audioContextManager.resume();
this.playPrev();
});
navigator.mediaSession.setActionHandler('nexttrack', async () => {
// Ensure audio context is active for iOS lock screen controls
if (!audioContextManager.isReady()) {
audioContextManager.init(this.audio);
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();
try {
await this.audio.play();
} catch (e) {
console.error('MediaSession play failed:', e);
// If play fails, try to handle it like a regular play/pause
this.handlePlayPause();
}
});
navigator.mediaSession.setActionHandler('seekto', (details) => {
if (details.seekTime !== undefined) {
this.audio.currentTime = Math.max(0, details.seekTime);
this.updateMediaSessionPositionState();
}
});
navigator.mediaSession.setActionHandler('pause', () => {
this.audio.pause();
});
navigator.mediaSession.setActionHandler('stop', () => {
this.audio.pause();
this.audio.currentTime = 0;
this.updateMediaSessionPlaybackState();
});
};
navigator.mediaSession.setActionHandler('previoustrack', async () => {
// Ensure audio context is active for iOS lock screen controls
if (!audioContextManager.isReady()) {
audioContextManager.init(this.audio);
this.applyReplayGain();
}
await audioContextManager.resume();
this.playPrev();
});
navigator.mediaSession.setActionHandler('nexttrack', async () => {
// Ensure audio context is active for iOS lock screen controls
if (!audioContextManager.isReady()) {
audioContextManager.init(this.audio);
this.applyReplayGain();
}
await audioContextManager.resume();
this.playNext();
});
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);
});
navigator.mediaSession.setActionHandler('seekto', (details) => {
if (details.seekTime !== undefined) {
this.audio.currentTime = Math.max(0, details.seekTime);
this.updateMediaSessionPositionState();
}
});
navigator.mediaSession.setActionHandler('stop', () => {
this.audio.pause();
this.audio.currentTime = 0;
this.updateMediaSessionPlaybackState();
});
if (this.isIOS) {
// iOS: set handlers only when playback starts. Setting them in the constructor makes
// the lock screen show +10/-10. Registering on first 'playing' gives next/previous track
this.audio.addEventListener('playing', () => setHandlers(), { once: true });
} else {
setHandlers();
}
}
setQuality(quality) {