use std::sync::{Arc, Mutex, RwLock};
use bitflags::bitflags;
use pipewire_native_macros as macros;
use pipewire_native_spa as spa;
use crate::{
core::Core,
new_refcounted,
properties::Properties,
protocol,
proxy::{HasProxy, Proxy},
proxy_object_invoke, refcounted,
types::{self, params::ParamBuilder},
HookId, Id, Refcounted,
};
refcounted! {
pub struct Node {
proxy: RwLock<Option<Proxy<Node>>>,
methods: Arc<Mutex<NodeMethods<Node>>>,
hooks: Arc<Mutex<spa::hook::HookList<NodeEvents>>>,
}
}
#[allow(clippy::type_complexity)]
pub(crate) struct NodeMethods<T: HasProxy + Refcounted> {
pub(crate) subscribe_params:
Box<dyn FnMut(&Proxy<T>, &[spa::param::ParamType]) -> std::io::Result<()>>,
pub(crate) enum_params: Box<
dyn FnMut(
&Proxy<T>,
u32,
Option<spa::param::ParamType>,
u32,
u32,
Option<ParamBuilder>,
) -> std::io::Result<()>,
>,
pub(crate) set_param: Box<
dyn FnMut(
&Proxy<T>,
spa::param::ParamType,
spa::pod::types::ObjectType,
u32,
Box<dyn FnOnce(spa::pod::builder::ObjectBuilder) -> spa::pod::builder::ObjectBuilder>,
) -> std::io::Result<()>,
>,
pub(crate) send_command: Box<
dyn FnMut(
&Proxy<T>,
Box<dyn FnOnce(spa::pod::builder::Builder) -> spa::pod::builder::Builder>,
) -> std::io::Result<()>,
>,
}
bitflags! {
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NodeChangeMask : u32 {
const INPUT_PORTS = (1 << 0);
const OUTPUT_PORTS = (1 << 1);
const STATE = (1 << 2);
const PROPS = (1 << 3);
const PARAMS = (1 << 4);
}
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, macros::EnumU32)]
pub enum NodeState {
Error,
Creating,
Suspended,
Idle,
Running,
}
pub struct NodeInfo<'a> {
pub id: Id,
pub max_input_ports: u32,
pub max_output_ports: u32,
pub mask: NodeChangeMask,
pub n_input_ports: u32,
pub n_output_ports: u32,
pub state: NodeState,
pub error: Option<&'a str>,
pub props: &'a Properties,
pub params: &'a [(spa::param::ParamType, spa::param::ParamInfoFlags)],
}
#[allow(clippy::type_complexity)]
#[derive(Default)]
pub struct NodeEvents {
pub info: Option<Box<dyn FnMut(&NodeInfo<'_>) + Send>>,
pub param:
Option<Box<dyn FnMut(u32, spa::param::ParamType, u32, u32, &spa::pod::RawPodOwned) + Send>>,
}
impl HasProxy for Node {
fn type_(&self) -> types::ObjectType {
types::interface::NODE
}
fn version(&self) -> u32 {
3
}
fn proxy(&self) -> Proxy<Self> {
self.inner
.proxy
.read()
.unwrap()
.as_ref()
.expect("Node proxy should be initialised on creation")
.clone()
}
}
impl Node {
pub(crate) fn new(core: &Core) -> Self {
let this = Self {
inner: new_refcounted(InnerNode::new(core)),
};
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: NodeEvents) -> 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 fn subscribe_params(&self, ids: &[spa::param::ParamType]) -> std::io::Result<()> {
let proxy = self.proxy();
proxy_object_invoke!(proxy, subscribe_params, ids)
}
pub fn enum_params(
&self,
seq: u32,
id: Option<spa::param::ParamType>,
start: u32,
num: u32,
filter: Option<ParamBuilder>,
) -> std::io::Result<()> {
let proxy = self.proxy();
proxy_object_invoke!(proxy, enum_params, seq, id, start, num, filter)
}
pub fn set_param(
&self,
param_id: spa::param::ParamType,
object_type: spa::pod::types::ObjectType,
flags: u32,
builder: Box<
dyn FnOnce(spa::pod::builder::ObjectBuilder) -> spa::pod::builder::ObjectBuilder,
>,
) -> std::io::Result<()> {
let proxy = self.proxy();
proxy_object_invoke!(proxy, set_param, param_id, object_type, flags, builder)
}
pub fn send_command(
&self,
builder: Box<dyn FnOnce(spa::pod::builder::Builder) -> spa::pod::builder::Builder>,
) -> std::io::Result<()> {
let proxy = self.proxy();
proxy_object_invoke!(proxy, send_command, builder)
}
pub(crate) fn methods(&self) -> Arc<Mutex<NodeMethods<Node>>> {
self.inner.methods.clone()
}
pub(crate) fn events(&self) -> Arc<Mutex<spa::hook::HookList<NodeEvents>>> {
self.inner.hooks.clone()
}
}
impl InnerNode {
fn new(core: &Core) -> Self {
Self {
proxy: RwLock::new(None),
methods: Arc::new(Mutex::new(protocol::marshal::node::Methods::marshal(
core.connection(),
))),
hooks: spa::hook::HookList::new(),
}
}
}