use std::{
ops::{Deref, DerefMut},
sync::{Arc, Mutex, RwLock},
};
use pipewire_native_spa::{self as spa, pod::types::Fraction};
use crate::{
core::Core,
new_refcounted,
proxy::{HasProxy, Proxy},
refcounted,
types::{self},
HookId, Id,
};
refcounted! {
pub struct Profiler {
proxy: RwLock<Option<Proxy<Profiler>>>,
hooks: Arc<Mutex<spa::hook::HookList<ProfilerEvents>>>,
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ProfilerSample<'a> {
pub info: SampleInfo,
pub driver: NodeSample<'a>,
pub driver_clock: DriverClockSample<'a>,
pub followers: &'a [FollowerNodeSample<'a>],
pub follower_clocks: &'a [ClockSample<'a>],
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SampleInfo {
pub counter: i64,
pub cpu_load_short_term: f32,
pub cpu_load_medium_term: f32,
pub cpu_load_long_term: f32,
pub xrun_count: u32,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct NodeSample<'a> {
pub id: Id,
pub name: &'a str,
pub prev_signal_time_ns: u64,
pub signal_time_ns: u64,
pub awake_time_ns: u64,
pub finish_time_ns: u64,
pub status: u32,
pub latency: Fraction,
pub xrun_count: u32,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct FollowerNodeSample<'a> {
pub node_sample: NodeSample<'a>,
pub async_: bool,
}
impl<'a> Deref for FollowerNodeSample<'a> {
type Target = NodeSample<'a>;
fn deref(&self) -> &Self::Target {
&self.node_sample
}
}
impl<'a> DerefMut for FollowerNodeSample<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.node_sample
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ClockSample<'a> {
pub id: Id,
pub name: &'a str,
pub nsec: u64,
pub rate: Fraction,
pub position: u64,
pub duration: u64,
pub delay: i64,
pub rate_diff: f64,
pub next_nsec: u64,
pub xrun_duration: u64,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DriverClockSample<'a> {
pub clock_sample: ClockSample<'a>,
pub flags: u32,
pub state: u32,
pub cycle: u32,
}
impl<'a> Deref for DriverClockSample<'a> {
type Target = ClockSample<'a>;
fn deref(&self) -> &Self::Target {
&self.clock_sample
}
}
impl<'a> DerefMut for DriverClockSample<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.clock_sample
}
}
#[allow(clippy::type_complexity)]
#[derive(Default)]
pub struct ProfilerEvents {
pub profile: Option<Box<dyn FnMut(&ProfilerSample<'_>) + Send>>,
}
impl HasProxy for Profiler {
fn type_(&self) -> types::ObjectType {
types::interface::PROFILER
}
fn version(&self) -> u32 {
3
}
fn proxy(&self) -> Proxy<Self> {
self.inner
.proxy
.read()
.unwrap()
.as_ref()
.expect("Profiler proxy should be initialised on creation")
.clone()
}
}
impl Profiler {
pub(crate) fn new(core: &Core) -> Self {
let this = Self {
inner: new_refcounted(InnerProfiler::new()),
};
let id = core.next_proxy_id();
this.inner
.proxy
.write()
.unwrap()
.replace(Proxy::new(id, &this));
core.add_proxy(&this, id);
this
}
pub fn add_listener(&self, events: ProfilerEvents) -> HookId {
self.inner.hooks.lock().unwrap().append(events)
}
pub fn remove_listener(&self, hook_id: HookId) {
self.inner.hooks.lock().unwrap().remove(hook_id);
}
pub(crate) fn events(&self) -> Arc<Mutex<spa::hook::HookList<ProfilerEvents>>> {
self.inner.hooks.clone()
}
}
impl InnerProfiler {
fn new() -> Self {
Self {
proxy: RwLock::new(None),
hooks: spa::hook::HookList::new(),
}
}
}