keep awake
This commit is contained in:
parent
4ce1874d78
commit
d074bb2aef
2 changed files with 67 additions and 0 deletions
|
|
@ -36,6 +36,7 @@ import { useMediaSession } from '@/hooks/audio/useMediaSession';
|
||||||
import { useAudioContext } from '@/hooks/audio/useAudioContext';
|
import { useAudioContext } from '@/hooks/audio/useAudioContext';
|
||||||
import { getLastDocumentLocation, setLastDocumentLocation } from '@/lib/dexie';
|
import { getLastDocumentLocation, setLastDocumentLocation } from '@/lib/dexie';
|
||||||
import { useBackgroundState } from '@/hooks/audio/useBackgroundState';
|
import { useBackgroundState } from '@/hooks/audio/useBackgroundState';
|
||||||
|
import { useWakeLock } from '@/hooks/audio/useWakeLock';
|
||||||
import { withRetry, generateTTS, alignAudio } from '@/lib/client';
|
import { withRetry, generateTTS, alignAudio } from '@/lib/client';
|
||||||
import { preprocessSentenceForAudio, splitTextToTtsBlocks, splitTextToTtsBlocksEPUB } from '@/lib/nlp';
|
import { preprocessSentenceForAudio, splitTextToTtsBlocks, splitTextToTtsBlocksEPUB } from '@/lib/nlp';
|
||||||
import { isKokoroModel } from '@/utils/voice';
|
import { isKokoroModel } from '@/utils/voice';
|
||||||
|
|
@ -1144,6 +1145,9 @@ export function TTSProvider({ children }: { children: ReactNode }): ReactElement
|
||||||
playAudio,
|
playAudio,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Prevent screen from sleeping during audio playback (mobile Safari)
|
||||||
|
useWakeLock(isPlaying);
|
||||||
|
|
||||||
// Track the current word index during playback using Howler's seek position
|
// Track the current word index during playback using Howler's seek position
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!activeHowl || !isPlaying || !currentSentenceAlignment || !currentSentenceAlignment.words.length) {
|
if (!activeHowl || !isPlaying || !currentSentenceAlignment || !currentSentenceAlignment.words.length) {
|
||||||
|
|
|
||||||
63
src/hooks/audio/useWakeLock.ts
Normal file
63
src/hooks/audio/useWakeLock.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
import { useEffect, useRef, useCallback } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests a screen wake lock to prevent the display from sleeping
|
||||||
|
* during audio playback. Automatically re-acquires the lock when the
|
||||||
|
* page regains visibility (Safari releases it on visibility change).
|
||||||
|
*/
|
||||||
|
export function useWakeLock(isPlaying: boolean) {
|
||||||
|
const wakeLockRef = useRef<WakeLockSentinel | null>(null);
|
||||||
|
|
||||||
|
const requestWakeLock = useCallback(async () => {
|
||||||
|
if (!('wakeLock' in navigator)) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
wakeLockRef.current = await navigator.wakeLock.request('screen');
|
||||||
|
wakeLockRef.current.addEventListener('release', () => {
|
||||||
|
wakeLockRef.current = null;
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
// Wake lock request can fail (e.g. low battery mode)
|
||||||
|
console.warn('Wake lock request failed:', err);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const releaseWakeLock = useCallback(async () => {
|
||||||
|
if (wakeLockRef.current) {
|
||||||
|
try {
|
||||||
|
await wakeLockRef.current.release();
|
||||||
|
} catch {
|
||||||
|
// Ignore release errors
|
||||||
|
}
|
||||||
|
wakeLockRef.current = null;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Acquire/release based on playback state
|
||||||
|
useEffect(() => {
|
||||||
|
if (isPlaying) {
|
||||||
|
requestWakeLock();
|
||||||
|
} else {
|
||||||
|
releaseWakeLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
releaseWakeLock();
|
||||||
|
};
|
||||||
|
}, [isPlaying, requestWakeLock, releaseWakeLock]);
|
||||||
|
|
||||||
|
// Re-acquire wake lock when page becomes visible again
|
||||||
|
// (Safari releases wake locks when the page is hidden)
|
||||||
|
useEffect(() => {
|
||||||
|
const handleVisibilityChange = () => {
|
||||||
|
if (document.visibilityState === 'visible' && isPlaying) {
|
||||||
|
requestWakeLock();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
||||||
|
};
|
||||||
|
}, [isPlaying, requestWakeLock]);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue