Browse and listen to thousands of radio stations across the globe right from your terminal ๐ŸŒŽ ๐Ÿ“ป ๐ŸŽตโœจ
radio rust tokio web-radio command-line-tool tui

app: on event action, send command to the OS as required

Changed files
+123 -23
src
+123 -23
src/app.rs
··· 476 KeyCode::Up => { 477 // inverted to act as zoom 478 update_value_f(&mut self.graph.scale, 0.01, magnitude, 0.0..10.0); 479 - raise_volume(&state, sink_cmd_tx); 480 } 481 KeyCode::Down => { 482 // inverted to act as zoom 483 update_value_f(&mut self.graph.scale, -0.01, magnitude, 0.0..10.0); 484 - lower_volume(&state, sink_cmd_tx); 485 } 486 KeyCode::Right => update_value_i( 487 &mut self.graph.samples, ··· 498 0..self.graph.width * 2, 499 ), 500 KeyCode::Char('q') => quit = true, 501 - KeyCode::Char(' ') => toggle_play_pause(&mut self.graph, sink_cmd_tx), 502 KeyCode::Char('s') => self.graph.scatter = !self.graph.scatter, 503 KeyCode::Char('h') => self.graph.show_ui = !self.graph.show_ui, 504 KeyCode::Char('r') => self.graph.references = !self.graph.references, 505 - KeyCode::Char('m') => mute_volume(&state, sink_cmd_tx), 506 KeyCode::Esc => { 507 self.graph.samples = self.graph.width; 508 self.graph.scale = 1.; ··· 528 } 529 } 530 KeyCode::Media(media_key_code) => match media_key_code { 531 - MediaKeyCode::Play => play(&mut self.graph, sink_cmd_tx), 532 - MediaKeyCode::Pause => pause(&mut self.graph, sink_cmd_tx), 533 - MediaKeyCode::PlayPause => toggle_play_pause(&mut self.graph, sink_cmd_tx), 534 MediaKeyCode::Stop => { 535 quit = true; 536 } 537 - MediaKeyCode::LowerVolume => lower_volume(&state, sink_cmd_tx), 538 - MediaKeyCode::RaiseVolume => raise_volume(&state, sink_cmd_tx), 539 - MediaKeyCode::MuteVolume => mute_volume(&state, sink_cmd_tx), 540 MediaKeyCode::TrackNext 541 | MediaKeyCode::TrackPrevious 542 | MediaKeyCode::Reverse ··· 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 ··· 652 } 653 654 /// Play music. 655 - fn play(graph: &mut GraphConfig, sink_cmd_tx: &UnboundedSender<SinkCommand>) { 656 graph.pause = false; 657 sink_cmd_tx 658 .send(SinkCommand::Play) 659 .expect("receiver never dropped"); 660 } 661 662 /// Pause music. 663 - fn pause(graph: &mut GraphConfig, sink_cmd_tx: &UnboundedSender<SinkCommand>) { 664 graph.pause = true; 665 sink_cmd_tx 666 .send(SinkCommand::Pause) 667 .expect("receiver never dropped"); 668 } 669 670 /// Toggle between play and pause. 671 - fn toggle_play_pause(graph: &mut GraphConfig, sink_cmd_tx: &UnboundedSender<SinkCommand>) { 672 graph.pause = !graph.pause; 673 - let sink_cmd = if graph.pause { 674 - SinkCommand::Pause 675 } else { 676 - SinkCommand::Play 677 }; 678 sink_cmd_tx.send(sink_cmd).expect("receiver never dropped"); 679 } 680 681 /// Lower the volume. 682 - fn lower_volume(state: &Arc<Mutex<State>>, sink_cmd_tx: &UnboundedSender<SinkCommand>) { 683 let mut state = state.lock().unwrap(); 684 state.volume.change_volume(-1.0); 685 sink_cmd_tx 686 .send(SinkCommand::SetVolume(state.volume.volume_ratio())) 687 .expect("receiver never dropped"); 688 } 689 690 /// Raise the volume. 691 - fn raise_volume(state: &Arc<Mutex<State>>, sink_cmd_tx: &UnboundedSender<SinkCommand>) { 692 let mut state = state.lock().unwrap(); 693 state.volume.change_volume(1.0); 694 sink_cmd_tx 695 .send(SinkCommand::SetVolume(state.volume.volume_ratio())) 696 .expect("receiver never dropped"); 697 } 698 699 /// Mute the volume. 700 - fn mute_volume(state: &Arc<Mutex<State>>, sink_cmd_tx: &UnboundedSender<SinkCommand>) { 701 let mut state = state.lock().unwrap(); 702 state.volume.toggle_mute(); 703 sink_cmd_tx 704 .send(SinkCommand::SetVolume(state.volume.volume_ratio())) 705 .expect("receiver never dropped"); ··· 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 }
··· 476 KeyCode::Up => { 477 // inverted to act as zoom 478 update_value_f(&mut self.graph.scale, 0.01, magnitude, 0.0..10.0); 479 + raise_volume(&state, self.os_media_controls.as_mut(), sink_cmd_tx); 480 } 481 KeyCode::Down => { 482 // inverted to act as zoom 483 update_value_f(&mut self.graph.scale, -0.01, magnitude, 0.0..10.0); 484 + lower_volume(&state, self.os_media_controls.as_mut(), sink_cmd_tx); 485 } 486 KeyCode::Right => update_value_i( 487 &mut self.graph.samples, ··· 498 0..self.graph.width * 2, 499 ), 500 KeyCode::Char('q') => quit = true, 501 + KeyCode::Char(' ') => toggle_play_pause( 502 + &mut self.graph, 503 + self.os_media_controls.as_mut(), 504 + sink_cmd_tx, 505 + ), 506 KeyCode::Char('s') => self.graph.scatter = !self.graph.scatter, 507 KeyCode::Char('h') => self.graph.show_ui = !self.graph.show_ui, 508 KeyCode::Char('r') => self.graph.references = !self.graph.references, 509 + KeyCode::Char('m') => { 510 + mute_volume(&state, self.os_media_controls.as_mut(), sink_cmd_tx) 511 + } 512 KeyCode::Esc => { 513 self.graph.samples = self.graph.width; 514 self.graph.scale = 1.; ··· 534 } 535 } 536 KeyCode::Media(media_key_code) => match media_key_code { 537 + MediaKeyCode::Play => play( 538 + &mut self.graph, 539 + self.os_media_controls.as_mut(), 540 + sink_cmd_tx, 541 + ), 542 + MediaKeyCode::Pause => pause( 543 + &mut self.graph, 544 + self.os_media_controls.as_mut(), 545 + sink_cmd_tx, 546 + ), 547 + MediaKeyCode::PlayPause => toggle_play_pause( 548 + &mut self.graph, 549 + self.os_media_controls.as_mut(), 550 + sink_cmd_tx, 551 + ), 552 MediaKeyCode::Stop => { 553 quit = true; 554 } 555 + MediaKeyCode::LowerVolume => { 556 + lower_volume(&state, self.os_media_controls.as_mut(), sink_cmd_tx) 557 + } 558 + MediaKeyCode::RaiseVolume => { 559 + raise_volume(&state, self.os_media_controls.as_mut(), sink_cmd_tx) 560 + } 561 + MediaKeyCode::MuteVolume => { 562 + mute_volume(&state, self.os_media_controls.as_mut(), sink_cmd_tx) 563 + } 564 MediaKeyCode::TrackNext 565 | MediaKeyCode::TrackPrevious 566 | MediaKeyCode::Reverse ··· 588 589 match event { 590 MediaControlEvent::Play => { 591 + play( 592 + &mut self.graph, 593 + self.os_media_controls.as_mut(), 594 + sink_cmd_tx, 595 + ); 596 } 597 MediaControlEvent::Pause => { 598 + pause( 599 + &mut self.graph, 600 + self.os_media_controls.as_mut(), 601 + sink_cmd_tx, 602 + ); 603 } 604 MediaControlEvent::Toggle => { 605 + toggle_play_pause( 606 + &mut self.graph, 607 + self.os_media_controls.as_mut(), 608 + sink_cmd_tx, 609 + ); 610 } 611 MediaControlEvent::Stop | MediaControlEvent::Quit => { 612 quit = true; 613 } 614 MediaControlEvent::SetVolume(volume) => { 615 + set_volume_ratio( 616 + volume as f32, 617 + state, 618 + self.os_media_controls.as_mut(), 619 + sink_cmd_tx, 620 + ); 621 } 622 MediaControlEvent::Next 623 | MediaControlEvent::Previous ··· 693 } 694 695 /// Play music. 696 + fn play( 697 + graph: &mut GraphConfig, 698 + os_media_controls: Option<&mut OsMediaControls>, 699 + sink_cmd_tx: &UnboundedSender<SinkCommand>, 700 + ) { 701 graph.pause = false; 702 + send_os_media_controls_command(os_media_controls, os_media_controls::Command::Play); 703 sink_cmd_tx 704 .send(SinkCommand::Play) 705 .expect("receiver never dropped"); 706 } 707 708 /// Pause music. 709 + fn pause( 710 + graph: &mut GraphConfig, 711 + os_media_controls: Option<&mut OsMediaControls>, 712 + sink_cmd_tx: &UnboundedSender<SinkCommand>, 713 + ) { 714 graph.pause = true; 715 + send_os_media_controls_command(os_media_controls, os_media_controls::Command::Pause); 716 sink_cmd_tx 717 .send(SinkCommand::Pause) 718 .expect("receiver never dropped"); 719 } 720 721 /// Toggle between play and pause. 722 + fn toggle_play_pause( 723 + graph: &mut GraphConfig, 724 + os_media_controls: Option<&mut OsMediaControls>, 725 + sink_cmd_tx: &UnboundedSender<SinkCommand>, 726 + ) { 727 graph.pause = !graph.pause; 728 + let (sink_cmd, os_media_controls_command) = if graph.pause { 729 + (SinkCommand::Pause, os_media_controls::Command::Pause) 730 } else { 731 + (SinkCommand::Play, os_media_controls::Command::Play) 732 }; 733 + send_os_media_controls_command(os_media_controls, os_media_controls_command); 734 sink_cmd_tx.send(sink_cmd).expect("receiver never dropped"); 735 } 736 737 /// Lower the volume. 738 + fn lower_volume( 739 + state: &Mutex<State>, 740 + os_media_controls: Option<&mut OsMediaControls>, 741 + sink_cmd_tx: &UnboundedSender<SinkCommand>, 742 + ) { 743 let mut state = state.lock().unwrap(); 744 state.volume.change_volume(-1.0); 745 + send_os_media_controls_command( 746 + os_media_controls, 747 + os_media_controls::Command::SetVolume(state.volume.volume_ratio() as f64), 748 + ); 749 sink_cmd_tx 750 .send(SinkCommand::SetVolume(state.volume.volume_ratio())) 751 .expect("receiver never dropped"); 752 } 753 754 /// Raise the volume. 755 + fn raise_volume( 756 + state: &Mutex<State>, 757 + os_media_controls: Option<&mut OsMediaControls>, 758 + sink_cmd_tx: &UnboundedSender<SinkCommand>, 759 + ) { 760 let mut state = state.lock().unwrap(); 761 state.volume.change_volume(1.0); 762 + send_os_media_controls_command( 763 + os_media_controls, 764 + os_media_controls::Command::SetVolume(state.volume.volume_ratio() as f64), 765 + ); 766 sink_cmd_tx 767 .send(SinkCommand::SetVolume(state.volume.volume_ratio())) 768 .expect("receiver never dropped"); 769 } 770 771 /// Mute the volume. 772 + fn mute_volume( 773 + state: &Mutex<State>, 774 + os_media_controls: Option<&mut OsMediaControls>, 775 + sink_cmd_tx: &UnboundedSender<SinkCommand>, 776 + ) { 777 let mut state = state.lock().unwrap(); 778 state.volume.toggle_mute(); 779 + send_os_media_controls_command( 780 + os_media_controls, 781 + os_media_controls::Command::SetVolume(state.volume.volume_ratio() as f64), 782 + ); 783 sink_cmd_tx 784 .send(SinkCommand::SetVolume(state.volume.volume_ratio())) 785 .expect("receiver never dropped"); ··· 789 fn set_volume_ratio( 790 volume_ratio: f32, 791 state: &Mutex<State>, 792 + os_media_controls: Option<&mut OsMediaControls>, 793 sink_cmd_tx: &UnboundedSender<SinkCommand>, 794 ) { 795 let mut state = state.lock().unwrap(); 796 state.volume.set_volume_ratio(volume_ratio); 797 + send_os_media_controls_command( 798 + os_media_controls, 799 + os_media_controls::Command::SetVolume(state.volume.volume_ratio() as f64), 800 + ); 801 sink_cmd_tx 802 .send(SinkCommand::SetVolume(state.volume.volume_ratio())) 803 .expect("receiver never dropped"); 804 } 805 + 806 + /// Send [`os_media_controls::Command`]. 807 + fn send_os_media_controls_command( 808 + os_media_controls: Option<&mut OsMediaControls>, 809 + command: os_media_controls::Command<'_>, 810 + ) { 811 + if let Some(os_media_controls) = os_media_controls { 812 + let _ = os_media_controls.send_to_os(command).inspect_err(|err| { 813 + eprintln!( 814 + "error: failed to send command to OS media controls due to `{}`", 815 + err 816 + ); 817 + }); 818 + } 819 + }