Implement mute (it was a stub)
Toggling mute did nothing: the server logged a FIXME and never touched the player, and the TUI ignored the Mute stream update. Now the player engine mutes by zeroing the sink volume and remembering the level to restore (setting the volume unmutes), ToggleMute drives it and broadcasts the new state, the TUI shows a Muted marker in the now-playing pane, and the web client mute button already reflected the Mute update so it now works too. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7f34f869a9
commit
80c4b6e7ed
|
|
@ -124,6 +124,15 @@ impl Player {
|
|||
Ok(rx.recv_async().await?)
|
||||
}
|
||||
|
||||
/// Toggles mute; resolves to the new muted state.
|
||||
pub async fn toggle_mute(&self) -> Result<bool> {
|
||||
let (tx, rx) = flume::bounded(1);
|
||||
self.tx_engine
|
||||
.send_async(PlayerEngineCommand::ToggleMute(tx))
|
||||
.await?;
|
||||
Ok(rx.recv_async().await?)
|
||||
}
|
||||
|
||||
pub async fn pause(&self) -> Result<()> {
|
||||
let (tx, rx) = flume::bounded(1);
|
||||
self.tx_engine
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ pub enum PlayerEngineCommand {
|
|||
GetElapsed(Sender<Result<Duration>>),
|
||||
SeekTo(Duration, Sender<Result<Duration>>),
|
||||
GetVolume(Sender<f32>),
|
||||
ToggleMute(Sender<bool>),
|
||||
GetPaused(Sender<Result<bool>>),
|
||||
/// End of stream for the source started by the given generation.
|
||||
/// Stale generations are ignored so an old track finishing can never
|
||||
|
|
@ -100,6 +101,10 @@ pub struct PlayerEngine {
|
|||
/// visualizer (architecture/spectrum.md). Handed out via
|
||||
/// [`Self::spectrum_tap`] so the server's FFT task can read it.
|
||||
spectrum: Arc<SpectrumTap>,
|
||||
/// Whether output is muted (sink volume zeroed).
|
||||
muted: bool,
|
||||
/// Volume to restore on unmute.
|
||||
pre_mute_volume: f32,
|
||||
}
|
||||
|
||||
impl PlayerEngine {
|
||||
|
|
@ -140,6 +145,8 @@ impl PlayerEngine {
|
|||
_owned_runtime: owned_runtime,
|
||||
http,
|
||||
spectrum,
|
||||
muted: false,
|
||||
pre_mute_volume: 1.0,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -174,6 +181,7 @@ impl PlayerEngine {
|
|||
send_reply(tx, self.set_volume(volume));
|
||||
}
|
||||
PlayerEngineCommand::GetVolume(tx) => send_reply(tx, self.volume()),
|
||||
PlayerEngineCommand::ToggleMute(tx) => send_reply(tx, self.toggle_mute()),
|
||||
PlayerEngineCommand::GetPaused(tx) => send_reply(tx, self.is_paused()),
|
||||
PlayerEngineCommand::Eos(generation) => self.handle_eos(generation),
|
||||
}
|
||||
|
|
@ -386,13 +394,37 @@ impl PlayerEngine {
|
|||
Ok(self.sink.get_pos())
|
||||
}
|
||||
|
||||
/// The user's intended volume — the level playback would resume at,
|
||||
/// which while muted is the remembered pre-mute level rather than the
|
||||
/// silenced sink volume.
|
||||
pub fn volume(&self) -> f32 {
|
||||
if self.muted {
|
||||
self.pre_mute_volume
|
||||
} else {
|
||||
self.sink.volume()
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the volume and unmutes: reaching for the volume is an intent
|
||||
/// to hear something.
|
||||
pub fn set_volume(&mut self, volume: f32) -> f32 {
|
||||
self.muted = false;
|
||||
self.sink.set_volume(volume.clamp(0.0, 1.1));
|
||||
self.sink.volume()
|
||||
}
|
||||
|
||||
pub fn set_volume(&mut self, volume: f32) -> f32 {
|
||||
self.sink.set_volume(volume.clamp(0.0, 1.1));
|
||||
self.sink.volume()
|
||||
/// Toggles mute by zeroing the sink volume and remembering the level
|
||||
/// to restore. Returns the new muted state.
|
||||
pub fn toggle_mute(&mut self) -> bool {
|
||||
if self.muted {
|
||||
self.sink.set_volume(self.pre_mute_volume);
|
||||
self.muted = false;
|
||||
} else {
|
||||
self.pre_mute_volume = self.sink.volume();
|
||||
self.sink.set_volume(0.0);
|
||||
self.muted = true;
|
||||
}
|
||||
self.muted
|
||||
}
|
||||
|
||||
fn handle_eos(&mut self, generation: u64) {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ pub struct NowPlaying {
|
|||
spectrum: Vec<f32>,
|
||||
/// Whether to draw the spectrum row (config `spectrum`, default on).
|
||||
spectrum_enabled: bool,
|
||||
/// Whether the server output is muted.
|
||||
muted: bool,
|
||||
}
|
||||
|
||||
impl Default for NowPlaying {
|
||||
|
|
@ -67,6 +69,7 @@ impl Default for NowPlaying {
|
|||
track: None,
|
||||
spectrum: Vec::new(),
|
||||
spectrum_enabled: true,
|
||||
muted: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -119,6 +122,10 @@ impl NowPlaying {
|
|||
pub fn set_spectrum_enabled(&mut self, enabled: bool) {
|
||||
self.spectrum_enabled = enabled;
|
||||
}
|
||||
/// Reflects the server's mute state.
|
||||
pub fn update_mute(&mut self, muted: bool) {
|
||||
self.muted = muted;
|
||||
}
|
||||
|
||||
pub fn render(&self, f: &mut Frame, area: Rect) {
|
||||
// With the spectrum on, the info block takes exactly the height
|
||||
|
|
@ -154,8 +161,10 @@ impl NowPlaying {
|
|||
None => "No album".to_string(),
|
||||
};
|
||||
let mods = format!(
|
||||
"Shuffle: {}, Repeat {}",
|
||||
self.modifiers.shuffle, self.modifiers.repeat
|
||||
"Shuffle: {}, Repeat: {}{}",
|
||||
self.modifiers.shuffle,
|
||||
self.modifiers.repeat,
|
||||
if self.muted { ", Muted" } else { "" },
|
||||
);
|
||||
vec![
|
||||
Line::from(Span::raw(mods)),
|
||||
|
|
@ -287,6 +296,7 @@ mod tests {
|
|||
}),
|
||||
spectrum: Vec::new(),
|
||||
spectrum_enabled: true,
|
||||
muted: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ fn run_ui(tx: Sender<MessageFromUi>, rx: Receiver<MessageToUi>, spectrum_enabled
|
|||
StreamUpdate::Mods(mods) => {
|
||||
app.now_playing.update_modifiers(&mods);
|
||||
}
|
||||
StreamUpdate::Mute(_) => { /* FIXME: implement */ }
|
||||
StreamUpdate::Mute(muted) => app.now_playing.update_mute(muted),
|
||||
StreamUpdate::Volume(_) => { /* FIXME: implement */ }
|
||||
StreamUpdate::CaptureProgress(progress) => {
|
||||
app.captures.apply(progress);
|
||||
|
|
|
|||
|
|
@ -352,10 +352,13 @@ impl Playback {
|
|||
};
|
||||
}
|
||||
|
||||
PlaybackCommand::ToggleMute => {
|
||||
// FIXME: implement mute in the player engine
|
||||
debug!("toggle mute requested (not implemented)");
|
||||
PlaybackCommand::ToggleMute => match self.player.toggle_mute().await {
|
||||
Ok(muted) => {
|
||||
debug!(muted, "toggled mute");
|
||||
self.broadcast(StreamUpdate::Mute(muted));
|
||||
}
|
||||
Err(err) => warn!("toggle_mute failed: {err:?}"),
|
||||
},
|
||||
|
||||
PlaybackCommand::Next => {
|
||||
let track = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue