fix: 🐛 unable to stop if paused at least once
This commit is contained in:
parent
14c84d2f40
commit
afa74f8177
3 changed files with 303 additions and 50 deletions
|
@ -14,6 +14,13 @@ use crate::{
|
|||
Config, BUFFER_LENGTH,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Player {
|
||||
Play,
|
||||
Pause,
|
||||
Stop,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Features {
|
||||
stream: bool,
|
||||
|
@ -36,6 +43,8 @@ pub enum Event {
|
|||
StopRecord,
|
||||
PlayAudio,
|
||||
StopAudio,
|
||||
PauseAudio,
|
||||
ContinueAudio,
|
||||
LoadConfig(Config),
|
||||
IcedEvent(iced::Event),
|
||||
CloseWindow(window::Id),
|
||||
|
@ -50,6 +59,8 @@ pub enum State {
|
|||
StopRecording,
|
||||
PlayingAudio,
|
||||
StopAudio,
|
||||
PausedAudio,
|
||||
ContinuedAudio,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -68,8 +79,8 @@ struct CommunicationChannel {
|
|||
streaming_to_base_sender: Sender<bool>,
|
||||
base_to_recording_sender: Sender<bool>,
|
||||
recording_to_base_sender: Sender<bool>,
|
||||
base_to_playing_sender: Sender<bool>,
|
||||
playing_to_base_sender: Sender<bool>,
|
||||
base_to_playing_sender: Sender<Player>,
|
||||
playing_to_base_sender: Sender<Player>,
|
||||
}
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum Condition {
|
||||
|
@ -83,6 +94,7 @@ struct GUIStatus {
|
|||
are_we_connect: Condition,
|
||||
are_we_record: Condition,
|
||||
are_we_play_audio: Condition,
|
||||
are_we_paused_audio: Condition,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct Streamer {
|
||||
|
@ -122,6 +134,7 @@ impl Streamer {
|
|||
are_we_connect: Condition::Passive,
|
||||
are_we_record: Condition::Passive,
|
||||
are_we_play_audio: Condition::Passive,
|
||||
are_we_paused_audio: Condition::Passive,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -239,7 +252,7 @@ impl Streamer {
|
|||
.metadata()
|
||||
.unwrap()
|
||||
.len() as usize
|
||||
* 1,
|
||||
* 4,
|
||||
)
|
||||
.0,
|
||||
);
|
||||
|
@ -253,7 +266,12 @@ impl Streamer {
|
|||
.base_to_playing_sender
|
||||
.subscribe();
|
||||
|
||||
let playing_to_base_receiver = self
|
||||
let playing_to_base_receiver_is_audio_finished = self
|
||||
.communication_channel
|
||||
.playing_to_base_sender
|
||||
.subscribe();
|
||||
|
||||
let playing_to_base_receiver_is_audio_stopped = self
|
||||
.communication_channel
|
||||
.playing_to_base_sender
|
||||
.subscribe();
|
||||
|
@ -283,7 +301,8 @@ impl Streamer {
|
|||
let is_finished_command = Command::perform(
|
||||
async move {
|
||||
gui_utils::is_playing_finished(
|
||||
playing_to_base_receiver,
|
||||
playing_to_base_receiver_is_audio_finished,
|
||||
playing_to_base_receiver_is_audio_stopped,
|
||||
base_to_playing_sender,
|
||||
decoded_to_playing_sender_for_is_finished,
|
||||
)
|
||||
|
@ -316,6 +335,50 @@ impl Streamer {
|
|||
Message::State,
|
||||
)
|
||||
}
|
||||
Event::PauseAudio => {
|
||||
println!("Pause Audio");
|
||||
self.gui_status.are_we_paused_audio = Condition::Loading;
|
||||
|
||||
let playing_to_base_receiver = self
|
||||
.communication_channel
|
||||
.playing_to_base_sender
|
||||
.subscribe();
|
||||
let base_to_playing_sender =
|
||||
self.communication_channel.base_to_playing_sender.clone();
|
||||
|
||||
Command::perform(
|
||||
async move {
|
||||
gui_utils::pause_playing(
|
||||
playing_to_base_receiver,
|
||||
base_to_playing_sender,
|
||||
)
|
||||
.await
|
||||
},
|
||||
Message::State,
|
||||
)
|
||||
}
|
||||
Event::ContinueAudio => {
|
||||
println!("Continue Audio");
|
||||
self.gui_status.are_we_paused_audio = Condition::Loading;
|
||||
|
||||
let playing_to_base_receiver = self
|
||||
.communication_channel
|
||||
.playing_to_base_sender
|
||||
.subscribe();
|
||||
let base_to_playing_sender =
|
||||
self.communication_channel.base_to_playing_sender.clone();
|
||||
|
||||
Command::perform(
|
||||
async move {
|
||||
gui_utils::continue_playing(
|
||||
playing_to_base_receiver,
|
||||
base_to_playing_sender,
|
||||
)
|
||||
.await
|
||||
},
|
||||
Message::State,
|
||||
)
|
||||
}
|
||||
Event::LoadConfig(config) => {
|
||||
self.config = Some(config);
|
||||
Command::none()
|
||||
|
@ -355,22 +418,31 @@ impl Streamer {
|
|||
}
|
||||
State::PlayingAudio => {
|
||||
self.gui_status.are_we_play_audio = Condition::Active;
|
||||
self.gui_status.are_we_paused_audio = Condition::Passive;
|
||||
Command::none()
|
||||
}
|
||||
State::StopAudio => {
|
||||
self.gui_status.are_we_play_audio = Condition::Passive;
|
||||
Command::none()
|
||||
}
|
||||
State::PausedAudio => {
|
||||
self.gui_status.are_we_paused_audio = Condition::Active;
|
||||
Command::none()
|
||||
}
|
||||
State::ContinuedAudio => {
|
||||
self.gui_status.are_we_paused_audio = Condition::Passive;
|
||||
Command::none()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn view(&self) -> Container<Message> {
|
||||
//let color_red = Color::from_rgb8(255, 0, 0);
|
||||
let color_green = Color::from_rgb8(0, 255, 0);
|
||||
//let color_blue = Color::from_rgb8(0, 0, 255);
|
||||
let color_blue = Color::from_rgb8(0, 0, 255);
|
||||
let color_yellow = Color::from_rgb8(255, 255, 0);
|
||||
//let color_white = Color::from_rgb8(255, 255, 255);
|
||||
//let color_grey = Color::from_rgb8(128, 128, 128);
|
||||
let color_grey = Color::from_rgb8(128, 128, 128);
|
||||
//let color_black = Color::from_rgb8(0, 0, 0);
|
||||
let color_pink = Color::from_rgb8(255, 150, 150);
|
||||
|
||||
|
@ -381,10 +453,12 @@ impl Streamer {
|
|||
let connection_text = text_centered("Connection");
|
||||
let recording_text = text_centered("Microphone");
|
||||
let play_audio_text = text_centered("Play Audio");
|
||||
let pause_audio_text = text_centered("Pause Audio");
|
||||
|
||||
let connection_status_text;
|
||||
let recording_status_text;
|
||||
let play_audio_status_text;
|
||||
let paused_audio_status_text;
|
||||
|
||||
let connect_button = match self.gui_status.are_we_connect {
|
||||
Condition::Active => {
|
||||
|
@ -431,6 +505,28 @@ impl Streamer {
|
|||
}
|
||||
};
|
||||
|
||||
let pause_audio_button = if let Condition::Active = self.gui_status.are_we_play_audio {
|
||||
match self.gui_status.are_we_paused_audio {
|
||||
Condition::Active => {
|
||||
paused_audio_status_text = text_centered("Paused").color(color_blue);
|
||||
button_with_centered_text("Continue Audio")
|
||||
.on_press(Message::Event(Event::ContinueAudio))
|
||||
}
|
||||
Condition::Loading => {
|
||||
paused_audio_status_text = text_centered("Loading").color(color_yellow);
|
||||
button_with_centered_text("Processing")
|
||||
}
|
||||
Condition::Passive => {
|
||||
paused_audio_status_text = text_centered("Playing").color(color_yellow);
|
||||
button_with_centered_text("Pause Audio")
|
||||
.on_press(Message::Event(Event::PauseAudio))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
paused_audio_status_text = text_centered("Waiting").color(color_grey);
|
||||
button_with_centered_text("No Purpose")
|
||||
};
|
||||
|
||||
let header_content = row![header].width(350).height(50);
|
||||
let text_content = row![
|
||||
connection_text,
|
||||
|
@ -438,6 +534,8 @@ impl Streamer {
|
|||
recording_text,
|
||||
Rule::vertical(1),
|
||||
play_audio_text,
|
||||
Rule::vertical(1),
|
||||
pause_audio_text,
|
||||
]
|
||||
.spacing(5)
|
||||
.width(350)
|
||||
|
@ -448,15 +546,22 @@ impl Streamer {
|
|||
Rule::vertical(1),
|
||||
recording_status_text,
|
||||
Rule::vertical(1),
|
||||
play_audio_status_text
|
||||
play_audio_status_text,
|
||||
Rule::vertical(1),
|
||||
paused_audio_status_text,
|
||||
]
|
||||
.spacing(5)
|
||||
.width(350)
|
||||
.height(35);
|
||||
let button_content = row![
|
||||
connect_button,
|
||||
record_button,
|
||||
play_audio_button,
|
||||
pause_audio_button
|
||||
]
|
||||
.spacing(5)
|
||||
.width(350)
|
||||
.height(35);
|
||||
let button_content = row![connect_button, record_button, play_audio_button]
|
||||
.spacing(5)
|
||||
.width(350)
|
||||
.height(35);
|
||||
|
||||
let content = column![
|
||||
header_content,
|
||||
|
@ -493,8 +598,8 @@ impl Streamer {
|
|||
base_to_streaming_sender: Sender<bool>,
|
||||
recording_to_base_receiver: Receiver<bool>,
|
||||
base_to_recording_sender: Sender<bool>,
|
||||
playing_to_base_receiver: Receiver<bool>,
|
||||
base_to_playing_sender: Sender<bool>,
|
||||
playing_to_base_receiver: Receiver<Player>,
|
||||
base_to_playing_sender: Sender<Player>,
|
||||
features_in_need: Features,
|
||||
window_id: window::Id,
|
||||
) -> Command<Message> {
|
||||
|
|
|
@ -2,7 +2,10 @@ use std::{fs::File, time::Duration};
|
|||
|
||||
use tokio::sync::broadcast::{Receiver, Sender};
|
||||
|
||||
use crate::{gui::State, playing, recording, streaming, Config};
|
||||
use crate::{
|
||||
gui::{Player, State},
|
||||
playing, recording, streaming, Config,
|
||||
};
|
||||
|
||||
pub async fn connect(
|
||||
sound_stream_receiver: Receiver<f32>,
|
||||
|
@ -20,7 +23,7 @@ pub async fn connect(
|
|||
match streaming_to_base_receiver.recv().await {
|
||||
Ok(_) => State::Connected,
|
||||
Err(err_val) => {
|
||||
eprintln!("Error: Communication | {}", err_val);
|
||||
eprintln!("Error: Communication | Streaming to Base | {}", err_val);
|
||||
State::Disconnected
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +37,7 @@ pub async fn disconnect(
|
|||
match streaming_to_base_receiver.recv().await {
|
||||
Ok(_) => State::Disconnected,
|
||||
Err(err_val) => {
|
||||
eprintln!("Error: Communication | {}", err_val);
|
||||
eprintln!("Error: Communication | Streaming to Base | {}", err_val);
|
||||
State::Connected
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +58,7 @@ pub async fn start_recording(
|
|||
match recording_to_base_receiver.recv().await {
|
||||
Ok(_) => State::Recording,
|
||||
Err(err_val) => {
|
||||
eprintln!("Error: Communication | Streaming | {}", err_val);
|
||||
eprintln!("Error: Communication | Recording to Base | {}", err_val);
|
||||
State::StopRecording
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +72,7 @@ pub async fn stop_recording(
|
|||
match recording_to_base_receiver.recv().await {
|
||||
Ok(_) => State::StopRecording,
|
||||
Err(err_val) => {
|
||||
eprintln!("Error: Communication | {}", err_val);
|
||||
eprintln!("Error: Communication | Recording to Base | {}", err_val);
|
||||
State::Recording
|
||||
}
|
||||
}
|
||||
|
@ -79,8 +82,8 @@ pub async fn start_playing(
|
|||
audio_stream_sender: Sender<f32>,
|
||||
decoded_to_playing_sender: Sender<f32>,
|
||||
file: File,
|
||||
playing_to_base_sender: Sender<bool>,
|
||||
base_to_playing_receiver: Receiver<bool>,
|
||||
playing_to_base_sender: Sender<Player>,
|
||||
base_to_playing_receiver: Receiver<Player>,
|
||||
) -> State {
|
||||
let mut playing_to_base_receiver = playing_to_base_sender.subscribe();
|
||||
tokio::spawn(playing::play(
|
||||
|
@ -90,43 +93,161 @@ pub async fn start_playing(
|
|||
playing_to_base_sender,
|
||||
base_to_playing_receiver,
|
||||
));
|
||||
match playing_to_base_receiver.recv().await {
|
||||
Ok(_) => State::PlayingAudio,
|
||||
let answer = playing_to_base_receiver.recv().await;
|
||||
drop(playing_to_base_receiver);
|
||||
match answer {
|
||||
Ok(state) => match state {
|
||||
Player::Play => State::PlayingAudio,
|
||||
Player::Pause => State::PausedAudio,
|
||||
Player::Stop => State::StopAudio,
|
||||
},
|
||||
Err(err_val) => {
|
||||
eprint!("Error: Communication | Playing | {}", err_val);
|
||||
eprint!(
|
||||
"Error: Communication | Playing to Base | Recv | Start | {}",
|
||||
err_val
|
||||
);
|
||||
State::StopAudio
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn stop_playing(
|
||||
mut playing_to_base_receiver: Receiver<bool>,
|
||||
base_to_playing_sender: Sender<bool>,
|
||||
mut playing_to_base_receiver: Receiver<Player>,
|
||||
base_to_playing_sender: Sender<Player>,
|
||||
) -> State {
|
||||
//let thread_solver_task = tokio::spawn(thread_solver(decoded_to_playing_sender));
|
||||
let _ = base_to_playing_sender.send(false);
|
||||
match playing_to_base_receiver.recv().await {
|
||||
Ok(_) => {
|
||||
//thread_solver_task.abort();
|
||||
State::StopAudio
|
||||
}
|
||||
match base_to_playing_sender.send(Player::Stop) {
|
||||
Ok(_) => {}
|
||||
Err(err_val) => {
|
||||
//thread_solver_task.abort();
|
||||
eprintln!("Error: Communication | {}", err_val);
|
||||
eprintln!(
|
||||
"Error: Communication | Base to Playing | Stop | Send | {}",
|
||||
err_val
|
||||
);
|
||||
}
|
||||
}
|
||||
drop(base_to_playing_sender);
|
||||
let answer = playing_to_base_receiver.recv().await;
|
||||
drop(playing_to_base_receiver);
|
||||
match answer {
|
||||
Ok(state) => match state {
|
||||
Player::Play => State::PlayingAudio,
|
||||
Player::Pause => State::PausedAudio,
|
||||
Player::Stop => State::StopAudio,
|
||||
},
|
||||
Err(err_val) => {
|
||||
eprintln!(
|
||||
"Error: Communication | Playing to Base | Recv | Stop | {}",
|
||||
err_val
|
||||
);
|
||||
State::PlayingAudio
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn is_playing_finished(
|
||||
mut playing_to_base_receiver: Receiver<bool>,
|
||||
base_to_playing_sender: Sender<bool>,
|
||||
mut playing_to_base_receiver_is_audio_finished: Receiver<Player>,
|
||||
mut playing_to_base_receiver_is_audio_stopped: Receiver<Player>,
|
||||
base_to_playing_sender: Sender<Player>,
|
||||
decoded_to_playing_sender: Sender<f32>,
|
||||
) -> State {
|
||||
let _ = playing_to_base_receiver.recv().await;
|
||||
while decoded_to_playing_sender.len() > 0 {
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
tokio::select! {
|
||||
is_audio_finished = tokio::spawn(async move {
|
||||
match playing_to_base_receiver_is_audio_finished.recv().await {
|
||||
Ok(state) => match state {
|
||||
Player::Play => {
|
||||
while !decoded_to_playing_sender.is_empty() {
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
stop_playing(playing_to_base_receiver_is_audio_finished, base_to_playing_sender).await
|
||||
}
|
||||
Player::Pause => State::PlayingAudio,
|
||||
Player::Stop => State::StopAudio,
|
||||
},
|
||||
Err(err_val) => {
|
||||
eprintln!("Error: Communication | Playing to Base | Recv | Is Finish | {}", err_val);
|
||||
State::PlayingAudio
|
||||
}
|
||||
}
|
||||
}) => is_audio_finished.unwrap(),
|
||||
is_audio_stopped = tokio::spawn(async move {
|
||||
loop {
|
||||
match playing_to_base_receiver_is_audio_stopped.recv().await {
|
||||
Ok(state) => if let Player::Stop = state {
|
||||
return State::StopAudio;
|
||||
},
|
||||
Err(err_val) => {
|
||||
eprintln!(
|
||||
"Error: Communication | Playing to Base | Recv | Is Stop | {}",
|
||||
err_val
|
||||
);
|
||||
return State::PlayingAudio;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
=>is_audio_stopped.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn pause_playing(
|
||||
mut playing_to_base_receiver: Receiver<Player>,
|
||||
base_to_playing_sender: Sender<Player>,
|
||||
) -> State {
|
||||
match base_to_playing_sender.send(Player::Pause) {
|
||||
Ok(_) => {}
|
||||
Err(err_val) => {
|
||||
eprintln!(
|
||||
"Error: Communication | Base to Playing | Pause | Send | {}",
|
||||
err_val
|
||||
);
|
||||
}
|
||||
}
|
||||
drop(base_to_playing_sender);
|
||||
let answer = playing_to_base_receiver.recv().await;
|
||||
drop(playing_to_base_receiver);
|
||||
match answer {
|
||||
Ok(state) => match state {
|
||||
Player::Play => State::PlayingAudio,
|
||||
Player::Pause => State::PausedAudio,
|
||||
Player::Stop => State::StopAudio,
|
||||
},
|
||||
Err(err_val) => {
|
||||
eprintln!(
|
||||
"Error: Communication | Playing to Base | Recv | Pause | {}",
|
||||
err_val
|
||||
);
|
||||
State::PlayingAudio
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn continue_playing(
|
||||
mut playing_to_base_receiver: Receiver<Player>,
|
||||
base_to_playing_sender: Sender<Player>,
|
||||
) -> State {
|
||||
match base_to_playing_sender.send(Player::Play) {
|
||||
Ok(_) => {}
|
||||
Err(err_val) => {
|
||||
eprintln!(
|
||||
"Error: Communication | Base to Playing | Send | Continue | {}",
|
||||
err_val
|
||||
);
|
||||
}
|
||||
}
|
||||
drop(base_to_playing_sender);
|
||||
let answer = playing_to_base_receiver.recv().await;
|
||||
drop(playing_to_base_receiver);
|
||||
match answer {
|
||||
Ok(state) => match state {
|
||||
Player::Play => State::PlayingAudio,
|
||||
Player::Pause => State::PausedAudio,
|
||||
Player::Stop => State::StopAudio,
|
||||
},
|
||||
Err(err_val) => {
|
||||
eprintln!(
|
||||
"Error: Communication | Playing to Base | Continue | {}",
|
||||
err_val
|
||||
);
|
||||
State::PausedAudio
|
||||
}
|
||||
}
|
||||
stop_playing(playing_to_base_receiver, base_to_playing_sender).await;
|
||||
State::StopAudio
|
||||
}
|
||||
|
|
|
@ -17,12 +17,14 @@ use tokio::{
|
|||
task,
|
||||
};
|
||||
|
||||
use crate::gui::Player;
|
||||
|
||||
pub async fn play(
|
||||
audio_stream_sender: Sender<f32>,
|
||||
file: File,
|
||||
decoded_to_playing_sender: Sender<f32>,
|
||||
playing_to_base_sender: Sender<bool>,
|
||||
mut base_to_playing_receiver: Receiver<bool>,
|
||||
playing_to_base_sender: Sender<Player>,
|
||||
mut base_to_playing_receiver: Receiver<Player>,
|
||||
) {
|
||||
let host = cpal::default_host();
|
||||
let output_device = host.default_output_device().unwrap();
|
||||
|
@ -64,20 +66,45 @@ pub async fn play(
|
|||
.unwrap();
|
||||
|
||||
output_stream.play().unwrap();
|
||||
tokio::spawn(let_the_base_know(playing_to_base_sender.clone()));
|
||||
tokio::spawn(let_the_base_know(
|
||||
playing_to_base_sender.clone(),
|
||||
Player::Play,
|
||||
));
|
||||
|
||||
task::block_in_place(|| {
|
||||
let _ = base_to_playing_receiver.blocking_recv();
|
||||
task::block_in_place(|| loop {
|
||||
match base_to_playing_receiver.blocking_recv() {
|
||||
Ok(state) => match state {
|
||||
Player::Play => {
|
||||
output_stream.play().unwrap();
|
||||
tokio::spawn(let_the_base_know(
|
||||
playing_to_base_sender.clone(),
|
||||
Player::Play,
|
||||
));
|
||||
}
|
||||
Player::Pause => match output_stream.pause() {
|
||||
Ok(_) => {
|
||||
tokio::spawn(let_the_base_know(
|
||||
playing_to_base_sender.clone(),
|
||||
Player::Pause,
|
||||
));
|
||||
}
|
||||
//todo when pause error, do software level stop
|
||||
Err(_) => todo!(),
|
||||
},
|
||||
Player::Stop => break,
|
||||
},
|
||||
Err(_) => break,
|
||||
}
|
||||
});
|
||||
drop(output_stream);
|
||||
tokio::spawn(let_the_base_know(playing_to_base_sender));
|
||||
tokio::spawn(let_the_base_know(playing_to_base_sender, Player::Stop));
|
||||
}
|
||||
|
||||
fn err_fn(err: cpal::StreamError) {
|
||||
eprintln!("Something Happened: {}", err);
|
||||
}
|
||||
async fn let_the_base_know(playing_to_base_sender: Sender<bool>) {
|
||||
let _ = playing_to_base_sender.send(true);
|
||||
async fn let_the_base_know(playing_to_base_sender: Sender<Player>, action: Player) {
|
||||
let _ = playing_to_base_sender.send(action);
|
||||
}
|
||||
fn decode_audio(output_device_sample_rate: u32, file: File) -> (Vec<f64>, Vec<f64>) {
|
||||
let mut audio_decoded_left = vec![];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue