feat(player): add WakeLock for background playback on mobile
This commit is contained in:
parent
ec937f8956
commit
d9bb9a0c1e
2 changed files with 54 additions and 0 deletions
|
|
@ -5,6 +5,7 @@ import { usePictureInPicture } from '@/features/player/hooks/usePictureInPicture
|
|||
import { useKeyboardShortcuts } from '@/features/player/hooks/useKeyboardShortcuts';
|
||||
import { useAudioAnalyser } from '@/features/player/hooks/useAudioAnalyser';
|
||||
import { useMediaSession } from '@/features/player/hooks/useMediaSession';
|
||||
import { useWakeLock } from '@/features/player/hooks/useWakeLock';
|
||||
import { useUIStore } from '@/stores/ui';
|
||||
import { formatTime } from '@/features/player/services/playerService';
|
||||
import { PlayerControls } from './PlayerControls';
|
||||
|
|
@ -53,6 +54,8 @@ export function GlobalPlayer() {
|
|||
currentTrack?.cover ?? null,
|
||||
);
|
||||
|
||||
useWakeLock(player.isPlaying);
|
||||
|
||||
const SEEK_STEP_SEC = 10;
|
||||
useMediaSession({
|
||||
track: currentTrack ?? null,
|
||||
|
|
|
|||
51
apps/web/src/features/player/hooks/useWakeLock.ts
Normal file
51
apps/web/src/features/player/hooks/useWakeLock.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* Wake Lock hook for background playback on mobile
|
||||
* v0.801: Prevents screen from sleeping while audio is playing
|
||||
*/
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
export function useWakeLock(isPlaying: boolean): void {
|
||||
const lockRef = useRef<WakeLockSentinel | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!('wakeLock' in navigator)) return;
|
||||
|
||||
const requestLock = async () => {
|
||||
try {
|
||||
const lock = await (navigator as Navigator & { wakeLock: { request: (type: 'screen') => Promise<WakeLockSentinel> } }).wakeLock.request('screen');
|
||||
lockRef.current = lock;
|
||||
lock.addEventListener('release', () => {
|
||||
lockRef.current = null;
|
||||
});
|
||||
} catch {
|
||||
/* WakeLock denied (battery saver, etc.) */
|
||||
}
|
||||
};
|
||||
|
||||
const releaseLock = () => {
|
||||
lockRef.current?.release().catch(() => {});
|
||||
lockRef.current = null;
|
||||
};
|
||||
|
||||
if (isPlaying) {
|
||||
requestLock();
|
||||
} else {
|
||||
releaseLock();
|
||||
}
|
||||
|
||||
const handleVisibilityChange = () => {
|
||||
if (document.visibilityState === 'visible' && isPlaying) {
|
||||
requestLock();
|
||||
} else {
|
||||
releaseLock();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
||||
releaseLock();
|
||||
};
|
||||
}, [isPlaying]);
|
||||
}
|
||||
Loading…
Reference in a new issue