Music Assistant Announce TTS System Volume Strategies: A Complete Guide

Music Assistant calculates TTS announcement volumes using four configurable strategies—absolute, relative, percentual, or none—defined in the player configuration and applied via the get_announcement_volume method in the players controller.

The music-assistant/server repository provides a sophisticated per-player system for handling text-to-speech announcements. When you trigger a TTS notification, the system automatically adjusts the volume based on your chosen strategy, ensuring announcements remain audible without disrupting your listening experience. This implementation leverages native player APIs where available, falling back to a generic volume-management approach for unsupported devices.

Configuration Schema Options

The volume strategy configuration resides in music_assistant/constants.py. The server defines four distinct strategies through the CONF_ENTRY_ANNOUNCE_VOLUME_STRATEGY configuration entry:


# music_assistant/constants.py (lines 79-89)

CONF_ENTRY_ANNOUNCE_VOLUME_STRATEGY = ConfigEntry(
    key=CONF_ANNOUNCE_VOLUME_STRATEGY,
    type=ConfigEntryType.STRING,
    options=[
        ConfigValueOption("absolute"),
        ConfigValueOption("relative"),
        ConfigValueOption("percentual"),
        ConfigValueOption("none"),
    ],
    default_value="percentual",
    category="announcements",
)

Additional entries control the base volume level and safety boundaries:

  • CONF_ENTRY_ANNOUNCE_VOLUME – Default value 85 (the base volume used in calculations)
  • CONF_ENTRY_ANNOUNCE_VOLUME_MIN – Default value 15 (minimum allowed announcement volume)
  • CONF_ENTRY_ANNOUNCE_VOLUME_MAX – Default value 75 (maximum allowed announcement volume)

These min/max clamps ensure that regardless of the strategy selected, announcements never exceed safe volume limits.

How Volume Strategies Work in Practice

The get_announcement_volume method in music_assistant/controllers/players/controller.py (lines 1998-2025) implements the calculation logic. When an announcement is requested, the system retrieves the player’s current state and applies the configured strategy.

Absolute Strategy

The absolute strategy ignores the player’s current volume entirely. It sets the announcement volume to the fixed value defined in CONF_ENTRY_ANNOUNCE_VOLUME (default 85).

if volume_level is None and volume_strategy == "absolute":
    volume_level = int(cast("float", volume_strategy_volume))

Use this when you want consistent announcement loudness regardless of whether the player is currently muted or playing quietly.

Relative Strategy

The relative strategy adds a fixed offset to the player’s current volume level. If the player is at 40% volume and the configured offset is 20, the announcement plays at 60%.

elif volume_level is None and volume_strategy == "relative":
    if (player := self.get_player(player_id)) and player.state.volume_level is not None:
        volume_level = int(player.state.volume_level + cast("float", volume_strategy_volume))

This approach ensures announcements are louder than background music but maintains proportional relationships.

Percentual Strategy

The percentual strategy (the default) calculates volume as a percentage increase over the current level. If the player is at 50% volume and the setting is 20, the announcement plays at 60% (50 + 20% of 50).

elif volume_level is None and volume_strategy == "percentual":
    if (player := self.get_player(player_id)) and player.state.volume_level is not None:
        percentual = (player.state.volume_level / 100) * cast("float", volume_strategy_volume)
        volume_level = int(player.state.volume_level + percentual)

This provides the most dynamic scaling, automatically adjusting for quiet evenings versus loud daytime listening.

None Strategy

Setting the strategy to none returns None from get_announcement_volume, instructing the player to use its current volume without modification. This is useful for pre-announcement chimes where you do not want to alter the volume explicitly.

Implementation in the Player Controller

The play_announcement method in music_assistant/controllers/players/controller.py (lines 1007-1015) orchestrates the process:

async def play_announcement(self, player_id: str, url: str,
                             pre_announce: bool | None = None,
                             volume_level: int | None = None,
                             pre_announce_url: str | None = None) -> None:
    # [...]

    # Resolve the final volume for the announcement

    announcement_volume = self.get_announcement_volume(player_id, volume_level)
    await announce_player.play_announcement(announcement, announcement_volume)

After calculating the strategy-based volume, the system applies the min/max clamps:

volume_level = max(int(announce_min), volume_level)
volume_level = min(int(announce_max), volume_level)

This dual-clamp approach prevents edge cases where relative or percentual calculations might push the volume into uncomfortable ranges.

Provider-Level Integration

Native announcement support varies by provider. The Sonos implementation in music_assistant/providers/sonos/player.py demonstrates how hardware-level volume control integrates with the strategy system:

async def play_announcement(self, announcement: PlayerMedia, volume_level: int | None = None):
    # Sonos allows a custom volume per-announcement

    if volume_level is not None:
        await self.soco.volume(volume_level)   # set volume for this announcement

    await self.soco.play_uri(announcement.uri)   # native playback

If volume_level is None (the "none" strategy), the provider skips the volume adjustment and uses the player’s existing state. For providers without PlayerFeature.PLAY_ANNOUNCEMENT, Music Assistant falls back to a generic implementation that temporarily stores the current volume, adjusts it for the announcement, then restores the original level.

API Usage Examples

You can override the configured strategy on a per-announcement basis via the API.

Python Client

from music_assistant import MusicAssistant

mas = MusicAssistant()
await mas.players.play_announcement(
    player_id="livingroom_speaker",
    url="http://tts.local/announce?text=Door+opened",
    volume_level=70,               # forces 70% volume regardless of strategy

    pre_announce=True,               # play the chime before the TTS payload

)

cURL Request

curl -X POST "http://localhost:8095/api/players/cmd/play_announcement" \
     -H "Authorization: Bearer <TOKEN>" \
     -H "Content-Type: application/json" \
     -d '{
           "player_id": "kitchen_speaker",
           "url": "http://tts.local/announce?text=Coffee+ready",
           "pre_announce": true,
           "volume_level": null         # let the server apply the configured strategy

         }'

Passing null for volume_level allows the server to calculate the volume using the player’s configured strategy, while passing an integer bypasses the calculation entirely.

Summary

  • Four strategy modes (absolute, relative, percentual, none) provide flexibility for different listening environments and hardware capabilities.
  • Safety clamping via CONF_ENTRY_ANNOUNCE_VOLUME_MIN and CONF_ENTRY_ANNOUNCE_VOLUME_MAX prevents announcements from being too quiet or dangerously loud.
  • Per-announcement overrides allow API consumers to bypass configuration when specific volume levels are required.
  • Native player support is preferred when available, with the generic fallback ensuring consistent behavior across all device types.

Frequently Asked Questions

What happens if I set the volume strategy to "none"?

The system returns None from get_announcement_volume, causing the player to use its current volume level without adjustment. This is ideal when you want announcements to respect the existing volume state or when using pre-announcement chimes that should not trigger volume changes.

How do min and max volume limits affect announcements?

After calculating the volume using your chosen strategy, Music Assistant clamps the result between the configured minimum (default 15%) and maximum (default 75%). This ensures that even if a relative calculation suggests 100% volume, the announcement will not exceed the safety ceiling defined in your player configuration.

Can I override the configured volume strategy for a single announcement?

Yes. When calling play_announcement via the API, provide an integer value for the volume_level parameter. This bypasses the strategy calculation entirely, forcing the specific volume you specify. Pass null or omit the parameter to use the configured strategy.

Which Music Assistant players support native announcement playback?

Players supporting the PlayerFeature.PLAY_ANNOUNCEMENT capability, such as the Sonos provider in music_assistant/providers/sonos/player.py, handle announcements natively. This allows the player to manage volume transitions internally. For unsupported players, Music Assistant uses a generic fallback that manually adjusts volume before and after playback.

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 →