feat: ✨ auto detect when playing audio end
This commit is contained in:
parent
c490cc752e
commit
6dbfd57072
3 changed files with 125 additions and 23 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
use std::fs::File;
|
||||||
|
|
||||||
use iced::{
|
use iced::{
|
||||||
alignment,
|
alignment,
|
||||||
widget::{column, container, row, text::LineHeight, Container, Rule},
|
widget::{column, container, row, text::LineHeight, Container, Rule},
|
||||||
|
@ -19,6 +21,12 @@ struct Features {
|
||||||
play_audio: bool,
|
play_audio: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct AudioFile {
|
||||||
|
file: Option<File>,
|
||||||
|
decoded_to_playing_sender: Option<Sender<f32>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
None,
|
None,
|
||||||
|
@ -81,6 +89,7 @@ pub struct Streamer {
|
||||||
config: Option<Config>,
|
config: Option<Config>,
|
||||||
data_channel: DataChannel,
|
data_channel: DataChannel,
|
||||||
communication_channel: CommunicationChannel,
|
communication_channel: CommunicationChannel,
|
||||||
|
audio_file: AudioFile,
|
||||||
gui_status: GUIStatus,
|
gui_status: GUIStatus,
|
||||||
}
|
}
|
||||||
impl Default for Streamer {
|
impl Default for Streamer {
|
||||||
|
@ -105,6 +114,10 @@ impl Streamer {
|
||||||
base_to_playing_sender: channel(1).0,
|
base_to_playing_sender: channel(1).0,
|
||||||
playing_to_base_sender: channel(1).0,
|
playing_to_base_sender: channel(1).0,
|
||||||
},
|
},
|
||||||
|
audio_file: AudioFile {
|
||||||
|
file: None,
|
||||||
|
decoded_to_playing_sender: None,
|
||||||
|
},
|
||||||
gui_status: GUIStatus {
|
gui_status: GUIStatus {
|
||||||
are_we_connect: Condition::Passive,
|
are_we_connect: Condition::Passive,
|
||||||
are_we_record: Condition::Passive,
|
are_we_record: Condition::Passive,
|
||||||
|
@ -213,6 +226,24 @@ impl Streamer {
|
||||||
Event::PlayAudio => {
|
Event::PlayAudio => {
|
||||||
println!("Play Audio");
|
println!("Play Audio");
|
||||||
self.gui_status.are_we_play_audio = Condition::Loading;
|
self.gui_status.are_we_play_audio = Condition::Loading;
|
||||||
|
|
||||||
|
let file = File::open("music.mp3").unwrap();
|
||||||
|
self.audio_file.file = Some(file);
|
||||||
|
|
||||||
|
self.audio_file.decoded_to_playing_sender = Some(
|
||||||
|
channel(
|
||||||
|
self.audio_file
|
||||||
|
.file
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.metadata()
|
||||||
|
.unwrap()
|
||||||
|
.len() as usize
|
||||||
|
* 4,
|
||||||
|
)
|
||||||
|
.0,
|
||||||
|
);
|
||||||
|
|
||||||
///////TEST İÇİN YANLIŞ VERDİM UNUTMA
|
///////TEST İÇİN YANLIŞ VERDİM UNUTMA
|
||||||
let audio_stream_sender = self.data_channel.microphone_stream_sender.clone();
|
let audio_stream_sender = self.data_channel.microphone_stream_sender.clone();
|
||||||
let playing_to_base_sender =
|
let playing_to_base_sender =
|
||||||
|
@ -222,30 +253,64 @@ impl Streamer {
|
||||||
.base_to_playing_sender
|
.base_to_playing_sender
|
||||||
.subscribe();
|
.subscribe();
|
||||||
|
|
||||||
Command::perform(
|
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();
|
||||||
|
|
||||||
|
let file = self.audio_file.file.as_ref().unwrap().try_clone().unwrap();
|
||||||
|
let decoded_to_playing_sender_for_playing =
|
||||||
|
self.audio_file.decoded_to_playing_sender.clone().unwrap();
|
||||||
|
|
||||||
|
let decoded_to_playing_sender_for_is_finished =
|
||||||
|
self.audio_file.decoded_to_playing_sender.clone().unwrap();
|
||||||
|
let playing_command = Command::perform(
|
||||||
async move {
|
async move {
|
||||||
gui_utils::start_playing(
|
gui_utils::start_playing(
|
||||||
audio_stream_sender,
|
audio_stream_sender,
|
||||||
|
decoded_to_playing_sender_for_playing,
|
||||||
|
file,
|
||||||
playing_to_base_sender,
|
playing_to_base_sender,
|
||||||
base_to_playing_receiver,
|
base_to_playing_receiver,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
},
|
},
|
||||||
Message::State,
|
Message::State,
|
||||||
|
);
|
||||||
|
let is_finished_command = Command::perform(
|
||||||
|
async move {
|
||||||
|
gui_utils::is_playing_finished(
|
||||||
|
playing_to_base_receiver,
|
||||||
|
base_to_playing_sender,
|
||||||
|
decoded_to_playing_sender_for_is_finished,
|
||||||
)
|
)
|
||||||
|
.await
|
||||||
|
},
|
||||||
|
Message::State,
|
||||||
|
);
|
||||||
|
let commands = vec![playing_command, is_finished_command];
|
||||||
|
Command::batch(commands)
|
||||||
}
|
}
|
||||||
Event::StopAudio => {
|
Event::StopAudio => {
|
||||||
println!("Stop Audio");
|
println!("Stop Audio");
|
||||||
self.gui_status.are_we_play_audio = Condition::Loading;
|
self.gui_status.are_we_play_audio = Condition::Loading;
|
||||||
|
|
||||||
|
let decoded_to_playing_sender =
|
||||||
|
self.audio_file.decoded_to_playing_sender.clone().unwrap();
|
||||||
let playing_to_base_receiver = self
|
let playing_to_base_receiver = self
|
||||||
.communication_channel
|
.communication_channel
|
||||||
.playing_to_base_sender
|
.playing_to_base_sender
|
||||||
.subscribe();
|
.subscribe();
|
||||||
let base_to_playing_sender =
|
let base_to_playing_sender =
|
||||||
self.communication_channel.base_to_playing_sender.clone();
|
self.communication_channel.base_to_playing_sender.clone();
|
||||||
|
|
||||||
Command::perform(
|
Command::perform(
|
||||||
async move {
|
async move {
|
||||||
gui_utils::stop_playing(
|
gui_utils::stop_playing(
|
||||||
|
decoded_to_playing_sender,
|
||||||
playing_to_base_receiver,
|
playing_to_base_receiver,
|
||||||
base_to_playing_sender,
|
base_to_playing_sender,
|
||||||
)
|
)
|
||||||
|
@ -431,6 +496,7 @@ impl Streamer {
|
||||||
base_to_streaming_sender: Sender<bool>,
|
base_to_streaming_sender: Sender<bool>,
|
||||||
recording_to_base_receiver: Receiver<bool>,
|
recording_to_base_receiver: Receiver<bool>,
|
||||||
base_to_recording_sender: Sender<bool>,
|
base_to_recording_sender: Sender<bool>,
|
||||||
|
decoded_to_playing_sender: Sender<f32>,
|
||||||
playing_to_base_receiver: Receiver<bool>,
|
playing_to_base_receiver: Receiver<bool>,
|
||||||
base_to_playing_sender: Sender<bool>,
|
base_to_playing_sender: Sender<bool>,
|
||||||
features_in_need: Features,
|
features_in_need: Features,
|
||||||
|
@ -447,7 +513,12 @@ impl Streamer {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
if features_in_need.play_audio {
|
if features_in_need.play_audio {
|
||||||
gui_utils::stop_playing(playing_to_base_receiver, base_to_playing_sender).await;
|
gui_utils::stop_playing(
|
||||||
|
decoded_to_playing_sender,
|
||||||
|
playing_to_base_receiver,
|
||||||
|
base_to_playing_sender,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
Event::CloseWindow(window_id)
|
Event::CloseWindow(window_id)
|
||||||
},
|
},
|
||||||
|
@ -482,6 +553,7 @@ impl Streamer {
|
||||||
.subscribe();
|
.subscribe();
|
||||||
let base_to_recording_sender = self.communication_channel.base_to_recording_sender.clone();
|
let base_to_recording_sender = self.communication_channel.base_to_recording_sender.clone();
|
||||||
|
|
||||||
|
let decoded_to_playing_sender = self.audio_file.decoded_to_playing_sender.clone().unwrap();
|
||||||
let playing_to_base_receiver = self
|
let playing_to_base_receiver = self
|
||||||
.communication_channel
|
.communication_channel
|
||||||
.playing_to_base_sender
|
.playing_to_base_sender
|
||||||
|
@ -493,6 +565,7 @@ impl Streamer {
|
||||||
base_to_streaming_sender,
|
base_to_streaming_sender,
|
||||||
recording_to_base_receiver,
|
recording_to_base_receiver,
|
||||||
base_to_recording_sender,
|
base_to_recording_sender,
|
||||||
|
decoded_to_playing_sender,
|
||||||
playing_to_base_receiver,
|
playing_to_base_receiver,
|
||||||
base_to_playing_sender,
|
base_to_playing_sender,
|
||||||
features_in_need,
|
features_in_need,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::{fs::File, time::Duration};
|
||||||
|
|
||||||
use tokio::sync::broadcast::{Receiver, Sender};
|
use tokio::sync::broadcast::{Receiver, Sender};
|
||||||
|
|
||||||
use crate::{gui::State, playing, recording, streaming, Config};
|
use crate::{gui::State, playing, recording, streaming, Config};
|
||||||
|
@ -75,12 +77,16 @@ pub async fn stop_recording(
|
||||||
|
|
||||||
pub async fn start_playing(
|
pub async fn start_playing(
|
||||||
audio_stream_sender: Sender<f32>,
|
audio_stream_sender: Sender<f32>,
|
||||||
|
decoded_to_playing_sender: Sender<f32>,
|
||||||
|
file: File,
|
||||||
playing_to_base_sender: Sender<bool>,
|
playing_to_base_sender: Sender<bool>,
|
||||||
base_to_playing_receiver: Receiver<bool>,
|
base_to_playing_receiver: Receiver<bool>,
|
||||||
) -> State {
|
) -> State {
|
||||||
let mut playing_to_base_receiver = playing_to_base_sender.subscribe();
|
let mut playing_to_base_receiver = playing_to_base_sender.subscribe();
|
||||||
tokio::spawn(playing::play(
|
tokio::spawn(playing::play(
|
||||||
audio_stream_sender,
|
audio_stream_sender,
|
||||||
|
file,
|
||||||
|
decoded_to_playing_sender,
|
||||||
playing_to_base_sender,
|
playing_to_base_sender,
|
||||||
base_to_playing_receiver,
|
base_to_playing_receiver,
|
||||||
));
|
));
|
||||||
|
@ -94,15 +100,45 @@ pub async fn start_playing(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn stop_playing(
|
pub async fn stop_playing(
|
||||||
|
decoded_to_playing_sender: Sender<f32>,
|
||||||
mut playing_to_base_receiver: Receiver<bool>,
|
mut playing_to_base_receiver: Receiver<bool>,
|
||||||
base_to_playing_sender: Sender<bool>,
|
base_to_playing_sender: Sender<bool>,
|
||||||
) -> State {
|
) -> State {
|
||||||
|
let thread_solver_task = tokio::spawn(thread_solver(decoded_to_playing_sender));
|
||||||
let _ = base_to_playing_sender.send(false);
|
let _ = base_to_playing_sender.send(false);
|
||||||
match playing_to_base_receiver.recv().await {
|
match playing_to_base_receiver.recv().await {
|
||||||
Ok(_) => State::StopAudio,
|
Ok(_) => {
|
||||||
|
thread_solver_task.abort();
|
||||||
|
State::StopAudio
|
||||||
|
}
|
||||||
Err(err_val) => {
|
Err(err_val) => {
|
||||||
|
thread_solver_task.abort();
|
||||||
eprintln!("Error: Communication | {}", err_val);
|
eprintln!("Error: Communication | {}", err_val);
|
||||||
State::PlayingAudio
|
State::PlayingAudio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn is_playing_finished(
|
||||||
|
mut playing_to_base_receiver: Receiver<bool>,
|
||||||
|
base_to_playing_sender: Sender<bool>,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
stop_playing(
|
||||||
|
decoded_to_playing_sender,
|
||||||
|
playing_to_base_receiver,
|
||||||
|
base_to_playing_sender,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
State::StopAudio
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn thread_solver(decoded_to_playing_sender: Sender<f32>) {
|
||||||
|
loop {
|
||||||
|
let _ = decoded_to_playing_sender.send(0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||||
use ringbuf::HeapRb;
|
|
||||||
use rubato::{
|
use rubato::{
|
||||||
Resampler, SincFixedIn, SincInterpolationParameters, SincInterpolationType, WindowFunction,
|
Resampler, SincFixedIn, SincInterpolationParameters, SincInterpolationType, WindowFunction,
|
||||||
};
|
};
|
||||||
|
@ -20,6 +19,8 @@ use tokio::{
|
||||||
|
|
||||||
pub async fn play(
|
pub async fn play(
|
||||||
audio_stream_sender: Sender<f32>,
|
audio_stream_sender: Sender<f32>,
|
||||||
|
file: File,
|
||||||
|
decoded_to_playing_sender: Sender<f32>,
|
||||||
playing_to_base_sender: Sender<bool>,
|
playing_to_base_sender: Sender<bool>,
|
||||||
mut base_to_playing_receiver: Receiver<bool>,
|
mut base_to_playing_receiver: Receiver<bool>,
|
||||||
) {
|
) {
|
||||||
|
@ -31,28 +32,23 @@ pub async fn play(
|
||||||
let output_device_sample_rate = output_device_config.sample_rate.0;
|
let output_device_sample_rate = output_device_config.sample_rate.0;
|
||||||
|
|
||||||
let (mut audio_resampled_left, mut audio_resampled_right) =
|
let (mut audio_resampled_left, mut audio_resampled_right) =
|
||||||
decode_audio(output_device_sample_rate);
|
decode_audio(output_device_sample_rate, file);
|
||||||
|
|
||||||
let total_ring_len = audio_resampled_left.len() + audio_resampled_right.len();
|
|
||||||
let (mut producer, mut receiver) = HeapRb::<f32>::new(total_ring_len).split();
|
|
||||||
|
|
||||||
|
let mut decoded_to_playing_receiver = decoded_to_playing_sender.subscribe();
|
||||||
for _ in 0..audio_resampled_left.clone().len() {
|
for _ in 0..audio_resampled_left.clone().len() {
|
||||||
producer
|
decoded_to_playing_sender
|
||||||
.push(audio_resampled_left.pop().unwrap() as f32)
|
.send(audio_resampled_left.pop().unwrap() as f32)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
producer
|
decoded_to_playing_sender
|
||||||
.push(audio_resampled_right.pop().unwrap() as f32)
|
.send(audio_resampled_right.pop().unwrap() as f32)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let output_data_fn = move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
|
let output_data_fn = move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
|
||||||
for sample in data {
|
for sample in data {
|
||||||
let single = match receiver.pop() {
|
let single = match decoded_to_playing_receiver.blocking_recv() {
|
||||||
Some(single) => {
|
Ok(single) => single,
|
||||||
//println!("{}", single);
|
Err(_) => 0.0,
|
||||||
single
|
|
||||||
}
|
|
||||||
None => 0.0,
|
|
||||||
};
|
};
|
||||||
if audio_stream_sender.receiver_count() > 0 {
|
if audio_stream_sender.receiver_count() > 0 {
|
||||||
let _ = audio_stream_sender.send(single);
|
let _ = audio_stream_sender.send(single);
|
||||||
|
@ -71,7 +67,6 @@ pub async fn play(
|
||||||
task::block_in_place(|| {
|
task::block_in_place(|| {
|
||||||
let _ = base_to_playing_receiver.blocking_recv();
|
let _ = base_to_playing_receiver.blocking_recv();
|
||||||
});
|
});
|
||||||
output_stream.pause().unwrap();
|
|
||||||
drop(output_stream);
|
drop(output_stream);
|
||||||
tokio::spawn(let_the_base_know(playing_to_base_sender));
|
tokio::spawn(let_the_base_know(playing_to_base_sender));
|
||||||
}
|
}
|
||||||
|
@ -82,9 +77,7 @@ fn err_fn(err: cpal::StreamError) {
|
||||||
async fn let_the_base_know(playing_to_base_sender: Sender<bool>) {
|
async fn let_the_base_know(playing_to_base_sender: Sender<bool>) {
|
||||||
let _ = playing_to_base_sender.send(true);
|
let _ = playing_to_base_sender.send(true);
|
||||||
}
|
}
|
||||||
fn decode_audio(output_device_sample_rate: u32) -> (Vec<f64>, Vec<f64>) {
|
fn decode_audio(output_device_sample_rate: u32, file: File) -> (Vec<f64>, Vec<f64>) {
|
||||||
let file = File::open("music.mp3").unwrap();
|
|
||||||
|
|
||||||
let mut audio_decoded_left = vec![];
|
let mut audio_decoded_left = vec![];
|
||||||
let mut audio_decoded_right = vec![];
|
let mut audio_decoded_right = vec![];
|
||||||
let media_source_stream = MediaSourceStream::new(Box::new(file), Default::default());
|
let media_source_stream = MediaSourceStream::new(Box::new(file), Default::default());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue