1 // Copyright © 2017 Mozilla Foundation
2 //
3 // This program is made available under an ISC-style license.  See the
4 // accompanying file LICENSE for details.
5 
6 #[macro_use]
7 extern crate bitflags;
8 extern crate pulse_ffi as ffi;
9 
10 #[macro_use]
11 mod error;
12 mod context;
13 mod mainloop_api;
14 mod operation;
15 mod proplist;
16 mod stream;
17 mod threaded_mainloop;
18 mod util;
19 
20 pub use context::Context;
21 pub use error::ErrorCode;
22 pub use ffi::pa_buffer_attr as BufferAttr;
23 pub use ffi::pa_channel_map as ChannelMap;
24 pub use ffi::pa_cvolume as CVolume;
25 pub use ffi::pa_sample_spec as SampleSpec;
26 pub use ffi::pa_server_info as ServerInfo;
27 pub use ffi::pa_sink_info as SinkInfo;
28 pub use ffi::pa_sink_input_info as SinkInputInfo;
29 pub use ffi::pa_source_info as SourceInfo;
30 pub use ffi::pa_usec_t as USec;
31 pub use ffi::pa_volume_t as Volume;
32 pub use ffi::timeval as TimeVal;
33 pub use mainloop_api::MainloopApi;
34 pub use operation::Operation;
35 pub use proplist::Proplist;
36 use std::os::raw::{c_char, c_uint};
37 pub use stream::Stream;
38 pub use threaded_mainloop::ThreadedMainloop;
39 
40 #[allow(non_camel_case_types)]
41 #[repr(i32)]
42 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
43 pub enum SampleFormat {
44     Invalid = ffi::PA_SAMPLE_INVALID,
45     U8 = ffi::PA_SAMPLE_U8,
46     Alaw = ffi::PA_SAMPLE_ALAW,
47     Ulaw = ffi::PA_SAMPLE_ULAW,
48     Signed16LE = ffi::PA_SAMPLE_S16LE,
49     Signed16BE = ffi::PA_SAMPLE_S16BE,
50     Float32LE = ffi::PA_SAMPLE_FLOAT32LE,
51     Float32BE = ffi::PA_SAMPLE_FLOAT32BE,
52     Signed32LE = ffi::PA_SAMPLE_S32LE,
53     Signed32BE = ffi::PA_SAMPLE_S32BE,
54     Signed24LE = ffi::PA_SAMPLE_S24LE,
55     Signed24BE = ffi::PA_SAMPLE_S24BE,
56     Signed24_32LE = ffi::PA_SAMPLE_S24_32LE,
57     Signed23_32BE = ffi::PA_SAMPLE_S24_32BE,
58 }
59 
60 impl Default for SampleFormat {
default() -> Self61     fn default() -> Self {
62         SampleFormat::Invalid
63     }
64 }
65 
66 impl Into<ffi::pa_sample_format_t> for SampleFormat {
into(self) -> ffi::pa_sample_format_t67     fn into(self) -> ffi::pa_sample_format_t {
68         self as ffi::pa_sample_format_t
69     }
70 }
71 
72 #[repr(i32)]
73 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
74 pub enum ContextState {
75     Unconnected = ffi::PA_CONTEXT_UNCONNECTED,
76     Connecting = ffi::PA_CONTEXT_CONNECTING,
77     Authorizing = ffi::PA_CONTEXT_AUTHORIZING,
78     SettingName = ffi::PA_CONTEXT_SETTING_NAME,
79     Ready = ffi::PA_CONTEXT_READY,
80     Failed = ffi::PA_CONTEXT_FAILED,
81     Terminated = ffi::PA_CONTEXT_TERMINATED,
82 }
83 
84 impl ContextState {
85     // This function implements the PA_CONTENT_IS_GOOD macro from pulse/def.h
86     // It must match the version from PA headers.
is_good(self) -> bool87     pub fn is_good(self) -> bool {
88         match self {
89             ContextState::Connecting |
90             ContextState::Authorizing |
91             ContextState::SettingName |
92             ContextState::Ready => true,
93             _ => false,
94         }
95     }
96 
try_from(x: ffi::pa_context_state_t) -> Option<Self>97     pub fn try_from(x: ffi::pa_context_state_t) -> Option<Self> {
98         if x >= ffi::PA_CONTEXT_UNCONNECTED && x <= ffi::PA_CONTEXT_TERMINATED {
99             Some(unsafe { ::std::mem::transmute(x) })
100         } else {
101             None
102         }
103     }
104 }
105 
106 impl Default for ContextState {
default() -> Self107     fn default() -> Self {
108         ContextState::Unconnected
109     }
110 }
111 
112 impl Into<ffi::pa_context_state_t> for ContextState {
into(self) -> ffi::pa_context_state_t113     fn into(self) -> ffi::pa_context_state_t {
114         self as ffi::pa_context_state_t
115     }
116 }
117 
118 #[repr(i32)]
119 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
120 pub enum StreamState {
121     Unconnected = ffi::PA_STREAM_UNCONNECTED,
122     Creating = ffi::PA_STREAM_CREATING,
123     Ready = ffi::PA_STREAM_READY,
124     Failed = ffi::PA_STREAM_FAILED,
125     Terminated = ffi::PA_STREAM_TERMINATED,
126 }
127 
128 impl StreamState {
129     // This function implements the PA_STREAM_IS_GOOD macro from pulse/def.h
130     // It must match the version from PA headers.
is_good(self) -> bool131     pub fn is_good(self) -> bool {
132         match self {
133             StreamState::Creating | StreamState::Ready => true,
134             _ => false,
135         }
136     }
137 
try_from(x: ffi::pa_stream_state_t) -> Option<Self>138     pub fn try_from(x: ffi::pa_stream_state_t) -> Option<Self> {
139         if x >= ffi::PA_STREAM_UNCONNECTED && x <= ffi::PA_STREAM_TERMINATED {
140             Some(unsafe { ::std::mem::transmute(x) })
141         } else {
142             None
143         }
144     }
145 }
146 
147 impl Default for StreamState {
default() -> Self148     fn default() -> Self {
149         StreamState::Unconnected
150     }
151 }
152 
153 impl Into<ffi::pa_stream_state_t> for StreamState {
into(self) -> ffi::pa_stream_state_t154     fn into(self) -> ffi::pa_stream_state_t {
155         self as ffi::pa_stream_state_t
156     }
157 }
158 
159 #[repr(i32)]
160 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
161 pub enum OperationState {
162     Running = ffi::PA_OPERATION_RUNNING,
163     Done = ffi::PA_OPERATION_DONE,
164     Cancelled = ffi::PA_OPERATION_CANCELLED,
165 }
166 
167 impl OperationState {
try_from(x: ffi::pa_operation_state_t) -> Option<Self>168     pub fn try_from(x: ffi::pa_operation_state_t) -> Option<Self> {
169         if x >= ffi::PA_OPERATION_RUNNING && x <= ffi::PA_OPERATION_CANCELLED {
170             Some(unsafe { ::std::mem::transmute(x) })
171         } else {
172             None
173         }
174     }
175 }
176 
177 impl Into<ffi::pa_operation_state_t> for OperationState {
into(self) -> ffi::pa_operation_state_t178     fn into(self) -> ffi::pa_operation_state_t {
179         self as ffi::pa_operation_state_t
180     }
181 }
182 
183 bitflags! {
184     pub struct ContextFlags: u32 {
185         const NOAUTOSPAWN = ffi::PA_CONTEXT_NOAUTOSPAWN;
186         const NOFAIL = ffi::PA_CONTEXT_NOFAIL;
187     }
188 }
189 
190 impl Into<ffi::pa_context_flags_t> for ContextFlags {
into(self) -> ffi::pa_context_flags_t191     fn into(self) -> ffi::pa_context_flags_t {
192         self.bits() as ffi::pa_context_flags_t
193     }
194 }
195 
196 #[repr(i32)]
197 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
198 pub enum DeviceType {
199     Sink = ffi::PA_DEVICE_TYPE_SINK,
200     Source = ffi::PA_DEVICE_TYPE_SOURCE,
201 }
202 
203 impl DeviceType {
try_from(x: ffi::pa_device_type_t) -> Option<Self>204     pub fn try_from(x: ffi::pa_device_type_t) -> Option<Self> {
205         if x >= ffi::PA_DEVICE_TYPE_SINK && x <= ffi::PA_DEVICE_TYPE_SOURCE {
206             Some(unsafe { ::std::mem::transmute(x) })
207         } else {
208             None
209         }
210     }
211 }
212 
213 impl Into<ffi::pa_device_type_t> for DeviceType {
into(self) -> ffi::pa_device_type_t214     fn into(self) -> ffi::pa_device_type_t {
215         self as ffi::pa_device_type_t
216     }
217 }
218 
219 
220 #[repr(i32)]
221 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
222 pub enum StreamDirection {
223     NoDirection = ffi::PA_STREAM_NODIRECTION,
224     Playback = ffi::PA_STREAM_PLAYBACK,
225     Record = ffi::PA_STREAM_RECORD,
226     StreamUpload = ffi::PA_STREAM_UPLOAD,
227 }
228 
229 impl StreamDirection {
try_from(x: ffi::pa_stream_direction_t) -> Option<Self>230     pub fn try_from(x: ffi::pa_stream_direction_t) -> Option<Self> {
231         if x >= ffi::PA_STREAM_NODIRECTION && x <= ffi::PA_STREAM_UPLOAD {
232             Some(unsafe { ::std::mem::transmute(x) })
233         } else {
234             None
235         }
236     }
237 }
238 
239 impl Into<ffi::pa_stream_direction_t> for StreamDirection {
into(self) -> ffi::pa_stream_direction_t240     fn into(self) -> ffi::pa_stream_direction_t {
241         self as ffi::pa_stream_direction_t
242     }
243 }
244 
245 bitflags! {
246     pub struct StreamFlags : u32 {
247         const START_CORKED = ffi::PA_STREAM_START_CORKED;
248         const INTERPOLATE_TIMING = ffi::PA_STREAM_INTERPOLATE_TIMING;
249         const NOT_MONOTONIC = ffi::PA_STREAM_NOT_MONOTONIC;
250         const AUTO_TIMING_UPDATE = ffi::PA_STREAM_AUTO_TIMING_UPDATE;
251         const NO_REMAP_CHANNELS = ffi::PA_STREAM_NO_REMAP_CHANNELS;
252         const NO_REMIX_CHANNELS = ffi::PA_STREAM_NO_REMIX_CHANNELS;
253         const FIX_FORMAT = ffi::PA_STREAM_FIX_FORMAT;
254         const FIX_RATE = ffi::PA_STREAM_FIX_RATE;
255         const FIX_CHANNELS = ffi::PA_STREAM_FIX_CHANNELS;
256         const DONT_MOVE = ffi::PA_STREAM_DONT_MOVE;
257         const VARIABLE_RATE = ffi::PA_STREAM_VARIABLE_RATE;
258         const PEAK_DETECT = ffi::PA_STREAM_PEAK_DETECT;
259         const START_MUTED = ffi::PA_STREAM_START_MUTED;
260         const ADJUST_LATENCY = ffi::PA_STREAM_ADJUST_LATENCY;
261         const EARLY_REQUESTS = ffi::PA_STREAM_EARLY_REQUESTS;
262         const DONT_INHIBIT_AUTO_SUSPEND = ffi::PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND;
263         const START_UNMUTED = ffi::PA_STREAM_START_UNMUTED;
264         const FAIL_ON_SUSPEND = ffi::PA_STREAM_FAIL_ON_SUSPEND;
265         const RELATIVE_VOLUME = ffi::PA_STREAM_RELATIVE_VOLUME;
266         const PASSTHROUGH = ffi::PA_STREAM_PASSTHROUGH;
267     }
268 }
269 
270 impl StreamFlags {
try_from(x: ffi::pa_stream_flags_t) -> Option<Self>271     pub fn try_from(x: ffi::pa_stream_flags_t) -> Option<Self> {
272         if (x &
273             !(ffi::PA_STREAM_NOFLAGS | ffi::PA_STREAM_START_CORKED | ffi::PA_STREAM_INTERPOLATE_TIMING |
274               ffi::PA_STREAM_NOT_MONOTONIC | ffi::PA_STREAM_AUTO_TIMING_UPDATE |
275               ffi::PA_STREAM_NO_REMAP_CHANNELS |
276               ffi::PA_STREAM_NO_REMIX_CHANNELS | ffi::PA_STREAM_FIX_FORMAT | ffi::PA_STREAM_FIX_RATE |
277               ffi::PA_STREAM_FIX_CHANNELS |
278               ffi::PA_STREAM_DONT_MOVE | ffi::PA_STREAM_VARIABLE_RATE | ffi::PA_STREAM_PEAK_DETECT |
279               ffi::PA_STREAM_START_MUTED | ffi::PA_STREAM_ADJUST_LATENCY |
280               ffi::PA_STREAM_EARLY_REQUESTS |
281               ffi::PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND |
282               ffi::PA_STREAM_START_UNMUTED | ffi::PA_STREAM_FAIL_ON_SUSPEND |
283               ffi::PA_STREAM_RELATIVE_VOLUME | ffi::PA_STREAM_PASSTHROUGH)) == 0 {
284             Some(unsafe { ::std::mem::transmute(x) })
285         } else {
286             None
287         }
288     }
289 }
290 
291 impl Into<ffi::pa_stream_flags_t> for StreamFlags {
into(self) -> ffi::pa_stream_flags_t292     fn into(self) -> ffi::pa_stream_flags_t {
293         self.bits() as ffi::pa_stream_flags_t
294     }
295 }
296 
297 pub enum StreamLatency {
298     Positive(u64),
299     Negative(u64),
300 }
301 
302 bitflags!{
303     pub struct SubscriptionMask : u32 {
304         const SINK = ffi::PA_SUBSCRIPTION_MASK_SINK;
305         const SOURCE = ffi::PA_SUBSCRIPTION_MASK_SOURCE;
306         const SINK_INPUT = ffi::PA_SUBSCRIPTION_MASK_SINK_INPUT;
307         const SOURCE_OUTPUT = ffi::PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT;
308         const MODULE = ffi::PA_SUBSCRIPTION_MASK_MODULE;
309         const CLIENT = ffi::PA_SUBSCRIPTION_MASK_CLIENT;
310         const SAMPLE_CACHE = ffi::PA_SUBSCRIPTION_MASK_SAMPLE_CACHE;
311         const SERVER = ffi::PA_SUBSCRIPTION_MASK_SERVER;
312         const AUTOLOAD = ffi::PA_SUBSCRIPTION_MASK_AUTOLOAD;
313         const CARD = ffi::PA_SUBSCRIPTION_MASK_CARD;
314     }
315 }
316 
317 impl SubscriptionMask {
try_from(x: ffi::pa_subscription_mask_t) -> Option<Self>318     pub fn try_from(x: ffi::pa_subscription_mask_t) -> Option<Self> {
319         if (x & !ffi::PA_SUBSCRIPTION_MASK_ALL) == 0 {
320             Some(unsafe { ::std::mem::transmute(x) })
321         } else {
322             None
323         }
324     }
325 }
326 
327 impl Into<ffi::pa_subscription_mask_t> for SubscriptionMask {
into(self) -> ffi::pa_subscription_mask_t328     fn into(self) -> ffi::pa_subscription_mask_t {
329         self.bits() as ffi::pa_subscription_mask_t
330     }
331 }
332 
333 #[repr(i32)]
334 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
335 pub enum SubscriptionEventFacility {
336     Sink = ffi::PA_SUBSCRIPTION_EVENT_SINK,
337     Source = ffi::PA_SUBSCRIPTION_EVENT_SOURCE,
338     SinkInput = ffi::PA_SUBSCRIPTION_EVENT_SINK_INPUT,
339     SourceOutput = ffi::PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT,
340     Module = ffi::PA_SUBSCRIPTION_EVENT_MODULE,
341     Client = ffi::PA_SUBSCRIPTION_EVENT_CLIENT,
342     SampleCache = ffi::PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE,
343     Server = ffi::PA_SUBSCRIPTION_EVENT_SERVER,
344     Autoload = ffi::PA_SUBSCRIPTION_EVENT_AUTOLOAD,
345     Card = ffi::PA_SUBSCRIPTION_EVENT_CARD,
346 }
347 
348 #[repr(C)]
349 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
350 pub enum SubscriptionEventType {
351     New,
352     Change,
353     Remove,
354 }
355 
356 #[repr(C)]
357 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
358 pub struct SubscriptionEvent(ffi::pa_subscription_event_type_t);
359 impl SubscriptionEvent {
try_from(x: ffi::pa_subscription_event_type_t) -> Option<Self>360     pub fn try_from(x: ffi::pa_subscription_event_type_t) -> Option<Self> {
361         if (x & !(ffi::PA_SUBSCRIPTION_EVENT_TYPE_MASK | ffi::PA_SUBSCRIPTION_EVENT_FACILITY_MASK)) == 0 {
362             Some(SubscriptionEvent(x))
363         } else {
364             None
365         }
366     }
367 
event_facility(self) -> SubscriptionEventFacility368     pub fn event_facility(self) -> SubscriptionEventFacility {
369         unsafe { ::std::mem::transmute(self.0 & ffi::PA_SUBSCRIPTION_EVENT_FACILITY_MASK) }
370     }
371 
event_type(self) -> SubscriptionEventType372     pub fn event_type(self) -> SubscriptionEventType {
373         unsafe { ::std::mem::transmute((self.0 & ffi::PA_SUBSCRIPTION_EVENT_TYPE_MASK) >> 4) }
374     }
375 }
376 
377 #[repr(i32)]
378 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
379 pub enum SeekMode {
380     Relative = ffi::PA_SEEK_RELATIVE,
381     Absolute = ffi::PA_SEEK_ABSOLUTE,
382     RelativeOnRead = ffi::PA_SEEK_RELATIVE_ON_READ,
383     RelativeEnd = ffi::PA_SEEK_RELATIVE_END,
384 }
385 
386 impl SeekMode {
try_from(x: ffi::pa_seek_mode_t) -> Option<Self>387     pub fn try_from(x: ffi::pa_seek_mode_t) -> Option<Self> {
388         if x >= ffi::PA_SEEK_RELATIVE && x <= ffi::PA_SEEK_RELATIVE_END {
389             Some(unsafe { ::std::mem::transmute(x) })
390         } else {
391             None
392         }
393     }
394 }
395 
396 impl Into<ffi::pa_seek_mode_t> for SeekMode {
into(self) -> ffi::pa_seek_mode_t397     fn into(self) -> ffi::pa_seek_mode_t {
398         self as ffi::pa_seek_mode_t
399     }
400 }
401 
402 bitflags! {
403     pub struct SinkFlags: u32 {
404         const HW_VOLUME_CTRL = ffi::PA_SINK_HW_VOLUME_CTRL;
405         const LATENCY = ffi::PA_SINK_LATENCY;
406         const HARDWARE = ffi::PA_SINK_HARDWARE;
407         const NETWORK = ffi::PA_SINK_NETWORK;
408         const HW_MUTE_CTRL = ffi::PA_SINK_HW_MUTE_CTRL;
409         const DECIBEL_VOLUME = ffi::PA_SINK_DECIBEL_VOLUME;
410         const FLAT_VOLUME = ffi::PA_SINK_FLAT_VOLUME;
411         const DYNAMIC_LATENCY = ffi::PA_SINK_DYNAMIC_LATENCY;
412         const SET_FORMATS = ffi::PA_SINK_SET_FORMATS;
413     }
414 }
415 
416 impl SinkFlags {
try_from(x: ffi::pa_sink_flags_t) -> Option<SinkFlags>417     pub fn try_from(x: ffi::pa_sink_flags_t) -> Option<SinkFlags> {
418         if (x &
419             !(ffi::PA_SINK_NOFLAGS | ffi::PA_SINK_HW_VOLUME_CTRL | ffi::PA_SINK_LATENCY |
420               ffi::PA_SINK_HARDWARE | ffi::PA_SINK_NETWORK | ffi::PA_SINK_HW_MUTE_CTRL |
421               ffi::PA_SINK_DECIBEL_VOLUME | ffi::PA_SINK_DYNAMIC_LATENCY |
422               ffi::PA_SINK_FLAT_VOLUME | ffi::PA_SINK_SET_FORMATS)) == 0 {
423             Some(unsafe { ::std::mem::transmute(x) })
424         } else {
425             None
426         }
427     }
428 }
429 
430 #[repr(i32)]
431 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
432 pub enum SinkState {
433     InvalidState = ffi::PA_SINK_INVALID_STATE,
434     Running = ffi::PA_SINK_RUNNING,
435     Idle = ffi::PA_SINK_IDLE,
436     Suspended = ffi::PA_SINK_SUSPENDED,
437     Init = ffi::PA_SINK_INIT,
438     Unlinked = ffi::PA_SINK_UNLINKED,
439 }
440 
441 bitflags!{
442     pub struct SourceFlags: u32 {
443         const HW_VOLUME_CTRL = ffi::PA_SOURCE_HW_VOLUME_CTRL;
444         const LATENCY = ffi::PA_SOURCE_LATENCY;
445         const HARDWARE = ffi::PA_SOURCE_HARDWARE;
446         const NETWORK = ffi::PA_SOURCE_NETWORK;
447         const HW_MUTE_CTRL = ffi::PA_SOURCE_HW_MUTE_CTRL;
448         const DECIBEL_VOLUME = ffi::PA_SOURCE_DECIBEL_VOLUME;
449         const DYNAMIC_LATENCY = ffi::PA_SOURCE_DYNAMIC_LATENCY;
450         const FLAT_VOLUME = ffi::PA_SOURCE_FLAT_VOLUME;
451     }
452 }
453 
454 impl Into<ffi::pa_source_flags_t> for SourceFlags {
into(self) -> ffi::pa_source_flags_t455     fn into(self) -> ffi::pa_source_flags_t {
456         self.bits() as ffi::pa_source_flags_t
457     }
458 }
459 
460 #[repr(i32)]
461 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
462 pub enum SourceState {
463     InvalidState = ffi::PA_SOURCE_INVALID_STATE,
464     Running = ffi::PA_SOURCE_RUNNING,
465     Idle = ffi::PA_SOURCE_IDLE,
466     Suspended = ffi::PA_SOURCE_SUSPENDED,
467     Init = ffi::PA_SOURCE_INIT,
468     Unlinked = ffi::PA_SOURCE_UNLINKED,
469 }
470 
471 #[repr(i32)]
472 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
473 pub enum PortAvailable {
474     Unknown = ffi::PA_PORT_AVAILABLE_UNKNOWN,
475     No = ffi::PA_PORT_AVAILABLE_NO,
476     Yes = ffi::PA_PORT_AVAILABLE_YES,
477 }
478 
479 impl PortAvailable {
try_from(x: ffi::pa_port_available_t) -> Option<Self>480     pub fn try_from(x: ffi::pa_port_available_t) -> Option<Self> {
481         if x >= ffi::PA_PORT_AVAILABLE_UNKNOWN && x <= ffi::PA_PORT_AVAILABLE_YES {
482             Some(unsafe { ::std::mem::transmute(x) })
483         } else {
484             None
485         }
486     }
487 }
488 
489 impl Into<ffi::pa_port_available_t> for PortAvailable {
into(self) -> ffi::pa_port_available_t490     fn into(self) -> ffi::pa_port_available_t {
491         self as ffi::pa_port_available_t
492     }
493 }
494 
495 #[repr(i32)]
496 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
497 pub enum ChannelPosition {
498     Invalid = ffi::PA_CHANNEL_POSITION_INVALID,
499     Mono = ffi::PA_CHANNEL_POSITION_MONO,
500     FrontLeft = ffi::PA_CHANNEL_POSITION_FRONT_LEFT,
501     FrontRight = ffi::PA_CHANNEL_POSITION_FRONT_RIGHT,
502     FrontCenter = ffi::PA_CHANNEL_POSITION_FRONT_CENTER,
503     RearCenter = ffi::PA_CHANNEL_POSITION_REAR_CENTER,
504     RearLeft = ffi::PA_CHANNEL_POSITION_REAR_LEFT,
505     RearRight = ffi::PA_CHANNEL_POSITION_REAR_RIGHT,
506     LowFreqEffects = ffi::PA_CHANNEL_POSITION_LFE,
507     FrontLeftOfCenter = ffi::PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
508     FrontRightOfCenter = ffi::PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
509     SideLeft = ffi::PA_CHANNEL_POSITION_SIDE_LEFT,
510     SideRight = ffi::PA_CHANNEL_POSITION_SIDE_RIGHT,
511     Aux0 = ffi::PA_CHANNEL_POSITION_AUX0,
512     Aux1 = ffi::PA_CHANNEL_POSITION_AUX1,
513     Aux2 = ffi::PA_CHANNEL_POSITION_AUX2,
514     Aux3 = ffi::PA_CHANNEL_POSITION_AUX3,
515     Aux4 = ffi::PA_CHANNEL_POSITION_AUX4,
516     Aux5 = ffi::PA_CHANNEL_POSITION_AUX5,
517     Aux6 = ffi::PA_CHANNEL_POSITION_AUX6,
518     Aux7 = ffi::PA_CHANNEL_POSITION_AUX7,
519     Aux8 = ffi::PA_CHANNEL_POSITION_AUX8,
520     Aux9 = ffi::PA_CHANNEL_POSITION_AUX9,
521     Aux10 = ffi::PA_CHANNEL_POSITION_AUX10,
522     Aux11 = ffi::PA_CHANNEL_POSITION_AUX11,
523     Aux12 = ffi::PA_CHANNEL_POSITION_AUX12,
524     Aux13 = ffi::PA_CHANNEL_POSITION_AUX13,
525     Aux14 = ffi::PA_CHANNEL_POSITION_AUX14,
526     Aux15 = ffi::PA_CHANNEL_POSITION_AUX15,
527     Aux16 = ffi::PA_CHANNEL_POSITION_AUX16,
528     Aux17 = ffi::PA_CHANNEL_POSITION_AUX17,
529     Aux18 = ffi::PA_CHANNEL_POSITION_AUX18,
530     Aux19 = ffi::PA_CHANNEL_POSITION_AUX19,
531     Aux20 = ffi::PA_CHANNEL_POSITION_AUX20,
532     Aux21 = ffi::PA_CHANNEL_POSITION_AUX21,
533     Aux22 = ffi::PA_CHANNEL_POSITION_AUX22,
534     Aux23 = ffi::PA_CHANNEL_POSITION_AUX23,
535     Aux24 = ffi::PA_CHANNEL_POSITION_AUX24,
536     Aux25 = ffi::PA_CHANNEL_POSITION_AUX25,
537     Aux26 = ffi::PA_CHANNEL_POSITION_AUX26,
538     Aux27 = ffi::PA_CHANNEL_POSITION_AUX27,
539     Aux28 = ffi::PA_CHANNEL_POSITION_AUX28,
540     Aux29 = ffi::PA_CHANNEL_POSITION_AUX29,
541     Aux30 = ffi::PA_CHANNEL_POSITION_AUX30,
542     Aux31 = ffi::PA_CHANNEL_POSITION_AUX31,
543     TopCenter = ffi::PA_CHANNEL_POSITION_TOP_CENTER,
544     TopFrontLeft = ffi::PA_CHANNEL_POSITION_TOP_FRONT_LEFT,
545     TopFrontRight = ffi::PA_CHANNEL_POSITION_TOP_FRONT_RIGHT,
546     TopFrontCenter = ffi::PA_CHANNEL_POSITION_TOP_FRONT_CENTER,
547     TopRearLeft = ffi::PA_CHANNEL_POSITION_TOP_REAR_LEFT,
548     TopRearRight = ffi::PA_CHANNEL_POSITION_TOP_REAR_RIGHT,
549     TopRearCenter = ffi::PA_CHANNEL_POSITION_TOP_REAR_CENTER,
550 }
551 
552 impl ChannelPosition {
try_from(x: ffi::pa_channel_position_t) -> Option<Self>553     pub fn try_from(x: ffi::pa_channel_position_t) -> Option<Self> {
554         if x >= ffi::PA_CHANNEL_POSITION_INVALID && x < ffi::PA_CHANNEL_POSITION_MAX {
555             Some(unsafe { ::std::mem::transmute(x) })
556         } else {
557             None
558         }
559     }
560 }
561 
562 impl Default for ChannelPosition {
default() -> Self563     fn default() -> Self {
564         ChannelPosition::Invalid
565     }
566 }
567 
568 impl Into<ffi::pa_channel_position_t> for ChannelPosition {
into(self) -> ffi::pa_channel_position_t569     fn into(self) -> ffi::pa_channel_position_t {
570         self as ffi::pa_channel_position_t
571     }
572 }
573 pub type Result<T> = ::std::result::Result<T, error::ErrorCode>;
574 
575 pub trait CVolumeExt {
set(&mut self, channels: c_uint, v: Volume)576     fn set(&mut self, channels: c_uint, v: Volume);
set_balance(&mut self, map: &ChannelMap, new_balance: f32)577     fn set_balance(&mut self, map: &ChannelMap, new_balance: f32);
578 }
579 
580 impl CVolumeExt for CVolume {
set(&mut self, channels: c_uint, v: Volume)581     fn set(&mut self, channels: c_uint, v: Volume) {
582         unsafe {
583             ffi::pa_cvolume_set(self, channels, v);
584         }
585     }
586 
set_balance(&mut self, map: &ChannelMap, new_balance: f32)587     fn set_balance(&mut self, map: &ChannelMap, new_balance: f32) {
588         unsafe {
589             ffi::pa_cvolume_set_balance(self, map, new_balance);
590         }
591     }
592 }
593 
594 pub trait ChannelMapExt {
init() -> ChannelMap595     fn init() -> ChannelMap;
init_auto(ch: u32, def: ffi::pa_channel_map_def_t) -> Option<ChannelMap>596     fn init_auto(ch: u32, def: ffi::pa_channel_map_def_t) -> Option<ChannelMap>;
can_balance(&self) -> bool597     fn can_balance(&self) -> bool;
598 }
599 
600 impl ChannelMapExt for ChannelMap {
init() -> ChannelMap601     fn init() -> ChannelMap {
602         let mut cm = ChannelMap::default();
603         unsafe {
604             ffi::pa_channel_map_init(&mut cm);
605         }
606         cm
607     }
init_auto(ch: u32, def: ffi::pa_channel_map_def_t) -> Option<ChannelMap>608     fn init_auto(ch: u32, def: ffi::pa_channel_map_def_t) -> Option<ChannelMap> {
609         let mut cm = ChannelMap::default();
610         let r: *mut ffi::pa_channel_map = unsafe {
611             ffi::pa_channel_map_init_auto(&mut cm, ch, def)
612         };
613         if r.is_null() {
614             None
615         } else {
616             Some(cm)
617         }
618     }
can_balance(&self) -> bool619     fn can_balance(&self) -> bool {
620         unsafe { ffi::pa_channel_map_can_balance(self) > 0 }
621     }
622 }
623 
624 pub trait ProplistExt {
proplist(&self) -> Proplist625     fn proplist(&self) -> Proplist;
626 }
627 
628 impl ProplistExt for SinkInfo {
proplist(&self) -> Proplist629     fn proplist(&self) -> Proplist {
630         unsafe { proplist::from_raw_ptr(self.proplist) }
631     }
632 }
633 
634 impl ProplistExt for SourceInfo {
proplist(&self) -> Proplist635     fn proplist(&self) -> Proplist {
636         unsafe { proplist::from_raw_ptr(self.proplist) }
637     }
638 }
639 
640 pub trait SampleSpecExt {
frame_size(&self) -> usize641     fn frame_size(&self) -> usize;
sample_size(&self) -> usize642     fn sample_size(&self) -> usize;
643 }
644 
645 impl SampleSpecExt for SampleSpec {
frame_size(&self) -> usize646     fn frame_size(&self) -> usize {
647         unsafe { ffi::pa_frame_size(self) }
648     }
sample_size(&self) -> usize649     fn sample_size(&self) -> usize {
650         unsafe { ffi::pa_sample_size(self) }
651     }
652 }
653 
654 pub trait USecExt {
to_bytes(self, spec: &SampleSpec) -> usize655     fn to_bytes(self, spec: &SampleSpec) -> usize;
656 }
657 
658 impl USecExt for USec {
to_bytes(self, spec: &SampleSpec) -> usize659     fn to_bytes(self, spec: &SampleSpec) -> usize {
660         unsafe { ffi::pa_usec_to_bytes(self, spec) }
661     }
662 }
663 
library_version() -> *const c_char664 pub fn library_version() -> *const c_char {
665     unsafe { ffi::pa_get_library_version() }
666 }
667 
sw_volume_from_linear(vol: f64) -> Volume668 pub fn sw_volume_from_linear(vol: f64) -> Volume {
669     unsafe { ffi::pa_sw_volume_from_linear(vol) }
670 }
671 
rtclock_now() -> USec672 pub fn rtclock_now() -> USec {
673     unsafe { ffi::pa_rtclock_now() }
674 }
675