refactor: Move SPA wrappers into own file

This commit is contained in:
Florian Olk 2024-11-15 19:09:14 +01:00
parent 0584f44812
commit 323007c1fd
2 changed files with 141 additions and 94 deletions

View file

@ -0,0 +1,126 @@
// FIXME: use libspa methods as soon as they are available
use std::{os::raw::c_void, ptr::{null, null_mut}};
use pipewire::spa::{pod::Pod, sys::{spa_pod, spa_pod_array, spa_pod_array_body, spa_pod_object, spa_pod_object_body, spa_pod_prop, spa_pod_prop_first, spa_pod_prop_is_inside, spa_pod_prop_next, spa_ptrinside}};
pub struct PodPropsIter<'a> {
size: u32,
body: &'a spa_pod_object_body,
cur_prop: * const spa_pod_prop,
}
impl<'a> PodPropsIter<'a> {
fn new(pod: &'a Pod) -> Self {
unsafe {
let raw_pod = pod.as_raw_ptr();
let size = (*raw_pod).size;
let obj = raw_pod as *const spa_pod_object;
let body = &(*obj).body;
let cur_prop = null();
Self {
size,
body,
cur_prop,
}
}
}
}
pub struct PodPropKV<'a> {
k: u32,
v: &'a Pod,
}
impl<'a> PodPropKV<'a> {
pub fn key(&self) -> u32 {
self.k
}
pub fn value(&self) -> &'a Pod {
self.v
}
}
impl<'a> Iterator for PodPropsIter<'a> {
type Item = PodPropKV<'a>;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
if self.cur_prop.is_null() {
self.cur_prop = spa_pod_prop_first(self.body);
} else {
self.cur_prop = spa_pod_prop_next(self.cur_prop);
}
if spa_pod_prop_is_inside(self.body, self.size, self.cur_prop) {
let inner_pod = Pod::from_raw(&(*self.cur_prop).value);
Some(PodPropKV {
k: (*self.cur_prop).key,
v: inner_pod,
})
} else {
None
}
}
}
}
pub struct PodArrayIter<'a> {
pod: &'a Pod,
size: u32,
body: * const spa_pod_array_body,
iter: * mut spa_pod,
}
impl<'a> PodArrayIter<'a> {
fn new(pod: &'a Pod) -> Self {
assert!(pod.is_array());
unsafe {
let raw_pod = pod.as_raw_ptr();
let arr = raw_pod as *const spa_pod_array;
let body = &(*arr).body as *const spa_pod_array_body;
let size = (*raw_pod).size;
let iter = null_mut();
Self {
pod,
body,
size,
iter,
}
}
}
}
impl<'a> Iterator for PodArrayIter<'a> {
type Item = &'a Pod;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
if self.iter.is_null() {
self.iter = self.pod.as_raw_ptr().byte_offset(size_of::<spa_pod_array_body>() as isize);
} else {
self.iter = self.iter.byte_offset((*self.body).child.size as isize);
}
if (*self.body).child.size > 0
&& spa_ptrinside(
self.body as *const c_void,
self.size as usize,
self.iter as *const c_void,
(*self.body).child.size as usize,
null_mut(),
) {
Some(pipewire::spa::pod::Pod::from_raw(self.iter))
} else {
None
}
}
}
}
pub trait PodExt {
fn iter_props(&self) -> PodPropsIter;
fn iter_array(&self) -> PodArrayIter;
}
impl PodExt for Pod {
fn iter_props(&self) -> PodPropsIter {
PodPropsIter::new(self)
}
fn iter_array(&self) -> PodArrayIter {
PodArrayIter::new(self)
}
}

View file

@ -15,18 +15,17 @@
// SPDX-License-Identifier: GPL-3.0-only
mod state;
mod libspa_ext;
use std::{
cell::RefCell,
collections::HashMap,
mem::MaybeUninit,
os::raw::c_void,
ptr::{null, null_mut},
rc::Rc,
time::Duration,
};
use adw::glib::{self, clone};
use libspa_ext::PodExt as _;
use log::{debug, error, info, warn};
use pipewire::{
context::Context,
@ -40,10 +39,7 @@ use pipewire::{
registry::{GlobalObject, Registry},
spa::{
param::{ParamInfoFlags, ParamType},
pod::parser::Parser,
sys::{
spa_pod, spa_pod_array, spa_pod_array_body, spa_pod_find_prop, spa_pod_frame, spa_pod_get_float, spa_pod_is_array, spa_pod_is_inside, spa_pod_object, spa_pod_object_body, spa_pod_parser_pod, spa_pod_prop, spa_pod_prop_first, spa_pod_prop_is_inside, spa_pod_prop_next, spa_ptrinside, SPA_PROP_channelVolumes, SPA_PROP_mute, SPA_PROP_volume, SPA_TYPE_OBJECT_Props
},
sys::{ SPA_PROP_channelVolumes, SPA_PROP_mute, SPA_PROP_volume },
utils::{dict::DictRef, result::SpaResult, SpaTypes},
},
types::ObjectType,
@ -353,90 +349,16 @@ fn parse_mute_pod(pod: &pipewire::spa::pod::Pod) -> bool {
fn parse_channelvolume_pod(pod: &pipewire::spa::pod::Pod) -> Vec<f32> {
let mut channel_volumes = vec![];
let pod = pod.as_raw_ptr();
let arr = pod as *const spa_pod_array;
unsafe {
let body = &(*arr).body as *const spa_pod_array_body;
let size = (*pod).size;
let mut iter =
pod.byte_offset(size_of::<spa_pod_array_body>() as isize);
while (*body).child.size > 0
&& spa_ptrinside(
body as *const c_void,
size as usize,
iter as *const c_void,
(*body).child.size as usize,
null_mut(),
)
{
let pod = pipewire::spa::pod::Pod::from_raw(iter);
if pod.is_float() {
let f = pod.get_float().unwrap();
debug!("Found channelVolume Prop entry: {f}");
channel_volumes.push(f);
}
iter = iter.byte_offset((*body).child.size as isize);
for p in pod.iter_array() {
if p.is_float() {
let f = p.get_float().unwrap();
debug!("Found channelVolume Prop entry: {f}");
channel_volumes.push(f);
}
}
channel_volumes
}
struct PodPropsIter<'a> {
pod: &'a pipewire::spa::pod::Pod,
size: u32,
body: &'a spa_pod_object_body,
cur_prop: * const spa_pod_prop,
}
impl<'a> PodPropsIter<'a> {
fn new(pod: &'a pipewire::spa::pod::Pod) -> Self {
unsafe {
let raw_pod = pod.as_raw_ptr();
let size = (*raw_pod).size;
let obj = raw_pod as *const spa_pod_object;
let body = &(*obj).body;
let cur_prop = null();
Self {
pod,
size,
body,
cur_prop,
}
}
}
}
struct PodPropKV<'a> {
key: u32,
value: &'a pipewire::spa::pod::Pod,
}
impl<'a> Iterator for PodPropsIter<'a> {
type Item = PodPropKV<'a>;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
if self.cur_prop.is_null() {
self.cur_prop = spa_pod_prop_first(self.body);
} else {
self.cur_prop = spa_pod_prop_next(self.cur_prop);
}
if !spa_pod_prop_is_inside(self.body, self.size, self.cur_prop) {
None
} else {
let inner_pod = pipewire::spa::pod::Pod::from_raw(&(*self.cur_prop).value);
Some(PodPropKV {
key: (*self.cur_prop).key,
value: inner_pod,
})
}
}
}
}
fn iter_pod_props(pod: &pipewire::spa::pod::Pod) -> PodPropsIter {
PodPropsIter::new(pod)
}
fn handle_node_params(
id: u32,
param_type: pipewire::spa::param::ParamType,
@ -462,14 +384,13 @@ fn handle_node_params(
let mut channel_volumes = vec![];
let mut mute = None;
// FIXME: use libspa methods as soon as they are available
let mut iter = iter_pod_props(pod);
while let Some(PodPropKV {key, value}) = iter.next() {
if key == SPA_PROP_volume && value.is_float() {
volume = Some(parse_volume_pod(value));
} else if key == SPA_PROP_channelVolumes && value.is_array() {
channel_volumes = parse_channelvolume_pod(value);
} else if key == SPA_PROP_mute && value.is_bool() {
mute = Some(parse_mute_pod(value));
for prop in pod.iter_props() {
if prop.key() == SPA_PROP_volume && prop.value().is_float() {
volume = Some(parse_volume_pod(prop.value()));
} else if prop.key() == SPA_PROP_channelVolumes && prop.value().is_array() {
channel_volumes = parse_channelvolume_pod(prop.value());
} else if prop.key() == SPA_PROP_mute && prop.value().is_bool() {
mute = Some(parse_mute_pod(prop.value()));
}
}
sender