generated from lks/eframe_template_android
Fix memory leak caused by unbounded channels not freeing memory
This commit is contained in:
parent
7abb089c04
commit
4724d23459
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
target
|
target
|
||||||
.DS_Store
|
.DS_Store
|
||||||
dist
|
dist
|
||||||
|
heaptrack.*.zst
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::mpsc::{self, Sender};
|
use std::sync::mpsc;
|
||||||
|
|
||||||
use egui::{Context, Ui};
|
use egui::{Context, Ui};
|
||||||
use egui_plot::{Line, Plot, PlotBounds, PlotPoints};
|
use egui_plot::{Line, Plot, PlotBounds, PlotPoints};
|
||||||
@ -10,25 +10,44 @@ pub enum PlotData {
|
|||||||
//F32(Vec<f32>),
|
//F32(Vec<f32>),
|
||||||
Bode32(Vec<Complex32>),
|
Bode32(Vec<Complex32>),
|
||||||
}
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DebugPlotSender {
|
||||||
|
tx: mpsc::SyncSender<(&'static str, PlotData)>,
|
||||||
|
}
|
||||||
|
impl DebugPlotSender {
|
||||||
|
pub fn send(
|
||||||
|
&self,
|
||||||
|
plot_name: &'static str,
|
||||||
|
plot_data: PlotData,
|
||||||
|
) -> Result<(), mpsc::SendError<PlotData>> {
|
||||||
|
match self.tx.try_send((plot_name, plot_data)) {
|
||||||
|
Err(mpsc::TrySendError::Full(_)) => {
|
||||||
|
log::warn!("Debug buffer is full!");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(mpsc::TrySendError::Disconnected((_, d))) => Err(mpsc::SendError(d)),
|
||||||
|
Ok(()) => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
pub struct DebugPlots {
|
pub struct DebugPlots {
|
||||||
plots: HashMap<&'static str, PlotData>,
|
plots: HashMap<&'static str, PlotData>,
|
||||||
plot_en: HashMap<&'static str, bool>,
|
plot_en: HashMap<&'static str, bool>,
|
||||||
rx: mpsc::Receiver<(&'static str, PlotData)>,
|
rx: mpsc::Receiver<(&'static str, PlotData)>,
|
||||||
tx: mpsc::Sender<(&'static str, PlotData)>,
|
tx: DebugPlotSender,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugPlots {
|
impl DebugPlots {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::sync_channel(128);
|
||||||
DebugPlots {
|
DebugPlots {
|
||||||
plots: HashMap::new(),
|
plots: HashMap::new(),
|
||||||
plot_en: HashMap::new(),
|
plot_en: HashMap::new(),
|
||||||
rx,
|
rx,
|
||||||
tx,
|
tx: DebugPlotSender { tx },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_sender(&self) -> Sender<(&'static str, PlotData)> {
|
pub fn get_sender(&self) -> DebugPlotSender {
|
||||||
self.tx.clone()
|
self.tx.clone()
|
||||||
}
|
}
|
||||||
pub fn update_plots(&mut self) {
|
pub fn update_plots(&mut self) {
|
||||||
|
|||||||
@ -1,24 +1,21 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use realfft::RealFftPlanner;
|
use realfft::RealFftPlanner;
|
||||||
use std::sync::mpsc::{self, Receiver, Sender};
|
use std::sync::mpsc::{self, Receiver, SyncSender, TrySendError};
|
||||||
|
|
||||||
use super::debug_plot::PlotData;
|
use super::debug_plot::{DebugPlotSender, PlotData};
|
||||||
|
|
||||||
pub struct Fft {
|
pub struct Fft {
|
||||||
pub tx: Sender<Vec<f32>>,
|
pub tx: SyncSender<Vec<f32>>,
|
||||||
pub output_len: usize,
|
pub output_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fft {
|
impl Fft {
|
||||||
pub fn new(
|
pub fn new(size: usize, plot_tx: DebugPlotSender) -> Result<(Self, mpsc::Receiver<Vec<u8>>)> {
|
||||||
size: usize,
|
|
||||||
plot_tx: Sender<(&'static str, PlotData)>,
|
|
||||||
) -> Result<(Self, mpsc::Receiver<Vec<u8>>)> {
|
|
||||||
let output_len = size / 2 + 1;
|
let output_len = size / 2 + 1;
|
||||||
|
|
||||||
// Create mpsc queue
|
// Create mpsc queue
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::sync_channel(10);
|
||||||
let (in_tx, in_rx): (Sender<Vec<f32>>, Receiver<Vec<f32>>) = mpsc::channel();
|
let (in_tx, in_rx): (SyncSender<Vec<f32>>, Receiver<Vec<f32>>) = mpsc::sync_channel(10);
|
||||||
|
|
||||||
// Setup fft use f32 for now
|
// Setup fft use f32 for now
|
||||||
let mut fft_planner = RealFftPlanner::<f32>::new();
|
let mut fft_planner = RealFftPlanner::<f32>::new();
|
||||||
@ -36,7 +33,7 @@ impl Fft {
|
|||||||
fft.process_with_scratch(&mut fft_in, &mut fft_out, &mut fft_scratch)
|
fft.process_with_scratch(&mut fft_in, &mut fft_out, &mut fft_scratch)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
plot_tx
|
plot_tx
|
||||||
.send(("FFT Output", PlotData::Bode32(fft_out.clone())))
|
.send("FFT Output", PlotData::Bode32(fft_out.clone()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
fft_in.clear();
|
fft_in.clear();
|
||||||
let output: Vec<u8> = fft_out
|
let output: Vec<u8> = fft_out
|
||||||
@ -48,9 +45,15 @@ impl Fft {
|
|||||||
.collect();
|
.collect();
|
||||||
assert_eq!(output_len, output.len());
|
assert_eq!(output_len, output.len());
|
||||||
plot_tx
|
plot_tx
|
||||||
.send(("FFT Processed Output", PlotData::U8(output.clone())))
|
.send("FFT Processed Output", PlotData::U8(output.clone()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
tx.send(output).unwrap();
|
match tx.try_send(output) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(TrySendError::Full(_)) => log::warn!("Waterfall buffer full."),
|
||||||
|
Err(TrySendError::Disconnected(_)) => {
|
||||||
|
panic!("The fft thread has disconnected from the waterfall!")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,9 +4,9 @@ use cpal::{
|
|||||||
traits::{DeviceTrait, HostTrait},
|
traits::{DeviceTrait, HostTrait},
|
||||||
BufferSize,
|
BufferSize,
|
||||||
};
|
};
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::{SyncSender, TrySendError};
|
||||||
|
|
||||||
use crate::app::debug_plot::PlotData;
|
use crate::app::debug_plot::DebugPlotSender;
|
||||||
|
|
||||||
pub struct Audio {
|
pub struct Audio {
|
||||||
pub stream: cpal::Stream,
|
pub stream: cpal::Stream,
|
||||||
@ -15,13 +15,19 @@ impl Audio {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
device: &cpal::Device,
|
device: &cpal::Device,
|
||||||
config: cpal::StreamConfig,
|
config: cpal::StreamConfig,
|
||||||
fft_input: Sender<Vec<f32>>,
|
fft_input: SyncSender<Vec<f32>>,
|
||||||
_plot_tx: Sender<(&'static str, PlotData)>,
|
_plot_tx: DebugPlotSender,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let stream = device.build_input_stream(
|
let stream = device.build_input_stream(
|
||||||
&config,
|
&config,
|
||||||
move |data: &[f32], _: &cpal::InputCallbackInfo| {
|
move |data: &[f32], _: &cpal::InputCallbackInfo| {
|
||||||
fft_input.send(data.to_vec()).unwrap();
|
match fft_input.try_send(data.to_vec()) {
|
||||||
|
Err(TrySendError::Disconnected(_)) => panic!(
|
||||||
|
"Error: Audio backend has lost connection to frontend! Can not continue!"
|
||||||
|
),
|
||||||
|
Err(TrySendError::Full(_)) => log::warn!("Audio Backend buffer full."),
|
||||||
|
Ok(()) => {}
|
||||||
|
};
|
||||||
},
|
},
|
||||||
move |err| log::error!("Audio Thread Error: {err}"),
|
move |err| log::error!("Audio Thread Error: {err}"),
|
||||||
None,
|
None,
|
||||||
@ -88,8 +94,8 @@ impl super::Backend for AudioBackend {
|
|||||||
|
|
||||||
fn build_device(
|
fn build_device(
|
||||||
&mut self,
|
&mut self,
|
||||||
fft_input: Sender<Vec<f32>>,
|
fft_input: SyncSender<Vec<f32>>,
|
||||||
_plot_tx: Sender<(&'static str, PlotData)>,
|
_plot_tx: DebugPlotSender,
|
||||||
) -> anyhow::Result<Box<dyn super::Device>> {
|
) -> anyhow::Result<Box<dyn super::Device>> {
|
||||||
let config = cpal::StreamConfig {
|
let config = cpal::StreamConfig {
|
||||||
channels: 1,
|
channels: 1,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::SyncSender;
|
||||||
|
|
||||||
use egui::Ui;
|
use egui::Ui;
|
||||||
|
|
||||||
use crate::app::debug_plot::PlotData;
|
use crate::app::debug_plot::DebugPlotSender;
|
||||||
mod audio;
|
mod audio;
|
||||||
pub trait Device {
|
pub trait Device {
|
||||||
fn show_settings(&mut self, ui: &mut Ui);
|
fn show_settings(&mut self, ui: &mut Ui);
|
||||||
@ -14,8 +14,8 @@ pub trait Backend {
|
|||||||
fn show_device_selection(&mut self, ui: &mut Ui);
|
fn show_device_selection(&mut self, ui: &mut Ui);
|
||||||
fn build_device(
|
fn build_device(
|
||||||
&mut self,
|
&mut self,
|
||||||
fft_input: Sender<Vec<f32>>,
|
fft_input: SyncSender<Vec<f32>>,
|
||||||
_plot_tx: Sender<(&'static str, PlotData)>,
|
_plot_tx: DebugPlotSender,
|
||||||
) -> anyhow::Result<Box<dyn Device>>;
|
) -> anyhow::Result<Box<dyn Device>>;
|
||||||
}
|
}
|
||||||
pub struct Backends(pub Vec<Box<dyn Backend>>);
|
pub struct Backends(pub Vec<Box<dyn Backend>>);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user