use pipewire_native_macros as macros;
use pipewire_native_spa::{
self as spa,
param::{ParamInfoFlags, ParamType},
pod::{builder::Builder, types::Id as SpaId, Pod, RawPodOwned},
};
use crate::{
closure, default_topic, log,
properties::Properties,
protocol::connection::Connection,
proxy::{
port::{Port, PortChangeMask, PortDirection, PortInfo, PortMethods},
Proxy,
},
proxy_object_notify, trace, warn, Id,
};
use super::PairList;
default_topic!(log::topic::PROTOCOL);
#[repr(u8)]
#[derive(Debug, macros::Marshallable)]
pub(crate) enum Methods {
SubscribeParams(SubscribeParams) = 1,
EnumParams(EnumParams),
}
#[derive(Debug, macros::PodStruct)]
pub(crate) struct SubscribeParams {
ids: Vec<SpaId<ParamType>>,
}
#[derive(Debug, macros::PodStruct)]
pub(crate) struct EnumParams {
seq: i32,
id: SpaId<u32>,
index: i32,
num: i32,
filter: spa::pod::RawPodOwned,
}
impl Methods {
pub(crate) fn marshal(connection: Connection) -> PortMethods<Port> {
PortMethods {
subscribe_params: closure!([connection] proxy, ids, {
connection.push(
proxy.id(),
Methods::SubscribeParams(SubscribeParams {
ids: ids.iter().map(|id| SpaId(*id)).collect::<Vec<_>>()
})
)
}),
enum_params: closure!([connection] proxy, seq, id, index, num, filter, {
let id = match id {
Some(id) => id as u32,
None => crate::ANY_ID,
};
let mut filter_data = [0u8; 16384];
match filter {
Some(param_builder) => {
let builder = Builder::new(filter_data.as_mut_slice());
builder
.push_object(
param_builder.object_type,
param_builder.param_id,
param_builder.builder
)
.build()
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Could not build param: {e:?}")
)
})?;
},
None => {
()
.encode(filter_data.as_mut_slice()).unwrap();
},
};
let filter = RawPodOwned::wrap(Vec::from(filter_data)).unwrap();
connection.push(
proxy.id(),
Methods::EnumParams(EnumParams {
seq: seq as i32,
id: SpaId(id),
index: index as i32,
num: num as i32,
filter,
})
)
}),
}
}
}
#[derive(Debug, macros::Marshallable)]
pub(crate) enum Events {
Info(Info),
Param(Param),
}
#[derive(Debug, macros::PodStruct)]
pub(crate) struct Info {
id: i32,
direction: i32,
change_mask: i64,
props: PairList<String, String>,
param_info: PairList<SpaId<ParamType>, i32>,
}
#[derive(Debug, macros::PodStruct)]
pub(crate) struct Param {
seq: i32,
id: SpaId<ParamType>,
index: i32,
next: i32,
param: RawPodOwned,
}
impl Events {
pub(crate) fn demarshal(
connection: &Connection,
header: &super::message::Header,
proxy: Proxy<Port>,
) -> std::io::Result<()> {
let event = connection.decode_core_message::<Events>(header)?;
trace!("got event: {event:?}");
match event {
Events::Info(info) => {
let props = Properties::new_vec(info.props.data);
let mut param_info = vec![];
for (id, flags) in info.param_info.data {
match ParamInfoFlags::from_bits(flags as u32) {
Some(flags) => param_info.push((id.0, flags)),
None => {
warn!("Invalid param info: {id:?} {flags}");
}
}
}
let port_info = PortInfo {
id: info.id as Id,
direction: PortDirection::try_from(info.direction as u32).unwrap(),
mask: PortChangeMask::from_bits_truncate(info.change_mask as u32),
props: &props,
params: param_info.as_slice(),
};
proxy_object_notify!(proxy, info, &port_info);
}
Events::Param(param) => {
let seq = param.seq as u32;
let param_id = param.id.0;
let index = param.index as u32;
let next = param.next as u32;
let param_pod = param.param;
proxy_object_notify!(proxy, param, seq, param_id, index, next, ¶m_pod);
}
}
Ok(())
}
}