pulsectl/controllers/
types.rs

1use pulse::{
2    channelmap,
3    context::introspect,
4    def,
5    def::PortAvailable,
6    format,
7    proplist::Proplist,
8    sample,
9    time::MicroSeconds,
10    volume::{ChannelVolumes, Volume},
11};
12
13/// These structs are direct representations of what libpulse_binding gives
14/// created to be copyable / cloneable for use in and out of callbacks
15
16/// This is a wrapper around SinkPortInfo and SourcePortInfo as they have the same members
17#[derive(Clone)]
18pub struct DevicePortInfo {
19    /// Name of the sink.
20    pub name: Option<String>,
21    /// Description of this sink.
22    pub description: Option<String>,
23    /// The higher this value is, the more useful this port is as a default.
24    pub priority: u32,
25    /// A flag indicating availability status of this port.
26    pub available: PortAvailable,
27}
28
29impl<'a> From<&'a Box<introspect::SinkPortInfo<'a>>> for DevicePortInfo {
30    fn from(item: &'a Box<introspect::SinkPortInfo<'a>>) -> Self {
31        DevicePortInfo {
32            name: item.name.as_ref().map(|cow| cow.to_string()),
33            description: item.description.as_ref().map(|cow| cow.to_string()),
34            priority: item.priority,
35            available: item.available,
36        }
37    }
38}
39
40impl<'a> From<&'a introspect::SinkPortInfo<'a>> for DevicePortInfo {
41    fn from(item: &'a introspect::SinkPortInfo<'a>) -> Self {
42        DevicePortInfo {
43            name: item.name.as_ref().map(|cow| cow.to_string()),
44            description: item.description.as_ref().map(|cow| cow.to_string()),
45            priority: item.priority,
46            available: item.available,
47        }
48    }
49}
50
51impl<'a> From<&'a Box<introspect::SourcePortInfo<'a>>> for DevicePortInfo {
52    fn from(item: &'a Box<introspect::SourcePortInfo<'a>>) -> Self {
53        DevicePortInfo {
54            name: item.name.as_ref().map(|cow| cow.to_string()),
55            description: item.description.as_ref().map(|cow| cow.to_string()),
56            priority: item.priority,
57            available: item.available,
58        }
59    }
60}
61
62impl<'a> From<&'a introspect::SourcePortInfo<'a>> for DevicePortInfo {
63    fn from(item: &'a introspect::SourcePortInfo<'a>) -> Self {
64        DevicePortInfo {
65            name: item.name.as_ref().map(|cow| cow.to_string()),
66            description: item.description.as_ref().map(|cow| cow.to_string()),
67            priority: item.priority,
68            available: item.available,
69        }
70    }
71}
72
73/// This is a wrapper around SinkState and SourceState as they have the same values
74#[derive(Debug, Copy, Clone, PartialEq, Eq)]
75pub enum DevState {
76    /// This state is used when the server does not support sink state introspection.
77    Invalid = -1,
78    /// Running, sink is playing and used by at least one non-corked sink-input.
79    Running = 0,
80    /// When idle, the sink is playing but there is no non-corked sink-input attached to it.
81    Idle = 1,
82    /// When suspended, actual sink access can be closed, for instance.
83    Suspended = 2,
84}
85
86impl<'a> From<def::SourceState> for DevState {
87    fn from(s: def::SourceState) -> Self {
88        match s {
89            def::SourceState::Idle => DevState::Idle,
90            def::SourceState::Invalid => DevState::Invalid,
91            def::SourceState::Running => DevState::Running,
92            def::SourceState::Suspended => DevState::Suspended,
93        }
94    }
95}
96
97impl<'a> From<def::SinkState> for DevState {
98    fn from(s: def::SinkState) -> Self {
99        match s {
100            def::SinkState::Idle => DevState::Idle,
101            def::SinkState::Invalid => DevState::Invalid,
102            def::SinkState::Running => DevState::Running,
103            def::SinkState::Suspended => DevState::Suspended,
104        }
105    }
106}
107
108#[derive(Clone)]
109pub enum Flags {
110    SourceFLags(def::SourceFlagSet),
111    SinkFlags(def::SinkFlagSet),
112}
113
114#[derive(Clone)]
115pub struct DeviceInfo {
116    /// Index of the sink.
117    pub index: u32,
118    /// Name of the sink.
119    pub name: Option<String>,
120    /// Description of this sink.
121    pub description: Option<String>,
122    /// Sample spec of this sink.
123    pub sample_spec: sample::Spec,
124    /// Channel map.
125    pub channel_map: channelmap::Map,
126    /// Index of the owning module of this sink, or `None` if is invalid.
127    pub owner_module: Option<u32>,
128    /// Volume of the sink.
129    pub volume: ChannelVolumes,
130    /// Mute switch of the sink.
131    pub mute: bool,
132    /// Index of the monitor source connected to this sink.
133    pub monitor: Option<u32>,
134    /// The name of the monitor source.
135    pub monitor_name: Option<String>,
136    /// Length of queued audio in the output buffer.
137    pub latency: MicroSeconds,
138    /// Driver name.
139    pub driver: Option<String>,
140    /// Flags.
141    pub flags: Flags,
142    /// Property list.
143    pub proplist: Proplist,
144    /// The latency this device has been configured to.
145    pub configured_latency: MicroSeconds,
146    /// Some kind of “base” volume that refers to unamplified/unattenuated volume in the context of
147    /// the output device.
148    pub base_volume: Volume,
149    /// State.
150    pub state: DevState,
151    /// Number of volume steps for sinks which do not support arbitrary volumes.
152    pub n_volume_steps: u32,
153    /// Card index, or `None` if invalid.
154    pub card: Option<u32>,
155    /// Set of available ports.
156    pub ports: Vec<DevicePortInfo>,
157    // Pointer to active port in the set, or None.
158    pub active_port: Option<DevicePortInfo>,
159    /// Set of formats supported by the sink.
160    pub formats: Vec<format::Info>,
161}
162
163impl<'a> From<&'a introspect::SinkInfo<'a>> for DeviceInfo {
164    fn from(item: &'a introspect::SinkInfo<'a>) -> Self {
165        DeviceInfo {
166            name: item.name.as_ref().map(|cow| cow.to_string()),
167            index: item.index,
168            description: item.description.as_ref().map(|cow| cow.to_string()),
169            sample_spec: item.sample_spec,
170            channel_map: item.channel_map,
171            owner_module: item.owner_module,
172            volume: item.volume,
173            mute: item.mute,
174            monitor: Some(item.monitor_source),
175            monitor_name: item.monitor_source_name.as_ref().map(|cow| cow.to_string()),
176            latency: item.latency,
177            driver: item.driver.as_ref().map(|cow| cow.to_string()),
178            flags: Flags::SinkFlags(item.flags),
179            proplist: item.proplist.clone(),
180            configured_latency: item.configured_latency,
181            base_volume: item.base_volume,
182            state: DevState::from(item.state),
183            n_volume_steps: item.n_volume_steps,
184            card: item.card,
185            ports: item.ports.iter().map(From::from).collect(),
186            active_port: item.active_port.as_ref().map(From::from),
187            formats: item.formats.clone(),
188        }
189    }
190}
191
192impl<'a> From<&'a introspect::SourceInfo<'a>> for DeviceInfo {
193    fn from(item: &'a introspect::SourceInfo<'a>) -> Self {
194        DeviceInfo {
195            name: item.name.as_ref().map(|cow| cow.to_string()),
196            index: item.index,
197            description: item.description.as_ref().map(|cow| cow.to_string()),
198            sample_spec: item.sample_spec,
199            channel_map: item.channel_map,
200            owner_module: item.owner_module,
201            volume: item.volume,
202            mute: item.mute,
203            monitor: item.monitor_of_sink,
204            monitor_name: item
205                .monitor_of_sink_name
206                .as_ref()
207                .map(|cow| cow.to_string()),
208            latency: item.latency,
209            driver: item.driver.as_ref().map(|cow| cow.to_string()),
210            flags: Flags::SourceFLags(item.flags),
211            proplist: item.proplist.clone(),
212            configured_latency: item.configured_latency,
213            base_volume: item.base_volume,
214            state: DevState::from(item.state),
215            n_volume_steps: item.n_volume_steps,
216            card: item.card,
217            ports: item.ports.iter().map(From::from).collect(),
218            active_port: item.active_port.as_ref().map(From::from),
219            formats: item.formats.clone(),
220        }
221    }
222}
223
224#[derive(Clone)]
225pub struct ApplicationInfo {
226    /// Index of the sink input.
227    pub index: u32,
228    /// Name of the sink input.
229    pub name: Option<String>,
230    /// Index of the module this sink input belongs to, or `None` when it does not belong to any
231    /// module.
232    pub owner_module: Option<u32>,
233    /// Index of the client this sink input belongs to, or invalid when it does not belong to any
234    /// client.
235    pub client: Option<u32>,
236    /// Index of the connected sink/source.
237    pub connection_id: u32,
238    /// The sample specification of the sink input.
239    pub sample_spec: sample::Spec,
240    /// Channel map.
241    pub channel_map: channelmap::Map,
242    /// The volume of this sink input.
243    pub volume: ChannelVolumes,
244    /// Latency due to buffering in sink input, see
245    /// [`def::TimingInfo`](../../def/struct.TimingInfo.html) for details.
246    pub buffer_usec: MicroSeconds,
247    /// Latency of the sink device, see
248    /// [`def::TimingInfo`](../../def/struct.TimingInfo.html) for details.
249    pub connection_usec: MicroSeconds,
250    /// The resampling method used by this sink input.
251    pub resample_method: Option<String>,
252    /// Driver name.
253    pub driver: Option<String>,
254    /// Stream muted.
255    pub mute: bool,
256    /// Property list.
257    pub proplist: Proplist,
258    /// Stream corked.
259    pub corked: bool,
260    /// Stream has volume. If not set, then the meaning of this struct’s volume member is unspecified.
261    pub has_volume: bool,
262    /// The volume can be set. If not set, the volume can still change even though clients can’t
263    /// control the volume.
264    pub volume_writable: bool,
265    /// Stream format information.
266    pub format: format::Info,
267}
268
269impl<'a> From<&'a introspect::SinkInputInfo<'a>> for ApplicationInfo {
270    fn from(item: &'a introspect::SinkInputInfo<'a>) -> Self {
271        ApplicationInfo {
272            index: item.index,
273            name: item.name.as_ref().map(|cow| cow.to_string()),
274            owner_module: item.owner_module,
275            client: item.client,
276            connection_id: item.sink,
277            sample_spec: item.sample_spec,
278            channel_map: item.channel_map,
279            volume: item.volume,
280            buffer_usec: item.buffer_usec,
281            connection_usec: item.sink_usec,
282            resample_method: item.resample_method.as_ref().map(|cow| cow.to_string()),
283            driver: item.driver.as_ref().map(|cow| cow.to_string()),
284            mute: item.mute,
285            proplist: item.proplist.clone(),
286            corked: item.corked,
287            has_volume: item.has_volume,
288            volume_writable: item.volume_writable,
289            format: item.format.clone(),
290        }
291    }
292}
293
294impl<'a> From<&'a introspect::SourceOutputInfo<'a>> for ApplicationInfo {
295    fn from(item: &'a introspect::SourceOutputInfo<'a>) -> Self {
296        ApplicationInfo {
297            index: item.index,
298            name: item.name.as_ref().map(|cow| cow.to_string()),
299            owner_module: item.owner_module,
300            client: item.client,
301            connection_id: item.source,
302            sample_spec: item.sample_spec,
303            channel_map: item.channel_map,
304            volume: item.volume,
305            buffer_usec: item.buffer_usec,
306            connection_usec: item.source_usec,
307            resample_method: item.resample_method.as_ref().map(|cow| cow.to_string()),
308            driver: item.driver.as_ref().map(|cow| cow.to_string()),
309            mute: item.mute,
310            proplist: item.proplist.clone(),
311            corked: item.corked,
312            has_volume: item.has_volume,
313            volume_writable: item.volume_writable,
314            format: item.format.clone(),
315        }
316    }
317}
318
319pub struct ServerInfo {
320    /// User name of the daemon process.
321    pub user_name: Option<String>,
322    /// Host name the daemon is running on.
323    pub host_name: Option<String>,
324    /// Version string of the daemon.
325    pub server_version: Option<String>,
326    /// Server package name (usually “pulseaudio”).
327    pub server_name: Option<String>,
328    /// Default sample specification.
329    pub sample_spec: sample::Spec,
330    /// Name of default sink.
331    pub default_sink_name: Option<String>,
332    /// Name of default source.
333    pub default_source_name: Option<String>,
334    /// A random cookie for identifying this instance of PulseAudio.
335    pub cookie: u32,
336    /// Default channel map.
337    pub channel_map: channelmap::Map,
338}
339
340impl<'a> From<&'a introspect::ServerInfo<'a>> for ServerInfo {
341    fn from(info: &'a introspect::ServerInfo<'a>) -> Self {
342        ServerInfo {
343            user_name: info.user_name.as_ref().map(|cow| cow.to_string()),
344            host_name: info.host_name.as_ref().map(|cow| cow.to_string()),
345            server_version: info.server_version.as_ref().map(|cow| cow.to_string()),
346            server_name: info.server_name.as_ref().map(|cow| cow.to_string()),
347            sample_spec: info.sample_spec,
348            default_sink_name: info.default_sink_name.as_ref().map(|cow| cow.to_string()),
349            default_source_name: info.default_source_name.as_ref().map(|cow| cow.to_string()),
350            cookie: info.cookie,
351            channel_map: info.channel_map,
352        }
353    }
354}