Skip to content

Commit 8d39d0d

Browse files
committed
Persistent Media Player Volume After Restart
* Extended Preferences and ServerState to store the normalized media volume and provide a helper to persist it only when the value changes. * Load the saved volume during startup and apply it immediately to both mpv players so the remembered level is active after every restart. * Initialize the media player entity with the stored volume and write back updates from Home Assistant so future sessions reuse the latest setting.
1 parent 5f0f595 commit 8d39d0d

File tree

4 files changed

+36
-2
lines changed

4 files changed

+36
-2
lines changed

linux_voice_assistant/__main__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ async def main() -> None:
133133
else:
134134
preferences = Preferences()
135135

136+
initial_volume = preferences.volume if preferences.volume is not None else 1.0
137+
initial_volume = max(0.0, min(1.0, float(initial_volume)))
138+
preferences.volume = initial_volume
139+
136140
libtensorflowlite_c_path = _LIB_DIR / "libtensorflowlite_c.so"
137141
_LOGGER.debug("libtensorflowlite_c path: %s", libtensorflowlite_c_path)
138142

@@ -190,8 +194,13 @@ async def main() -> None:
190194
oww_melspectrogram_path=Path(args.oww_melspectrogram_model),
191195
oww_embedding_path=Path(args.oww_embedding_model),
192196
refractory_seconds=args.refractory_seconds,
197+
volume=initial_volume,
193198
)
194199

200+
initial_volume_percent = int(round(initial_volume * 100))
201+
state.music_player.set_volume(initial_volume_percent)
202+
state.tts_player.set_volume(initial_volume_percent)
203+
195204
process_audio_thread = threading.Thread(
196205
target=process_audio, args=(state,), daemon=True
197206
)

linux_voice_assistant/entity.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,17 @@ def __init__(
4242
object_id: str,
4343
music_player: MpvMediaPlayer,
4444
announce_player: MpvMediaPlayer,
45+
initial_volume: float = 1.0,
4546
) -> None:
4647
ESPHomeEntity.__init__(self, server)
4748

4849
self.key = key
4950
self.name = name
5051
self.object_id = object_id
5152
self.state = MediaPlayerState.IDLE
52-
self.volume = 1.0
53+
self.volume = max(0.0, min(1.0, initial_volume))
5354
self.muted = False
54-
self.previous_volume = 1.0
55+
self.previous_volume = self.volume
5556
self.music_player = music_player
5657
self.announce_player = announce_player
5758

@@ -140,6 +141,10 @@ def handle_message(self, msg: message.Message) -> Iterable[message.Message]:
140141
self.music_player.set_volume(volume)
141142
self.announce_player.set_volume(volume)
142143
self.volume = msg.volume
144+
if hasattr(self.server, "state") and getattr(
145+
self.server, "state", None
146+
) is not None:
147+
self.server.state.persist_volume(self.volume) # type: ignore[attr-defined]
143148
yield self._update_state(self.state)
144149
elif isinstance(msg, ListEntitiesRequest):
145150
yield ListEntitiesMediaPlayerResponse(

linux_voice_assistant/models.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def load(
5656
@dataclass
5757
class Preferences:
5858
active_wake_words: List[str] = field(default_factory=list)
59+
volume: Optional[float] = None
5960

6061

6162
@dataclass
@@ -86,6 +87,7 @@ class ServerState:
8687
refractory_seconds: float = 2.0
8788
muted: bool = False
8889
connected: bool = False
90+
volume: float = 1.0
8991

9092
def save_preferences(self) -> None:
9193
"""Save preferences as JSON."""
@@ -95,3 +97,18 @@ def save_preferences(self) -> None:
9597
json.dump(
9698
asdict(self.preferences), preferences_file, ensure_ascii=False, indent=4
9799
)
100+
101+
def persist_volume(self, volume: float) -> None:
102+
"""Persist the normalized media volume (0.0 - 1.0)."""
103+
clamped_volume = max(0.0, min(1.0, volume))
104+
105+
if (
106+
abs(self.volume - clamped_volume) < 0.0001
107+
and self.preferences.volume is not None
108+
and abs(self.preferences.volume - clamped_volume) < 0.0001
109+
):
110+
return
111+
112+
self.volume = clamped_volume
113+
self.preferences.volume = clamped_volume
114+
self.save_preferences()

linux_voice_assistant/satellite.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,15 @@ def __init__(self, state: ServerState) -> None:
8787
object_id="linux_voice_assistant_media_player",
8888
music_player=state.music_player,
8989
announce_player=state.tts_player,
90+
initial_volume=state.volume,
9091
)
9192
self.state.entities.append(self.state.media_player_entity)
9293
elif self.state.media_player_entity not in self.state.entities:
9394
self.state.entities.append(self.state.media_player_entity)
9495

9596
self.state.media_player_entity.server = self
97+
self.state.media_player_entity.volume = state.volume
98+
self.state.media_player_entity.previous_volume = state.volume
9699

97100
# Add/update mute switch entity (like ESPHome Voice PE)
98101
mute_switch = self.state.mute_switch_entity

0 commit comments

Comments
 (0)