Skip to content

fix(ios): prevent UI freeze from sync artwork fetch and duration access#148

Open
erik-lissen wants to merge 6 commits intoevergrace-co:mainfrom
lissengithub:fix/ios-blocking-artwork-duration
Open

fix(ios): prevent UI freeze from sync artwork fetch and duration access#148
erik-lissen wants to merge 6 commits intoevergrace-co:mainfrom
lissengithub:fix/ios-blocking-artwork-duration

Conversation

@erik-lissen
Copy link

Fixes #147

Summary

Fixes two iOS blocking issues that cause the app to freeze on slow/bad networks:

  1. Artwork fetch blocked threads - Data(contentsOf:) and semaphore-based URLSession calls blocked GCD threads while fetching artwork for the lock screen. On failure, onError() tore down the entire player. Now uses fully async URLSession with a 10s timeout and emits a soft PLAYBACK_ERROR on failure.

  2. item.asset.duration.seconds blocked on HLS - Accessing AVAsset.duration synchronously forces metadata loading, which requires fetching and parsing the m3u8 playlist. Removed this synchronous access; duration is already set via progress events once the player item is loaded.

  3. Artwork is now optional - Empty or missing artwork no longer causes validation failures or player errors. The AudioProTrack.artwork field is now optional in the TypeScript type and all JS/native validation.

Reproduction

  1. Use Network Link Conditioner set to "Very Bad Network"
  2. Play any HLS track with a remote artwork URL
  3. Before fix: entire app freezes for 5-30 seconds
  4. After fix: audio plays immediately, artwork loads asynchronously when available

Changes

  • src/types.ts - Make artwork optional in AudioProTrack
  • src/utils.ts - Allow empty artwork in validation
  • ios/AudioPro.swift - Three changes:
    • Extract artwork from required guard statement
    • Replace sync artwork fetch with async URLSession + 10s timeout
    • Remove sync item.asset.duration.seconds access

Test plan

  • Play track with artwork - artwork appears on lock screen
  • Play track without artwork - no crash, audio plays
  • Play on very bad network - no freeze
  • Rapid track switching on bad network - no freeze
  • Lock screen controls work correctly
  • Duration shows correctly on lock screen after load

erik-lissen and others added 6 commits February 3, 2026 21:34
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Data(contentsOf:) and semaphore-based fetch blocked threads during
slow network conditions. On failure, onError() tore down the entire
player. Now uses URLSession with 10s timeout and emits soft
PLAYBACK_ERROR on failure instead of destroying playback.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Accessing duration on an AVAsset synchronously blocks the calling
thread while fetching stream metadata (especially m3u8/HLS). Duration
is already set via progress events once the player item is loaded.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Capture currentTrack before starting async artwork fetch and verify it
still matches when the fetch completes - prevents stale artwork from
overwriting the lock screen when rapidly switching tracks.

Also call session.finishTasksAndInvalidate() in the completion handler
to properly clean up the URLSession and avoid resource leaks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[iOS] App freezes on slow networks due to sync artwork fetch and HLS duration access

1 participant