How Player Configuration Profiles Control Playback Behavior in Music Assistant

Player configuration profiles determine HTTP transport headers, audio normalization, and metadata injection, directly controlling how players buffer, seek, and display now-playing information.

Music Assistant's server architecture allows granular control over audio delivery through player-specific configuration profiles. These profiles, stored per-player in the configuration database, dictate everything from HTTP response formatting to PCM normalization. Understanding how these settings interact with the streaming pipeline is essential for resolving buffering issues, early playback stops, or missing metadata displays on specific hardware.

HTTP Transport Profiles and Stream Delivery

The most critical profile is the HTTP profile (CONF_HTTP_PROFILE), defined in music_assistant/constants.py. This setting determines how the streaming controller in music_assistant/controllers/streams/controller.py constructs HTTP responses when delivering audio to players.

Chunked Encoding ("chunked")

When set to "chunked", the server calls resp.enable_chunked_encoding() on the HTTP response. This omits the Content-Length header and streams data using HTTP/1.1 chunked transfer encoding.

This profile works best with players that support continuous streaming and ignore content size. The player begins playback immediately without waiting for complete track metadata, as data arrives in discrete chunks until the connection closes.

No Content Length ("no_content_length") — Default

The default profile sends audio as a raw stream without chunked encoding and without a Content-Length header. The response body flows continuously until the connection terminates.

This approach suits most modern players that handle steady data streams efficiently. It eliminates the overhead of chunk markers while maintaining compatibility with players that don't require explicit size declarations.

Forced Content Length ("forced_content_length")

This profile calculates and injects an explicit Content-Length header. In music_assistant/controllers/streams/controller.py, the logic distinguishes between known and unknown track durations:

if http_profile == "forced_content_length" and not queue_item.duration:
    resp.content_length = calculate_content_length(output_format, 12 * 3600)
elif http_profile == "forced_content_length" and queue_item.duration:
    resp.content_length = await get_content_length(...)

When the duration is unknown, the server uses a 12-hour placeholder (43,200 seconds). When known, it estimates byte count via calculate_content_length or get_content_length. This forces strict players to maintain connections for the entire track duration, though it may introduce extra buffering if estimates are inaccurate.

Audio Processing and Metadata Profiles

Beyond transport layer configuration, additional player configuration profiles affect audio processing and metadata delivery.

PCM Normalization Profiles

Provider-specific modules implement PCM normalization profiles that control gain adjustment. For example, in music_assistant/providers/yandex_ynison/streaming.py, these profiles select presets that equalize volume across tracks. This ensures consistent loudness levels regardless of the source material's original dynamic range.

ICY Metadata Profiles

The CONF_ENABLE_ICY_METADATA setting (defined in music_assistant/constants.py) controls whether the server injects ICY tags containing artist, title, and cover art into the stream. When enabled, compatible players display real-time now-playing information extracted from these metadata frames.

Configuring Profiles via the API

Player profiles are stored per-player in the configuration database and can be manipulated programmatically. Changes typically trigger player reinitialization due to requires_reload=True on the configuration entries.

Reading Current Profile Settings

Retrieve the current HTTP profile for a specific player:

player_id = "my_sonos_player"
http_profile = await mass.config.get_player_config_value(
    player_id, CONF_HTTP_PROFILE, default="no_content_length", return_type=str
)
print(f"The HTTP profile for {player_id} is: {http_profile}")

Modifying HTTP Profiles

Change a player to use forced content length:

await mass.config.set_player_config_value(
    player_id, CONF_HTTP_PROFILE, "forced_content_length"
)

Enabling Metadata and Normalization

Enable ICY metadata injection:

await mass.config.set_player_config_value(
    player_id, CONF_ENABLE_ICY_METADATA, "full"
)

Set PCM normalization for supported providers:

await mass.config.set_player_config_value(
    player_id, "pcm_normalization_profile", "high_dynamic_range"
)

Implementation Details in the Streaming Controller

The profile selection logic resides in music_assistant/controllers/streams/controller.py. When handling audio requests, the controller queries the configuration and applies the appropriate HTTP formatting:

http_profile = await self.mass.config.get_player_config_value(
    player_id, CONF_HTTP_PROFILE, default="default", return_type=str
)
if http_profile == "forced_content_length" and not queue_item.duration:
    resp.content_length = calculate_content_length(output_format, 12 * 3600)
elif http_profile == "forced_content_length" and queue_item.duration:
    resp.content_length = await get_content_length(...)
elif http_profile == "chunked":
    resp.enable_chunked_encoding()

This implementation shows how the selected profile directly modifies the HTTP response object before transmission, altering the headers that the player receives and consequently how it manages buffering and playback continuity.

Summary

  • Player configuration profiles determine HTTP transport behavior, audio normalization, and metadata injection in Music Assistant.
  • The HTTP profile (CONF_HTTP_PROFILE) offers three modes: chunked encoding, no content length (default), and forced content length, each affecting how players buffer and maintain connections.
  • Forced content length calculates explicit byte counts using calculate_content_length or get_content_length, essential for legacy players that require Content-Length headers.
  • PCM normalization profiles and ICY metadata settings provide additional control over audio processing and now-playing information display.
  • Configuration changes are stored per-player and trigger reloads when requires_reload=True is set on the configuration entry.
  • Profile application occurs in music_assistant/controllers/streams/controller.py, directly modifying HTTP response headers before streaming begins.

Frequently Asked Questions

What is the default HTTP profile in Music Assistant and when should I change it?

The default profile is "no_content_length", defined in music_assistant/constants.py. This setting streams audio without explicit size declarations or chunked encoding, working well for most modern players. Change to "forced_content_length" if your player stops playback early or buffers excessively, as some legacy hardware requires explicit Content-Length headers to maintain connections.

How does chunked encoding affect playback latency?

Chunked encoding ("chunked") typically reduces initial playback latency because the player starts receiving and processing data immediately without waiting for a complete track download. However, some players may exhibit instability if they expect traditional content-length headers or if their HTTP client libraries don't handle chunked transfers efficiently.

Can I use different profiles for different players in the same group?

Yes. Music Assistant stores profiles per-player in the configuration database. When using universal groups (music_assistant/providers/universal_group/player.py), the system handles individual player profiles separately, though the group itself may have its own configuration that affects how child players are managed.

Why does changing a player profile require a reload?

Configuration entries for player profiles specify requires_reload=True, meaning changes trigger player reinitialization. This ensures the new HTTP header strategies, normalization settings, or metadata injection parameters take effect immediately, as the streaming controller must rebuild the audio pipeline with the new parameters.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →