summaryrefslogtreecommitdiffstats
path: root/third_party/rust/pulse
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/pulse')
-rw-r--r--third_party/rust/pulse/.cargo-checksum.json1
-rw-r--r--third_party/rust/pulse/Cargo.toml22
-rw-r--r--third_party/rust/pulse/src/context.rs487
-rw-r--r--third_party/rust/pulse/src/error.rs54
-rw-r--r--third_party/rust/pulse/src/lib.rs693
-rw-r--r--third_party/rust/pulse/src/mainloop_api.rs60
-rw-r--r--third_party/rust/pulse/src/operation.rs43
-rw-r--r--third_party/rust/pulse/src/proplist.rs32
-rw-r--r--third_party/rust/pulse/src/stream.rs456
-rw-r--r--third_party/rust/pulse/src/threaded_mainloop.rs92
-rw-r--r--third_party/rust/pulse/src/util.rs42
11 files changed, 1982 insertions, 0 deletions
diff --git a/third_party/rust/pulse/.cargo-checksum.json b/third_party/rust/pulse/.cargo-checksum.json
new file mode 100644
index 0000000000..bb4198b1fd
--- /dev/null
+++ b/third_party/rust/pulse/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"630a54435ea8717b2e6ede25b38c97d1dc86b7c0b70e7e14adf9cb392b41e3b1","src/context.rs":"849333d1d3b443700ea13e07696c68b3fe7ad3c4ee136b17ea888c494e871812","src/error.rs":"7cca3f0b0a238743db01d707881eee0c7b5b2ba530d579b6a2bd82bc8dd7dd30","src/lib.rs":"37edfc5ddfaf0a9442f69ca0139a652627f88f7ce68f245ae7f967ce2ba66dc1","src/mainloop_api.rs":"6374f8f62233277f4cf460b9978db0347a8829eb04f62101eaaa5533b6aca769","src/operation.rs":"c0d3e28ef7db52d60b19f931fe7bb44271127009b2e82693da2b7e342e804022","src/proplist.rs":"ce53f1e92fae51727aa564d371b1e0d59078f5cbbd655b39bc1c7741c8ba2f87","src/stream.rs":"ba14551ff34f6b23e94e450384487b3c35be75ac4456c22c14b36ade23282978","src/threaded_mainloop.rs":"057928b5b84b1ea8c839150840ccd88cb944b60ca0aa2ec5389aaa6676c8e505","src/util.rs":"1613909f460eb008b282801ac803dd28b4bfe59926c14fe030da6482fdacd70f"},"package":null} \ No newline at end of file
diff --git a/third_party/rust/pulse/Cargo.toml b/third_party/rust/pulse/Cargo.toml
new file mode 100644
index 0000000000..230b838fde
--- /dev/null
+++ b/third_party/rust/pulse/Cargo.toml
@@ -0,0 +1,22 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+name = "pulse"
+version = "0.3.0"
+authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
+license = "ISC"
+
+[dependencies]
+bitflags = "2"
+
+[dependencies.pulse-ffi]
+path = "../pulse-ffi"
diff --git a/third_party/rust/pulse/src/context.rs b/third_party/rust/pulse/src/context.rs
new file mode 100644
index 0000000000..6c435c9c65
--- /dev/null
+++ b/third_party/rust/pulse/src/context.rs
@@ -0,0 +1,487 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details.
+
+use ffi;
+use std::ffi::CStr;
+use std::mem::{forget, MaybeUninit};
+use std::os::raw::{c_int, c_void};
+use std::ptr;
+use util::UnwrapCStr;
+use *;
+
+// A note about `wrapped` functions
+//
+// C FFI demands `unsafe extern fn(*mut pa_context, ...) -> i32`, etc,
+// but we want to allow such callbacks to be safe. This means no
+// `unsafe` or `extern`, and callbacks should be called with a safe
+// wrapper of `*mut pa_context`. Since the callback doesn't take
+// ownership, this is `&Context`. `fn wrapped<T>(...)` defines a
+// function that converts from our safe signature to the unsafe
+// signature.
+//
+// Currently, we use a property of Rust, namely that each function
+// gets its own unique type. These unique types can't be written
+// directly, so we use generic and a type parameter, and let the Rust
+// compiler fill in the name for us:
+//
+// fn get_sink_input_info<CB>(&self, ..., _: CB, ...) -> ...
+// where CB: Fn(&Context, *const SinkInputInfo, i32, *mut c_void)
+//
+// Because we aren't storing or passing any state, we assert, at run-time :-(,
+// that our functions are zero-sized:
+//
+// assert!(mem::size_of::<F>() == 0);
+//
+// We need to obtain a value of type F in order to call it. Since we
+// can't name the function, we have to unsafely construct that value
+// somehow - we do this using mem::uninitialized. Then, we call that
+// function with a reference to the Context, and save the result:
+//
+// | generate value || call it |
+// let result = ::std::mem::uninitialized::<F>()(&mut object);
+//
+// Lastly, since our Object is an owned type, we need to avoid
+// dropping it, then return the result we just generated.
+//
+// mem::forget(object);
+// result
+
+// Aid in returning Operation from callbacks
+macro_rules! op_or_err {
+ ($self_:ident, $e:expr) => {{
+ let o = unsafe { $e };
+ if o.is_null() {
+ Err(ErrorCode::from_error_code($self_.errno()))
+ } else {
+ Ok(unsafe { operation::from_raw_ptr(o) })
+ }
+ }};
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct Context(*mut ffi::pa_context);
+
+impl Context {
+ pub fn new<'a, OPT>(api: &MainloopApi, name: OPT) -> Option<Self>
+ where
+ OPT: Into<Option<&'a CStr>>,
+ {
+ let ptr = unsafe { ffi::pa_context_new(api.raw_mut(), name.unwrap_cstr()) };
+ if ptr.is_null() {
+ None
+ } else {
+ Some(Context(ptr))
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn raw_mut(&self) -> &mut ffi::pa_context {
+ unsafe { &mut *self.0 }
+ }
+
+ pub fn unref(self) {
+ unsafe {
+ ffi::pa_context_unref(self.raw_mut());
+ }
+ }
+
+ pub fn clear_state_callback(&self) {
+ unsafe {
+ ffi::pa_context_set_state_callback(self.raw_mut(), None, ptr::null_mut());
+ }
+ }
+
+ pub fn set_state_callback<CB>(&self, _: CB, userdata: *mut c_void)
+ where
+ CB: Fn(&Context, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, userdata: *mut c_void)
+ where
+ F: Fn(&Context, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ unsafe {
+ ffi::pa_context_set_state_callback(self.raw_mut(), Some(wrapped::<CB>), userdata);
+ }
+ }
+
+ pub fn errno(&self) -> ffi::pa_error_code_t {
+ unsafe { ffi::pa_context_errno(self.raw_mut()) }
+ }
+
+ pub fn get_state(&self) -> ContextState {
+ ContextState::try_from(unsafe { ffi::pa_context_get_state(self.raw_mut()) })
+ .expect("pa_context_get_state returned invalid ContextState")
+ }
+
+ pub fn connect<'a, OPT>(
+ &self,
+ server: OPT,
+ flags: ContextFlags,
+ api: *const ffi::pa_spawn_api,
+ ) -> Result<()>
+ where
+ OPT: Into<Option<&'a CStr>>,
+ {
+ let r = unsafe {
+ ffi::pa_context_connect(
+ self.raw_mut(),
+ server.into().unwrap_cstr(),
+ flags.into(),
+ api,
+ )
+ };
+ error_result!((), r)
+ }
+
+ pub fn disconnect(&self) {
+ unsafe {
+ ffi::pa_context_disconnect(self.raw_mut());
+ }
+ }
+
+ pub fn drain<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
+ where
+ CB: Fn(&Context, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, userdata: *mut c_void)
+ where
+ F: Fn(&Context, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_drain(self.raw_mut(), Some(wrapped::<CB>), userdata)
+ )
+ }
+
+ pub fn rttime_new<CB>(
+ &self,
+ usec: USec,
+ _: CB,
+ userdata: *mut c_void,
+ ) -> *mut ffi::pa_time_event
+ where
+ CB: Fn(&MainloopApi, *mut ffi::pa_time_event, &TimeVal, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ a: *mut ffi::pa_mainloop_api,
+ e: *mut ffi::pa_time_event,
+ tv: *const TimeVal,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&MainloopApi, *mut ffi::pa_time_event, &TimeVal, *mut c_void),
+ {
+ let api = mainloop_api::from_raw_ptr(a);
+ let timeval = &*tv;
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&api, e, timeval, userdata);
+ forget(api);
+
+ result
+ }
+
+ unsafe { ffi::pa_context_rttime_new(self.raw_mut(), usec, Some(wrapped::<CB>), userdata) }
+ }
+
+ pub fn get_server_info<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
+ where
+ CB: Fn(&Context, Option<&ServerInfo>, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ i: *const ffi::pa_server_info,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, Option<&ServerInfo>, *mut c_void),
+ {
+ let info = if i.is_null() { None } else { Some(&*i) };
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, info, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_get_server_info(self.raw_mut(), Some(wrapped::<CB>), userdata)
+ )
+ }
+
+ pub fn get_sink_info_by_name<'str, CS, CB>(
+ &self,
+ name: CS,
+ _: CB,
+ userdata: *mut c_void,
+ ) -> Result<Operation>
+ where
+ CB: Fn(&Context, *const SinkInfo, i32, *mut c_void),
+ CS: Into<Option<&'str CStr>>,
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ info: *const ffi::pa_sink_info,
+ eol: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, *const SinkInfo, i32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_get_sink_info_by_name(
+ self.raw_mut(),
+ name.into().unwrap_cstr(),
+ Some(wrapped::<CB>),
+ userdata
+ )
+ )
+ }
+
+ pub fn get_sink_info_list<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
+ where
+ CB: Fn(&Context, *const SinkInfo, i32, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ info: *const ffi::pa_sink_info,
+ eol: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, *const SinkInfo, i32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_get_sink_info_list(self.raw_mut(), Some(wrapped::<CB>), userdata)
+ )
+ }
+
+ pub fn get_sink_input_info<CB>(
+ &self,
+ idx: u32,
+ _: CB,
+ userdata: *mut c_void,
+ ) -> Result<Operation>
+ where
+ CB: Fn(&Context, *const SinkInputInfo, i32, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ info: *const ffi::pa_sink_input_info,
+ eol: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, *const SinkInputInfo, i32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_get_sink_input_info(self.raw_mut(), idx, Some(wrapped::<CB>), userdata)
+ )
+ }
+
+ pub fn get_source_info_list<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
+ where
+ CB: Fn(&Context, *const SourceInfo, i32, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ info: *const ffi::pa_source_info,
+ eol: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, *const SourceInfo, i32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_get_source_info_list(self.raw_mut(), Some(wrapped::<CB>), userdata)
+ )
+ }
+
+ pub fn set_sink_input_volume<CB>(
+ &self,
+ idx: u32,
+ volume: &CVolume,
+ _: CB,
+ userdata: *mut c_void,
+ ) -> Result<Operation>
+ where
+ CB: Fn(&Context, i32, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ success: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, i32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, success, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_set_sink_input_volume(
+ self.raw_mut(),
+ idx,
+ volume,
+ Some(wrapped::<CB>),
+ userdata
+ )
+ )
+ }
+
+ pub fn subscribe<CB>(
+ &self,
+ m: SubscriptionMask,
+ _: CB,
+ userdata: *mut c_void,
+ ) -> Result<Operation>
+ where
+ CB: Fn(&Context, i32, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ success: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, i32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, success, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(
+ self,
+ ffi::pa_context_subscribe(self.raw_mut(), m.into(), Some(wrapped::<CB>), userdata)
+ )
+ }
+
+ pub fn clear_subscribe_callback(&self) {
+ unsafe {
+ ffi::pa_context_set_subscribe_callback(self.raw_mut(), None, ptr::null_mut());
+ }
+ }
+
+ pub fn set_subscribe_callback<CB>(&self, _: CB, userdata: *mut c_void)
+ where
+ CB: Fn(&Context, SubscriptionEvent, u32, *mut c_void),
+ {
+ assert_eq!(::std::mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ c: *mut ffi::pa_context,
+ t: ffi::pa_subscription_event_type_t,
+ idx: u32,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Context, SubscriptionEvent, u32, *mut c_void),
+ {
+ let ctx = context::from_raw_ptr(c);
+ let event = SubscriptionEvent::try_from(t)
+ .expect("pa_context_subscribe_cb_t passed invalid pa_subscription_event_type_t");
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&ctx, event, idx, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ unsafe {
+ ffi::pa_context_set_subscribe_callback(self.raw_mut(), Some(wrapped::<CB>), userdata);
+ }
+ }
+}
+
+#[doc(hidden)]
+pub unsafe fn from_raw_ptr(ptr: *mut ffi::pa_context) -> Context {
+ Context(ptr)
+}
diff --git a/third_party/rust/pulse/src/error.rs b/third_party/rust/pulse/src/error.rs
new file mode 100644
index 0000000000..2e6f7074f2
--- /dev/null
+++ b/third_party/rust/pulse/src/error.rs
@@ -0,0 +1,54 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details.
+
+use ffi;
+use std::ffi::CStr;
+
+#[macro_export]
+macro_rules! error_result {
+ ($t:expr, $err:expr) => {
+ if $err >= 0 {
+ Ok($t)
+ } else {
+ Err(ErrorCode::from_error_result($err))
+ }
+ };
+}
+
+#[derive(Debug, PartialEq)]
+pub struct ErrorCode {
+ err: ffi::pa_error_code_t,
+}
+
+impl ErrorCode {
+ pub fn from_error_result(err: i32) -> Self {
+ debug_assert!(err < 0);
+ ErrorCode {
+ err: (-err) as ffi::pa_error_code_t,
+ }
+ }
+
+ pub fn from_error_code(err: ffi::pa_error_code_t) -> Self {
+ debug_assert!(err > 0);
+ ErrorCode { err: err }
+ }
+
+ fn desc(&self) -> &'static str {
+ let cstr = unsafe { CStr::from_ptr(ffi::pa_strerror(self.err)) };
+ cstr.to_str().unwrap()
+ }
+}
+
+impl ::std::error::Error for ErrorCode {
+ fn description(&self) -> &str {
+ self.desc()
+ }
+}
+
+impl ::std::fmt::Display for ErrorCode {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ write!(f, "{:?}: {}", self, self.desc())
+ }
+}
diff --git a/third_party/rust/pulse/src/lib.rs b/third_party/rust/pulse/src/lib.rs
new file mode 100644
index 0000000000..f8c1644b1c
--- /dev/null
+++ b/third_party/rust/pulse/src/lib.rs
@@ -0,0 +1,693 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details.
+
+#[macro_use]
+extern crate bitflags;
+extern crate pulse_ffi as ffi;
+
+#[macro_use]
+mod error;
+mod context;
+mod mainloop_api;
+mod operation;
+mod proplist;
+mod stream;
+mod threaded_mainloop;
+mod util;
+
+pub use context::Context;
+pub use error::ErrorCode;
+pub use ffi::pa_buffer_attr as BufferAttr;
+pub use ffi::pa_channel_map as ChannelMap;
+pub use ffi::pa_cvolume as CVolume;
+pub use ffi::pa_sample_spec as SampleSpec;
+pub use ffi::pa_server_info as ServerInfo;
+pub use ffi::pa_sink_info as SinkInfo;
+pub use ffi::pa_sink_input_info as SinkInputInfo;
+pub use ffi::pa_source_info as SourceInfo;
+pub use ffi::pa_usec_t as USec;
+pub use ffi::pa_volume_t as Volume;
+pub use ffi::timeval as TimeVal;
+pub use mainloop_api::MainloopApi;
+pub use operation::Operation;
+pub use proplist::Proplist;
+use std::os::raw::{c_char, c_uint};
+pub use stream::Stream;
+pub use threaded_mainloop::ThreadedMainloop;
+
+#[allow(non_camel_case_types)]
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum SampleFormat {
+ Invalid = ffi::PA_SAMPLE_INVALID,
+ U8 = ffi::PA_SAMPLE_U8,
+ Alaw = ffi::PA_SAMPLE_ALAW,
+ Ulaw = ffi::PA_SAMPLE_ULAW,
+ Signed16LE = ffi::PA_SAMPLE_S16LE,
+ Signed16BE = ffi::PA_SAMPLE_S16BE,
+ Float32LE = ffi::PA_SAMPLE_FLOAT32LE,
+ Float32BE = ffi::PA_SAMPLE_FLOAT32BE,
+ Signed32LE = ffi::PA_SAMPLE_S32LE,
+ Signed32BE = ffi::PA_SAMPLE_S32BE,
+ Signed24LE = ffi::PA_SAMPLE_S24LE,
+ Signed24BE = ffi::PA_SAMPLE_S24BE,
+ Signed24_32LE = ffi::PA_SAMPLE_S24_32LE,
+ Signed23_32BE = ffi::PA_SAMPLE_S24_32BE,
+}
+
+impl Default for SampleFormat {
+ fn default() -> Self {
+ SampleFormat::Invalid
+ }
+}
+
+impl Into<ffi::pa_sample_format_t> for SampleFormat {
+ fn into(self) -> ffi::pa_sample_format_t {
+ self as ffi::pa_sample_format_t
+ }
+}
+
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum ContextState {
+ Unconnected = ffi::PA_CONTEXT_UNCONNECTED,
+ Connecting = ffi::PA_CONTEXT_CONNECTING,
+ Authorizing = ffi::PA_CONTEXT_AUTHORIZING,
+ SettingName = ffi::PA_CONTEXT_SETTING_NAME,
+ Ready = ffi::PA_CONTEXT_READY,
+ Failed = ffi::PA_CONTEXT_FAILED,
+ Terminated = ffi::PA_CONTEXT_TERMINATED,
+}
+
+impl ContextState {
+ // This function implements the PA_CONTENT_IS_GOOD macro from pulse/def.h
+ // It must match the version from PA headers.
+ pub fn is_good(self) -> bool {
+ match self {
+ ContextState::Connecting
+ | ContextState::Authorizing
+ | ContextState::SettingName
+ | ContextState::Ready => true,
+ _ => false,
+ }
+ }
+
+ pub fn try_from(x: ffi::pa_context_state_t) -> Option<Self> {
+ if x >= ffi::PA_CONTEXT_UNCONNECTED && x <= ffi::PA_CONTEXT_TERMINATED {
+ Some(unsafe { ::std::mem::transmute(x) })
+ } else {
+ None
+ }
+ }
+}
+
+impl Default for ContextState {
+ fn default() -> Self {
+ ContextState::Unconnected
+ }
+}
+
+impl Into<ffi::pa_context_state_t> for ContextState {
+ fn into(self) -> ffi::pa_context_state_t {
+ self as ffi::pa_context_state_t
+ }
+}
+
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum StreamState {
+ Unconnected = ffi::PA_STREAM_UNCONNECTED,
+ Creating = ffi::PA_STREAM_CREATING,
+ Ready = ffi::PA_STREAM_READY,
+ Failed = ffi::PA_STREAM_FAILED,
+ Terminated = ffi::PA_STREAM_TERMINATED,
+}
+
+impl StreamState {
+ // This function implements the PA_STREAM_IS_GOOD macro from pulse/def.h
+ // It must match the version from PA headers.
+ pub fn is_good(self) -> bool {
+ match self {
+ StreamState::Creating | StreamState::Ready => true,
+ _ => false,
+ }
+ }
+
+ pub fn try_from(x: ffi::pa_stream_state_t) -> Option<Self> {
+ if x >= ffi::PA_STREAM_UNCONNECTED && x <= ffi::PA_STREAM_TERMINATED {
+ Some(unsafe { ::std::mem::transmute(x) })
+ } else {
+ None
+ }
+ }
+}
+
+impl Default for StreamState {
+ fn default() -> Self {
+ StreamState::Unconnected
+ }
+}
+
+impl Into<ffi::pa_stream_state_t> for StreamState {
+ fn into(self) -> ffi::pa_stream_state_t {
+ self as ffi::pa_stream_state_t
+ }
+}
+
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum OperationState {
+ Running = ffi::PA_OPERATION_RUNNING,
+ Done = ffi::PA_OPERATION_DONE,
+ Cancelled = ffi::PA_OPERATION_CANCELLED,
+}
+
+impl OperationState {
+ pub fn try_from(x: ffi::pa_operation_state_t) -> Option<Self> {
+ if x >= ffi::PA_OPERATION_RUNNING && x <= ffi::PA_OPERATION_CANCELLED {
+ Some(unsafe { ::std::mem::transmute(x) })
+ } else {
+ None
+ }
+ }
+}
+
+impl Into<ffi::pa_operation_state_t> for OperationState {
+ fn into(self) -> ffi::pa_operation_state_t {
+ self as ffi::pa_operation_state_t
+ }
+}
+
+bitflags! {
+ pub struct ContextFlags: u32 {
+ const NOAUTOSPAWN = ffi::PA_CONTEXT_NOAUTOSPAWN;
+ const NOFAIL = ffi::PA_CONTEXT_NOFAIL;
+ }
+}
+
+impl Into<ffi::pa_context_flags_t> for ContextFlags {
+ fn into(self) -> ffi::pa_context_flags_t {
+ self.bits() as ffi::pa_context_flags_t
+ }
+}
+
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum DeviceType {
+ Sink = ffi::PA_DEVICE_TYPE_SINK,
+ Source = ffi::PA_DEVICE_TYPE_SOURCE,
+}
+
+impl DeviceType {
+ pub fn try_from(x: ffi::pa_device_type_t) -> Option<Self> {
+ if x >= ffi::PA_DEVICE_TYPE_SINK && x <= ffi::PA_DEVICE_TYPE_SOURCE {
+ Some(unsafe { ::std::mem::transmute(x) })
+ } else {
+ None
+ }
+ }
+}
+
+impl Into<ffi::pa_device_type_t> for DeviceType {
+ fn into(self) -> ffi::pa_device_type_t {
+ self as ffi::pa_device_type_t
+ }
+}
+
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum StreamDirection {
+ NoDirection = ffi::PA_STREAM_NODIRECTION,
+ Playback = ffi::PA_STREAM_PLAYBACK,
+ Record = ffi::PA_STREAM_RECORD,
+ StreamUpload = ffi::PA_STREAM_UPLOAD,
+}
+
+impl StreamDirection {
+ pub fn try_from(x: ffi::pa_stream_direction_t) -> Option<Self> {
+ if x >= ffi::PA_STREAM_NODIRECTION && x <= ffi::PA_STREAM_UPLOAD {
+ Some(unsafe { ::std::mem::transmute(x) })
+ } else {
+ None
+ }
+ }
+}
+
+impl Into<ffi::pa_stream_direction_t> for StreamDirection {
+ fn into(self) -> ffi::pa_stream_direction_t {
+ self as ffi::pa_stream_direction_t
+ }
+}
+
+bitflags! {
+ pub struct StreamFlags : u32 {
+ const START_CORKED = ffi::PA_STREAM_START_CORKED;
+ const INTERPOLATE_TIMING = ffi::PA_STREAM_INTERPOLATE_TIMING;
+ const NOT_MONOTONIC = ffi::PA_STREAM_NOT_MONOTONIC;
+ const AUTO_TIMING_UPDATE = ffi::PA_STREAM_AUTO_TIMING_UPDATE;
+ const NO_REMAP_CHANNELS = ffi::PA_STREAM_NO_REMAP_CHANNELS;
+ const NO_REMIX_CHANNELS = ffi::PA_STREAM_NO_REMIX_CHANNELS;
+ const FIX_FORMAT = ffi::PA_STREAM_FIX_FORMAT;
+ const FIX_RATE = ffi::PA_STREAM_FIX_RATE;
+ const FIX_CHANNELS = ffi::PA_STREAM_FIX_CHANNELS;
+ const DONT_MOVE = ffi::PA_STREAM_DONT_MOVE;
+ const VARIABLE_RATE = ffi::PA_STREAM_VARIABLE_RATE;
+ const PEAK_DETECT = ffi::PA_STREAM_PEAK_DETECT;
+ const START_MUTED = ffi::PA_STREAM_START_MUTED;
+ const ADJUST_LATENCY = ffi::PA_STREAM_ADJUST_LATENCY;
+ const EARLY_REQUESTS = ffi::PA_STREAM_EARLY_REQUESTS;
+ const DONT_INHIBIT_AUTO_SUSPEND = ffi::PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND;
+ const START_UNMUTED = ffi::PA_STREAM_START_UNMUTED;
+ const FAIL_ON_SUSPEND = ffi::PA_STREAM_FAIL_ON_SUSPEND;
+ const RELATIVE_VOLUME = ffi::PA_STREAM_RELATIVE_VOLUME;
+ const PASSTHROUGH = ffi::PA_STREAM_PASSTHROUGH;
+ }
+}
+
+impl StreamFlags {
+ pub fn try_from(x: ffi::pa_stream_flags_t) -> Option<Self> {
+ if (x & !(ffi::PA_STREAM_NOFLAGS
+ | ffi::PA_STREAM_START_CORKED
+ | ffi::PA_STREAM_INTERPOLATE_TIMING
+ | ffi::PA_STREAM_NOT_MONOTONIC
+ | ffi::PA_STREAM_AUTO_TIMING_UPDATE
+ | ffi::PA_STREAM_NO_REMAP_CHANNELS
+ | ffi::PA_STREAM_NO_REMIX_CHANNELS
+ | ffi::PA_STREAM_FIX_FORMAT
+ | ffi::PA_STREAM_FIX_RATE
+ | ffi::PA_STREAM_FIX_CHANNELS
+ | ffi::PA_STREAM_DONT_MOVE
+ | ffi::PA_STREAM_VARIABLE_RATE
+ | ffi::PA_STREAM_PEAK_DETECT
+ | ffi::PA_STREAM_START_MUTED
+ | ffi::PA_STREAM_ADJUST_LATENCY
+ | ffi::PA_STREAM_EARLY_REQUESTS
+ | ffi::PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND
+ | ffi::PA_STREAM_START_UNMUTED
+ | ffi::PA_STREAM_FAIL_ON_SUSPEND
+ | ffi::PA_STREAM_RELATIVE_VOLUME
+ | ffi::PA_STREAM_PASSTHROUGH))
+ == 0
+ {
+ Some(unsafe { ::std::mem::transmute(x) })
+ } else {
+ None
+ }
+ }
+}
+
+impl Into<ffi::pa_stream_flags_t> for StreamFlags {
+ fn into(self) -> ffi::pa_stream_flags_t {
+ self.bits() as ffi::pa_stream_flags_t
+ }
+}
+
+pub enum StreamLatency {
+ Positive(u64),
+ Negative(u64),
+}
+
+bitflags! {
+ pub struct SubscriptionMask : u32 {
+ const SINK = ffi::PA_SUBSCRIPTION_MASK_SINK;
+ const SOURCE = ffi::PA_SUBSCRIPTION_MASK_SOURCE;
+ const SINK_INPUT = ffi::PA_SUBSCRIPTION_MASK_SINK_INPUT;
+ const SOURCE_OUTPUT = ffi::PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT;
+ const MODULE = ffi::PA_SUBSCRIPTION_MASK_MODULE;
+ const CLIENT = ffi::PA_SUBSCRIPTION_MASK_CLIENT;
+ const SAMPLE_CACHE = ffi::PA_SUBSCRIPTION_MASK_SAMPLE_CACHE;
+ const SERVER = ffi::PA_SUBSCRIPTION_MASK_SERVER;
+ const AUTOLOAD = ffi::PA_SUBSCRIPTION_MASK_AUTOLOAD;
+ const CARD = ffi::PA_SUBSCRIPTION_MASK_CARD;
+ }
+}
+
+impl SubscriptionMask {
+ pub fn try_from(x: ffi::pa_subscription_mask_t) -> Option<Self> {
+ if (x & !ffi::PA_SUBSCRIPTION_MASK_ALL) == 0 {
+ Some(unsafe { ::std::mem::transmute(x) })
+ } else {
+ None
+ }
+ }
+}
+
+impl Into<ffi::pa_subscription_mask_t> for SubscriptionMask {
+ fn into(self) -> ffi::pa_subscription_mask_t {
+ self.bits() as ffi::pa_subscription_mask_t
+ }
+}
+
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum SubscriptionEventFacility {
+ Sink = ffi::PA_SUBSCRIPTION_EVENT_SINK,
+ Source = ffi::PA_SUBSCRIPTION_EVENT_SOURCE,
+ SinkInput = ffi::PA_SUBSCRIPTION_EVENT_SINK_INPUT,
+ SourceOutput = ffi::PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT,
+ Module = ffi::PA_SUBSCRIPTION_EVENT_MODULE,
+ Client = ffi::PA_SUBSCRIPTION_EVENT_CLIENT,
+ SampleCache = ffi::PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE,
+ Server = ffi::PA_SUBSCRIPTION_EVENT_SERVER,
+ Autoload = ffi::PA_SUBSCRIPTION_EVENT_AUTOLOAD,
+ Card = ffi::PA_SUBSCRIPTION_EVENT_CARD,
+}
+
+#[repr(C)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum SubscriptionEventType {
+ New,
+ Change,
+ Remove,
+}
+
+#[repr(C)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct SubscriptionEvent(ffi::pa_subscription_event_type_t);
+impl SubscriptionEvent {
+ pub fn try_from(x: ffi::pa_subscription_event_type_t) -> Option<Self> {
+ if (x & !(ffi::PA_SUBSCRIPTION_EVENT_TYPE_MASK | ffi::PA_SUBSCRIPTION_EVENT_FACILITY_MASK))
+ == 0
+ {
+ Some(SubscriptionEvent(x))
+ } else {
+ None
+ }
+ }
+
+ pub fn event_facility(self) -> SubscriptionEventFacility {
+ unsafe { ::std::mem::transmute(self.0 & ffi::PA_SUBSCRIPTION_EVENT_FACILITY_MASK) }
+ }
+
+ pub fn event_type(self) -> SubscriptionEventType {
+ unsafe { ::std::mem::transmute((self.0 & ffi::PA_SUBSCRIPTION_EVENT_TYPE_MASK) >> 4) }
+ }
+}
+
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum SeekMode {
+ Relative = ffi::PA_SEEK_RELATIVE,
+ Absolute = ffi::PA_SEEK_ABSOLUTE,
+ RelativeOnRead = ffi::PA_SEEK_RELATIVE_ON_READ,
+ RelativeEnd = ffi::PA_SEEK_RELATIVE_END,
+}
+
+impl SeekMode {
+ pub fn try_from(x: ffi::pa_seek_mode_t) -> Option<Self> {
+ if x >= ffi::PA_SEEK_RELATIVE && x <= ffi::PA_SEEK_RELATIVE_END {
+ Some(unsafe { ::std::mem::transmute(x) })
+ } else {
+ None
+ }
+ }
+}
+
+impl Into<ffi::pa_seek_mode_t> for SeekMode {
+ fn into(self) -> ffi::pa_seek_mode_t {
+ self as ffi::pa_seek_mode_t
+ }
+}
+
+bitflags! {
+ #[derive(Debug, Clone, Copy)]
+ pub struct SinkFlags: u32 {
+ const HW_VOLUME_CTRL = ffi::PA_SINK_HW_VOLUME_CTRL;
+ const LATENCY = ffi::PA_SINK_LATENCY;
+ const HARDWARE = ffi::PA_SINK_HARDWARE;
+ const NETWORK = ffi::PA_SINK_NETWORK;
+ const HW_MUTE_CTRL = ffi::PA_SINK_HW_MUTE_CTRL;
+ const DECIBEL_VOLUME = ffi::PA_SINK_DECIBEL_VOLUME;
+ const FLAT_VOLUME = ffi::PA_SINK_FLAT_VOLUME;
+ const DYNAMIC_LATENCY = ffi::PA_SINK_DYNAMIC_LATENCY;
+ const SET_FORMATS = ffi::PA_SINK_SET_FORMATS;
+ }
+}
+
+impl SinkFlags {
+ pub fn try_from(x: ffi::pa_sink_flags_t) -> Option<SinkFlags> {
+ if (x & !(ffi::PA_SINK_NOFLAGS
+ | ffi::PA_SINK_HW_VOLUME_CTRL
+ | ffi::PA_SINK_LATENCY
+ | ffi::PA_SINK_HARDWARE
+ | ffi::PA_SINK_NETWORK
+ | ffi::PA_SINK_HW_MUTE_CTRL
+ | ffi::PA_SINK_DECIBEL_VOLUME
+ | ffi::PA_SINK_DYNAMIC_LATENCY
+ | ffi::PA_SINK_FLAT_VOLUME
+ | ffi::PA_SINK_SET_FORMATS))
+ == 0
+ {
+ Some(unsafe { ::std::mem::transmute(x) })
+ } else {
+ None
+ }
+ }
+}
+
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum SinkState {
+ InvalidState = ffi::PA_SINK_INVALID_STATE,
+ Running = ffi::PA_SINK_RUNNING,
+ Idle = ffi::PA_SINK_IDLE,
+ Suspended = ffi::PA_SINK_SUSPENDED,
+ Init = ffi::PA_SINK_INIT,
+ Unlinked = ffi::PA_SINK_UNLINKED,
+}
+
+bitflags! {
+ pub struct SourceFlags: u32 {
+ const HW_VOLUME_CTRL = ffi::PA_SOURCE_HW_VOLUME_CTRL;
+ const LATENCY = ffi::PA_SOURCE_LATENCY;
+ const HARDWARE = ffi::PA_SOURCE_HARDWARE;
+ const NETWORK = ffi::PA_SOURCE_NETWORK;
+ const HW_MUTE_CTRL = ffi::PA_SOURCE_HW_MUTE_CTRL;
+ const DECIBEL_VOLUME = ffi::PA_SOURCE_DECIBEL_VOLUME;
+ const DYNAMIC_LATENCY = ffi::PA_SOURCE_DYNAMIC_LATENCY;
+ const FLAT_VOLUME = ffi::PA_SOURCE_FLAT_VOLUME;
+ }
+}
+
+impl Into<ffi::pa_source_flags_t> for SourceFlags {
+ fn into(self) -> ffi::pa_source_flags_t {
+ self.bits() as ffi::pa_source_flags_t
+ }
+}
+
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum SourceState {
+ InvalidState = ffi::PA_SOURCE_INVALID_STATE,
+ Running = ffi::PA_SOURCE_RUNNING,
+ Idle = ffi::PA_SOURCE_IDLE,
+ Suspended = ffi::PA_SOURCE_SUSPENDED,
+ Init = ffi::PA_SOURCE_INIT,
+ Unlinked = ffi::PA_SOURCE_UNLINKED,
+}
+
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum PortAvailable {
+ Unknown = ffi::PA_PORT_AVAILABLE_UNKNOWN,
+ No = ffi::PA_PORT_AVAILABLE_NO,
+ Yes = ffi::PA_PORT_AVAILABLE_YES,
+}
+
+impl PortAvailable {
+ pub fn try_from(x: ffi::pa_port_available_t) -> Option<Self> {
+ if x >= ffi::PA_PORT_AVAILABLE_UNKNOWN && x <= ffi::PA_PORT_AVAILABLE_YES {
+ Some(unsafe { ::std::mem::transmute(x) })
+ } else {
+ None
+ }
+ }
+}
+
+impl Into<ffi::pa_port_available_t> for PortAvailable {
+ fn into(self) -> ffi::pa_port_available_t {
+ self as ffi::pa_port_available_t
+ }
+}
+
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum ChannelPosition {
+ Invalid = ffi::PA_CHANNEL_POSITION_INVALID,
+ Mono = ffi::PA_CHANNEL_POSITION_MONO,
+ FrontLeft = ffi::PA_CHANNEL_POSITION_FRONT_LEFT,
+ FrontRight = ffi::PA_CHANNEL_POSITION_FRONT_RIGHT,
+ FrontCenter = ffi::PA_CHANNEL_POSITION_FRONT_CENTER,
+ RearCenter = ffi::PA_CHANNEL_POSITION_REAR_CENTER,
+ RearLeft = ffi::PA_CHANNEL_POSITION_REAR_LEFT,
+ RearRight = ffi::PA_CHANNEL_POSITION_REAR_RIGHT,
+ LowFreqEffects = ffi::PA_CHANNEL_POSITION_LFE,
+ FrontLeftOfCenter = ffi::PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
+ FrontRightOfCenter = ffi::PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
+ SideLeft = ffi::PA_CHANNEL_POSITION_SIDE_LEFT,
+ SideRight = ffi::PA_CHANNEL_POSITION_SIDE_RIGHT,
+ Aux0 = ffi::PA_CHANNEL_POSITION_AUX0,
+ Aux1 = ffi::PA_CHANNEL_POSITION_AUX1,
+ Aux2 = ffi::PA_CHANNEL_POSITION_AUX2,
+ Aux3 = ffi::PA_CHANNEL_POSITION_AUX3,
+ Aux4 = ffi::PA_CHANNEL_POSITION_AUX4,
+ Aux5 = ffi::PA_CHANNEL_POSITION_AUX5,
+ Aux6 = ffi::PA_CHANNEL_POSITION_AUX6,
+ Aux7 = ffi::PA_CHANNEL_POSITION_AUX7,
+ Aux8 = ffi::PA_CHANNEL_POSITION_AUX8,
+ Aux9 = ffi::PA_CHANNEL_POSITION_AUX9,
+ Aux10 = ffi::PA_CHANNEL_POSITION_AUX10,
+ Aux11 = ffi::PA_CHANNEL_POSITION_AUX11,
+ Aux12 = ffi::PA_CHANNEL_POSITION_AUX12,
+ Aux13 = ffi::PA_CHANNEL_POSITION_AUX13,
+ Aux14 = ffi::PA_CHANNEL_POSITION_AUX14,
+ Aux15 = ffi::PA_CHANNEL_POSITION_AUX15,
+ Aux16 = ffi::PA_CHANNEL_POSITION_AUX16,
+ Aux17 = ffi::PA_CHANNEL_POSITION_AUX17,
+ Aux18 = ffi::PA_CHANNEL_POSITION_AUX18,
+ Aux19 = ffi::PA_CHANNEL_POSITION_AUX19,
+ Aux20 = ffi::PA_CHANNEL_POSITION_AUX20,
+ Aux21 = ffi::PA_CHANNEL_POSITION_AUX21,
+ Aux22 = ffi::PA_CHANNEL_POSITION_AUX22,
+ Aux23 = ffi::PA_CHANNEL_POSITION_AUX23,
+ Aux24 = ffi::PA_CHANNEL_POSITION_AUX24,
+ Aux25 = ffi::PA_CHANNEL_POSITION_AUX25,
+ Aux26 = ffi::PA_CHANNEL_POSITION_AUX26,
+ Aux27 = ffi::PA_CHANNEL_POSITION_AUX27,
+ Aux28 = ffi::PA_CHANNEL_POSITION_AUX28,
+ Aux29 = ffi::PA_CHANNEL_POSITION_AUX29,
+ Aux30 = ffi::PA_CHANNEL_POSITION_AUX30,
+ Aux31 = ffi::PA_CHANNEL_POSITION_AUX31,
+ TopCenter = ffi::PA_CHANNEL_POSITION_TOP_CENTER,
+ TopFrontLeft = ffi::PA_CHANNEL_POSITION_TOP_FRONT_LEFT,
+ TopFrontRight = ffi::PA_CHANNEL_POSITION_TOP_FRONT_RIGHT,
+ TopFrontCenter = ffi::PA_CHANNEL_POSITION_TOP_FRONT_CENTER,
+ TopRearLeft = ffi::PA_CHANNEL_POSITION_TOP_REAR_LEFT,
+ TopRearRight = ffi::PA_CHANNEL_POSITION_TOP_REAR_RIGHT,
+ TopRearCenter = ffi::PA_CHANNEL_POSITION_TOP_REAR_CENTER,
+}
+
+impl ChannelPosition {
+ pub fn try_from(x: ffi::pa_channel_position_t) -> Option<Self> {
+ if x >= ffi::PA_CHANNEL_POSITION_INVALID && x < ffi::PA_CHANNEL_POSITION_MAX {
+ Some(unsafe { ::std::mem::transmute(x) })
+ } else {
+ None
+ }
+ }
+}
+
+impl Default for ChannelPosition {
+ fn default() -> Self {
+ ChannelPosition::Invalid
+ }
+}
+
+impl Into<ffi::pa_channel_position_t> for ChannelPosition {
+ fn into(self) -> ffi::pa_channel_position_t {
+ self as ffi::pa_channel_position_t
+ }
+}
+pub type Result<T> = ::std::result::Result<T, error::ErrorCode>;
+
+pub trait CVolumeExt {
+ fn set(&mut self, channels: c_uint, v: Volume);
+ fn set_balance(&mut self, map: &ChannelMap, new_balance: f32);
+}
+
+impl CVolumeExt for CVolume {
+ fn set(&mut self, channels: c_uint, v: Volume) {
+ unsafe {
+ ffi::pa_cvolume_set(self, channels, v);
+ }
+ }
+
+ fn set_balance(&mut self, map: &ChannelMap, new_balance: f32) {
+ unsafe {
+ ffi::pa_cvolume_set_balance(self, map, new_balance);
+ }
+ }
+}
+
+pub trait ChannelMapExt {
+ fn init() -> ChannelMap;
+ fn init_auto(ch: u32, def: ffi::pa_channel_map_def_t) -> Option<ChannelMap>;
+ fn can_balance(&self) -> bool;
+}
+
+impl ChannelMapExt for ChannelMap {
+ fn init() -> ChannelMap {
+ let mut cm = ChannelMap::default();
+ unsafe {
+ ffi::pa_channel_map_init(&mut cm);
+ }
+ cm
+ }
+ fn init_auto(ch: u32, def: ffi::pa_channel_map_def_t) -> Option<ChannelMap> {
+ let mut cm = ChannelMap::default();
+ let r: *mut ffi::pa_channel_map =
+ unsafe { ffi::pa_channel_map_init_auto(&mut cm, ch, def) };
+ if r.is_null() {
+ None
+ } else {
+ Some(cm)
+ }
+ }
+ fn can_balance(&self) -> bool {
+ unsafe { ffi::pa_channel_map_can_balance(self) > 0 }
+ }
+}
+
+pub trait ProplistExt {
+ fn proplist(&self) -> Proplist;
+}
+
+impl ProplistExt for SinkInfo {
+ fn proplist(&self) -> Proplist {
+ unsafe { proplist::from_raw_ptr(self.proplist) }
+ }
+}
+
+impl ProplistExt for SourceInfo {
+ fn proplist(&self) -> Proplist {
+ unsafe { proplist::from_raw_ptr(self.proplist) }
+ }
+}
+
+pub trait SampleSpecExt {
+ fn frame_size(&self) -> usize;
+ fn sample_size(&self) -> usize;
+}
+
+impl SampleSpecExt for SampleSpec {
+ fn frame_size(&self) -> usize {
+ unsafe { ffi::pa_frame_size(self) }
+ }
+ fn sample_size(&self) -> usize {
+ unsafe { ffi::pa_sample_size(self) }
+ }
+}
+
+pub trait USecExt {
+ fn to_bytes(self, spec: &SampleSpec) -> usize;
+}
+
+impl USecExt for USec {
+ fn to_bytes(self, spec: &SampleSpec) -> usize {
+ unsafe { ffi::pa_usec_to_bytes(self, spec) }
+ }
+}
+
+pub fn library_version() -> *const c_char {
+ unsafe { ffi::pa_get_library_version() }
+}
+
+pub fn sw_volume_from_linear(vol: f64) -> Volume {
+ unsafe { ffi::pa_sw_volume_from_linear(vol) }
+}
+
+pub fn rtclock_now() -> USec {
+ unsafe { ffi::pa_rtclock_now() }
+}
diff --git a/third_party/rust/pulse/src/mainloop_api.rs b/third_party/rust/pulse/src/mainloop_api.rs
new file mode 100644
index 0000000000..4b2ad426c3
--- /dev/null
+++ b/third_party/rust/pulse/src/mainloop_api.rs
@@ -0,0 +1,60 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details.
+
+use ffi;
+use std::mem;
+use std::os::raw::c_void;
+
+#[allow(non_camel_case_types)]
+type pa_once_cb_t =
+ Option<unsafe extern "C" fn(m: *mut ffi::pa_mainloop_api, userdata: *mut c_void)>;
+fn wrap_once_cb<F>(_: F) -> pa_once_cb_t
+where
+ F: Fn(&MainloopApi, *mut c_void),
+{
+ assert!(mem::size_of::<F>() == 0);
+
+ unsafe extern "C" fn wrapped<F>(m: *mut ffi::pa_mainloop_api, userdata: *mut c_void)
+ where
+ F: Fn(&MainloopApi, *mut c_void),
+ {
+ let api = from_raw_ptr(m);
+ let result = mem::transmute::<_, &F>(&())(&api, userdata);
+ mem::forget(api);
+ result
+ }
+
+ Some(wrapped::<F>)
+}
+
+pub struct MainloopApi(*mut ffi::pa_mainloop_api);
+
+impl MainloopApi {
+ pub fn raw_mut(&self) -> &mut ffi::pa_mainloop_api {
+ unsafe { &mut *self.0 }
+ }
+
+ pub fn once<CB>(&self, cb: CB, userdata: *mut c_void)
+ where
+ CB: Fn(&MainloopApi, *mut c_void),
+ {
+ let wrapped = wrap_once_cb(cb);
+ unsafe {
+ ffi::pa_mainloop_api_once(self.raw_mut(), wrapped, userdata);
+ }
+ }
+
+ pub fn time_free(&self, e: *mut ffi::pa_time_event) {
+ unsafe {
+ if let Some(f) = self.raw_mut().time_free {
+ f(e);
+ }
+ }
+ }
+}
+
+pub unsafe fn from_raw_ptr(raw: *mut ffi::pa_mainloop_api) -> MainloopApi {
+ MainloopApi(raw)
+}
diff --git a/third_party/rust/pulse/src/operation.rs b/third_party/rust/pulse/src/operation.rs
new file mode 100644
index 0000000000..0b6823b2cc
--- /dev/null
+++ b/third_party/rust/pulse/src/operation.rs
@@ -0,0 +1,43 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details.
+
+use ffi;
+
+#[derive(Debug)]
+pub struct Operation(*mut ffi::pa_operation);
+
+impl Operation {
+ pub unsafe fn from_raw_ptr(raw: *mut ffi::pa_operation) -> Operation {
+ Operation(raw)
+ }
+
+ pub fn cancel(&mut self) {
+ unsafe {
+ ffi::pa_operation_cancel(self.0);
+ }
+ }
+
+ pub fn get_state(&self) -> ffi::pa_operation_state_t {
+ unsafe { ffi::pa_operation_get_state(self.0) }
+ }
+}
+
+impl Clone for Operation {
+ fn clone(&self) -> Self {
+ Operation(unsafe { ffi::pa_operation_ref(self.0) })
+ }
+}
+
+impl Drop for Operation {
+ fn drop(&mut self) {
+ unsafe {
+ ffi::pa_operation_unref(self.0);
+ }
+ }
+}
+
+pub unsafe fn from_raw_ptr(raw: *mut ffi::pa_operation) -> Operation {
+ Operation::from_raw_ptr(raw)
+}
diff --git a/third_party/rust/pulse/src/proplist.rs b/third_party/rust/pulse/src/proplist.rs
new file mode 100644
index 0000000000..460473f467
--- /dev/null
+++ b/third_party/rust/pulse/src/proplist.rs
@@ -0,0 +1,32 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details.
+
+use ffi;
+use std::ffi::{CStr, CString};
+
+#[derive(Debug)]
+pub struct Proplist(*mut ffi::pa_proplist);
+
+impl Proplist {
+ pub fn gets<T>(&self, key: T) -> Option<&CStr>
+ where
+ T: Into<Vec<u8>>,
+ {
+ let key = match CString::new(key) {
+ Ok(k) => k,
+ _ => return None,
+ };
+ let r = unsafe { ffi::pa_proplist_gets(self.0, key.as_ptr()) };
+ if r.is_null() {
+ None
+ } else {
+ Some(unsafe { CStr::from_ptr(r) })
+ }
+ }
+}
+
+pub unsafe fn from_raw_ptr(raw: *mut ffi::pa_proplist) -> Proplist {
+ return Proplist(raw);
+}
diff --git a/third_party/rust/pulse/src/stream.rs b/third_party/rust/pulse/src/stream.rs
new file mode 100644
index 0000000000..4548fb533a
--- /dev/null
+++ b/third_party/rust/pulse/src/stream.rs
@@ -0,0 +1,456 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details.
+
+use context;
+use ffi;
+use operation;
+use std::ffi::CStr;
+use std::mem::{self, forget, MaybeUninit};
+use std::os::raw::{c_int, c_void};
+use std::ptr;
+use util::*;
+use *;
+
+#[derive(Debug)]
+pub struct Stream(*mut ffi::pa_stream);
+
+impl Stream {
+ pub fn new<'a, CM>(
+ c: &Context,
+ name: &::std::ffi::CStr,
+ ss: &SampleSpec,
+ map: CM,
+ ) -> Option<Self>
+ where
+ CM: Into<Option<&'a ChannelMap>>,
+ {
+ let ptr = unsafe {
+ ffi::pa_stream_new(
+ c.raw_mut(),
+ name.as_ptr(),
+ ss as *const _,
+ to_ptr(map.into()),
+ )
+ };
+ if ptr.is_null() {
+ None
+ } else {
+ Some(Stream(ptr))
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn raw_mut(&self) -> &mut ffi::pa_stream {
+ unsafe { &mut *self.0 }
+ }
+
+ pub fn unref(self) {
+ unsafe {
+ ffi::pa_stream_unref(self.raw_mut());
+ }
+ }
+
+ pub fn get_state(&self) -> StreamState {
+ StreamState::try_from(unsafe { ffi::pa_stream_get_state(self.raw_mut()) })
+ .expect("pa_stream_get_state returned invalid StreamState")
+ }
+
+ pub fn get_context(&self) -> Option<Context> {
+ let ptr = unsafe { ffi::pa_stream_get_context(self.raw_mut()) };
+ if ptr.is_null() {
+ return None;
+ }
+
+ let ctx = unsafe { context::from_raw_ptr(ptr) };
+ Some(ctx)
+ }
+
+ pub fn get_index(&self) -> u32 {
+ unsafe { ffi::pa_stream_get_index(self.raw_mut()) }
+ }
+
+ pub fn get_device_name<'a>(&'a self) -> Result<&'a CStr> {
+ let r = unsafe { ffi::pa_stream_get_device_name(self.raw_mut()) };
+ if r.is_null() {
+ let err = if let Some(c) = self.get_context() {
+ c.errno()
+ } else {
+ ffi::PA_ERR_UNKNOWN
+ };
+ return Err(ErrorCode::from_error_code(err));
+ }
+ Ok(unsafe { CStr::from_ptr(r) })
+ }
+
+ pub fn is_suspended(&self) -> Result<bool> {
+ let r = unsafe { ffi::pa_stream_is_suspended(self.raw_mut()) };
+ error_result!(r != 0, r)
+ }
+
+ pub fn is_corked(&self) -> Result<bool> {
+ let r = unsafe { ffi::pa_stream_is_corked(self.raw_mut()) };
+ error_result!(r != 0, r)
+ }
+
+ pub fn connect_playback<'a, D, A, V, S>(
+ &self,
+ dev: D,
+ attr: A,
+ flags: StreamFlags,
+ volume: V,
+ sync_stream: S,
+ ) -> Result<()>
+ where
+ D: Into<Option<&'a CStr>>,
+ A: Into<Option<&'a BufferAttr>>,
+ V: Into<Option<&'a CVolume>>,
+ S: Into<Option<&'a mut Stream>>,
+ {
+ let r = unsafe {
+ ffi::pa_stream_connect_playback(
+ self.raw_mut(),
+ str_to_ptr(dev.into()),
+ to_ptr(attr.into()),
+ flags.into(),
+ to_ptr(volume.into()),
+ map_to_mut_ptr(sync_stream.into(), |p| p.0),
+ )
+ };
+ error_result!((), r)
+ }
+
+ pub fn connect_record<'a, D, A>(&self, dev: D, attr: A, flags: StreamFlags) -> Result<()>
+ where
+ D: Into<Option<&'a CStr>>,
+ A: Into<Option<&'a BufferAttr>>,
+ {
+ let r = unsafe {
+ ffi::pa_stream_connect_record(
+ self.raw_mut(),
+ str_to_ptr(dev.into()),
+ to_ptr(attr.into()),
+ flags.into(),
+ )
+ };
+ error_result!((), r)
+ }
+
+ pub fn disconnect(&self) -> Result<()> {
+ let r = unsafe { ffi::pa_stream_disconnect(self.raw_mut()) };
+ error_result!((), r)
+ }
+
+ pub fn begin_write(&self, req_bytes: usize) -> Result<(*mut c_void, usize)> {
+ let mut data: *mut c_void = ptr::null_mut();
+ let mut nbytes = req_bytes;
+ let r = unsafe { ffi::pa_stream_begin_write(self.raw_mut(), &mut data, &mut nbytes) };
+ error_result!((data, nbytes), r)
+ }
+
+ pub fn cancel_write(&self) -> Result<()> {
+ let r = unsafe { ffi::pa_stream_cancel_write(self.raw_mut()) };
+ error_result!((), r)
+ }
+
+ pub fn write(
+ &self,
+ data: *const c_void,
+ nbytes: usize,
+ offset: i64,
+ seek: SeekMode,
+ ) -> Result<()> {
+ let r = unsafe {
+ ffi::pa_stream_write(self.raw_mut(), data, nbytes, None, offset, seek.into())
+ };
+ error_result!((), r)
+ }
+
+ pub unsafe fn peek(&self, data: *mut *const c_void, length: *mut usize) -> Result<()> {
+ let r = ffi::pa_stream_peek(self.raw_mut(), data, length);
+ error_result!((), r)
+ }
+
+ pub fn drop(&self) -> Result<()> {
+ let r = unsafe { ffi::pa_stream_drop(self.raw_mut()) };
+ error_result!((), r)
+ }
+
+ pub fn writable_size(&self) -> Result<usize> {
+ let r = unsafe { ffi::pa_stream_writable_size(self.raw_mut()) };
+ if r == ::std::usize::MAX {
+ let err = if let Some(c) = self.get_context() {
+ c.errno()
+ } else {
+ ffi::PA_ERR_UNKNOWN
+ };
+ return Err(ErrorCode::from_error_code(err));
+ }
+ Ok(r)
+ }
+
+ pub fn readable_size(&self) -> Result<usize> {
+ let r = unsafe { ffi::pa_stream_readable_size(self.raw_mut()) };
+ if r == ::std::usize::MAX {
+ let err = if let Some(c) = self.get_context() {
+ c.errno()
+ } else {
+ ffi::PA_ERR_UNKNOWN
+ };
+ return Err(ErrorCode::from_error_code(err));
+ }
+ Ok(r)
+ }
+
+ pub fn update_timing_info<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
+ where
+ CB: Fn(&Stream, i32, *mut c_void),
+ {
+ assert_eq!(mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ s: *mut ffi::pa_stream,
+ success: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Stream, i32, *mut c_void),
+ {
+ let mut stm = stream::from_raw_ptr(s);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&mut stm, success, userdata);
+ forget(stm);
+
+ result
+ }
+
+ let r = unsafe {
+ ffi::pa_stream_update_timing_info(self.raw_mut(), Some(wrapped::<CB>), userdata)
+ };
+ if r.is_null() {
+ let err = if let Some(c) = self.get_context() {
+ c.errno()
+ } else {
+ ffi::PA_ERR_UNKNOWN
+ };
+ return Err(ErrorCode::from_error_code(err));
+ }
+ Ok(unsafe { operation::from_raw_ptr(r) })
+ }
+
+ pub fn clear_state_callback(&self) {
+ unsafe {
+ ffi::pa_stream_set_state_callback(self.raw_mut(), None, ptr::null_mut());
+ }
+ }
+
+ pub fn set_state_callback<CB>(&self, _: CB, userdata: *mut c_void)
+ where
+ CB: Fn(&Stream, *mut c_void),
+ {
+ assert_eq!(mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(s: *mut ffi::pa_stream, userdata: *mut c_void)
+ where
+ F: Fn(&Stream, *mut c_void),
+ {
+ let mut stm = stream::from_raw_ptr(s);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&mut stm, userdata);
+ forget(stm);
+
+ result
+ }
+
+ unsafe {
+ ffi::pa_stream_set_state_callback(self.raw_mut(), Some(wrapped::<CB>), userdata);
+ }
+ }
+
+ pub fn clear_write_callback(&self) {
+ unsafe {
+ ffi::pa_stream_set_write_callback(self.raw_mut(), None, ptr::null_mut());
+ }
+ }
+
+ pub fn set_write_callback<CB>(&self, _: CB, userdata: *mut c_void)
+ where
+ CB: Fn(&Stream, usize, *mut c_void),
+ {
+ assert_eq!(mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ s: *mut ffi::pa_stream,
+ nbytes: usize,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Stream, usize, *mut c_void),
+ {
+ let mut stm = stream::from_raw_ptr(s);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&mut stm, nbytes, userdata);
+ forget(stm);
+
+ result
+ }
+
+ unsafe {
+ ffi::pa_stream_set_write_callback(self.raw_mut(), Some(wrapped::<CB>), userdata);
+ }
+ }
+
+ pub fn clear_read_callback(&self) {
+ unsafe {
+ ffi::pa_stream_set_read_callback(self.raw_mut(), None, ptr::null_mut());
+ }
+ }
+
+ pub fn set_read_callback<CB>(&self, _: CB, userdata: *mut c_void)
+ where
+ CB: Fn(&Stream, usize, *mut c_void),
+ {
+ assert_eq!(mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ s: *mut ffi::pa_stream,
+ nbytes: usize,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Stream, usize, *mut c_void),
+ {
+ let mut stm = stream::from_raw_ptr(s);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&mut stm, nbytes, userdata);
+ forget(stm);
+
+ result
+ }
+
+ unsafe {
+ ffi::pa_stream_set_read_callback(self.raw_mut(), Some(wrapped::<CB>), userdata);
+ }
+ }
+
+ pub fn cork<CB>(&self, b: i32, _: CB, userdata: *mut c_void) -> Result<Operation>
+ where
+ CB: Fn(&Stream, i32, *mut c_void),
+ {
+ assert_eq!(mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ s: *mut ffi::pa_stream,
+ success: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Stream, i32, *mut c_void),
+ {
+ let mut stm = stream::from_raw_ptr(s);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&mut stm, success, userdata);
+ forget(stm);
+
+ result
+ }
+
+ let r = unsafe { ffi::pa_stream_cork(self.raw_mut(), b, Some(wrapped::<CB>), userdata) };
+ if r.is_null() {
+ let err = if let Some(c) = self.get_context() {
+ c.errno()
+ } else {
+ ffi::PA_ERR_UNKNOWN
+ };
+ return Err(ErrorCode::from_error_code(err));
+ }
+ Ok(unsafe { operation::from_raw_ptr(r) })
+ }
+
+ pub fn get_time(&self) -> Result<USec> {
+ let mut usec: USec = 0;
+ let r = unsafe { ffi::pa_stream_get_time(self.raw_mut(), &mut usec) };
+ error_result!(usec, r)
+ }
+
+ pub fn get_latency(&self) -> Result<StreamLatency> {
+ let mut usec: u64 = 0;
+ let mut negative: i32 = 0;
+ let r = unsafe { ffi::pa_stream_get_latency(self.raw_mut(), &mut usec, &mut negative) };
+ error_result!(
+ if negative == 0 {
+ StreamLatency::Positive(usec)
+ } else {
+ StreamLatency::Negative(usec)
+ },
+ r
+ )
+ }
+
+ pub fn get_sample_spec(&self) -> &SampleSpec {
+ unsafe {
+ let ptr = ffi::pa_stream_get_sample_spec(self.raw_mut());
+ debug_assert!(!ptr.is_null());
+ &*ptr
+ }
+ }
+
+ pub fn get_channel_map(&self) -> &ChannelMap {
+ unsafe {
+ let ptr = ffi::pa_stream_get_channel_map(self.raw_mut());
+ debug_assert!(!ptr.is_null());
+ &*ptr
+ }
+ }
+
+ pub fn get_buffer_attr(&self) -> &BufferAttr {
+ unsafe {
+ let ptr = ffi::pa_stream_get_buffer_attr(self.raw_mut());
+ debug_assert!(!ptr.is_null());
+ &*ptr
+ }
+ }
+
+ pub fn set_name<CB>(&self, name: &CStr, _: CB, userdata: *mut c_void) -> Result<Operation>
+ where
+ CB: Fn(&Stream, i32, *mut c_void),
+ {
+ assert_eq!(mem::size_of::<CB>(), 0);
+
+ // See: A note about `wrapped` functions
+ unsafe extern "C" fn wrapped<F>(
+ s: *mut ffi::pa_stream,
+ success: c_int,
+ userdata: *mut c_void,
+ ) where
+ F: Fn(&Stream, i32, *mut c_void),
+ {
+ let mut stm = stream::from_raw_ptr(s);
+ let cb = MaybeUninit::<F>::uninit();
+ let result = (*cb.as_ptr())(&mut stm, success, userdata);
+ forget(stm);
+
+ result
+ }
+
+ let r = unsafe {
+ ffi::pa_stream_set_name(self.raw_mut(), name.as_ptr(), Some(wrapped::<CB>), userdata)
+ };
+ if r.is_null() {
+ let err = if let Some(c) = self.get_context() {
+ c.errno()
+ } else {
+ ffi::PA_ERR_UNKNOWN
+ };
+ return Err(ErrorCode::from_error_code(err));
+ }
+ Ok(unsafe { operation::from_raw_ptr(r) })
+ }
+}
+
+#[doc(hidden)]
+pub unsafe fn from_raw_ptr(ptr: *mut ffi::pa_stream) -> Stream {
+ Stream(ptr)
+}
diff --git a/third_party/rust/pulse/src/threaded_mainloop.rs b/third_party/rust/pulse/src/threaded_mainloop.rs
new file mode 100644
index 0000000000..74d2410d63
--- /dev/null
+++ b/third_party/rust/pulse/src/threaded_mainloop.rs
@@ -0,0 +1,92 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details.
+
+use ffi;
+use mainloop_api;
+use mainloop_api::MainloopApi;
+use ErrorCode;
+use Result;
+
+#[derive(Debug)]
+pub struct ThreadedMainloop(*mut ffi::pa_threaded_mainloop);
+
+impl ThreadedMainloop {
+ pub unsafe fn from_raw_ptr(raw: *mut ffi::pa_threaded_mainloop) -> Self {
+ ThreadedMainloop(raw)
+ }
+
+ pub fn new() -> Self {
+ unsafe { ThreadedMainloop::from_raw_ptr(ffi::pa_threaded_mainloop_new()) }
+ }
+
+ pub fn raw_mut(&self) -> &mut ffi::pa_threaded_mainloop {
+ unsafe { &mut *self.0 }
+ }
+
+ pub fn is_null(&self) -> bool {
+ self.0.is_null()
+ }
+
+ pub fn start(&self) -> Result<()> {
+ match unsafe { ffi::pa_threaded_mainloop_start(self.raw_mut()) } {
+ 0 => Ok(()),
+ _ => Err(ErrorCode::from_error_code(ffi::PA_ERR_UNKNOWN)),
+ }
+ }
+
+ pub fn stop(&self) {
+ unsafe {
+ ffi::pa_threaded_mainloop_stop(self.raw_mut());
+ }
+ }
+
+ pub fn lock(&self) {
+ unsafe {
+ ffi::pa_threaded_mainloop_lock(self.raw_mut());
+ }
+ }
+
+ pub fn unlock(&self) {
+ unsafe {
+ ffi::pa_threaded_mainloop_unlock(self.raw_mut());
+ }
+ }
+
+ pub fn wait(&self) {
+ unsafe {
+ ffi::pa_threaded_mainloop_wait(self.raw_mut());
+ }
+ }
+
+ pub fn signal(&self) {
+ unsafe {
+ ffi::pa_threaded_mainloop_signal(self.raw_mut(), 0);
+ }
+ }
+
+ pub fn get_api(&self) -> MainloopApi {
+ unsafe { mainloop_api::from_raw_ptr(ffi::pa_threaded_mainloop_get_api(self.raw_mut())) }
+ }
+
+ pub fn in_thread(&self) -> bool {
+ unsafe { ffi::pa_threaded_mainloop_in_thread(self.raw_mut()) != 0 }
+ }
+}
+
+impl ::std::default::Default for ThreadedMainloop {
+ fn default() -> Self {
+ ThreadedMainloop(::std::ptr::null_mut())
+ }
+}
+
+impl ::std::ops::Drop for ThreadedMainloop {
+ fn drop(&mut self) {
+ if !self.is_null() {
+ unsafe {
+ ffi::pa_threaded_mainloop_free(self.raw_mut());
+ }
+ }
+ }
+}
diff --git a/third_party/rust/pulse/src/util.rs b/third_party/rust/pulse/src/util.rs
new file mode 100644
index 0000000000..8f18a49857
--- /dev/null
+++ b/third_party/rust/pulse/src/util.rs
@@ -0,0 +1,42 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details.
+
+use std::ffi::CStr;
+use std::os::raw::c_char;
+use std::ptr;
+
+pub trait UnwrapCStr {
+ fn unwrap_cstr(self) -> *const c_char;
+}
+
+impl<'a, U> UnwrapCStr for U
+where
+ U: Into<Option<&'a CStr>>,
+{
+ fn unwrap_cstr(self) -> *const c_char {
+ self.into().map(|o| o.as_ptr()).unwrap_or(0 as *const _)
+ }
+}
+
+pub fn map_to_mut_ptr<T, U, F: FnOnce(&T) -> *mut U>(t: Option<&mut T>, f: F) -> *mut U {
+ match t {
+ Some(x) => f(x),
+ None => ptr::null_mut(),
+ }
+}
+
+pub fn str_to_ptr(s: Option<&CStr>) -> *const c_char {
+ match s {
+ Some(x) => x.as_ptr(),
+ None => ptr::null(),
+ }
+}
+
+pub fn to_ptr<T>(t: Option<&T>) -> *const T {
+ match t {
+ Some(x) => x as *const T,
+ None => ptr::null(),
+ }
+}