Add the ability to control microphone volume (#287)
Control microphone volume via UI in device page. Set to the maximum by default and saved in preferences to restore upon restarts.
This commit is contained in:
1 parent
4ee7bb04bc
commit
c284806b73
3 files changed
+43
-1
No files matched your search
@@ -375,6 +375,7 @@ async def main() -> None:
|
||||
output_only=args.output_only,
|
||||
download_dir=args.download_dir,
|
||||
volume=initial_volume,
|
||||
mic_volume=preferences.mic_volume,
|
||||
mic_auto_gain=preferences.mic_auto_gain,
|
||||
mic_noise_suppression=preferences.mic_noise_suppression,
|
||||
timer_max_ring_seconds=args.timer_max_ring_seconds,
|
||||
@@ -455,7 +456,8 @@ def process_audio(state: ServerState, mic, block_size: int):
|
||||
while True:
|
||||
audio_chunk_array = mic_in.record(block_size).reshape(-1)
|
||||
# little-endian 16-bit signed
|
||||
audio_chunk = (np.clip(audio_chunk_array, -1.0, 1.0) * 32767.0).astype("<i2").tobytes()
|
||||
mic_vol_scalar = max(0.1, min(1.0, state.mic_volume / 100.0))
|
||||
audio_chunk = (np.clip(audio_chunk_array * mic_vol_scalar, -1.0, 1.0) * 32767.0).astype("<i2").tobytes()
|
||||
|
||||
if state.satellite is None:
|
||||
continue
|
||||
|
||||
@@ -62,6 +62,7 @@ class Preferences:
|
||||
thinking_sound: int = 0 # 0 = disabled, 1 = enabled
|
||||
mic_auto_gain: int = 0
|
||||
mic_noise_suppression: int = 0
|
||||
mic_volume: int = 100 # 1–100, default maximum
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -96,6 +97,7 @@ class ServerState:
|
||||
thinking_sound_entity: "Optional[ThinkingSoundEntity]" = None
|
||||
mic_gain_entity: "Optional[MicSettingEntity]" = None
|
||||
mic_noise_suppression_entity: "Optional[MicSettingEntity]" = None
|
||||
mic_volume_entity: "Optional[MicSettingEntity]" = None
|
||||
wake_words_changed: bool = False
|
||||
refractory_seconds: float = 2.0
|
||||
thinking_sound_enabled: bool = False
|
||||
@@ -105,6 +107,7 @@ class ServerState:
|
||||
volume: float = 1.0
|
||||
mic_auto_gain: int = 0
|
||||
mic_noise_suppression: int = 0
|
||||
mic_volume: int = 100 # 1–100, default maximum
|
||||
timer_max_ring_seconds: float = 900.0
|
||||
|
||||
def save_preferences(self) -> None:
|
||||
@@ -158,3 +161,14 @@ class ServerState:
|
||||
self.mic_noise_suppression = noise_int
|
||||
self.preferences.mic_noise_suppression = noise_int
|
||||
self.save_preferences()
|
||||
|
||||
def persist_mic_volume(self, volume: float) -> None:
|
||||
"""Persist the microphone input volume (0–100)."""
|
||||
volume_int = max(1, min(100, int(round(volume))))
|
||||
if self.mic_volume == volume_int and self.preferences.mic_volume == volume_int:
|
||||
return
|
||||
|
||||
self.mic_volume = volume_int
|
||||
self.preferences.mic_volume = volume_int
|
||||
_LOGGER.info("Saving mic_volume %s to %s", volume_int, self.preferences_path)
|
||||
self.save_preferences()
|
||||
@@ -213,6 +213,29 @@ class VoiceSatelliteProtocol(APIServer):
|
||||
self.state.mic_noise_suppression_entity.update_set_value(_set_noise_label)
|
||||
self.state.mic_noise_suppression_entity.sync_with_state()
|
||||
|
||||
# Mic Volume
|
||||
if self.state.mic_volume_entity is None:
|
||||
self.state.mic_volume_entity = MicSettingEntity(
|
||||
server=self,
|
||||
key=len(self.state.entities),
|
||||
name="Mic Volume",
|
||||
object_id="mic_volume",
|
||||
min_value=1.0,
|
||||
max_value=100.0,
|
||||
get_value=lambda: float(self.state.mic_volume),
|
||||
set_value=lambda val: self.state.persist_mic_volume(float(val)),
|
||||
icon="mdi:microphone-settings",
|
||||
)
|
||||
self.state.entities.append(self.state.mic_volume_entity)
|
||||
elif self.state.mic_volume_entity not in self.state.entities:
|
||||
self.state.entities.append(self.state.mic_volume_entity)
|
||||
|
||||
self.state.mic_volume_entity.server = self
|
||||
self.state.mic_volume_entity.update_get_value(lambda: float(self.state.mic_volume))
|
||||
self.state.mic_volume_entity.update_set_value(lambda val: self.state.persist_mic_volume(float(val)))
|
||||
|
||||
# ---- Instance variables ----
|
||||
|
||||
self._is_streaming_audio = False
|
||||
self._tts_url: Optional[str] = None
|
||||
self._tts_played = False
|
||||
@@ -605,6 +628,9 @@ class VoiceSatelliteProtocol(APIServer):
|
||||
if self.state.mic_noise_suppression_entity is not None:
|
||||
self.state.mic_noise_suppression_entity.sync_with_state()
|
||||
|
||||
if self.state.mic_volume_entity is not None:
|
||||
self.state.mic_volume_entity.sync_with_state()
|
||||
|
||||
_LOGGER.info("Disconnected from Home Assistant; waiting for reconnection")
|
||||
|
||||
def process_packet(self, msg_type: int, packet_data: bytes) -> None:
|
||||
|
||||
Reference in new issue
Block a user