"use client"; /** * Global Audio Player Context — production audio engine * * Bug fixes in this revision: * A. Generation counter (genRef) — every speakSegment call captures the current * generation. cancel() increments it, which immediately invalidates every * pending setTimeout / onend / onerror callback. This is the root cause of * sentence repeats: the stall watchdog and the inter-sentence timer could both * call speakSegment(idx) for the same idx. * B. pendingRef — true while we are inside a pauseBeforeMs timeout or the tiny * inter-sentence gap. The stall watchdog skips its restart check while * pendingRef is true, eliminating the 600 ms chapter-title double-start. * C. Silent HTMLAudioElement for iOS lock screen — iOS Safari ignores * AudioContext nodes for MediaSession; only a real looping