/
/
/
1"""Constants for the AmpliPi player provider."""
2
3import aiohttp
4from pyamplipi.error import AmpliPiError
5from pydantic import ValidationError
6
7DOMAIN = "amplipi"
8
9# Errors the pyamplipi client raises when the controller is unreachable, returns an API
10# error, or sends an unexpected/garbled response (AmpliPiUnreachableError/APIError extend
11# AmpliPiError; a malformed payload surfaces as a pydantic ValidationError or a KeyError on
12# a missing top-level field). Caught where an AmpliPi call is best-effort and a failure
13# should not abort the surrounding operation.
14AMPLIPI_API_ERRORS = (AmpliPiError, aiohttp.ClientError, TimeoutError, ValidationError, KeyError)
15
16
17CONF_HOST = "host"
18
19# AmpliPi zone source_id sentinels (mirrors the AmpliPi server constants):
20# a zone connected to a source uses its source_id (0..3),
21# SOURCE_DISCONNECTED means "powered on but no source connected" (zone is silent),
22# ZONE_OFF means the zone is "off" (used to model MA's power state).
23SOURCE_DISCONNECTED = -1
24ZONE_OFF = -2
25
26# AmpliPi has no push interface, so we poll the controller for state updates.
27POLL_INTERVAL = 5
28
29# values of Source.input that indicate the source is free/unassigned.
30FREE_SOURCE_INPUTS = ("", "None", None)
31
32# AmpliPi stream type used for Music Assistant playback. The "internetradio" type is
33# built for continuous HTTP streams and supports reliable play/stop, unlike the
34# "fileplayer" type (which is intended for one-shot announcements). Note: AmpliPi has
35# no native pause for this type; pause is emulated via stop in the player.
36MA_STREAM_TYPE = "internetradio"
37
38# name prefix for the streams Music Assistant creates on the AmpliPi controller; used to
39# identify and clean up our own streams (one per source) across reloads.
40MA_STREAM_NAME = "Music Assistant"
41
42# AmpliPi stream types for physical passthrough inputs. RCA inputs are first-class streams
43# (type="rca", index 0-3, ids 996-999, names "Input 1-4") connected to a source like any
44# stream: source.input = "stream=<id>". "aux" is the front-panel auxiliary input. Both are
45# pure passthrough: no transport (play/stop endpoints 404, info.state stays "stopped"); MA
46# can route them to zones and set volume, but the wired source owns the audio.
47RCA_STREAM_TYPE = "rca"
48AUX_STREAM_TYPE = "aux"
49INPUT_STREAM_TYPES = (RCA_STREAM_TYPE, AUX_STREAM_TYPE)
50
51# Friendly labels for AmpliPi stream types, used to disambiguate selectable sources in the
52# UI: native streams can share a name (e.g. a Spotify and an AirPlay endpoint both named
53# "AmpliPro 1"), so non-input sources are labelled "<name> (<type label>)".
54STREAM_TYPE_LABELS = {
55 "spotify": "Spotify",
56 "airplay": "AirPlay",
57 "pandora": "Pandora",
58 "dlna": "DLNA",
59 "internetradio": "Internet Radio",
60 "plexamp": "Plexamp",
61 "bluetooth": "Bluetooth",
62 "lms": "LMS",
63}
64
65# Stream types that should NOT be offered to the user as selectable sources. "fileplayer"
66# is AmpliPi's built-in announcement player ("External Media"), not a real source.
67# TODO(announcements): fileplayer is excluded from the source picker, but it is the right
68# mechanism for MA's PLAY_ANNOUNCEMENT/TTS feature (one-shot URL playback). When we add
69# announcement support, USE the fileplayer stream here rather than surfacing it as a source.
70EXCLUDED_SELECTABLE_STREAM_TYPES = ("fileplayer",)
71
72# Music Assistant PlayerSource ids for AmpliPi-side selectable sources are namespaced as
73# "stream=<amplipi stream id>", which doubles as the value written to source.input.
74SOURCE_ID_STREAM_PREFIX = "stream="
75
76# AmpliPi's volume scale is linear in dB over a wide range (~-80..0 dB), so mapping Music
77# Assistant's 0-100 directly onto it leaves the lower half of the slider near-silent.
78# Instead we map 0-100 onto a usable dB window (this floor .. 0 dB), mirroring how the
79# AirPlay provider maps onto a usable window. Volume 0 -> floor, 100 -> 0 dB (max).
80VOLUME_DB_FLOOR = -60
81