diff --git a/utils/tracers/src/buffer_lateness/imp.rs b/utils/tracers/src/buffer_lateness/imp.rs index 7196f566..d7b17bba 100644 --- a/utils/tracers/src/buffer_lateness/imp.rs +++ b/utils/tracers/src/buffer_lateness/imp.rs @@ -44,7 +44,7 @@ * * By default this is not set. */ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::path::PathBuf; use std::str::FromStr; use std::sync::{Arc, Mutex}; @@ -139,6 +139,7 @@ struct State { pads: HashMap, log: Vec, settings: Settings, + logs_written: HashSet, } struct Pad { @@ -163,6 +164,51 @@ pub struct BufferLateness { state: Mutex, } +impl BufferLateness { + fn write_log(&self, file_path: Option<&str>) { + use std::io::prelude::*; + + let mut state = self.state.lock().unwrap(); + let path = file_path.map_or_else(|| state.settings.file.clone(), PathBuf::from); + let first_write = state.logs_written.contains(&path); + + let mut file = match std::fs::OpenOptions::new() + .append(!first_write) + .create(true) + .open(path.clone()) + { + Ok(file) => file, + Err(err) => { + gst::error!(CAT, imp = self, "Failed to create file: {err}"); + return; + } + }; + + let log = std::mem::take(&mut state.log); + state.logs_written.insert(path); + drop(state); + + gst::debug!(CAT, imp = self, "Writing file {:?}", file); + + for LogLine { + timestamp, + element_name, + pad_name, + ptr, + buffer_clock_time, + pipeline_clock_time, + lateness, + min_latency, + } in &log + { + if let Err(err) = writeln!(&mut file, "{timestamp},{element_name}:{pad_name},0x{ptr:08x},{buffer_clock_time},{pipeline_clock_time},{lateness},{min_latency}") { + gst::error!(CAT, imp = self, "Failed to write to file: {err}"); + return; + } + } + } +} + #[glib::object_subclass] impl ObjectSubclass for BufferLateness { const NAME: &'static str = "GstBufferLateness"; @@ -186,42 +232,26 @@ impl ObjectImpl for BufferLateness { self.register_hook(TracerHook::PadQueryPost); } + fn signals() -> &'static [glib::subclass::Signal] { + static SIGNALS: LazyLock> = LazyLock::new(|| { + vec![glib::subclass::Signal::builder("write-log") + .action() + .param_types([Option::::static_type()]) + .class_handler(|_, args| { + let obj = args[0].get::().unwrap(); + + obj.imp().write_log(args[1].get::>().unwrap()); + + None + }) + .build()] + }); + + SIGNALS.as_ref() + } + fn dispose(&self) { - use std::io::prelude::*; - - let state = self.state.lock().unwrap(); - - let mut file = match std::fs::File::create(&state.settings.file) { - Ok(file) => file, - Err(err) => { - gst::error!(CAT, imp = self, "Failed to create file: {err}"); - return; - } - }; - - gst::debug!( - CAT, - imp = self, - "Writing file {}", - state.settings.file.display() - ); - - for LogLine { - timestamp, - element_name, - pad_name, - ptr, - buffer_clock_time, - pipeline_clock_time, - lateness, - min_latency, - } in &state.log - { - if let Err(err) = writeln!(&mut file, "{timestamp},{element_name}:{pad_name},0x{ptr:08x},{buffer_clock_time},{pipeline_clock_time},{lateness},{min_latency}") { - gst::error!(CAT, imp = self, "Failed to write to file: {err}"); - return; - } - } + self.write_log(None); } }