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 476 KeyCode::Up => { 477 477 // inverted to act as zoom 478 478 update_value_f(&mut self.graph.scale, 0.01, magnitude, 0.0..10.0); 479 - raise_volume(&state, sink_cmd_tx); 479 + raise_volume(&state, self.os_media_controls.as_mut(), sink_cmd_tx); 480 480 } 481 481 KeyCode::Down => { 482 482 // inverted to act as zoom 483 483 update_value_f(&mut self.graph.scale, -0.01, magnitude, 0.0..10.0); 484 - lower_volume(&state, sink_cmd_tx); 484 + lower_volume(&state, self.os_media_controls.as_mut(), sink_cmd_tx); 485 485 } 486 486 KeyCode::Right => update_value_i( 487 487 &mut self.graph.samples, ··· 498 498 0..self.graph.width * 2, 499 499 ), 500 500 KeyCode::Char('q') => quit = true, 501 - KeyCode::Char(' ') => toggle_play_pause(&mut self.graph, sink_cmd_tx), 501 + KeyCode::Char(' ') => toggle_play_pause( 502 + &mut self.graph, 503 + self.os_media_controls.as_mut(), 504 + sink_cmd_tx, 505 + ), 502 506 KeyCode::Char('s') => self.graph.scatter = !self.graph.scatter, 503 507 KeyCode::Char('h') => self.graph.show_ui = !self.graph.show_ui, 504 508 KeyCode::Char('r') => self.graph.references = !self.graph.references, 505 - KeyCode::Char('m') => mute_volume(&state, sink_cmd_tx), 509 + KeyCode::Char('m') => { 510 + mute_volume(&state, self.os_media_controls.as_mut(), sink_cmd_tx) 511 + } 506 512 KeyCode::Esc => { 507 513 self.graph.samples = self.graph.width; 508 514 self.graph.scale = 1.; ··· 528 534 } 529 535 } 530 536 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), 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 + ), 534 552 MediaKeyCode::Stop => { 535 553 quit = true; 536 554 } 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), 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 + } 540 564 MediaKeyCode::TrackNext 541 565 | MediaKeyCode::TrackPrevious 542 566 | MediaKeyCode::Reverse ··· 564 588 565 589 match event { 566 590 MediaControlEvent::Play => { 567 - play(&mut self.graph, sink_cmd_tx); 591 + play( 592 + &mut self.graph, 593 + self.os_media_controls.as_mut(), 594 + sink_cmd_tx, 595 + ); 568 596 } 569 597 MediaControlEvent::Pause => { 570 - pause(&mut self.graph, sink_cmd_tx); 598 + pause( 599 + &mut self.graph, 600 + self.os_media_controls.as_mut(), 601 + sink_cmd_tx, 602 + ); 571 603 } 572 604 MediaControlEvent::Toggle => { 573 - toggle_play_pause(&mut self.graph, sink_cmd_tx); 605 + toggle_play_pause( 606 + &mut self.graph, 607 + self.os_media_controls.as_mut(), 608 + sink_cmd_tx, 609 + ); 574 610 } 575 611 MediaControlEvent::Stop | MediaControlEvent::Quit => { 576 612 quit = true; 577 613 } 578 614 MediaControlEvent::SetVolume(volume) => { 579 - set_volume_ratio(volume as f32, state, sink_cmd_tx); 615 + set_volume_ratio( 616 + volume as f32, 617 + state, 618 + self.os_media_controls.as_mut(), 619 + sink_cmd_tx, 620 + ); 580 621 } 581 622 MediaControlEvent::Next 582 623 | MediaControlEvent::Previous ··· 652 693 } 653 694 654 695 /// Play music. 655 - fn play(graph: &mut GraphConfig, sink_cmd_tx: &UnboundedSender<SinkCommand>) { 696 + fn play( 697 + graph: &mut GraphConfig, 698 + os_media_controls: Option<&mut OsMediaControls>, 699 + sink_cmd_tx: &UnboundedSender<SinkCommand>, 700 + ) { 656 701 graph.pause = false; 702 + send_os_media_controls_command(os_media_controls, os_media_controls::Command::Play); 657 703 sink_cmd_tx 658 704 .send(SinkCommand::Play) 659 705 .expect("receiver never dropped"); 660 706 } 661 707 662 708 /// Pause music. 663 - fn pause(graph: &mut GraphConfig, sink_cmd_tx: &UnboundedSender<SinkCommand>) { 709 + fn pause( 710 + graph: &mut GraphConfig, 711 + os_media_controls: Option<&mut OsMediaControls>, 712 + sink_cmd_tx: &UnboundedSender<SinkCommand>, 713 + ) { 664 714 graph.pause = true; 715 + send_os_media_controls_command(os_media_controls, os_media_controls::Command::Pause); 665 716 sink_cmd_tx 666 717 .send(SinkCommand::Pause) 667 718 .expect("receiver never dropped"); 668 719 } 669 720 670 721 /// Toggle between play and pause. 671 - fn toggle_play_pause(graph: &mut GraphConfig, sink_cmd_tx: &UnboundedSender<SinkCommand>) { 722 + fn toggle_play_pause( 723 + graph: &mut GraphConfig, 724 + os_media_controls: Option<&mut OsMediaControls>, 725 + sink_cmd_tx: &UnboundedSender<SinkCommand>, 726 + ) { 672 727 graph.pause = !graph.pause; 673 - let sink_cmd = if graph.pause { 674 - SinkCommand::Pause 728 + let (sink_cmd, os_media_controls_command) = if graph.pause { 729 + (SinkCommand::Pause, os_media_controls::Command::Pause) 675 730 } else { 676 - SinkCommand::Play 731 + (SinkCommand::Play, os_media_controls::Command::Play) 677 732 }; 733 + send_os_media_controls_command(os_media_controls, os_media_controls_command); 678 734 sink_cmd_tx.send(sink_cmd).expect("receiver never dropped"); 679 735 } 680 736 681 737 /// Lower the volume. 682 - fn lower_volume(state: &Arc<Mutex<State>>, sink_cmd_tx: &UnboundedSender<SinkCommand>) { 738 + fn lower_volume( 739 + state: &Mutex<State>, 740 + os_media_controls: Option<&mut OsMediaControls>, 741 + sink_cmd_tx: &UnboundedSender<SinkCommand>, 742 + ) { 683 743 let mut state = state.lock().unwrap(); 684 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 + ); 685 749 sink_cmd_tx 686 750 .send(SinkCommand::SetVolume(state.volume.volume_ratio())) 687 751 .expect("receiver never dropped"); 688 752 } 689 753 690 754 /// Raise the volume. 691 - fn raise_volume(state: &Arc<Mutex<State>>, sink_cmd_tx: &UnboundedSender<SinkCommand>) { 755 + fn raise_volume( 756 + state: &Mutex<State>, 757 + os_media_controls: Option<&mut OsMediaControls>, 758 + sink_cmd_tx: &UnboundedSender<SinkCommand>, 759 + ) { 692 760 let mut state = state.lock().unwrap(); 693 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 + ); 694 766 sink_cmd_tx 695 767 .send(SinkCommand::SetVolume(state.volume.volume_ratio())) 696 768 .expect("receiver never dropped"); 697 769 } 698 770 699 771 /// Mute the volume. 700 - fn mute_volume(state: &Arc<Mutex<State>>, sink_cmd_tx: &UnboundedSender<SinkCommand>) { 772 + fn mute_volume( 773 + state: &Mutex<State>, 774 + os_media_controls: Option<&mut OsMediaControls>, 775 + sink_cmd_tx: &UnboundedSender<SinkCommand>, 776 + ) { 701 777 let mut state = state.lock().unwrap(); 702 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 + ); 703 783 sink_cmd_tx 704 784 .send(SinkCommand::SetVolume(state.volume.volume_ratio())) 705 785 .expect("receiver never dropped"); ··· 709 789 fn set_volume_ratio( 710 790 volume_ratio: f32, 711 791 state: &Mutex<State>, 792 + os_media_controls: Option<&mut OsMediaControls>, 712 793 sink_cmd_tx: &UnboundedSender<SinkCommand>, 713 794 ) { 714 795 let mut state = state.lock().unwrap(); 715 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 + ); 716 801 sink_cmd_tx 717 802 .send(SinkCommand::SetVolume(state.volume.volume_ratio())) 718 803 .expect("receiver never dropped"); 719 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 + }