1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use crate::{prelude::*, PipewireObject, SpaPod};

#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))]
#[derive(Debug)]
pub struct SpaProps {
	params: SpaPod,
}

impl SpaProps {
	pub fn with_params(params: SpaPod) -> crate::Result<Self> {
		// TODO: assert id/type
		Ok(Self { params })
	}

	pub fn into_params(self) -> SpaPod {
		self.params
	}

	pub fn params(&self) -> crate::Result<impl Iterator<Item = (String, SpaPod)>> {
		match self.params.find_spa_property(&libspa_sys::SPA_PROP_params) {
			Some(params) => params.struct_fields(false),
			None => Ok(Vec::new().into_iter()),
		}
	}

	pub fn has_volume(&self) -> bool {
		self
			.params
			.find_spa_property(&libspa_sys::SPA_PROP_channelVolumes)
			.is_some()
			|| self.params.find_spa_property(&libspa_sys::SPA_PROP_volume).is_some()
	}

	pub fn mute(&self) -> bool {
		self
			.params
			.find_spa_property(&libspa_sys::SPA_PROP_mute)
			.and_then(|pod| pod.boolean())
			.unwrap_or_default()
	}

	pub fn channel_volume(&self, channel_index: u32) -> f32 {
		self
			.params
			.find_spa_property(&libspa_sys::SPA_PROP_channelVolumes)
			.and_then(|pod| pod.array_iterator::<f32>().nth(channel_index as usize))
			.or_else(|| {
				self
					.params
					.find_spa_property(&libspa_sys::SPA_PROP_volume)
					.and_then(|pod| pod.float())
			})
			.unwrap_or(1.0f32)
	}

	pub fn set_channel_volume(&self, channel_index: u32, volume: f32) -> Result<(), ()> {
		let succ = match self.params.find_spa_property(&libspa_sys::SPA_PROP_channelVolumes) {
			Some(pod) => {
				let mut data: Vec<f32> = pod.array_iterator().collect();
				*data.get_mut(channel_index as usize).ok_or(())? = volume;
				pod.set_pod(&data.into_iter().collect())
			},
			None => {
				let pod = self.params.find_spa_property(&libspa_sys::SPA_PROP_volume).ok_or(())?;
				pod.set_float(volume)
			},
		};
		if succ {
			Ok(())
		} else {
			Err(())
		}
	}

	pub async fn from_object<O: IsA<PipewireObject>>(obj: &O) -> crate::Result<Self> {
		let params = obj.params_future(Some("Props"), None).await?;
		for item in params {
			if item.find_spa_property(&libspa_sys::SPA_PROP_volume).is_some() {
				return Self::with_params(item)
			}
		}
		Err(todo!())
	}
}