mirror of
https://gitlab.freedesktop.org/pipewire/helvum.git
synced 2026-05-02 05:08:00 +02:00
refactor: Move SPA wrappers into own file
This commit is contained in:
parent
0584f44812
commit
323007c1fd
2 changed files with 141 additions and 94 deletions
126
src/pipewire_connection/libspa_ext.rs
Normal file
126
src/pipewire_connection/libspa_ext.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue