BUG FIX RELEASE
- HXMusicEngine: Fixed a fatal
IllegalStateExceptioncrash that could terminate the application during gapless looped playback.
What Was Fixed
Applications using gapless playback via .gapless(true) or HXMusic.playGaplessLoop(...) could crash with an IllegalStateException originating entirely inside android.media.MediaPlayer, with no HXAudio frames present in the stack trace.
When a looped track reached its end, the native media framework promoted the secondary player that HXMusicEngine had queued through setNextMediaPlayer(), and called start() on it from a detached thread that has no exception handler. If the application paused, stopped, cleared, or switched tracks at that same instant, HXMusicEngine had already reset and released that player, so the framework's start() call terminated the process. Because the offending call is made on a framework-owned thread, no application-level try/catch could prevent the crash.
Players unlinked from a gapless chain are now muted and torn down after a short grace period rather than immediately, so an unavoidable auto-start is silent and harmless instead of fatal.
Additional Hardening
- HXMusicEngine:
pause(),stop(),clear(), and track switches now halt the outgoing player before unlinking the gapless chain, andrelease()now unlinks the chain before releasing either player. - HXMusicEngine:
pause()now always unlinks the queued player, instead of skipping the unlink when the outgoing player reported that it was not playing — which was the case at exactly the moment of a gapless handoff. - HXMusicEngine: Stale prepared and completion callbacks are now discarded by player identity, which also prevents a superseded track from starting playback after a rapid track switch.
- HXMusicEngine: All MediaPlayer references and playback state are now guarded by a single internal lock, as MediaPlayer callbacks, audio focus changes, and the HXMusic operation executor reach the engine from three separate threads.
Upgrade Notes
- No public API changes. No source or behavioral changes are required when upgrading from 4.0.0.
- Applications on 4.0.0 that cannot upgrade immediately can avoid the crash by using
.looped(true)instead of.gapless(true), which never engagessetNextMediaPlayer().
Full Changelog: v4.0.0...v4.0.1