libpulse_binding/
def.rs

1// Copyright 2017 Lyndon Brown
2//
3// This file is part of the PulseAudio Rust language binding.
4//
5// Licensed under the MIT license or the Apache license (version 2.0), at your option. You may not
6// copy, modify, or distribute this file except in compliance with said license. You can find copies
7// of these licenses either in the LICENSE-MIT and LICENSE-APACHE files, or alternatively at
8// <http://opensource.org/licenses/MIT> and <http://www.apache.org/licenses/LICENSE-2.0>
9// respectively.
10//
11// Portions of documentation are copied from the LGPL 2.1+ licensed PulseAudio C headers on a
12// fair-use basis, as discussed in the overall project readme (available in the git repository).
13
14//! Global definitions.
15
16use std::os::raw::c_void;
17use bitflags::bitflags;
18use num_derive::{FromPrimitive, ToPrimitive};
19use crate::time::{MicroSeconds, UnixTs};
20
21pub use capi::PA_INVALID_INDEX as INVALID_INDEX;
22pub use capi::pa_device_type_t as Device;
23pub use capi::pa_port_available_t as PortAvailable;
24pub use capi::pa_device_port_type_t as DevicePortType;
25
26/// A callback type for releasing allocations.
27pub type FreeCb = extern "C" fn(p: *mut c_void);
28
29/// PulseAudio 'quit return value' type.
30pub type RetvalActual = i32;
31
32/// A wrapper around integer ‘quit return values’ returned by PulseAudio.
33#[repr(transparent)]
34#[derive(Debug, Copy, Clone, PartialEq, Eq)]
35pub struct Retval(pub RetvalActual);
36
37/// Playback and record buffer metrics.
38#[repr(C)]
39#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
40pub struct BufferAttr {
41    /* NOTE: This struct must be directly usable by the C API, thus same attributes/layout/etc */
42
43    /// Maximum length of the buffer in bytes.
44    ///
45    /// Setting this to [`std::u32::MAX`] will initialize this to the maximum value supported by the
46    /// server, which is recommended. In strict low-latency playback scenarios you might want to set
47    /// this to a lower value, likely together with the [`stream::FlagSet::ADJUST_LATENCY`] flag. If
48    /// you do so, you ensure that the latency doesn’t grow beyond what is acceptable for the use
49    /// case, at the cost of getting more underruns if the latency is lower than what the server can
50    /// reliably handle.
51    ///
52    /// [`stream::FlagSet::ADJUST_LATENCY`]: crate::stream::FlagSet::ADJUST_LATENCY
53    pub maxlength: u32,
54
55    /// Target length of the buffer (playback only). The server tries to assure that at least
56    /// `tlength` bytes are always available in the per-stream server-side playback buffer. The
57    /// server will only send requests for more data as long as the buffer has less than this number
58    /// of bytes of data.
59    ///
60    /// It is recommended to set this to [`std::u32::MAX`], which will initialize this to a value
61    /// that is deemed sensible by the server. However, this value will default to something like
62    /// 2s; for applications that have specific latency requirements this value should be set to
63    /// the maximum latency that the application can deal with.
64    ///
65    /// When [`stream::FlagSet::ADJUST_LATENCY`] is not set this value will influence only the
66    /// per-stream playback buffer size. When [`stream::FlagSet::ADJUST_LATENCY`] is set, the
67    /// overall latency of the sink plus the playback buffer size is configured to this value. Set
68    /// [`stream::FlagSet::ADJUST_LATENCY`] if you are interested in adjusting the overall latency.
69    /// Don’t set it if you are interested in configuring the server-side per-stream playback buffer
70    /// size.
71    ///
72    /// [`stream::FlagSet::ADJUST_LATENCY`]: crate::stream::FlagSet::ADJUST_LATENCY
73    pub tlength: u32,
74
75    /// Pre-buffering (playback only). The server does not start with playback before at least
76    /// `prebuf` bytes are available in the buffer. It is recommended to set this to
77    /// [`std::u32::MAX`], which will initialize this to the same value as `tlength`, whatever that
78    /// may be.
79    ///
80    /// Initialize to `0` to enable manual start/stop control of the stream. This means that
81    /// playback will not stop on underrun and playback will not start automatically, instead
82    /// [`Stream::cork()`] needs to be called explicitly. If you set this value to `0` you should
83    /// also set [`stream::FlagSet::START_CORKED`]. Should underrun occur, the read index of the
84    /// output buffer overtakes the write index, and hence the fill level of the buffer is negative.
85    ///
86    /// Start of playback can be forced using [`Stream::trigger()`] even though the prebuffer size
87    /// hasn’t been reached. If a buffer underrun occurs, this prebuffering will be again enabled.
88    ///
89    /// [`Stream::cork()`]: crate::stream::Stream::cork
90    /// [`Stream::trigger()`]: crate::stream::Stream::trigger
91    /// [`stream::FlagSet::START_CORKED`]: crate::stream::FlagSet::START_CORKED
92    pub prebuf: u32,
93
94    /// Minimum request (playback only). The server does not request less than `minreq` bytes from
95    /// the client, instead it waits until the buffer is free enough to request more bytes at once.
96    ///
97    /// It is recommended to set this to [`std::u32::MAX`], which will initialize this to a value
98    /// that is deemed sensible by the server. This should be set to a value that gives PulseAudio
99    /// enough time to move the data from the per-stream playback buffer into the hardware playback
100    /// buffer.
101    pub minreq: u32,
102
103    /// Fragment size (recording only). The server sends data in blocks of `fragsize` bytes size.
104    ///
105    /// Large values diminish interactivity with other operations on the connection context but
106    /// decrease control overhead. It is recommended to set this to `std::u32::MAX`, which will
107    /// initialize this to a value that is deemed sensible by the server. However, this value will
108    /// default to something like 2s; For applications that have specific latency requirements this
109    /// value should be set to the maximum latency that the application can deal with.
110    ///
111    /// If [`stream::FlagSet::ADJUST_LATENCY`] is set the overall source latency will be adjusted
112    /// according to this value. If it is not set the source latency is left unmodified.
113    ///
114    /// [`stream::FlagSet::ADJUST_LATENCY`]: crate::stream::FlagSet::ADJUST_LATENCY
115    pub fragsize: u32,
116}
117
118/// Test size is equal to `sys` equivalent (duplicated here for different documentation)
119#[test]
120fn bufferattr_compare_capi() {
121    assert_eq!(std::mem::size_of::<BufferAttr>(), std::mem::size_of::<capi::pa_buffer_attr>());
122    assert_eq!(std::mem::align_of::<BufferAttr>(), std::mem::align_of::<capi::pa_buffer_attr>());
123}
124
125impl AsRef<capi::pa_buffer_attr> for BufferAttr {
126    #[inline]
127    fn as_ref(&self) -> &capi::pa_buffer_attr {
128        unsafe { &*(self as *const Self as *const capi::pa_buffer_attr) }
129    }
130}
131impl AsRef<BufferAttr> for capi::pa_buffer_attr {
132    #[inline]
133    fn as_ref(&self) -> &BufferAttr {
134        unsafe { &*(self as *const Self as *const BufferAttr) }
135    }
136}
137
138/// A structure for all kinds of timing information of a stream.
139///
140/// See [`Stream::update_timing_info()`] and [`Stream::get_timing_info()`].
141///
142/// The total output latency a sample that is written with [`Stream::write()`] takes to be played
143/// may be estimated by:
144///
145/// ``
146/// sink_usec + buffer_usec + transport_usec
147/// ``
148///
149/// (Where `buffer_usec` is defined as the result of passing ``write_index - read_index`` to
150/// [`Spec::bytes_to_usec()`]). The output buffer which `buffer_usec` relates to may be manipulated
151/// freely (with [`Stream::write()`]’s `seek` argument, [`Stream::flush()`] and friends), the
152/// buffers `sink_usec` and `source_usec` relate to are first-in first-out (FIFO) buffers which
153/// cannot be flushed or manipulated in any way. The total input latency a sample that is recorded
154/// takes to be delivered to the application is:
155///
156/// ``
157/// source_usec + buffer_usec + transport_usec - sink_usec
158/// ``
159///
160/// (Take care of sign issues!). When connected to a monitor source `sink_usec` contains the latency
161/// of the owning sink. The two latency estimations described here are implemented in
162/// [`Stream::get_latency()`].
163///
164/// All time values are in the sound card clock domain, unless noted otherwise. The sound card clock
165/// usually runs at a slightly different rate than the system clock.
166///
167/// Please note that this structure can be extended as part of evolutionary API updates at any time
168/// in any new release.
169///
170/// [`Spec::bytes_to_usec()`]: crate::sample::Spec::bytes_to_usec
171/// [`Stream::update_timing_info()`]: crate::stream::Stream::update_timing_info
172/// [`Stream::get_timing_info()`]: crate::stream::Stream::get_timing_info
173/// [`Stream::write()`]: crate::stream::Stream::write
174/// [`Stream::flush()`]: crate::stream::Stream::flush
175/// [`Stream::get_latency()`]: crate::stream::Stream::get_latency
176#[repr(C)]
177#[derive(Debug, Copy, Clone, PartialEq, Eq)]
178pub struct TimingInfo {
179    /* NOTE: This struct must be directly usable by the C API, thus same attributes/layout/etc */
180
181    /// The system clock time when this timing info structure was current.
182    pub timestamp: UnixTs,
183
184    /// Non-zero if the local and the remote machine have synchronized clocks. If synchronized
185    /// clocks are detected `transport_usec` becomes much more reliable. However, the code that
186    /// detects synchronized clocks is very limited and unreliable itself.
187    pub synchronized_clocks: i32,
188
189    /// Time in usecs a sample takes to be played on the sink. For playback streams and record
190    /// streams connected to a monitor source.
191    pub sink_usec: MicroSeconds,
192
193    /// Time in usecs a sample takes from being recorded to being delivered to the application. Only
194    /// for record streams.
195    pub source_usec: MicroSeconds,
196
197    /// Estimated time in usecs a sample takes to be transferred to/from the daemon. For both
198    /// playback and record streams.
199    pub transport_usec: MicroSeconds,
200
201    /// Non-zero when the stream is currently not underrun and data is being passed on to the
202    /// device. Only for playback streams. This field does not say whether the data is actually
203    /// already being played. To determine this check whether `since_underrun` (converted to usec)
204    /// is larger than `sink_usec`.
205    pub playing: i32,
206
207    /// Non-zero if `write_index` is not up-to-date because a local write command that corrupted it
208    /// has been issued in the time since this latency info was current. Only write commands with
209    /// [`SeekMode::RelativeOnRead`] and [`SeekMode::RelativeEnd`] can corrupt `write_index`.
210    ///
211    /// [`SeekMode::RelativeOnRead`]: crate::stream::SeekMode::RelativeOnRead
212    /// [`SeekMode::RelativeEnd`]: crate::stream::SeekMode::RelativeEnd
213    pub write_index_corrupt: i32,
214
215    /// Current write index into the playback buffer in bytes.
216    ///
217    /// Think twice before using this for seeking purposes: it might be out of date at the time you
218    /// want to use it. Consider using [`SeekMode::Relative`] instead.
219    ///
220    /// [`SeekMode::Relative`]: crate::stream::SeekMode::Relative
221    pub write_index: i64,
222
223    /// Non-zero if `read_index` is not up-to-date because a local pause or flush request that
224    /// corrupted it has been issued in the time since this latency info was current.
225    pub read_index_corrupt: i32,
226
227    /// Current read index into the playback buffer in bytes.
228    ///
229    /// Think twice before using this for seeking purposes: it might be out of date at the time you
230    /// want to use it. Consider using [`SeekMode::RelativeOnRead`] instead.
231    ///
232    /// [`SeekMode::RelativeOnRead`]: crate::stream::SeekMode::RelativeOnRead
233    pub read_index: i64,
234
235    /// The configured latency for the sink.
236    pub configured_sink_usec: MicroSeconds,
237
238    /// The configured latency for the source.
239    pub configured_source_usec: MicroSeconds,
240
241    /// Bytes that were handed to the sink since the last underrun happened, or since playback
242    /// started again after the last underrun. `playing` will tell you which case it is.
243    pub since_underrun: i64,
244}
245
246/// Test size is equal to `sys` equivalent (duplicated here for different documentation)
247#[test]
248fn timinginfo_compare_capi() {
249    assert_eq!(std::mem::size_of::<TimingInfo>(), std::mem::size_of::<capi::pa_timing_info>());
250    assert_eq!(std::mem::align_of::<TimingInfo>(), std::mem::align_of::<capi::pa_timing_info>());
251}
252
253impl AsRef<TimingInfo> for capi::pa_timing_info {
254    #[inline]
255    fn as_ref(&self) -> &TimingInfo {
256        unsafe { &*(self as *const Self as *const TimingInfo) }
257    }
258}
259
260/// A structure for the spawn API.
261///
262/// This may be used to integrate auto spawned daemons into your application. For more information
263/// see [`Context::connect()`]. When spawning a new child process the `waitpid()` is used on the
264/// child’s PID. The spawn routine will not block or ignore SIGCHLD signals, since this cannot be
265/// done in a thread compatible way. You might have to do this in prefork/postfork.
266///
267/// [`Context::connect()`]: crate::context::Context::connect
268#[repr(C)]
269#[derive(Debug)]
270pub struct SpawnApi {
271    /* NOTE: This struct must be directly usable by the C API, thus same attributes/layout/etc */
272
273    /// Is called just before the fork in the parent process.
274    pub prefork: Option<extern "C" fn()>,
275
276    /// Is called immediately after the fork in the parent process.
277    pub postfork: Option<extern "C" fn()>,
278
279    /// Is called immediately after the fork in the child process.
280    ///
281    /// It is not safe to close all file descriptors in this function unconditionally, since a UNIX
282    /// socket (created using socketpair()) is passed to the new process.
283    pub atfork: Option<extern "C" fn()>,
284}
285
286/// Test size is equal to `sys` equivalent (duplicated here for different documentation)
287#[test]
288fn spawnapi_compare_capi() {
289    assert_eq!(std::mem::size_of::<SpawnApi>(), std::mem::size_of::<capi::pa_spawn_api>());
290    assert_eq!(std::mem::align_of::<SpawnApi>(), std::mem::align_of::<capi::pa_spawn_api>());
291}
292
293impl AsRef<capi::pa_spawn_api> for SpawnApi {
294    #[inline]
295    fn as_ref(&self) -> &capi::pa_spawn_api {
296        unsafe { &*(self as *const Self as *const capi::pa_spawn_api) }
297    }
298}
299
300bitflags! {
301    /// Set of sink flags.
302    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
303    #[repr(transparent)]
304    pub struct SinkFlagSet: u32 {
305        /// Flag to pass when no specific options are needed.
306        const NOFLAGS = capi::PA_SINK_NOFLAGS;
307
308        /// Supports hardware volume control. This is a dynamic flag and may change at runtime after
309        /// the sink has initialized.
310        const HW_VOLUME_CTRL = capi::PA_SINK_HW_VOLUME_CTRL;
311
312        /// Supports latency querying.
313        const LATENCY = capi::PA_SINK_LATENCY;
314
315        /// Is a hardware sink of some kind, in contrast to “virtual”/software sinks.
316        const HARDWARE = capi::PA_SINK_HARDWARE;
317
318        /// Is a networked sink of some kind.
319        const NETWORK = capi::PA_SINK_NETWORK;
320
321        /// Supports hardware mute control. This is a dynamic flag and may change at runtime after
322        /// the sink has initialized.
323        const HW_MUTE_CTRL = capi::PA_SINK_HW_MUTE_CTRL;
324
325        /// Volume can be translated to dB with the `From` based conversions between [`Volume`],
326        /// [`VolumeLinear`] and [`VolumeDB`] types. This is a dynamic flag and may change at
327        /// runtime after the sink has initialized.
328        ///
329        /// [`Volume`]: crate::volume::Volume
330        /// [`VolumeDB`]: crate::volume::VolumeDB
331        /// [`VolumeLinear`]: crate::volume::VolumeLinear
332        const DECIBEL_VOLUME = capi::PA_SINK_DECIBEL_VOLUME;
333
334        /// This sink is in flat volume mode, i.e. always the maximum of the volume  of all
335        /// connected inputs.
336        const FLAT_VOLUME = capi::PA_SINK_FLAT_VOLUME;
337
338        /// The latency can be adjusted dynamically depending on the needs of the connected streams.
339        const DYNAMIC_LATENCY = capi::PA_SINK_DYNAMIC_LATENCY;
340
341        /// The sink allows setting what formats are supported by the connected hardware. The actual
342        /// functionality to do this might be provided by an extension.
343        const SET_FORMATS = capi::PA_SINK_SET_FORMATS;
344    }
345}
346
347/// Sink state.
348#[repr(C)]
349#[derive(Debug, Copy, Clone, PartialEq, Eq)]
350#[derive(FromPrimitive, ToPrimitive)]
351pub enum SinkState {
352    /* NOTE: This enum’s variants and variant values **must** remain identical to the `sys` crate
353       (C API) equivalent */
354
355    /// This state is used when the server does not support sink state introspection.
356    Invalid = -1,
357
358    /// Running, sink is playing and used by at least one non-corked sink-input.
359    Running = 0,
360
361    /// When idle, the sink is playing but there is no non-corked sink-input attached to it.
362    Idle = 1,
363
364    /// When suspended, actual sink access can be closed, for instance.
365    Suspended = 2,
366}
367
368/// Check is equal to `sys` equivalent
369#[test]
370fn sink_state_compare_capi() {
371    assert_eq!(std::mem::size_of::<SinkState>(), std::mem::size_of::<capi::pa_sink_state_t>());
372    assert_eq!(std::mem::align_of::<SinkState>(), std::mem::align_of::<capi::pa_sink_state_t>());
373
374    // Check order and value of variants match
375    // No point checking conversions in both directions since both are a transmute
376    assert_eq!(SinkState::Invalid,   SinkState::from(capi::pa_sink_state_t::Invalid));
377    assert_eq!(SinkState::Running,   SinkState::from(capi::pa_sink_state_t::Running));
378    assert_eq!(SinkState::Idle,      SinkState::from(capi::pa_sink_state_t::Idle));
379    assert_eq!(SinkState::Suspended, SinkState::from(capi::pa_sink_state_t::Suspended));
380}
381
382impl From<SinkState> for capi::pa_sink_state_t {
383    #[inline]
384    fn from(s: SinkState) -> Self {
385        unsafe { std::mem::transmute(s) }
386    }
387}
388impl From<capi::pa_sink_state_t> for SinkState {
389    #[inline]
390    fn from(s: capi::pa_sink_state_t) -> Self {
391        unsafe { std::mem::transmute(s) }
392    }
393}
394
395impl SinkState {
396    /// Checks if sink is playing: running or idle.
397    #[inline]
398    pub fn is_opened(self) -> bool {
399        self == SinkState::Running || self == SinkState::Idle
400    }
401
402    /// Checks if sink is running.
403    #[inline]
404    pub fn is_running(self) -> bool {
405        self == SinkState::Running
406    }
407}
408
409bitflags! {
410    /// Set of source flags.
411    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
412    #[repr(transparent)]
413    pub struct SourceFlagSet: u32 {
414        /// Flag to pass when no specific options are needed.
415        const NOFLAGS = capi::PA_SOURCE_NOFLAGS;
416
417        /// Supports hardware volume control. This is a dynamic flag and may change at runtime after
418        /// the source has initialized.
419        const HW_VOLUME_CTRL = capi::PA_SOURCE_HW_VOLUME_CTRL;
420
421        /// Supports latency querying.
422        const LATENCY = capi::PA_SOURCE_LATENCY;
423
424        /// Is a hardware source of some kind, in contrast to “virtual”/software source.
425        const HARDWARE = capi::PA_SOURCE_HARDWARE;
426
427        /// Is a networked source of some kind.
428        const NETWORK = capi::PA_SOURCE_NETWORK;
429
430        /// Supports hardware mute control. This is a dynamic flag and may change at runtime after
431        /// the source has initialized.
432        const HW_MUTE_CTRL = capi::PA_SOURCE_HW_MUTE_CTRL;
433
434        /// Volume can be translated to dB with the `From` based conversions between [`Volume`],
435        /// [`VolumeLinear`] and [`VolumeDB`] types. This is a dynamic flag and may change at
436        /// runtime after the source has initialized.
437        ///
438        /// [`Volume`]: crate::volume::Volume
439        /// [`VolumeDB`]: crate::volume::VolumeDB
440        /// [`VolumeLinear`]: crate::volume::VolumeLinear
441        const DECIBEL_VOLUME = capi::PA_SOURCE_DECIBEL_VOLUME;
442
443        /// The latency can be adjusted dynamically depending on the needs of the connected streams.
444        const DYNAMIC_LATENCY = capi::PA_SOURCE_DYNAMIC_LATENCY;
445
446        /// This source is in flat volume mode, i.e. always the maximum of the volume of all
447        /// connected outputs.
448        const FLAT_VOLUME = capi::PA_SOURCE_FLAT_VOLUME;
449    }
450}
451
452/// Source state.
453#[repr(C)]
454#[derive(Debug, Copy, Clone, PartialEq, Eq)]
455#[derive(FromPrimitive, ToPrimitive)]
456pub enum SourceState {
457    /* NOTE: This enum’s variants and variant values **must** remain identical to the `sys` crate
458       (C API) equivalent */
459
460    /// This state is used when the server does not support source state introspection.
461    Invalid = -1,
462
463    /// Running, source is recording and used by at least one non-corked source-output.
464    Running = 0,
465
466    /// When idle, the source is still recording but there is no non-corked source-output.
467    Idle = 1,
468
469    /// When suspended, actual source access can be closed, for instance.
470    Suspended = 2,
471}
472
473/// Check is equal to `sys` equivalent
474#[test]
475fn source_state_compare_capi() {
476    assert_eq!(std::mem::size_of::<SourceState>(), std::mem::size_of::<capi::pa_source_state_t>());
477    assert_eq!(std::mem::align_of::<SourceState>(), std::mem::align_of::<capi::pa_source_state_t>());
478
479    // Check order and value of variants match
480    // No point checking conversions in both directions since both are a transmute
481    assert_eq!(SourceState::Invalid,   SourceState::from(capi::pa_source_state_t::Invalid));
482    assert_eq!(SourceState::Running,   SourceState::from(capi::pa_source_state_t::Running));
483    assert_eq!(SourceState::Idle,      SourceState::from(capi::pa_source_state_t::Idle));
484    assert_eq!(SourceState::Suspended, SourceState::from(capi::pa_source_state_t::Suspended));
485}
486
487impl From<SourceState> for capi::pa_source_state_t {
488    #[inline]
489    fn from(s: SourceState) -> Self {
490        unsafe { std::mem::transmute(s) }
491    }
492}
493impl From<capi::pa_source_state_t> for SourceState {
494    #[inline]
495    fn from(s: capi::pa_source_state_t) -> Self {
496        unsafe { std::mem::transmute(s) }
497    }
498}
499
500impl SourceState {
501    /// Checks if source is recording: running or idle.
502    #[inline]
503    pub fn is_opened(self) -> bool {
504        self == SourceState::Running || self == SourceState::Idle
505    }
506
507    /// Checks if source is running.
508    #[inline]
509    pub fn is_running(self) -> bool {
510        self == SourceState::Running
511    }
512}