Skip to content

Album art API can block the foobar2000 main thread during artwork retrieval #381

Description

@sergimola

Summary

A single request to the album art endpoint can block/freeze the foobar2000 UI while the artwork is being retrieved.

This can happen with just one request; high request concurrency is not required.

The duration is not necessarily limited to around one second. In my environment, the stall can be substantially longer depending on the artwork/file being accessed and the responsiveness of the underlying filesystem.

Reproduction

  1. Run foobar2000 with Beefweb enabled.
  2. Open Beefweb's web interface.
  3. Open the album-art view.

Alternatively, request a single artwork directly:

GET /api/artwork/<playlist>/<index>
  1. Observe foobar2000 while the artwork is being retrieved.

Opening the album-art view in Beefweb's own web UI is sufficient to reproduce the UI stall.

The problem can also be reproduced with a single direct artwork request, so this does not require a large number of concurrent requests.

Environment

  • foobar2000 is running locally on my laptop.
  • My music library is stored on a remote home server.
  • The library is accessed remotely through Tailscale.
  • Therefore, accessing artwork for a track can involve remote filesystem/network I/O.

This makes the problem particularly easy to reproduce when the underlying file/artwork access is slow.

Actual behavior

While Beefweb retrieves the artwork, foobar2000's UI becomes unresponsive.

The duration can be substantially longer than one second depending on the particular file/artwork and the responsiveness of the remote filesystem.

For example, a slow remote filesystem operation can result in a correspondingly long apparent foobar2000 freeze.

Suspected cause

Looking at the Beefweb source, the album-art endpoint is routed through the foobar2000 work queue.

The foobar2000 implementation creates an Fb2kWorkQueue, whose schedule() implementation uses fb2k::inMainThread().

The queued callback ultimately calls PlayerImpl::fetchArtwork(), which performs the album-art operations synchronously:

auto extractor = albumArtManager_->open(
    pfc::list_single_ref_t(itemHandle),
    pfc::list_single_ref_t(album_art_ids::cover_front),
    dummyCallback);

...

extractor->query(
    album_art_ids::cover_front,
    artData,
    dummyCallback);

The result is only wrapped in a future after these operations have completed.

As a result, the effective execution path appears to be:

HTTP request
    ↓
Beefweb artwork controller
    ↓
WorkQueue
    ↓
Fb2kWorkQueue
    ↓
fb2k::inMainThread()
    ↓
foobar2000 main thread
    ↓
album_art_manager_->open()
    ↓
extractor->query()
    ↓
artwork data
    ↓
HTTP response

If album_art_manager_->open() or extractor->query() performs filesystem or other potentially slow I/O, the foobar2000 main thread appears to remain blocked for the duration of that operation.

This is particularly problematic when the media library is on a remote filesystem, because network/filesystem latency can be much higher or less predictable than local storage latency.

Why this is problematic

The issue is not simply that album-art requests are slow.

A slow HTTP request is acceptable if it happens asynchronously without blocking the application's UI.

The problem is that the artwork retrieval appears to be performed on the foobar2000 main thread.

Consequently, a slow artwork lookup can turn into a complete foobar2000 UI freeze.

This also means that limiting the client to a small number of concurrent artwork requests does not necessarily solve the underlying problem. Even a single request can block the UI, and multiple requests could simply queue additional blocking artwork operations.

Expected behavior

Album-art retrieval through the HTTP API should not block the foobar2000 UI/main thread.

Potentially slow operations such as locating, opening, reading, or extracting album artwork should ideally be performed asynchronously/on an appropriate worker thread, with the HTTP request receiving the result when the operation completes.

If the relevant foobar2000 album-art APIs cannot safely be called from a worker thread, an alternative asynchronous/cached mechanism may be necessary.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions