+76
src/app.rs
+76
src/app.rs
···
3
3
prelude::*,
4
4
widgets::{block::*, *},
5
5
};
6
+
use souvlaki::MediaControlEvent;
6
7
use std::{
7
8
io,
8
9
ops::Range,
···
11
12
time::{Duration, Instant},
12
13
};
13
14
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
15
+
use tunein_cli::os_media_controls::{self, OsMediaControls};
14
16
15
17
use crate::{
16
18
extract::get_currently_playing,
···
76
78
self.is_muted = !self.is_muted;
77
79
}
78
80
81
+
/// Set the volume to the given volume ratio.
82
+
///
83
+
/// `1.0` is 100% volume.
84
+
pub const fn set_volume_ratio(&mut self, volume: f32) {
85
+
self.raw_volume_percent = volume * 100.0;
86
+
self.raw_volume_percent = self.raw_volume_percent.max(0.0);
87
+
}
88
+
79
89
/// Change the volume by the given step percent.
80
90
///
81
91
/// To increase the volume, use a positive step. To decrease the
···
135
145
spectroscope: Spectroscope,
136
146
mode: CurrentDisplayMode,
137
147
frame_rx: Receiver<minimp3::Frame>,
148
+
/// [`OsMediaControls`].
149
+
os_media_controls: Option<OsMediaControls>,
138
150
}
139
151
140
152
impl App {
···
143
155
source: &crate::cfg::SourceOptions,
144
156
frame_rx: Receiver<minimp3::Frame>,
145
157
mode: CurrentDisplayMode,
158
+
os_media_controls: Option<OsMediaControls>,
146
159
) -> Self {
147
160
let graph = GraphConfig {
148
161
axis_color: Color::DarkGray,
···
175
188
mode,
176
189
channels: source.channels as u8,
177
190
frame_rx,
191
+
os_media_controls,
178
192
}
179
193
}
180
194
}
···
387
401
.unwrap();
388
402
}
389
403
404
+
while let Some(event) = self
405
+
.os_media_controls
406
+
.as_mut()
407
+
.and_then(|os_media_controls| os_media_controls.try_recv_os_event())
408
+
{
409
+
if self.process_os_media_control_event(event, &new_state, &mut sink_cmd_tx) {
410
+
return;
411
+
}
412
+
}
413
+
390
414
while event::poll(Duration::from_millis(0)).unwrap() {
391
415
// process all enqueued events
392
416
let event = event::read().unwrap();
···
526
550
527
551
Ok(quit)
528
552
}
553
+
554
+
/// Process OS media control event.
555
+
///
556
+
/// Returns [`true`] if application should quit.
557
+
fn process_os_media_control_event(
558
+
&mut self,
559
+
event: MediaControlEvent,
560
+
state: &Mutex<State>,
561
+
sink_cmd_tx: &mut UnboundedSender<SinkCommand>,
562
+
) -> bool {
563
+
let mut quit = false;
564
+
565
+
match event {
566
+
MediaControlEvent::Play => {
567
+
play(&mut self.graph, sink_cmd_tx);
568
+
}
569
+
MediaControlEvent::Pause => {
570
+
pause(&mut self.graph, sink_cmd_tx);
571
+
}
572
+
MediaControlEvent::Toggle => {
573
+
toggle_play_pause(&mut self.graph, sink_cmd_tx);
574
+
}
575
+
MediaControlEvent::Stop | MediaControlEvent::Quit => {
576
+
quit = true;
577
+
}
578
+
MediaControlEvent::SetVolume(volume) => {
579
+
set_volume_ratio(volume as f32, state, sink_cmd_tx);
580
+
}
581
+
MediaControlEvent::Next
582
+
| MediaControlEvent::Previous
583
+
| MediaControlEvent::Seek(_)
584
+
| MediaControlEvent::SeekBy(_, _)
585
+
| MediaControlEvent::SetPosition(_)
586
+
| MediaControlEvent::OpenUri(_)
587
+
| MediaControlEvent::Raise => {}
588
+
}
589
+
590
+
quit
591
+
}
529
592
}
530
593
531
594
pub fn update_value_f(val: &mut f64, base: f64, magnitude: f64, range: Range<f64>) {
···
641
704
.send(SinkCommand::SetVolume(state.volume.volume_ratio()))
642
705
.expect("receiver never dropped");
643
706
}
707
+
708
+
/// Set the volume to the given volume ratio.
709
+
fn set_volume_ratio(
710
+
volume_ratio: f32,
711
+
state: &Mutex<State>,
712
+
sink_cmd_tx: &UnboundedSender<SinkCommand>,
713
+
) {
714
+
let mut state = state.lock().unwrap();
715
+
state.volume.set_volume_ratio(volume_ratio);
716
+
sink_cmd_tx
717
+
.send(SinkCommand::SetVolume(state.volume.volume_ratio()))
718
+
.expect("receiver never dropped");
719
+
}
+11
-1
src/play.rs
+11
-1
src/play.rs
···
2
2
3
3
use anyhow::Error;
4
4
use hyper::header::HeaderValue;
5
+
use tunein_cli::os_media_controls::OsMediaControls;
5
6
6
7
use crate::{
7
8
app::{App, CurrentDisplayMode, State, Volume},
···
57
58
tune: None,
58
59
};
59
60
60
-
let mut app = App::new(&ui, &opts, frame_rx, display_mode);
61
+
let os_media_controls = OsMediaControls::new()
62
+
.inspect_err(|err| {
63
+
eprintln!(
64
+
"error: failed to initialize os media controls due to `{}`",
65
+
err
66
+
);
67
+
})
68
+
.ok();
69
+
70
+
let mut app = App::new(&ui, &opts, frame_rx, display_mode, os_media_controls);
61
71
let station_name = station.name.clone();
62
72
63
73
thread::spawn(move || {