# Music Assistant Announce TTS System Volume Strategies: A Complete Guide

> Master Music Assistant TTS announcement volume strategies. Explore absolute, relative, percentual, and none options for custom audio control. Integrate seamlessly for perfect sound.

- Repository: [Music Assistant/server](https://github.com/music-assistant/server)
- Tags: how-to-guide
- Published: 2026-06-21

---

**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`](https://github.com/music-assistant/server/blob/main/music_assistant/constants.py). The server defines four distinct strategies through the `CONF_ENTRY_ANNOUNCE_VOLUME_STRATEGY` configuration entry:

```python

# 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`](https://github.com/music-assistant/server/blob/main/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).

```python
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%.

```python
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).

```python
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`](https://github.com/music-assistant/server/blob/main/music_assistant/controllers/players/controller.py) (lines 1007-1015) orchestrates the process:

```python
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:

```python
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`](https://github.com/music-assistant/server/blob/main/music_assistant/providers/sonos/player.py) demonstrates how hardware-level volume control integrates with the strategy system:

```python
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

```python
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

```bash
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`](https://github.com/music-assistant/server/blob/main/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.