firefox/build-cubeb-pulse-arm.patch
2017-08-04 14:34:40 +02:00

4947 lines
190 KiB
Diff

diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/Cargo.toml.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/Cargo.toml
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/Cargo.toml.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/Cargo.toml 2017-08-04 13:37:46.383821740 +0200
@@ -7,7 +7,11 @@ description = "Cubeb backed for PulseAud
[features]
pulse-dlopen = ["pulse-ffi/dlopen"]
+[lib]
+crate-type = ["staticlib", "rlib"]
+
[dependencies]
cubeb-ffi = { path = "cubeb-ffi" }
pulse-ffi = { path = "pulse-ffi" }
+pulse = { path = "pulse-rs" }
semver = "^0.6"
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs 2017-08-04 13:37:46.384821737 +0200
@@ -11,45 +11,45 @@ pub enum Context {}
pub enum Stream {}
// These need to match cubeb_sample_format
-pub const SAMPLE_S16LE: c_int = 0;
-pub const SAMPLE_S16BE: c_int = 1;
-pub const SAMPLE_FLOAT32LE: c_int = 2;
-pub const SAMPLE_FLOAT32BE: c_int = 3;
pub type SampleFormat = c_int;
+pub const SAMPLE_S16LE: SampleFormat = 0;
+pub const SAMPLE_S16BE: SampleFormat = 1;
+pub const SAMPLE_FLOAT32LE: SampleFormat = 2;
+pub const SAMPLE_FLOAT32BE: SampleFormat = 3;
#[cfg(target_endian = "little")]
-pub const SAMPLE_S16NE: c_int = SAMPLE_S16LE;
+pub const SAMPLE_S16NE: SampleFormat = SAMPLE_S16LE;
#[cfg(target_endian = "little")]
-pub const SAMPLE_FLOAT32NE: c_int = SAMPLE_FLOAT32LE;
+pub const SAMPLE_FLOAT32NE: SampleFormat = SAMPLE_FLOAT32LE;
#[cfg(target_endian = "big")]
-pub const SAMPLE_S16NE: c_int = SAMPLE_S16BE;
+pub const SAMPLE_S16NE: SampleFormat = SAMPLE_S16BE;
#[cfg(target_endian = "big")]
-pub const SAMPLE_FLOAT32NE: c_int = SAMPLE_FLOAT32BE;
+pub const SAMPLE_FLOAT32NE: SampleFormat = SAMPLE_FLOAT32BE;
pub type DeviceId = *const c_void;
// These need to match cubeb_channel_layout
-pub const LAYOUT_UNDEFINED: c_int = 0;
-pub const LAYOUT_DUAL_MONO: c_int = 1;
-pub const LAYOUT_DUAL_MONO_LFE: c_int = 2;
-pub const LAYOUT_MONO: c_int = 3;
-pub const LAYOUT_MONO_LFE: c_int = 4;
-pub const LAYOUT_STEREO: c_int = 5;
-pub const LAYOUT_STEREO_LFE: c_int = 6;
-pub const LAYOUT_3F: c_int = 7;
-pub const LAYOUT_3F_LFE: c_int = 8;
-pub const LAYOUT_2F1: c_int = 9;
-pub const LAYOUT_2F1_LFE: c_int = 10;
-pub const LAYOUT_3F1: c_int = 11;
-pub const LAYOUT_3F1_LFE: c_int = 12;
-pub const LAYOUT_2F2: c_int = 13;
-pub const LAYOUT_2F2_LFE: c_int = 14;
-pub const LAYOUT_3F2: c_int = 15;
-pub const LAYOUT_3F2_LFE: c_int = 16;
-pub const LAYOUT_3F3R_LFE: c_int = 17;
-pub const LAYOUT_3F4_LFE: c_int = 18;
-pub const LAYOUT_MAX: c_int = 19;
pub type ChannelLayout = c_int;
+pub const LAYOUT_UNDEFINED: ChannelLayout = 0;
+pub const LAYOUT_DUAL_MONO: ChannelLayout = 1;
+pub const LAYOUT_DUAL_MONO_LFE: ChannelLayout = 2;
+pub const LAYOUT_MONO: ChannelLayout = 3;
+pub const LAYOUT_MONO_LFE: ChannelLayout = 4;
+pub const LAYOUT_STEREO: ChannelLayout = 5;
+pub const LAYOUT_STEREO_LFE: ChannelLayout = 6;
+pub const LAYOUT_3F: ChannelLayout = 7;
+pub const LAYOUT_3F_LFE: ChannelLayout = 8;
+pub const LAYOUT_2F1: ChannelLayout = 9;
+pub const LAYOUT_2F1_LFE: ChannelLayout = 10;
+pub const LAYOUT_3F1: ChannelLayout = 11;
+pub const LAYOUT_3F1_LFE: ChannelLayout = 12;
+pub const LAYOUT_2F2: ChannelLayout = 13;
+pub const LAYOUT_2F2_LFE: ChannelLayout = 14;
+pub const LAYOUT_3F2: ChannelLayout = 15;
+pub const LAYOUT_3F2_LFE: ChannelLayout = 16;
+pub const LAYOUT_3F3R_LFE: ChannelLayout = 17;
+pub const LAYOUT_3F4_LFE: ChannelLayout = 18;
+pub const LAYOUT_MAX: ChannelLayout = 256;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@@ -77,11 +77,11 @@ impl Default for Device {
}
// These need to match cubeb_state
-pub const STATE_STARTED: c_int = 0;
-pub const STATE_STOPPED: c_int = 1;
-pub const STATE_DRAINED: c_int = 2;
-pub const STATE_ERROR: c_int = 3;
pub type State = c_int;
+pub const STATE_STARTED: State = 0;
+pub const STATE_STOPPED: State = 1;
+pub const STATE_DRAINED: State = 2;
+pub const STATE_ERROR: State = 3;
pub const OK: i32 = 0;
pub const ERROR: i32 = -1;
@@ -249,32 +249,42 @@ pub struct LayoutMap {
}
// cubeb_mixer.h
+pub type Channel = c_int;
// These need to match cubeb_channel
-pub const CHANNEL_INVALID: c_int = -1;
-pub const CHANNEL_MONO: c_int = 0;
-pub const CHANNEL_LEFT: c_int = 1;
-pub const CHANNEL_RIGHT: c_int = 2;
-pub const CHANNEL_CENTER: c_int = 3;
-pub const CHANNEL_LS: c_int = 4;
-pub const CHANNEL_RS: c_int = 5;
-pub const CHANNEL_RLS: c_int = 6;
-pub const CHANNEL_RCENTER: c_int = 7;
-pub const CHANNEL_RRS: c_int = 8;
-pub const CHANNEL_LFE: c_int = 9;
-pub const CHANNEL_MAX: c_int = 256;
-pub type Channel = c_int;
+pub const CHANNEL_INVALID: Channel = -1;
+pub const CHANNEL_MONO: Channel = 0;
+pub const CHANNEL_LEFT: Channel = 1;
+pub const CHANNEL_RIGHT: Channel = 2;
+pub const CHANNEL_CENTER: Channel = 3;
+pub const CHANNEL_LS: Channel = 4;
+pub const CHANNEL_RS: Channel = 5;
+pub const CHANNEL_RLS: Channel = 6;
+pub const CHANNEL_RCENTER: Channel = 7;
+pub const CHANNEL_RRS: Channel = 8;
+pub const CHANNEL_LFE: Channel = 9;
+pub const CHANNEL_MAX: Channel = 10;
#[repr(C)]
+#[derive(Clone, Copy, Debug)]
pub struct ChannelMap {
pub channels: c_uint,
- pub map: [Channel; 256],
+ pub map: [Channel; CHANNEL_MAX as usize],
}
impl ::std::default::Default for ChannelMap {
fn default() -> Self {
ChannelMap {
channels: 0,
- map: unsafe { ::std::mem::zeroed() },
+ map: [CHANNEL_INVALID,
+ CHANNEL_INVALID,
+ CHANNEL_INVALID,
+ CHANNEL_INVALID,
+ CHANNEL_INVALID,
+ CHANNEL_INVALID,
+ CHANNEL_INVALID,
+ CHANNEL_INVALID,
+ CHANNEL_INVALID,
+ CHANNEL_INVALID],
}
}
}
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs 2017-08-04 13:37:46.384821737 +0200
@@ -8,8 +8,8 @@ macro_rules! cstr {
#[cfg(not(feature = "dlopen"))]
mod static_fns {
- use std::os::raw::{c_char, c_double, c_int, c_float, c_uint, c_void};
use super::*;
+ use std::os::raw::{c_char, c_double, c_float, c_int, c_uint, c_void};
#[link(name = "pulse")]
extern "C" {
@@ -62,6 +62,7 @@ mod static_fns {
userdata: *mut c_void)
-> *mut pa_operation;
pub fn pa_context_set_state_callback(c: *mut pa_context, cb: pa_context_notify_cb_t, userdata: *mut c_void);
+ pub fn pa_context_errno(c: *mut pa_context) -> c_int;
pub fn pa_context_set_subscribe_callback(c: *mut pa_context,
cb: pa_context_subscribe_cb_t,
userdata: *mut c_void);
@@ -70,6 +71,7 @@ mod static_fns {
cb: pa_context_success_cb_t,
userdata: *mut c_void)
-> *mut pa_operation;
+ pub fn pa_context_ref(c: *mut pa_context) -> *mut pa_context;
pub fn pa_context_unref(c: *mut pa_context);
pub fn pa_cvolume_set(a: *mut pa_cvolume, channels: c_uint, v: pa_volume_t) -> *mut pa_cvolume;
pub fn pa_cvolume_set_balance(v: *mut pa_cvolume,
@@ -80,12 +82,20 @@ mod static_fns {
pub fn pa_mainloop_api_once(m: *mut pa_mainloop_api,
callback: pa_mainloop_api_once_cb_t,
userdata: *mut c_void);
- pub fn pa_operation_get_state(o: *const pa_operation) -> pa_operation_state_t;
+ pub fn pa_strerror(error: pa_error_code_t) -> *const c_char;
+ pub fn pa_operation_ref(o: *mut pa_operation) -> *mut pa_operation;
pub fn pa_operation_unref(o: *mut pa_operation);
+ pub fn pa_operation_cancel(o: *mut pa_operation);
+ pub fn pa_operation_get_state(o: *const pa_operation) -> pa_operation_state_t;
+ pub fn pa_operation_set_state_callback(o: *mut pa_operation,
+ cb: pa_operation_notify_cb_t,
+ userdata: *mut c_void);
pub fn pa_proplist_gets(p: *mut pa_proplist, key: *const c_char) -> *const c_char;
pub fn pa_rtclock_now() -> pa_usec_t;
pub fn pa_stream_begin_write(p: *mut pa_stream, data: *mut *mut c_void, nbytes: *mut usize) -> c_int;
pub fn pa_stream_cancel_write(p: *mut pa_stream) -> c_int;
+ pub fn pa_stream_is_suspended(s: *const pa_stream) -> c_int;
+ pub fn pa_stream_is_corked(s: *const pa_stream) -> c_int;
pub fn pa_stream_connect_playback(s: *mut pa_stream,
dev: *const c_char,
attr: *const pa_buffer_attr,
@@ -112,6 +122,7 @@ mod static_fns {
pub fn pa_stream_get_latency(s: *const pa_stream, r_usec: *mut pa_usec_t, negative: *mut c_int) -> c_int;
pub fn pa_stream_get_sample_spec(s: *const pa_stream) -> *const pa_sample_spec;
pub fn pa_stream_get_state(p: *const pa_stream) -> pa_stream_state_t;
+ pub fn pa_stream_get_context(s: *const pa_stream) -> *mut pa_context;
pub fn pa_stream_get_time(s: *const pa_stream, r_usec: *mut pa_usec_t) -> c_int;
pub fn pa_stream_new(c: *mut pa_context,
name: *const c_char,
@@ -123,6 +134,7 @@ mod static_fns {
pub fn pa_stream_set_state_callback(s: *mut pa_stream, cb: pa_stream_notify_cb_t, userdata: *mut c_void);
pub fn pa_stream_set_write_callback(p: *mut pa_stream, cb: pa_stream_request_cb_t, userdata: *mut c_void);
pub fn pa_stream_set_read_callback(p: *mut pa_stream, cb: pa_stream_request_cb_t, userdata: *mut c_void);
+ pub fn pa_stream_ref(s: *mut pa_stream) -> *mut pa_stream;
pub fn pa_stream_unref(s: *mut pa_stream);
pub fn pa_stream_update_timing_info(p: *mut pa_stream,
cb: pa_stream_success_cb_t,
@@ -148,8 +160,6 @@ mod static_fns {
pub fn pa_threaded_mainloop_unlock(m: *mut pa_threaded_mainloop);
pub fn pa_threaded_mainloop_wait(m: *mut pa_threaded_mainloop);
pub fn pa_usec_to_bytes(t: pa_usec_t, spec: *const pa_sample_spec) -> usize;
- pub fn pa_xfree(ptr: *mut c_void);
- pub fn pa_xstrdup(str: *const c_char) -> *mut c_char;
pub fn pa_xrealloc(ptr: *mut c_void, size: usize) -> *mut c_void;
}
}
@@ -159,9 +169,9 @@ pub use self::static_fns::*;
#[cfg(feature = "dlopen")]
mod dynamic_fns {
- use std::os::raw::{c_char, c_double, c_int, c_float, c_uint, c_void};
- use libc::{dlclose, dlopen, dlsym, RTLD_LAZY};
use super::*;
+ use libc::{RTLD_LAZY, dlclose, dlopen, dlsym};
+ use std::os::raw::{c_char, c_double, c_float, c_int, c_uint, c_void};
#[derive(Debug)]
pub struct LibLoader {
@@ -287,6 +297,13 @@ mod dynamic_fns {
}
fp
};
+ PA_CONTEXT_ERRNO = {
+ let fp = dlsym(h, cstr!("pa_context_errno"));
+ if fp.is_null() {
+ return None;
+ }
+ fp
+ };
PA_CONTEXT_SET_SUBSCRIBE_CALLBACK = {
let fp = dlsym(h, cstr!("pa_context_set_subscribe_callback"));
if fp.is_null() {
@@ -301,6 +318,13 @@ mod dynamic_fns {
}
fp
};
+ PA_CONTEXT_REF = {
+ let fp = dlsym(h, cstr!("pa_context_ref"));
+ if fp.is_null() {
+ return None;
+ }
+ fp
+ };
PA_CONTEXT_UNREF = {
let fp = dlsym(h, cstr!("pa_context_unref"));
if fp.is_null() {
@@ -336,8 +360,15 @@ mod dynamic_fns {
}
fp
};
- PA_OPERATION_GET_STATE = {
- let fp = dlsym(h, cstr!("pa_operation_get_state"));
+ PA_STRERROR = {
+ let fp = dlsym(h, cstr!("pa_strerror"));
+ if fp.is_null() {
+ return None;
+ }
+ fp
+ };
+ PA_OPERATION_REF = {
+ let fp = dlsym(h, cstr!("pa_operation_ref"));
if fp.is_null() {
return None;
}
@@ -350,6 +381,27 @@ mod dynamic_fns {
}
fp
};
+ PA_OPERATION_CANCEL = {
+ let fp = dlsym(h, cstr!("pa_operation_cancel"));
+ if fp.is_null() {
+ return None;
+ }
+ fp
+ };
+ PA_OPERATION_GET_STATE = {
+ let fp = dlsym(h, cstr!("pa_operation_get_state"));
+ if fp.is_null() {
+ return None;
+ }
+ fp
+ };
+ PA_OPERATION_SET_STATE_CALLBACK = {
+ let fp = dlsym(h, cstr!("pa_operation_set_state_callback"));
+ if fp.is_null() {
+ return None;
+ }
+ fp
+ };
PA_PROPLIST_GETS = {
let fp = dlsym(h, cstr!("pa_proplist_gets"));
if fp.is_null() {
@@ -378,6 +430,20 @@ mod dynamic_fns {
}
fp
};
+ PA_STREAM_IS_SUSPENDED = {
+ let fp = dlsym(h, cstr!("pa_stream_is_suspended"));
+ if fp.is_null() {
+ return None;
+ }
+ fp
+ };
+ PA_STREAM_IS_CORKED = {
+ let fp = dlsym(h, cstr!("pa_stream_is_corked"));
+ if fp.is_null() {
+ return None;
+ }
+ fp
+ };
PA_STREAM_CONNECT_PLAYBACK = {
let fp = dlsym(h, cstr!("pa_stream_connect_playback"));
if fp.is_null() {
@@ -462,6 +528,13 @@ mod dynamic_fns {
}
fp
};
+ PA_STREAM_GET_CONTEXT = {
+ let fp = dlsym(h, cstr!("pa_stream_get_context"));
+ if fp.is_null() {
+ return None;
+ }
+ fp
+ };
PA_STREAM_GET_TIME = {
let fp = dlsym(h, cstr!("pa_stream_get_time"));
if fp.is_null() {
@@ -511,6 +584,13 @@ mod dynamic_fns {
}
fp
};
+ PA_STREAM_REF = {
+ let fp = dlsym(h, cstr!("pa_stream_ref"));
+ if fp.is_null() {
+ return None;
+ }
+ fp
+ };
PA_STREAM_UNREF = {
let fp = dlsym(h, cstr!("pa_stream_unref"));
if fp.is_null() {
@@ -623,20 +703,6 @@ mod dynamic_fns {
}
fp
};
- PA_XFREE = {
- let fp = dlsym(h, cstr!("pa_xfree"));
- if fp.is_null() {
- return None;
- }
- fp
- };
- PA_XSTRDUP = {
- let fp = dlsym(h, cstr!("pa_xstrdup"));
- if fp.is_null() {
- return None;
- }
- fp
- };
PA_XREALLOC = {
let fp = dlsym(h, cstr!("pa_xrealloc"));
if fp.is_null() {
@@ -837,6 +903,12 @@ mod dynamic_fns {
*mut c_void)>(PA_CONTEXT_SET_STATE_CALLBACK))(c, cb, userdata)
}
+ static mut PA_CONTEXT_ERRNO: *mut ::libc::c_void = 0 as *mut _;
+ #[inline]
+ pub unsafe fn pa_context_errno(c: *mut pa_context) -> c_int {
+ (::std::mem::transmute::<_, extern "C" fn(*mut pa_context) -> c_int>(PA_CONTEXT_ERRNO))(c)
+ }
+
static mut PA_CONTEXT_SET_SUBSCRIBE_CALLBACK: *mut ::libc::c_void = 0 as *mut _;
#[inline]
pub unsafe fn pa_context_set_subscribe_callback(c: *mut pa_context,
@@ -863,6 +935,12 @@ mod dynamic_fns {
-> *mut pa_operation>(PA_CONTEXT_SUBSCRIBE))(c, m, cb, userdata)
}
+ static mut PA_CONTEXT_REF: *mut ::libc::c_void = 0 as *mut _;
+ #[inline]
+ pub unsafe fn pa_context_ref(c: *mut pa_context) -> *mut pa_context {
+ (::std::mem::transmute::<_, extern "C" fn(*mut pa_context) -> *mut pa_context>(PA_CONTEXT_REF))(c)
+ }
+
static mut PA_CONTEXT_UNREF: *mut ::libc::c_void = 0 as *mut _;
#[inline]
pub unsafe fn pa_context_unref(c: *mut pa_context) {
@@ -907,6 +985,30 @@ mod dynamic_fns {
*mut c_void)>(PA_MAINLOOP_API_ONCE))(m, callback, userdata)
}
+ static mut PA_STRERROR: *mut ::libc::c_void = 0 as *mut _;
+ #[inline]
+ pub unsafe fn pa_strerror(error: pa_error_code_t) -> *const c_char {
+ (::std::mem::transmute::<_, extern "C" fn(pa_error_code_t) -> *const c_char>(PA_STRERROR))(error)
+ }
+
+ static mut PA_OPERATION_REF: *mut ::libc::c_void = 0 as *mut _;
+ #[inline]
+ pub unsafe fn pa_operation_ref(o: *mut pa_operation) -> *mut pa_operation {
+ (::std::mem::transmute::<_, extern "C" fn(*mut pa_operation) -> *mut pa_operation>(PA_OPERATION_REF))(o)
+ }
+
+ static mut PA_OPERATION_UNREF: *mut ::libc::c_void = 0 as *mut _;
+ #[inline]
+ pub unsafe fn pa_operation_unref(o: *mut pa_operation) {
+ (::std::mem::transmute::<_, extern "C" fn(*mut pa_operation)>(PA_OPERATION_UNREF))(o)
+ }
+
+ static mut PA_OPERATION_CANCEL: *mut ::libc::c_void = 0 as *mut _;
+ #[inline]
+ pub unsafe fn pa_operation_cancel(o: *mut pa_operation) {
+ (::std::mem::transmute::<_, extern "C" fn(*mut pa_operation)>(PA_OPERATION_CANCEL))(o)
+ }
+
static mut PA_OPERATION_GET_STATE: *mut ::libc::c_void = 0 as *mut _;
#[inline]
pub unsafe fn pa_operation_get_state(o: *const pa_operation) -> pa_operation_state_t {
@@ -915,10 +1017,15 @@ mod dynamic_fns {
-> pa_operation_state_t>(PA_OPERATION_GET_STATE))(o)
}
- static mut PA_OPERATION_UNREF: *mut ::libc::c_void = 0 as *mut _;
+ static mut PA_OPERATION_SET_STATE_CALLBACK: *mut ::libc::c_void = 0 as *mut _;
#[inline]
- pub unsafe fn pa_operation_unref(o: *mut pa_operation) {
- (::std::mem::transmute::<_, extern "C" fn(*mut pa_operation)>(PA_OPERATION_UNREF))(o)
+ pub unsafe fn pa_operation_set_state_callback(o: *mut pa_operation,
+ cb: pa_operation_notify_cb_t,
+ userdata: *mut c_void) {
+ (::std::mem::transmute::<_,
+ extern "C" fn(*mut pa_operation,
+ pa_operation_notify_cb_t,
+ *mut c_void)>(PA_OPERATION_SET_STATE_CALLBACK))(o, cb, userdata)
}
static mut PA_PROPLIST_GETS: *mut ::libc::c_void = 0 as *mut _;
@@ -951,6 +1058,18 @@ mod dynamic_fns {
(::std::mem::transmute::<_, extern "C" fn(*mut pa_stream) -> c_int>(PA_STREAM_CANCEL_WRITE))(p)
}
+ static mut PA_STREAM_IS_SUSPENDED: *mut ::libc::c_void = 0 as *mut _;
+ #[inline]
+ pub unsafe fn pa_stream_is_suspended(s: *const pa_stream) -> c_int {
+ (::std::mem::transmute::<_, extern "C" fn(*const pa_stream) -> c_int>(PA_STREAM_IS_SUSPENDED))(s)
+ }
+
+ static mut PA_STREAM_IS_CORKED: *mut ::libc::c_void = 0 as *mut _;
+ #[inline]
+ pub unsafe fn pa_stream_is_corked(s: *const pa_stream) -> c_int {
+ (::std::mem::transmute::<_, extern "C" fn(*const pa_stream) -> c_int>(PA_STREAM_IS_CORKED))(s)
+ }
+
static mut PA_STREAM_CONNECT_PLAYBACK: *mut ::libc::c_void = 0 as *mut _;
#[inline]
pub unsafe fn pa_stream_connect_playback(s: *mut pa_stream,
@@ -1066,6 +1185,12 @@ mod dynamic_fns {
(::std::mem::transmute::<_, extern "C" fn(*const pa_stream) -> pa_stream_state_t>(PA_STREAM_GET_STATE))(p)
}
+ static mut PA_STREAM_GET_CONTEXT: *mut ::libc::c_void = 0 as *mut _;
+ #[inline]
+ pub unsafe fn pa_stream_get_context(s: *const pa_stream) -> *mut pa_context {
+ (::std::mem::transmute::<_, extern "C" fn(*const pa_stream) -> *mut pa_context>(PA_STREAM_GET_CONTEXT))(s)
+ }
+
static mut PA_STREAM_GET_TIME: *mut ::libc::c_void = 0 as *mut _;
#[inline]
pub unsafe fn pa_stream_get_time(s: *const pa_stream, r_usec: *mut pa_usec_t) -> c_int {
@@ -1132,6 +1257,12 @@ mod dynamic_fns {
*mut c_void)>(PA_STREAM_SET_READ_CALLBACK))(p, cb, userdata)
}
+ static mut PA_STREAM_REF: *mut ::libc::c_void = 0 as *mut _;
+ #[inline]
+ pub unsafe fn pa_stream_ref(s: *mut pa_stream) -> *mut pa_stream {
+ (::std::mem::transmute::<_, extern "C" fn(*mut pa_stream) -> *mut pa_stream>(PA_STREAM_REF))(s)
+ }
+
static mut PA_STREAM_UNREF: *mut ::libc::c_void = 0 as *mut _;
#[inline]
pub unsafe fn pa_stream_unref(s: *mut pa_stream) {
@@ -1253,18 +1384,6 @@ mod dynamic_fns {
spec)
}
- static mut PA_XFREE: *mut ::libc::c_void = 0 as *mut _;
- #[inline]
- pub unsafe fn pa_xfree(ptr: *mut c_void) {
- (::std::mem::transmute::<_, extern "C" fn(*mut c_void)>(PA_XFREE))(ptr)
- }
-
- static mut PA_XSTRDUP: *mut ::libc::c_void = 0 as *mut _;
- #[inline]
- pub unsafe fn pa_xstrdup(str: *const c_char) -> *mut c_char {
- (::std::mem::transmute::<_, extern "C" fn(*const c_char) -> *mut c_char>(PA_XSTRDUP))(str)
- }
-
static mut PA_XREALLOC: *mut ::libc::c_void = 0 as *mut _;
#[inline]
pub unsafe fn pa_xrealloc(ptr: *mut c_void, size: usize) -> *mut c_void {
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_types.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_types.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_types.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_types.rs 2017-08-04 13:37:46.384821737 +0200
@@ -1,6 +1,6 @@
#![allow(non_camel_case_types)]
-use std::os::raw::{c_char, c_int, c_long, c_ulong, c_void};
+use std::os::raw::{c_char, c_int, c_long, c_uint, c_ulong, c_void};
/* automatically generated by rust-bindgen */
pub const PA_RATE_MAX: u32 = 48000 * 8;
@@ -74,10 +74,10 @@ pub const PA_OPERATION_DONE: c_int = 1;
pub const PA_OPERATION_CANCELLED: c_int = 2;
pub type pa_operation_state_t = c_int;
-pub const PA_CONTEXT_NOFLAGS: c_int = 0;
-pub const PA_CONTEXT_NOAUTOSPAWN: c_int = 1;
-pub const PA_CONTEXT_NOFAIL: c_int = 2;
-pub type pa_context_flags_t = c_int;
+pub const PA_CONTEXT_NOFLAGS: c_uint = 0;
+pub const PA_CONTEXT_NOAUTOSPAWN: c_uint = 1;
+pub const PA_CONTEXT_NOFAIL: c_uint = 2;
+pub type pa_context_flags_t = c_uint;
pub const PA_DIRECTION_OUTPUT: c_int = 1;
pub const PA_DIRECTION_INPUT: c_int = 2;
@@ -93,28 +93,28 @@ pub const PA_STREAM_RECORD: c_int = 2;
pub const PA_STREAM_UPLOAD: c_int = 3;
pub type pa_stream_direction_t = c_int;
-pub const PA_STREAM_NOFLAGS: c_int = 0x0_0000;
-pub const PA_STREAM_START_CORKED: c_int = 0x0_0001;
-pub const PA_STREAM_INTERPOLATE_TIMING: c_int = 0x0_0002;
-pub const PA_STREAM_NOT_MONOTONIC: c_int = 0x0_0004;
-pub const PA_STREAM_AUTO_TIMING_UPDATE: c_int = 0x0_0008;
-pub const PA_STREAM_NO_REMAP_CHANNELS: c_int = 0x0_0010;
-pub const PA_STREAM_NO_REMIX_CHANNELS: c_int = 0x0_0020;
-pub const PA_STREAM_FIX_FORMAT: c_int = 0x0_0040;
-pub const PA_STREAM_FIX_RATE: c_int = 0x0_0080;
-pub const PA_STREAM_FIX_CHANNELS: c_int = 0x0_0100;
-pub const PA_STREAM_DONT_MOVE: c_int = 0x0_0200;
-pub const PA_STREAM_VARIABLE_RATE: c_int = 0x0_0400;
-pub const PA_STREAM_PEAK_DETECT: c_int = 0x0_0800;
-pub const PA_STREAM_START_MUTED: c_int = 0x0_1000;
-pub const PA_STREAM_ADJUST_LATENCY: c_int = 0x0_2000;
-pub const PA_STREAM_EARLY_REQUESTS: c_int = 0x0_4000;
-pub const PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND: c_int = 0x0_8000;
-pub const PA_STREAM_START_UNMUTED: c_int = 0x1_0000;
-pub const PA_STREAM_FAIL_ON_SUSPEND: c_int = 0x2_0000;
-pub const PA_STREAM_RELATIVE_VOLUME: c_int = 0x4_0000;
-pub const PA_STREAM_PASSTHROUGH: c_int = 0x8_0000;
-pub type pa_stream_flags_t = c_int;
+pub const PA_STREAM_NOFLAGS: c_uint = 0x0_0000;
+pub const PA_STREAM_START_CORKED: c_uint = 0x0_0001;
+pub const PA_STREAM_INTERPOLATE_TIMING: c_uint = 0x0_0002;
+pub const PA_STREAM_NOT_MONOTONIC: c_uint = 0x0_0004;
+pub const PA_STREAM_AUTO_TIMING_UPDATE: c_uint = 0x0_0008;
+pub const PA_STREAM_NO_REMAP_CHANNELS: c_uint = 0x0_0010;
+pub const PA_STREAM_NO_REMIX_CHANNELS: c_uint = 0x0_0020;
+pub const PA_STREAM_FIX_FORMAT: c_uint = 0x0_0040;
+pub const PA_STREAM_FIX_RATE: c_uint = 0x0_0080;
+pub const PA_STREAM_FIX_CHANNELS: c_uint = 0x0_0100;
+pub const PA_STREAM_DONT_MOVE: c_uint = 0x0_0200;
+pub const PA_STREAM_VARIABLE_RATE: c_uint = 0x0_0400;
+pub const PA_STREAM_PEAK_DETECT: c_uint = 0x0_0800;
+pub const PA_STREAM_START_MUTED: c_uint = 0x0_1000;
+pub const PA_STREAM_ADJUST_LATENCY: c_uint = 0x0_2000;
+pub const PA_STREAM_EARLY_REQUESTS: c_uint = 0x0_4000;
+pub const PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND: c_uint = 0x0_8000;
+pub const PA_STREAM_START_UNMUTED: c_uint = 0x1_0000;
+pub const PA_STREAM_FAIL_ON_SUSPEND: c_uint = 0x2_0000;
+pub const PA_STREAM_RELATIVE_VOLUME: c_uint = 0x4_0000;
+pub const PA_STREAM_PASSTHROUGH: c_uint = 0x8_0000;
+pub type pa_stream_flags_t = c_uint;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@@ -162,19 +162,19 @@ pub const PA_ERR_BUSY: c_int = 26;
pub const PA_ERR_MAX: c_int = 27;
pub type pa_error_code_t = c_int;
-pub const PA_SUBSCRIPTION_MASK_NULL: c_int = 0;
-pub const PA_SUBSCRIPTION_MASK_SINK: c_int = 1;
-pub const PA_SUBSCRIPTION_MASK_SOURCE: c_int = 2;
-pub const PA_SUBSCRIPTION_MASK_SINK_INPUT: c_int = 4;
-pub const PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT: c_int = 8;
-pub const PA_SUBSCRIPTION_MASK_MODULE: c_int = 16;
-pub const PA_SUBSCRIPTION_MASK_CLIENT: c_int = 32;
-pub const PA_SUBSCRIPTION_MASK_SAMPLE_CACHE: c_int = 64;
-pub const PA_SUBSCRIPTION_MASK_SERVER: c_int = 128;
-pub const PA_SUBSCRIPTION_MASK_AUTOLOAD: c_int = 256;
-pub const PA_SUBSCRIPTION_MASK_CARD: c_int = 512;
-pub const PA_SUBSCRIPTION_MASK_ALL: c_int = 767;
-pub type pa_subscription_mask_t = c_int;
+pub const PA_SUBSCRIPTION_MASK_NULL: c_uint = 0x0;
+pub const PA_SUBSCRIPTION_MASK_SINK: c_uint = 0x1;
+pub const PA_SUBSCRIPTION_MASK_SOURCE: c_uint = 0x2;
+pub const PA_SUBSCRIPTION_MASK_SINK_INPUT: c_uint = 0x4;
+pub const PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT: c_uint = 0x8;
+pub const PA_SUBSCRIPTION_MASK_MODULE: c_uint = 0x10;
+pub const PA_SUBSCRIPTION_MASK_CLIENT: c_uint = 0x20;
+pub const PA_SUBSCRIPTION_MASK_SAMPLE_CACHE: c_uint = 0x40;
+pub const PA_SUBSCRIPTION_MASK_SERVER: c_uint = 0x80;
+pub const PA_SUBSCRIPTION_MASK_AUTOLOAD: c_uint = 0x100;
+pub const PA_SUBSCRIPTION_MASK_CARD: c_uint = 0x200;
+pub const PA_SUBSCRIPTION_MASK_ALL: c_uint = 0x3FF;
+pub type pa_subscription_mask_t = c_uint;
pub const PA_SUBSCRIPTION_EVENT_SINK: c_int = 0;
pub const PA_SUBSCRIPTION_EVENT_SOURCE: c_int = 1;
@@ -244,17 +244,17 @@ pub const PA_SEEK_RELATIVE_ON_READ: c_in
pub const PA_SEEK_RELATIVE_END: c_int = 3;
pub type pa_seek_mode_t = c_int;
-pub const PA_SINK_NOFLAGS: c_int = 0;
-pub const PA_SINK_HW_VOLUME_CTRL: c_int = 1;
-pub const PA_SINK_LATENCY: c_int = 2;
-pub const PA_SINK_HARDWARE: c_int = 4;
-pub const PA_SINK_NETWORK: c_int = 8;
-pub const PA_SINK_HW_MUTE_CTRL: c_int = 16;
-pub const PA_SINK_DECIBEL_VOLUME: c_int = 32;
-pub const PA_SINK_FLAT_VOLUME: c_int = 64;
-pub const PA_SINK_DYNAMIC_LATENCY: c_int = 128;
-pub const PA_SINK_SET_FORMATS: c_int = 256;
-pub type pa_sink_flags_t = c_int;
+pub const PA_SINK_NOFLAGS: c_uint = 0x000;
+pub const PA_SINK_HW_VOLUME_CTRL: c_uint = 0x001;
+pub const PA_SINK_LATENCY: c_uint = 0x002;
+pub const PA_SINK_HARDWARE: c_uint = 0x004;
+pub const PA_SINK_NETWORK: c_uint = 0x008;
+pub const PA_SINK_HW_MUTE_CTRL: c_uint = 0x010;
+pub const PA_SINK_DECIBEL_VOLUME: c_uint = 0x020;
+pub const PA_SINK_FLAT_VOLUME: c_uint = 0x040;
+pub const PA_SINK_DYNAMIC_LATENCY: c_uint = 0x080;
+pub const PA_SINK_SET_FORMATS: c_uint = 0x100;
+pub type pa_sink_flags_t = c_uint;
pub const PA_SINK_INVALID_STATE: c_int = -1;
pub const PA_SINK_RUNNING: c_int = 0;
@@ -264,16 +264,16 @@ pub const PA_SINK_INIT: c_int = -2;
pub const PA_SINK_UNLINKED: c_int = -3;
pub type pa_sink_state_t = c_int;
-pub const PA_SOURCE_NOFLAGS: c_int = 0x00;
-pub const PA_SOURCE_HW_VOLUME_CTRL: c_int = 0x01;
-pub const PA_SOURCE_LATENCY: c_int = 0x02;
-pub const PA_SOURCE_HARDWARE: c_int = 0x04;
-pub const PA_SOURCE_NETWORK: c_int = 0x08;
-pub const PA_SOURCE_HW_MUTE_CTRL: c_int = 0x10;
-pub const PA_SOURCE_DECIBEL_VOLUME: c_int = 0x20;
-pub const PA_SOURCE_DYNAMIC_LATENCY: c_int = 0x40;
-pub const PA_SOURCE_FLAT_VOLUME: c_int = 0x80;
-pub type pa_source_flags_t = c_int;
+pub const PA_SOURCE_NOFLAGS: c_uint = 0x00;
+pub const PA_SOURCE_HW_VOLUME_CTRL: c_uint = 0x01;
+pub const PA_SOURCE_LATENCY: c_uint = 0x02;
+pub const PA_SOURCE_HARDWARE: c_uint = 0x04;
+pub const PA_SOURCE_NETWORK: c_uint = 0x08;
+pub const PA_SOURCE_HW_MUTE_CTRL: c_uint = 0x10;
+pub const PA_SOURCE_DECIBEL_VOLUME: c_uint = 0x20;
+pub const PA_SOURCE_DYNAMIC_LATENCY: c_uint = 0x40;
+pub const PA_SOURCE_FLAT_VOLUME: c_uint = 0x80;
+pub type pa_source_flags_t = c_uint;
pub const PA_SOURCE_INVALID_STATE: c_int = -1;
pub const PA_SOURCE_RUNNING: c_int = 0;
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/Cargo.toml.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/Cargo.toml
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/Cargo.toml.cubeb-pulse-arm 2017-08-04 13:37:46.384821737 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/Cargo.toml 2017-08-04 13:37:46.384821737 +0200
@@ -0,0 +1,8 @@
+[package]
+name = "pulse"
+version = "0.1.0"
+authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
+
+[dependencies]
+bitflags = "^0.7.0"
+pulse-ffi = { path = "../pulse-ffi" }
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/context.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/context.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/context.rs.cubeb-pulse-arm 2017-08-04 13:37:46.385821734 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/context.rs 2017-08-04 13:37:46.385821734 +0200
@@ -0,0 +1,394 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details.
+
+use ::*;
+use ffi;
+use std::ffi::CStr;
+use std::os::raw::{c_int, c_void};
+use std::ptr;
+use util::UnwrapCStr;
+
+// 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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let ctx = context::from_raw_ptr(c);
+ let result = uninitialized::<F>()(&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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let ctx = context::from_raw_ptr(c);
+ let result = uninitialized::<F>()(&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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let api = mainloop_api::from_raw_ptr(a);
+ let timeval = &*tv;
+ let result = uninitialized::<F>()(&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, &ServerInfo, *mut c_void)
+ {
+ debug_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, &ServerInfo, *mut c_void)
+ {
+ use std::mem::{forget, uninitialized};
+ debug_assert_ne!(i, ptr::null_mut());
+ let info = &*i;
+ let ctx = context::from_raw_ptr(c);
+ let result = uninitialized::<F>()(&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<CB>(&self, name: &CStr, _: CB, userdata: *mut c_void) -> Result<Operation>
+ where CB: Fn(&Context, *const SinkInfo, i32, *mut c_void)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let ctx = context::from_raw_ptr(c);
+ let result = uninitialized::<F>()(&ctx, info, eol, userdata);
+ forget(ctx);
+
+ result
+ }
+
+ op_or_err!(self,
+ ffi::pa_context_get_sink_info_by_name(self.raw_mut(), name.as_ptr(), 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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let ctx = context::from_raw_ptr(c);
+ let result = uninitialized::<F>()(&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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let ctx = context::from_raw_ptr(c);
+ let result = uninitialized::<F>()(&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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let ctx = context::from_raw_ptr(c);
+ let result = uninitialized::<F>()(&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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let ctx = context::from_raw_ptr(c);
+ let result = uninitialized::<F>()(&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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let ctx = context::from_raw_ptr(c);
+ let result = uninitialized::<F>()(&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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ 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 result = uninitialized::<F>()(&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 -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/error.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/error.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/error.rs.cubeb-pulse-arm 2017-08-04 13:37:46.385821734 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/error.rs 2017-08-04 13:37:46.385821734 +0200
@@ -0,0 +1,56 @@
+// 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 -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs.cubeb-pulse-arm 2017-08-04 13:37:46.385821734 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs 2017-08-04 13:37:46.385821734 +0200
@@ -0,0 +1,653 @@
+// 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 flags ContextFlags: u32 {
+ const CONTEXT_FLAGS_NOAUTOSPAWN = ffi::PA_CONTEXT_NOAUTOSPAWN,
+ const CONTEXT_FLAGS_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 flags StreamFlags : u32 {
+ const STREAM_START_CORKED = ffi::PA_STREAM_START_CORKED,
+ const STREAM_INTERPOLATE_TIMING = ffi::PA_STREAM_INTERPOLATE_TIMING,
+ const STREAM_NOT_MONOTONIC = ffi::PA_STREAM_NOT_MONOTONIC,
+ const STREAM_AUTO_TIMING_UPDATE = ffi::PA_STREAM_AUTO_TIMING_UPDATE,
+ const STREAM_NO_REMAP_CHANNELS = ffi::PA_STREAM_NO_REMAP_CHANNELS,
+ const STREAM_NO_REMIX_CHANNELS = ffi::PA_STREAM_NO_REMIX_CHANNELS,
+ const STREAM_FIX_FORMAT = ffi::PA_STREAM_FIX_FORMAT,
+ const STREAM_FIX_RATE = ffi::PA_STREAM_FIX_RATE,
+ const STREAM_FIX_CHANNELS = ffi::PA_STREAM_FIX_CHANNELS,
+ const STREAM_DONT_MOVE = ffi::PA_STREAM_DONT_MOVE,
+ const STREAM_VARIABLE_RATE = ffi::PA_STREAM_VARIABLE_RATE,
+ const STREAM_PEAK_DETECT = ffi::PA_STREAM_PEAK_DETECT,
+ const STREAM_START_MUTED = ffi::PA_STREAM_START_MUTED,
+ const STREAM_ADJUST_LATENCY = ffi::PA_STREAM_ADJUST_LATENCY,
+ const STREAM_EARLY_REQUESTS = ffi::PA_STREAM_EARLY_REQUESTS,
+ const STREAM_DONT_INHIBIT_AUTO_SUSPEND = ffi::PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND,
+ const STREAM_START_UNMUTED = ffi::PA_STREAM_START_UNMUTED,
+ const STREAM_FAIL_ON_SUSPEND = ffi::PA_STREAM_FAIL_ON_SUSPEND,
+ const STREAM_RELATIVE_VOLUME = ffi::PA_STREAM_RELATIVE_VOLUME,
+ const STREAM_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
+ }
+}
+
+bitflags!{
+ pub flags SubscriptionMask : u32 {
+ const SUBSCRIPTION_MASK_SINK = ffi::PA_SUBSCRIPTION_MASK_SINK,
+ const SUBSCRIPTION_MASK_SOURCE = ffi::PA_SUBSCRIPTION_MASK_SOURCE,
+ const SUBSCRIPTION_MASK_SINK_INPUT = ffi::PA_SUBSCRIPTION_MASK_SINK_INPUT,
+ const SUBSCRIPTION_MASK_SOURCE_OUTPUT = ffi::PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT,
+ const SUBSCRIPTION_MASK_MODULE = ffi::PA_SUBSCRIPTION_MASK_MODULE,
+ const SUBSCRIPTION_MASK_CLIENT = ffi::PA_SUBSCRIPTION_MASK_CLIENT,
+ const SUBSCRIPTION_MASK_SAMPLE_CACHE = ffi::PA_SUBSCRIPTION_MASK_SAMPLE_CACHE,
+ const SUBSCRIPTION_MASK_SERVER = ffi::PA_SUBSCRIPTION_MASK_SERVER,
+ const SUBSCRIPTION_MASK_AUTOLOAD = ffi::PA_SUBSCRIPTION_MASK_AUTOLOAD,
+ const SUBSCRIPTION_MASK_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! {
+ pub flags SinkFlags: u32 {
+ const SINK_HW_VOLUME_CTRL = ffi::PA_SINK_HW_VOLUME_CTRL,
+ const SINK_LATENCY = ffi::PA_SINK_LATENCY,
+ const SINK_HARDWARE = ffi::PA_SINK_HARDWARE,
+ const SINK_NETWORK = ffi::PA_SINK_NETWORK,
+ const SINK_HW_MUTE_CTRL = ffi::PA_SINK_HW_MUTE_CTRL,
+ const SINK_DECIBEL_VOLUME = ffi::PA_SINK_DECIBEL_VOLUME,
+ const SINK_FLAT_VOLUME = ffi::PA_SINK_FLAT_VOLUME,
+ const SINK_DYNAMIC_LATENCY = ffi::PA_SINK_DYNAMIC_LATENCY,
+ const SINK_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_SOURCE_NOFLAGS | ffi::PA_SOURCE_HW_VOLUME_CTRL | ffi::PA_SOURCE_LATENCY |
+ ffi::PA_SOURCE_HARDWARE | ffi::PA_SOURCE_NETWORK | ffi::PA_SOURCE_HW_MUTE_CTRL |
+ ffi::PA_SOURCE_DECIBEL_VOLUME |
+ ffi::PA_SOURCE_DYNAMIC_LATENCY | ffi::PA_SOURCE_FLAT_VOLUME)) == 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 flags SourceFlags: u32 {
+ const SOURCE_FLAGS_HW_VOLUME_CTRL = ffi::PA_SOURCE_HW_VOLUME_CTRL,
+ const SOURCE_FLAGS_LATENCY = ffi::PA_SOURCE_LATENCY,
+ const SOURCE_FLAGS_HARDWARE = ffi::PA_SOURCE_HARDWARE,
+ const SOURCE_FLAGS_NETWORK = ffi::PA_SOURCE_NETWORK,
+ const SOURCE_FLAGS_HW_MUTE_CTRL = ffi::PA_SOURCE_HW_MUTE_CTRL,
+ const SOURCE_FLAGS_DECIBEL_VOLUME = ffi::PA_SOURCE_DECIBEL_VOLUME,
+ const SOURCE_FLAGS_DYNAMIC_LATENCY = ffi::PA_SOURCE_DYNAMIC_LATENCY,
+ const SOURCE_FLAGS_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 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 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;
+}
+
+impl SampleSpecExt for SampleSpec {
+ fn frame_size(&self) -> usize {
+ unsafe { ffi::pa_frame_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 -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/mainloop_api.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/mainloop_api.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/mainloop_api.rs.cubeb-pulse-arm 2017-08-04 13:37:46.385821734 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/mainloop_api.rs 2017-08-04 13:37:46.385821734 +0200
@@ -0,0 +1,58 @@
+// 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 -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/operation.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/operation.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/operation.rs.cubeb-pulse-arm 2017-08-04 13:37:46.385821734 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/operation.rs 2017-08-04 13:37:46.385821734 +0200
@@ -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 -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/proplist.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/proplist.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/proplist.rs.cubeb-pulse-arm 2017-08-04 13:37:46.385821734 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/proplist.rs 2017-08-04 13:37:46.385821734 +0200
@@ -0,0 +1,31 @@
+// 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 -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs.cubeb-pulse-arm 2017-08-04 13:37:46.386821731 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs 2017-08-04 13:37:46.386821731 +0200
@@ -0,0 +1,367 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details.
+
+use ::*;
+use context;
+use ffi;
+use operation;
+use std::ffi::CStr;
+use std::mem;
+use std::os::raw::{c_int, c_void};
+use std::ptr;
+use util::*;
+
+#[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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let mut stm = stream::from_raw_ptr(s);
+ let result = uninitialized::<F>()(&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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let mut stm = stream::from_raw_ptr(s);
+ let result = uninitialized::<F>()(&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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let mut stm = stream::from_raw_ptr(s);
+ let result = uninitialized::<F>()(&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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let mut stm = stream::from_raw_ptr(s);
+ let result = uninitialized::<F>()(&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)
+ {
+ debug_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)
+ {
+ use std::mem::{forget, uninitialized};
+ let mut stm = stream::from_raw_ptr(s);
+ let result = uninitialized::<F>()(&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<(u64)> {
+ let mut usec: u64 = 0;
+ let r = unsafe { ffi::pa_stream_get_time(self.raw_mut(), &mut usec) };
+ error_result!(usec, r)
+ }
+
+ pub fn get_latency(&self) -> Result<(u64, bool)> {
+ 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!((usec, negative != 0), 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
+ }
+ }
+}
+
+#[doc(hidden)]
+pub unsafe fn from_raw_ptr(ptr: *mut ffi::pa_stream) -> Stream {
+ Stream(ptr)
+}
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/threaded_mainloop.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/threaded_mainloop.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/threaded_mainloop.rs.cubeb-pulse-arm 2017-08-04 13:37:46.386821731 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/threaded_mainloop.rs 2017-08-04 13:37:46.386821731 +0200
@@ -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 ErrorCode;
+use Result;
+use ffi;
+use mainloop_api;
+use mainloop_api::MainloopApi;
+
+#[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 -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/util.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/util.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/util.rs.cubeb-pulse-arm 2017-08-04 13:37:46.386821731 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/util.rs 2017-08-04 13:37:46.386821731 +0200
@@ -0,0 +1,41 @@
+// 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(),
+ }
+}
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/README.md.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/README.md
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/README.md.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/README.md 2017-08-04 13:37:46.383821740 +0200
@@ -3,3 +3,4 @@
Implementation of PulseAudio backend for Cubeb written in Rust.
[![Travis Build Status](https://travis-ci.org/djg/cubeb-pulse-rs.svg?branch=master)](https://travis-ci.org/djg/cubeb-pulse-rs)
+[![Travis Build Status](https://travis-ci.org/djg/cubeb-pulse-rs.svg?branch=dev)](https://travis-ci.org/djg/cubeb-pulse-rs)
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/README_MOZILLA.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/README_MOZILLA
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/README_MOZILLA.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/README_MOZILLA 2017-08-04 13:37:46.383821740 +0200
@@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla
The cubeb-pulse-rs git repository is: https://github.com/djg/cubeb-pulse-rs.git
-The git commit ID used was dbcd7f96aea8d249a4b78f9a7597768c9dff22eb (2017-04-25 11:42:10 +1000)
+The git commit ID used was 64515819cdf54a16626df5dce5f5c7cb1220d53b (2017-06-19 17:41:30 +1000)
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs 2017-08-04 13:50:38.145480458 +0200
@@ -4,67 +4,60 @@
// accompanying file LICENSE for details.
use backend::*;
-use backend::cork_state::CorkState;
use capi::PULSE_OPS;
use cubeb;
+use pulse::{self, ProplistExt};
use pulse_ffi::*;
use semver;
use std::default::Default;
-use std::ffi::CStr;
+use std::ffi::{CStr, CString};
use std::mem;
-use std::os::raw::{c_char, c_int, c_void};
+use std::os::raw::{c_char, c_void};
use std::ptr;
-macro_rules! dup_str {
- ($Dst: expr, $Src: expr) => {
- if !$Dst.is_null() {
- pa_xfree($Dst as *mut _);
- }
-
- $Dst = pa_xstrdup($Src);
- }
-}
-
-fn pa_channel_to_cubeb_channel(channel: pa_channel_position_t) -> cubeb::Channel {
- assert_ne!(channel, PA_CHANNEL_POSITION_INVALID);
+fn pa_channel_to_cubeb_channel(channel: pulse::ChannelPosition) -> cubeb::Channel {
+ use pulse::ChannelPosition;
+ assert_ne!(channel, ChannelPosition::Invalid);
match channel {
- PA_CHANNEL_POSITION_MONO => cubeb::CHANNEL_MONO,
- PA_CHANNEL_POSITION_FRONT_LEFT => cubeb::CHANNEL_LEFT,
- PA_CHANNEL_POSITION_FRONT_RIGHT => cubeb::CHANNEL_RIGHT,
- PA_CHANNEL_POSITION_FRONT_CENTER => cubeb::CHANNEL_CENTER,
- PA_CHANNEL_POSITION_SIDE_LEFT => cubeb::CHANNEL_LS,
- PA_CHANNEL_POSITION_SIDE_RIGHT => cubeb::CHANNEL_RS,
- PA_CHANNEL_POSITION_REAR_LEFT => cubeb::CHANNEL_RLS,
- PA_CHANNEL_POSITION_REAR_CENTER => cubeb::CHANNEL_RCENTER,
- PA_CHANNEL_POSITION_REAR_RIGHT => cubeb::CHANNEL_RRS,
- PA_CHANNEL_POSITION_LFE => cubeb::CHANNEL_LFE,
+ ChannelPosition::Mono => cubeb::CHANNEL_MONO,
+ ChannelPosition::FrontLeft => cubeb::CHANNEL_LEFT,
+ ChannelPosition::FrontRight => cubeb::CHANNEL_RIGHT,
+ ChannelPosition::FrontCenter => cubeb::CHANNEL_CENTER,
+ ChannelPosition::SideLeft => cubeb::CHANNEL_LS,
+ ChannelPosition::SideRight => cubeb::CHANNEL_RS,
+ ChannelPosition::RearLeft => cubeb::CHANNEL_RLS,
+ ChannelPosition::RearCenter => cubeb::CHANNEL_RCENTER,
+ ChannelPosition::RearRight => cubeb::CHANNEL_RRS,
+ ChannelPosition::LowFreqEffects => cubeb::CHANNEL_LFE,
_ => cubeb::CHANNEL_INVALID,
}
}
-fn channel_map_to_layout(cm: &pa_channel_map) -> cubeb::ChannelLayout {
+fn channel_map_to_layout(cm: &pulse::ChannelMap) -> cubeb::ChannelLayout {
+ use pulse::ChannelPosition;
let mut cubeb_map: cubeb::ChannelMap = Default::default();
cubeb_map.channels = cm.channels as u32;
for i in 0usize..cm.channels as usize {
- cubeb_map.map[i] = pa_channel_to_cubeb_channel(cm.map[i]);
+ cubeb_map.map[i] = pa_channel_to_cubeb_channel(ChannelPosition::try_from(cm.map[i])
+ .unwrap_or(ChannelPosition::Invalid));
}
unsafe { cubeb::cubeb_channel_map_to_layout(&cubeb_map) }
}
#[derive(Debug)]
pub struct DefaultInfo {
- pub sample_spec: pa_sample_spec,
- pub channel_map: pa_channel_map,
- pub flags: pa_sink_flags_t,
+ pub sample_spec: pulse::SampleSpec,
+ pub channel_map: pulse::ChannelMap,
+ pub flags: pulse::SinkFlags,
}
#[derive(Debug)]
pub struct Context {
pub ops: *const cubeb::Ops,
- pub mainloop: *mut pa_threaded_mainloop,
- pub context: *mut pa_context,
+ pub mainloop: pulse::ThreadedMainloop,
+ pub context: Option<pulse::Context>,
pub default_sink_info: Option<DefaultInfo>,
- pub context_name: *const c_char,
+ pub context_name: Option<CString>,
pub collection_changed_callback: cubeb::DeviceCollectionChangedCallback,
pub collection_changed_user_ptr: *mut c_void,
pub error: bool,
@@ -82,7 +75,7 @@ impl Drop for Context {
impl Context {
#[cfg(feature = "pulse-dlopen")]
- fn _new(name: *const i8) -> Result<Box<Self>> {
+ fn _new(name: Option<CString>) -> Result<Box<Self>> {
let libpulse = unsafe { open() };
if libpulse.is_none() {
return Err(cubeb::ERROR);
@@ -91,12 +84,12 @@ impl Context {
let ctx = Box::new(Context {
ops: &PULSE_OPS,
libpulse: libpulse.unwrap(),
- mainloop: unsafe { pa_threaded_mainloop_new() },
- context: 0 as *mut _,
+ mainloop: pulse::ThreadedMainloop::new(),
+ context: None,
default_sink_info: None,
context_name: name,
collection_changed_callback: None,
- collection_changed_user_ptr: 0 as *mut _,
+ collection_changed_user_ptr: ptr::null_mut(),
error: true,
version_0_9_8: false,
version_2_0_0: false,
@@ -106,15 +99,15 @@ impl Context {
}
#[cfg(not(feature = "pulse-dlopen"))]
- fn _new(name: *const i8) -> Result<Box<Self>> {
+ fn _new(name: Option<CString>) -> Result<Box<Self>> {
Ok(Box::new(Context {
ops: &PULSE_OPS,
- mainloop: unsafe { pa_threaded_mainloop_new() },
- context: 0 as *mut _,
+ mainloop: pulse::ThreadedMainloop::new(),
+ context: None,
default_sink_info: None,
context_name: name,
collection_changed_callback: None,
- collection_changed_user_ptr: 0 as *mut _,
+ collection_changed_user_ptr: ptr::null_mut(),
error: true,
version_0_9_8: false,
version_2_0_0: false,
@@ -122,53 +115,66 @@ impl Context {
}
pub fn new(name: *const c_char) -> Result<Box<Self>> {
+ fn server_info_cb(context: &pulse::Context, info: &pulse::ServerInfo, u: *mut c_void) {
+ fn sink_info_cb(_: &pulse::Context, i: *const pulse::SinkInfo, eol: i32, u: *mut c_void) {
+ let mut ctx = unsafe { &mut *(u as *mut Context) };
+ if eol == 0 {
+ let info = unsafe { &*i };
+ let flags = pulse::SinkFlags::try_from(info.flags).expect("SinkInfo contains invalid flags");
+ ctx.default_sink_info = Some(DefaultInfo {
+ sample_spec: info.sample_spec,
+ channel_map: info.channel_map,
+ flags: flags,
+ });
+ }
+ ctx.mainloop.signal();
+ }
+
+ let _ = context.get_sink_info_by_name(unsafe { CStr::from_ptr(info.default_sink_name) },
+ sink_info_cb,
+ u);
+ }
+
+ let name = super::try_cstr_from(name).map(|s| s.to_owned());
let mut ctx = try!(Context::_new(name));
- unsafe { pa_threaded_mainloop_start(ctx.mainloop) };
+ if ctx.mainloop.start().is_err() {
+ ctx.destroy();
+ return Err(cubeb::ERROR);
+ }
- if ctx.pulse_context_init() != cubeb::OK {
+ if ctx.context_init() != cubeb::OK {
ctx.destroy();
return Err(cubeb::ERROR);
}
- unsafe {
- /* server_info_callback performs a second async query,
- * which is responsible for initializing default_sink_info
- * and signalling the mainloop to end the wait. */
- pa_threaded_mainloop_lock(ctx.mainloop);
- let o = pa_context_get_server_info(ctx.context,
- Some(server_info_callback),
- ctx.as_mut() as *mut Context as *mut _);
- if !o.is_null() {
- ctx.operation_wait(ptr::null_mut(), o);
- pa_operation_unref(o);
+ ctx.mainloop.lock();
+ /* server_info_callback performs a second async query,
+ * which is responsible for initializing default_sink_info
+ * and signalling the mainloop to end the wait. */
+ let user_data: *mut c_void = ctx.as_mut() as *mut _ as *mut _;
+ if let Some(ref context) = ctx.context {
+ if let Ok(o) = context.get_server_info(server_info_cb, user_data) {
+ ctx.operation_wait(None, &o);
}
- pa_threaded_mainloop_unlock(ctx.mainloop);
- assert!(ctx.default_sink_info.is_some());
}
+ assert!(ctx.default_sink_info.is_some());
+ ctx.mainloop.unlock();
// Return the result.
Ok(ctx)
}
pub fn destroy(&mut self) {
- if !self.context.is_null() {
- unsafe { self.pulse_context_destroy() };
- }
- assert!(self.context.is_null());
+ self.context_destroy();
if !self.mainloop.is_null() {
- unsafe {
- pa_threaded_mainloop_stop(self.mainloop);
- pa_threaded_mainloop_free(self.mainloop);
- self.mainloop = ptr::null_mut();
- }
+ self.mainloop.stop();
}
- assert!(self.mainloop.is_null());
}
pub fn new_stream(&mut self,
- stream_name: *const c_char,
+ stream_name: &CStr,
input_device: cubeb::DeviceId,
input_stream_params: Option<cubeb::StreamParams>,
output_device: cubeb::DeviceId,
@@ -178,7 +184,7 @@ impl Context {
state_callback: cubeb::StateCallback,
user_ptr: *mut c_void)
-> Result<Box<Stream>> {
- if self.error && self.pulse_context_init() != 0 {
+ if self.error && self.context_init() != 0 {
return Err(cubeb::ERROR);
}
@@ -221,41 +227,151 @@ impl Context {
}
pub fn enumerate_devices(&self, devtype: cubeb::DeviceType) -> Result<cubeb::DeviceCollection> {
- let mut user_data: PulseDevListData = Default::default();
- user_data.context = self as *const _ as *mut _;
+ fn add_output_device(_: &pulse::Context, i: *const pulse::SinkInfo, eol: i32, user_data: *mut c_void) {
+ if eol != 0 {
+ return;
+ }
- unsafe {
- pa_threaded_mainloop_lock(self.mainloop);
+ debug_assert!(!i.is_null());
+ debug_assert!(!user_data.is_null());
+
+ let mut list_data = unsafe { &mut *(user_data as *mut PulseDevListData) };
+ let info = unsafe { &*i };
+
+ let group_id = match info.proplist().gets("sysfs.path") {
+ Some(p) => p.to_owned().into_raw(),
+ _ => ptr::null_mut(),
+ };
+
+ let vendor_name = match info.proplist().gets("device.vendor.name") {
+ Some(p) => p.to_owned().into_raw(),
+ _ => ptr::null_mut(),
+ };
+
+ let info_name = unsafe { CStr::from_ptr(info.name) }.to_owned();
+ let info_description = unsafe { CStr::from_ptr(info.description) }.to_owned();
+
+ let preferred = if info_name == list_data.default_sink_name {
+ cubeb::DEVICE_PREF_ALL
+ } else {
+ cubeb::DevicePref::empty()
+ };
+
+ let ctx = &(*list_data.context);
+
+ let device_id = info_name.into_raw();
+ let friendly_name = info_description.into_raw();
+ let devinfo = cubeb::DeviceInfo {
+ device_id: device_id,
+ devid: device_id as cubeb::DeviceId,
+ friendly_name: friendly_name,
+ group_id: group_id,
+ vendor_name: vendor_name,
+ devtype: cubeb::DEVICE_TYPE_OUTPUT,
+ state: ctx.state_from_port(info.active_port),
+ preferred: preferred,
+ format: cubeb::DeviceFmt::all(),
+ default_format: pulse_format_to_cubeb_format(info.sample_spec.format),
+ max_channels: info.channel_map.channels as u32,
+ min_rate: 1,
+ max_rate: PA_RATE_MAX,
+ default_rate: info.sample_spec.rate,
+ latency_lo: 0,
+ latency_hi: 0,
+ };
+ list_data.devinfo.push(devinfo);
+
+ ctx.mainloop.signal();
+ }
+
+ fn add_input_device(_: &pulse::Context, i: *const pulse::SourceInfo, eol: i32, user_data: *mut c_void) {
+ if eol != 0 {
+ return;
+ }
+
+ debug_assert!(!user_data.is_null());
+ debug_assert!(!i.is_null());
+
+ let mut list_data = unsafe { &mut *(user_data as *mut PulseDevListData) };
+ let info = unsafe { &*i };
+
+ let group_id = match info.proplist().gets("sysfs.path") {
+ Some(p) => p.to_owned().into_raw(),
+ _ => ptr::null_mut(),
+ };
+
+ let vendor_name = match info.proplist().gets("device.vendor.name") {
+ Some(p) => p.to_owned().into_raw(),
+ _ => ptr::null_mut(),
+ };
- let o = pa_context_get_server_info(self.context,
- Some(pulse_server_info_cb),
- &mut user_data as *mut _ as *mut _);
- if !o.is_null() {
- self.operation_wait(ptr::null_mut(), o);
- pa_operation_unref(o);
+ let info_name = unsafe { CStr::from_ptr(info.name) }.to_owned();
+ let info_description = unsafe { CStr::from_ptr(info.description) }.to_owned();
+
+ let preferred = if info_name == list_data.default_source_name {
+ cubeb::DEVICE_PREF_ALL
+ } else {
+ cubeb::DevicePref::empty()
+ };
+
+ let ctx = &(*list_data.context);
+ let device_id = info_name.into_raw();
+ let friendly_name = info_description.into_raw();
+ let devinfo = cubeb::DeviceInfo {
+ device_id: device_id,
+ devid: device_id as cubeb::DeviceId,
+ friendly_name: friendly_name,
+ group_id: group_id,
+ vendor_name: vendor_name,
+ devtype: cubeb::DEVICE_TYPE_INPUT,
+ state: ctx.state_from_port(info.active_port),
+ preferred: preferred,
+ format: cubeb::DeviceFmt::all(),
+ default_format: pulse_format_to_cubeb_format(info.sample_spec.format),
+ max_channels: info.channel_map.channels as u32,
+ min_rate: 1,
+ max_rate: PA_RATE_MAX,
+ default_rate: info.sample_spec.rate,
+ latency_lo: 0,
+ latency_hi: 0,
+ };
+
+ list_data.devinfo.push(devinfo);
+
+ ctx.mainloop.signal();
+ }
+
+ fn default_device_names(_: &pulse::Context, info: &pulse::ServerInfo, user_data: *mut c_void) {
+ let list_data = unsafe { &mut *(user_data as *mut PulseDevListData) };
+
+ list_data.default_sink_name = unsafe { CStr::from_ptr(info.default_sink_name) }.to_owned();
+ list_data.default_source_name = unsafe { CStr::from_ptr(info.default_source_name) }.to_owned();
+
+ (*list_data.context).mainloop.signal();
+ }
+
+ let mut user_data = PulseDevListData::new(self);
+
+ if let Some(ref context) = self.context {
+ self.mainloop.lock();
+
+ if let Ok(o) = context.get_server_info(default_device_names, &mut user_data as *mut _ as *mut _) {
+ self.operation_wait(None, &o);
}
if devtype == cubeb::DEVICE_TYPE_OUTPUT {
- let o = pa_context_get_sink_info_list(self.context,
- Some(pulse_sink_info_cb),
- &mut user_data as *mut _ as *mut _);
- if !o.is_null() {
- self.operation_wait(ptr::null_mut(), o);
- pa_operation_unref(o);
+ if let Ok(o) = context.get_sink_info_list(add_output_device, &mut user_data as *mut _ as *mut _) {
+ self.operation_wait(None, &o);
}
}
if devtype == cubeb::DEVICE_TYPE_INPUT {
- let o = pa_context_get_source_info_list(self.context,
- Some(pulse_source_info_cb),
- &mut user_data as *mut _ as *mut _);
- if !o.is_null() {
- self.operation_wait(ptr::null_mut(), o);
- pa_operation_unref(o);
+ if let Ok(o) = context.get_source_info_list(add_input_device, &mut user_data as *mut _ as *mut _) {
+ self.operation_wait(None, &o);
}
}
- pa_threaded_mainloop_unlock(self.mainloop);
+ self.mainloop.unlock();
}
// Extract the array of cubeb_device_info from
@@ -282,16 +398,16 @@ impl Context {
coll.count);
for dev in devices.iter_mut() {
if !dev.device_id.is_null() {
- pa_xfree(dev.device_id as *mut _);
+ let _ = CString::from_raw(dev.device_id as *mut _);
}
if !dev.group_id.is_null() {
- pa_xfree(dev.group_id as *mut _);
+ let _ = CString::from_raw(dev.group_id as *mut _);
}
if !dev.vendor_name.is_null() {
- pa_xfree(dev.vendor_name as *mut _);
+ let _ = CString::from_raw(dev.vendor_name as *mut _);
}
if !dev.friendly_name.is_null() {
- pa_xfree(dev.friendly_name as *mut _);
+ let _ = CString::from_raw(dev.friendly_name as *mut _);
}
}
}
@@ -302,115 +418,125 @@ impl Context {
cb: cubeb::DeviceCollectionChangedCallback,
user_ptr: *mut c_void)
-> i32 {
- unsafe extern "C" fn subscribe_success(_: *mut pa_context, success: i32, user_data: *mut c_void) {
- let ctx = &*(user_data as *mut Context);
+ fn update_collection(_: &pulse::Context, event: pulse::SubscriptionEvent, index: u32, user_data: *mut c_void) {
+ let mut ctx = unsafe { &mut *(user_data as *mut Context) };
+
+ let (f, t) = (event.event_facility(), event.event_type());
+ match f {
+ pulse::SubscriptionEventFacility::Source |
+ pulse::SubscriptionEventFacility::Sink => {
+ match t {
+ pulse::SubscriptionEventType::Remove |
+ pulse::SubscriptionEventType::New => {
+ if cubeb::log_enabled() {
+ let op = if t == pulse::SubscriptionEventType::New {
+ "Adding"
+ } else {
+ "Removing"
+ };
+ let dev = if f == pulse::SubscriptionEventFacility::Sink {
+ "sink"
+ } else {
+ "source "
+ };
+ log!("{} {} index {}", op, dev, index);
+
+ unsafe {
+ ctx.collection_changed_callback.unwrap()(ctx as *mut _ as *mut _,
+ ctx.collection_changed_user_ptr);
+ }
+ }
+ },
+ _ => {},
+ }
+ },
+ _ => {},
+ }
+ }
+
+ fn success(_: &pulse::Context, success: i32, user_data: *mut c_void) {
+ let ctx = unsafe { &*(user_data as *mut Context) };
debug_assert_ne!(success, 0);
- pa_threaded_mainloop_signal(ctx.mainloop, 0);
+ ctx.mainloop.signal();
}
self.collection_changed_callback = cb;
self.collection_changed_user_ptr = user_ptr;
- unsafe {
- pa_threaded_mainloop_lock(self.mainloop);
+ let user_data: *mut c_void = self as *mut _ as *mut _;
+ if let Some(ref context) = self.context {
+ self.mainloop.lock();
- let mut mask: pa_subscription_mask_t = PA_SUBSCRIPTION_MASK_NULL;
+ let mut mask = pulse::SubscriptionMask::empty();
if self.collection_changed_callback.is_none() {
// Unregister subscription
- pa_context_set_subscribe_callback(self.context, None, ptr::null_mut());
+ context.clear_subscribe_callback();
} else {
- pa_context_set_subscribe_callback(self.context,
- Some(pulse_subscribe_callback),
- self as *mut _ as *mut _);
- if devtype == cubeb::DEVICE_TYPE_INPUT {
- mask |= PA_SUBSCRIPTION_MASK_SOURCE
+ context.set_subscribe_callback(update_collection, user_data);
+ if devtype.contains(cubeb::DEVICE_TYPE_INPUT) {
+ mask |= pulse::SUBSCRIPTION_MASK_SOURCE
};
- if devtype == cubeb::DEVICE_TYPE_OUTPUT {
- mask |= PA_SUBSCRIPTION_MASK_SOURCE
+ if devtype.contains(cubeb::DEVICE_TYPE_OUTPUT) {
+ mask = pulse::SUBSCRIPTION_MASK_SINK
};
}
- let o = pa_context_subscribe(self.context,
- mask,
- Some(subscribe_success),
- self as *const _ as *mut _);
- if o.is_null() {
+ if let Ok(o) = context.subscribe(mask, success, self as *const _ as *mut _) {
+ self.operation_wait(None, &o);
+ } else {
log!("Context subscribe failed");
return cubeb::ERROR;
}
- self.operation_wait(ptr::null_mut(), o);
- pa_operation_unref(o);
- pa_threaded_mainloop_unlock(self.mainloop);
+ self.mainloop.unlock();
}
cubeb::OK
}
- //
-
- pub fn pulse_stream_cork(&self, stream: *mut pa_stream, state: CorkState) {
- unsafe extern "C" fn cork_success(_: *mut pa_stream, _: i32, u: *mut c_void) {
- let mainloop = u as *mut pa_threaded_mainloop;
- pa_threaded_mainloop_signal(mainloop, 0);
+ pub fn context_init(&mut self) -> i32 {
+ fn error_state(c: &pulse::Context, u: *mut c_void) {
+ let mut ctx = unsafe { &mut *(u as *mut Context) };
+ if !c.get_state().is_good() {
+ ctx.error = true;
+ }
+ ctx.mainloop.signal();
}
- if stream.is_null() {
- return;
+ if self.context.is_some() {
+ debug_assert!(self.error);
+ self.context_destroy();
}
- let o = unsafe {
- pa_stream_cork(stream,
- state.is_cork() as i32,
- Some(cork_success),
- self.mainloop as *mut _)
+ self.context = {
+ let name = match self.context_name.as_ref() {
+ Some(s) => Some(s.as_ref()),
+ None => None,
+ };
+ pulse::Context::new(&self.mainloop.get_api(), name)
};
- if !o.is_null() {
- self.operation_wait(stream, o);
- unsafe { pa_operation_unref(o) };
+ let context_ptr: *mut c_void = self as *mut _ as *mut _;
+ if self.context.is_none() {
+ return cubeb::ERROR;
}
- }
- pub fn pulse_context_init(&mut self) -> i32 {
- unsafe extern "C" fn error_state(c: *mut pa_context, u: *mut c_void) {
- let mut ctx = &mut *(u as *mut Context);
- if !PA_CONTEXT_IS_GOOD(pa_context_get_state(c)) {
- ctx.error = true;
- }
- pa_threaded_mainloop_signal(ctx.mainloop, 0);
+ self.mainloop.lock();
+ if let Some(ref context) = self.context {
+ context.set_state_callback(error_state, context_ptr);
+ let _ = context.connect(None, pulse::ContextFlags::empty(), ptr::null());
}
- if !self.context.is_null() {
- debug_assert!(self.error);
- unsafe { self.pulse_context_destroy() };
+ if !self.wait_until_context_ready() {
+ self.mainloop.unlock();
+ self.context_destroy();
+ return cubeb::ERROR;
}
- unsafe {
- self.context = pa_context_new(pa_threaded_mainloop_get_api(self.mainloop),
- self.context_name);
-
- if self.context.is_null() {
- return cubeb::ERROR;
- }
-
- pa_context_set_state_callback(self.context, Some(error_state), self as *mut _ as *mut _);
-
- pa_threaded_mainloop_lock(self.mainloop);
- pa_context_connect(self.context, ptr::null(), 0, ptr::null());
-
- if !self.wait_until_context_ready() {
- pa_threaded_mainloop_unlock(self.mainloop);
- self.pulse_context_destroy();
- assert!(self.context.is_null());
- return cubeb::ERROR;
- }
+ self.mainloop.unlock();
- pa_threaded_mainloop_unlock(self.mainloop);
- }
-
- let version_str = unsafe { CStr::from_ptr(pa_get_library_version()) };
- if let Ok(version) = semver::Version::parse(version_str.to_string_lossy().as_ref()) {
+ let version_str = unsafe { CStr::from_ptr(pulse::library_version()) };
+ if let Ok(version) = semver::Version::parse(&version_str.to_string_lossy()) {
self.version_0_9_8 = version >= semver::Version::parse("0.9.8").expect("Failed to parse version");
self.version_2_0_0 = version >= semver::Version::parse("2.0.0").expect("Failed to parse version");
}
@@ -420,34 +546,42 @@ impl Context {
cubeb::OK
}
- unsafe fn pulse_context_destroy(&mut self) {
- unsafe extern "C" fn drain_complete(_c: *mut pa_context, u: *mut c_void) {
- let mainloop = u as *mut pa_threaded_mainloop;
- pa_threaded_mainloop_signal(mainloop, 0);
- }
-
- pa_threaded_mainloop_lock(self.mainloop);
- let o = pa_context_drain(self.context, Some(drain_complete), self.mainloop as *mut _);
- if !o.is_null() {
- self.operation_wait(ptr::null_mut(), o);
- pa_operation_unref(o);
- }
- pa_context_set_state_callback(self.context, None, ptr::null_mut());
- pa_context_disconnect(self.context);
- pa_context_unref(self.context);
- self.context = ptr::null_mut();
- pa_threaded_mainloop_unlock(self.mainloop);
+ fn context_destroy(&mut self) {
+ fn drain_complete(_: &pulse::Context, u: *mut c_void) {
+ let ctx = unsafe { &*(u as *mut Context) };
+ ctx.mainloop.signal();
+ }
+
+ let context_ptr: *mut c_void = self as *mut _ as *mut _;
+ match self.context.take() {
+ Some(ctx) => {
+ self.mainloop.lock();
+ if let Ok(o) = ctx.drain(drain_complete, context_ptr) {
+ self.operation_wait(None, &o);
+ }
+ ctx.clear_state_callback();
+ ctx.disconnect();
+ ctx.unref();
+ self.mainloop.unlock();
+ },
+ _ => {},
+ }
}
- pub fn operation_wait(&self, stream: *mut pa_stream, o: *mut pa_operation) -> bool {
- unsafe {
- while pa_operation_get_state(o) == PA_OPERATION_RUNNING {
- pa_threaded_mainloop_wait(self.mainloop);
- if !PA_CONTEXT_IS_GOOD(pa_context_get_state(self.context)) {
+ pub fn operation_wait<'a, S>(&self, s: S, o: &pulse::Operation) -> bool
+ where S: Into<Option<&'a pulse::Stream>>
+ {
+ let stream = s.into();
+ while o.get_state() == PA_OPERATION_RUNNING {
+ self.mainloop.wait();
+ if let Some(ref context) = self.context {
+ if !context.get_state().is_good() {
return false;
}
+ }
- if !stream.is_null() && !PA_STREAM_IS_GOOD(pa_stream_get_state(stream)) {
+ if let Some(stm) = stream {
+ if !stm.get_state().is_good() {
return false;
}
}
@@ -457,36 +591,23 @@ impl Context {
}
pub fn wait_until_context_ready(&self) -> bool {
- loop {
- let state = unsafe { pa_context_get_state(self.context) };
- if !PA_CONTEXT_IS_GOOD(state) {
- return false;
- }
- if state == PA_CONTEXT_READY {
- break;
- }
- unsafe {
- pa_threaded_mainloop_wait(self.mainloop);
+ if let Some(ref context) = self.context {
+ loop {
+ let state = context.get_state();
+ if !state.is_good() {
+ return false;
+ }
+ if state == pulse::ContextState::Ready {
+ break;
+ }
+ self.mainloop.wait();
}
}
true
}
- fn state_from_sink_port(&self, i: *const pa_port_info) -> cubeb::DeviceState {
- if !i.is_null() {
- let info = unsafe { *i };
- if self.version_2_0_0 && info.available == PA_PORT_AVAILABLE_NO {
- cubeb::DeviceState::Unplugged
- } else {
- cubeb::DeviceState::Enabled
- }
- } else {
- cubeb::DeviceState::Enabled
- }
- }
-
- fn state_from_source_port(&self, i: *mut pa_port_info) -> cubeb::DeviceState {
+ fn state_from_port(&self, i: *const pa_port_info) -> cubeb::DeviceState {
if !i.is_null() {
let info = unsafe { *i };
if self.version_2_0_0 && info.available == PA_PORT_AVAILABLE_NO {
@@ -500,62 +621,30 @@ impl Context {
}
}
-// Callbacks
-unsafe extern "C" fn server_info_callback(context: *mut pa_context, info: *const pa_server_info, u: *mut c_void) {
- unsafe extern "C" fn sink_info_callback(_context: *mut pa_context,
- info: *const pa_sink_info,
- eol: i32,
- u: *mut c_void) {
- let mut ctx = &mut *(u as *mut Context);
- if eol == 0 {
- let info = *info;
- ctx.default_sink_info = Some(DefaultInfo {
- sample_spec: info.sample_spec,
- channel_map: info.channel_map,
- flags: info.flags,
- });
- }
- pa_threaded_mainloop_signal(ctx.mainloop, 0);
- }
-
- let o = pa_context_get_sink_info_by_name(context,
- (*info).default_sink_name,
- Some(sink_info_callback),
- u);
- if !o.is_null() {
- pa_operation_unref(o);
- }
-}
-
-struct PulseDevListData {
- default_sink_name: *mut c_char,
- default_source_name: *mut c_char,
+struct PulseDevListData<'a> {
+ default_sink_name: CString,
+ default_source_name: CString,
devinfo: Vec<cubeb::DeviceInfo>,
- context: *mut Context,
+ context: &'a Context,
}
-impl Drop for PulseDevListData {
- fn drop(&mut self) {
- if !self.default_sink_name.is_null() {
- unsafe {
- pa_xfree(self.default_sink_name as *mut _);
- }
- }
- if !self.default_source_name.is_null() {
- unsafe {
- pa_xfree(self.default_source_name as *mut _);
- }
+impl<'a> PulseDevListData<'a> {
+ pub fn new<'b>(context: &'b Context) -> Self
+ where 'b: 'a
+ {
+ PulseDevListData {
+ default_sink_name: CString::default(),
+ default_source_name: CString::default(),
+ devinfo: Vec::new(),
+ context: context,
}
}
}
-impl Default for PulseDevListData {
- fn default() -> Self {
- PulseDevListData {
- default_sink_name: ptr::null_mut(),
- default_source_name: ptr::null_mut(),
- devinfo: Vec::new(),
- context: ptr::null_mut(),
+impl<'a> Drop for PulseDevListData<'a> {
+ fn drop(&mut self) {
+ for elem in &mut self.devinfo {
+ let _ = unsafe { Box::from_raw(elem) };
}
}
}
@@ -566,192 +655,7 @@ fn pulse_format_to_cubeb_format(format:
PA_SAMPLE_S16BE => cubeb::DEVICE_FMT_S16BE,
PA_SAMPLE_FLOAT32LE => cubeb::DEVICE_FMT_F32LE,
PA_SAMPLE_FLOAT32BE => cubeb::DEVICE_FMT_F32BE,
- _ => {
- panic!("Invalid format");
- },
+ // Unsupported format, return F32NE
+ _ => cubeb::CUBEB_FMT_F32NE,
}
}
-
-unsafe extern "C" fn pulse_sink_info_cb(_context: *mut pa_context,
- i: *const pa_sink_info,
- eol: i32,
- user_data: *mut c_void) {
- if eol != 0 || i.is_null() {
- return;
- }
-
- debug_assert!(!user_data.is_null());
-
- let info = *i;
- let mut list_data = &mut *(user_data as *mut PulseDevListData);
-
- let device_id = pa_xstrdup(info.name);
-
- let group_id = {
- let prop = pa_proplist_gets(info.proplist, b"sysfs.path\0".as_ptr() as *const c_char);
- if !prop.is_null() {
- pa_xstrdup(prop)
- } else {
- ptr::null_mut()
- }
- };
-
- let vendor_name = {
- let prop = pa_proplist_gets(info.proplist,
- b"device.vendor.name\0".as_ptr() as *const c_char);
- if !prop.is_null() {
- pa_xstrdup(prop)
- } else {
- ptr::null_mut()
- }
- };
-
- let preferred = if strcmp(info.name, list_data.default_sink_name) == 0 {
- cubeb::DEVICE_PREF_ALL
- } else {
- cubeb::DevicePref::empty()
- };
-
- let ctx = &(*list_data.context);
-
- let devinfo = cubeb::DeviceInfo {
- device_id: device_id,
- devid: device_id as cubeb::DeviceId,
- friendly_name: pa_xstrdup(info.description),
- group_id: group_id,
- vendor_name: vendor_name,
- devtype: cubeb::DEVICE_TYPE_OUTPUT,
- state: ctx.state_from_sink_port(info.active_port),
- preferred: preferred,
- format: cubeb::DeviceFmt::all(),
- default_format: pulse_format_to_cubeb_format(info.sample_spec.format),
- max_channels: info.channel_map.channels as u32,
- min_rate: 1,
- max_rate: PA_RATE_MAX,
- default_rate: info.sample_spec.rate,
- latency_lo: 0,
- latency_hi: 0,
- };
- list_data.devinfo.push(devinfo);
-
- pa_threaded_mainloop_signal(ctx.mainloop, 0);
-}
-
-unsafe extern "C" fn pulse_source_info_cb(_context: *mut pa_context,
- i: *const pa_source_info,
- eol: i32,
- user_data: *mut c_void) {
- if eol != 0 || i.is_null() {
- return;
- }
-
- debug_assert!(!user_data.is_null());
-
- let info = *i;
- let mut list_data = &mut *(user_data as *mut PulseDevListData);
-
- let device_id = pa_xstrdup(info.name);
-
- let group_id = {
- let prop = pa_proplist_gets(info.proplist, b"sysfs.path\0".as_ptr() as *mut c_char);
- if !prop.is_null() {
- pa_xstrdup(prop)
- } else {
- ptr::null_mut()
- }
- };
-
- let vendor_name = {
- let prop = pa_proplist_gets(info.proplist,
- b"device.vendor.name\0".as_ptr() as *mut c_char);
- if !prop.is_null() {
- pa_xstrdup(prop)
- } else {
- ptr::null_mut()
- }
- };
-
- let preferred = if strcmp(info.name, list_data.default_source_name) == 0 {
- cubeb::DEVICE_PREF_ALL
- } else {
- cubeb::DevicePref::empty()
- };
-
- let ctx = &(*list_data.context);
-
- let devinfo = cubeb::DeviceInfo {
- device_id: device_id,
- devid: device_id as cubeb::DeviceId,
- friendly_name: pa_xstrdup(info.description),
- group_id: group_id,
- vendor_name: vendor_name,
- devtype: cubeb::DEVICE_TYPE_INPUT,
- state: ctx.state_from_source_port(info.active_port),
- preferred: preferred,
- format: cubeb::DeviceFmt::all(),
- default_format: pulse_format_to_cubeb_format(info.sample_spec.format),
- max_channels: info.channel_map.channels as u32,
- min_rate: 1,
- max_rate: PA_RATE_MAX,
- default_rate: info.sample_spec.rate,
- latency_lo: 0,
- latency_hi: 0,
- };
-
- list_data.devinfo.push(devinfo);
-
- pa_threaded_mainloop_signal(ctx.mainloop, 0);
-}
-
-unsafe extern "C" fn pulse_server_info_cb(_context: *mut pa_context,
- i: *const pa_server_info,
- user_data: *mut c_void) {
- assert!(!i.is_null());
- let info = *i;
- let list_data = &mut *(user_data as *mut PulseDevListData);
-
- dup_str!(list_data.default_sink_name, info.default_sink_name);
- dup_str!(list_data.default_source_name, info.default_source_name);
-
- pa_threaded_mainloop_signal((*list_data.context).mainloop, 0);
-}
-
-unsafe extern "C" fn pulse_subscribe_callback(_ctx: *mut pa_context,
- t: pa_subscription_event_type_t,
- index: u32,
- user_data: *mut c_void) {
- let mut ctx = &mut *(user_data as *mut Context);
-
- match t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK {
- PA_SUBSCRIPTION_EVENT_SOURCE |
- PA_SUBSCRIPTION_EVENT_SINK => {
-
- if cubeb::log_enabled() {
- if (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE &&
- (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE {
- log!("Removing sink index %d", index);
- } else if (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE &&
- (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW {
- log!("Adding sink index %d", index);
- }
- if (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK &&
- (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE {
- log!("Removing source index %d", index);
- } else if (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK &&
- (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW {
- log!("Adding source index %d", index);
- }
- }
-
- if (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE ||
- (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW {
- ctx.collection_changed_callback.unwrap()(ctx as *mut _ as *mut _, ctx.collection_changed_user_ptr);
- }
- },
- _ => {},
- }
-}
-
-extern "C" {
- pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int;
-}
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs 2017-08-04 13:37:46.386821731 +0200
@@ -7,8 +7,16 @@ mod context;
mod cork_state;
mod stream;
+use std::os::raw::c_char;
+use std::ffi::CStr;
+
pub type Result<T> = ::std::result::Result<T, i32>;
pub use self::context::Context;
pub use self::stream::Device;
pub use self::stream::Stream;
+
+// helper to convert *const c_char to Option<CStr>
+fn try_cstr_from<'str>(s: *const c_char) -> Option<&'str CStr> {
+ if s.is_null() { None } else { Some(unsafe { CStr::from_ptr(s) }) }
+}
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs 2017-08-04 13:37:46.387821728 +0200
@@ -6,8 +6,10 @@
use backend::*;
use backend::cork_state::CorkState;
use cubeb;
+use pulse::{self, CVolumeExt, ChannelMapExt, SampleSpecExt, USecExt};
use pulse_ffi::*;
-use std::os::raw::{c_char, c_long, c_void};
+use std::ffi::{CStr, CString};
+use std::os::raw::{c_long, c_void};
use std::ptr;
const PULSE_NO_GAIN: f32 = -1.0;
@@ -36,15 +38,12 @@ fn cubeb_channel_to_pa_channel(channel:
MAP[idx as usize]
}
-fn layout_to_channel_map(layout: cubeb::ChannelLayout) -> pa_channel_map {
+fn layout_to_channel_map(layout: cubeb::ChannelLayout) -> pulse::ChannelMap {
assert_ne!(layout, cubeb::LAYOUT_UNDEFINED);
let order = cubeb::mixer::channel_index_to_order(layout);
- let mut cm: pa_channel_map = Default::default();
- unsafe {
- pa_channel_map_init(&mut cm);
- }
+ let mut cm = pulse::ChannelMap::init();
cm.channels = order.len() as u8;
for (s, d) in order.iter().zip(cm.map.iter_mut()) {
*d = cubeb_channel_to_pa_channel(*s);
@@ -57,24 +56,27 @@ pub struct Device(cubeb::Device);
impl Drop for Device {
fn drop(&mut self) {
unsafe {
- pa_xfree(self.0.input_name as *mut _);
- pa_xfree(self.0.output_name as *mut _);
+ if !self.0.input_name.is_null() {
+ let _ = CString::from_raw(self.0.input_name);
+ }
+ if !self.0.output_name.is_null() {
+ let _ = CString::from_raw(self.0.output_name);
+ }
}
}
}
-
#[derive(Debug)]
pub struct Stream<'ctx> {
context: &'ctx Context,
- output_stream: *mut pa_stream,
- input_stream: *mut pa_stream,
+ output_stream: Option<pulse::Stream>,
+ input_stream: Option<pulse::Stream>,
data_callback: cubeb::DataCallback,
state_callback: cubeb::StateCallback,
user_ptr: *mut c_void,
drain_timer: *mut pa_time_event,
- output_sample_spec: pa_sample_spec,
- input_sample_spec: pa_sample_spec,
+ output_sample_spec: pulse::SampleSpec,
+ input_sample_spec: pulse::SampleSpec,
shutdown: bool,
volume: f32,
state: cubeb::State,
@@ -88,7 +90,7 @@ impl<'ctx> Drop for Stream<'ctx> {
impl<'ctx> Stream<'ctx> {
pub fn new(context: &'ctx Context,
- stream_name: *const c_char,
+ stream_name: &CStr,
input_device: cubeb::DeviceId,
input_stream_params: Option<cubeb::StreamParams>,
output_device: cubeb::DeviceId,
@@ -99,83 +101,167 @@ impl<'ctx> Stream<'ctx> {
user_ptr: *mut c_void)
-> Result<Box<Stream<'ctx>>> {
+ fn check_error(s: &pulse::Stream, u: *mut c_void) {
+ let stm = unsafe { &mut *(u as *mut Stream) };
+ if !s.get_state().is_good() {
+ stm.state_change_callback(cubeb::STATE_ERROR);
+ }
+ stm.context.mainloop.signal();
+ }
+
+ fn read_data(s: &pulse::Stream, nbytes: usize, u: *mut c_void) {
+ fn read_from_input(s: &pulse::Stream, buffer: *mut *const c_void, size: *mut usize) -> i32 {
+ let readable_size: i32 = s.readable_size()
+ .and_then(|s| Ok(s as i32))
+ .unwrap_or(-1);
+ if readable_size > 0 {
+ if unsafe { s.peek(buffer, size).is_err() } {
+ return -1;
+ }
+ }
+ readable_size
+ }
+
+ logv!("Input callback buffer size {}", nbytes);
+ let mut stm = unsafe { &mut *(u as *mut Stream) };
+ if stm.shutdown {
+ return;
+ }
+
+ let mut read_data: *const c_void = ptr::null();
+ let mut read_size: usize = 0;
+ while read_from_input(s, &mut read_data, &mut read_size) > 0 {
+ /* read_data can be NULL in case of a hole. */
+ if !read_data.is_null() {
+ let in_frame_size = stm.input_sample_spec.frame_size();
+ let read_frames = read_size / in_frame_size;
+
+ if stm.output_stream.is_some() {
+ // input/capture + output/playback operation
+ let out_frame_size = stm.output_sample_spec.frame_size();
+ let write_size = read_frames * out_frame_size;
+ // Offer full duplex data for writing
+ stm.trigger_user_callback(read_data, write_size);
+ } else {
+ // input/capture only operation. Call callback directly
+ let got = unsafe {
+ stm.data_callback.unwrap()(stm as *mut _ as *mut _,
+ stm.user_ptr,
+ read_data,
+ ptr::null_mut(),
+ read_frames as c_long)
+ };
+
+ if got < 0 || got as usize != read_frames {
+ let _ = s.cancel_write();
+ stm.shutdown = true;
+ break;
+ }
+ }
+ }
+
+ if read_size > 0 {
+ let _ = s.drop();
+ }
+
+ if stm.shutdown {
+ return;
+ }
+ }
+ }
+
+ fn write_data(_: &pulse::Stream, nbytes: usize, u: *mut c_void) {
+ logv!("Output callback to be written buffer size {}", nbytes);
+ let mut stm = unsafe { &mut *(u as *mut Stream) };
+ if stm.shutdown || stm.state != cubeb::STATE_STARTED {
+ return;
+ }
+
+ if stm.input_stream.is_none() {
+ // Output/playback only operation.
+ // Write directly to output
+ debug_assert!(stm.output_stream.is_some());
+ stm.trigger_user_callback(ptr::null(), nbytes);
+ }
+ }
+
let mut stm = Box::new(Stream {
context: context,
- output_stream: ptr::null_mut(),
- input_stream: ptr::null_mut(),
+ output_stream: None,
+ input_stream: None,
data_callback: data_callback,
state_callback: state_callback,
user_ptr: user_ptr,
drain_timer: ptr::null_mut(),
- output_sample_spec: pa_sample_spec::default(),
- input_sample_spec: pa_sample_spec::default(),
+ output_sample_spec: pulse::SampleSpec::default(),
+ input_sample_spec: pulse::SampleSpec::default(),
shutdown: false,
volume: PULSE_NO_GAIN,
state: cubeb::STATE_ERROR,
});
- unsafe {
- pa_threaded_mainloop_lock(stm.context.mainloop);
+ if let Some(ref context) = stm.context.context {
+ stm.context.mainloop.lock();
+
+ // Setup output stream
if let Some(ref stream_params) = output_stream_params {
- match stm.pulse_stream_init(stream_params, stream_name) {
- Ok(s) => stm.output_stream = s,
+ match Stream::stream_init(context, stream_params, stream_name) {
+ Ok(s) => {
+ stm.output_sample_spec = *s.get_sample_spec();
+
+ s.set_state_callback(check_error, stm.as_mut() as *mut _ as *mut _);
+ s.set_write_callback(write_data, stm.as_mut() as *mut _ as *mut _);
+
+ let battr = set_buffering_attribute(latency_frames, &stm.output_sample_spec);
+ let device_name = super::try_cstr_from(output_device as *const _);
+ let _ = s.connect_playback(device_name,
+ &battr,
+ pulse::STREAM_AUTO_TIMING_UPDATE | pulse::STREAM_INTERPOLATE_TIMING |
+ pulse::STREAM_START_CORKED |
+ pulse::STREAM_ADJUST_LATENCY,
+ None,
+ None);
+
+ stm.output_stream = Some(s);
+ },
Err(e) => {
- pa_threaded_mainloop_unlock(stm.context.mainloop);
+ stm.context.mainloop.unlock();
stm.destroy();
return Err(e);
},
}
- stm.output_sample_spec = *pa_stream_get_sample_spec(stm.output_stream);
-
- pa_stream_set_state_callback(stm.output_stream,
- Some(stream_state_callback),
- stm.as_mut() as *mut _ as *mut _);
- pa_stream_set_write_callback(stm.output_stream,
- Some(stream_write_callback),
- stm.as_mut() as *mut _ as *mut _);
-
- let battr = set_buffering_attribute(latency_frames, &stm.output_sample_spec);
- pa_stream_connect_playback(stm.output_stream,
- output_device as *mut c_char,
- &battr,
- PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING |
- PA_STREAM_START_CORKED |
- PA_STREAM_ADJUST_LATENCY,
- ptr::null(),
- ptr::null_mut());
}
// Set up input stream
if let Some(ref stream_params) = input_stream_params {
- match stm.pulse_stream_init(stream_params, stream_name) {
- Ok(s) => stm.input_stream = s,
+ match Stream::stream_init(context, stream_params, stream_name) {
+ Ok(s) => {
+ stm.input_sample_spec = *s.get_sample_spec();
+
+ s.set_state_callback(check_error, stm.as_mut() as *mut _ as *mut _);
+ s.set_read_callback(read_data, stm.as_mut() as *mut _ as *mut _);
+
+ let battr = set_buffering_attribute(latency_frames, &stm.input_sample_spec);
+ let device_name = super::try_cstr_from(input_device as *const _);
+ let _ = s.connect_record(device_name,
+ &battr,
+ pulse::STREAM_AUTO_TIMING_UPDATE | pulse::STREAM_INTERPOLATE_TIMING |
+ pulse::STREAM_START_CORKED |
+ pulse::STREAM_ADJUST_LATENCY);
+
+ stm.input_stream = Some(s);
+ },
Err(e) => {
- pa_threaded_mainloop_unlock(stm.context.mainloop);
+ stm.context.mainloop.unlock();
stm.destroy();
return Err(e);
},
}
- stm.input_sample_spec = *(pa_stream_get_sample_spec(stm.input_stream));
-
- pa_stream_set_state_callback(stm.input_stream,
- Some(stream_state_callback),
- stm.as_mut() as *mut _ as *mut _);
- pa_stream_set_read_callback(stm.input_stream,
- Some(stream_read_callback),
- stm.as_mut() as *mut _ as *mut _);
-
- let battr = set_buffering_attribute(latency_frames, &stm.input_sample_spec);
- pa_stream_connect_record(stm.input_stream,
- input_device as *mut c_char,
- &battr,
- PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING |
- PA_STREAM_START_CORKED |
- PA_STREAM_ADJUST_LATENCY);
}
- let r = if stm.wait_until_stream_ready() {
+ let r = if stm.wait_until_ready() {
/* force a timing update now, otherwise timing info does not become valid
until some point after initialization has completed. */
stm.update_timing_info()
@@ -183,7 +269,7 @@ impl<'ctx> Stream<'ctx> {
false
};
- pa_threaded_mainloop_unlock(stm.context.mainloop);
+ stm.context.mainloop.unlock();
if !r {
stm.destroy();
@@ -191,10 +277,10 @@ impl<'ctx> Stream<'ctx> {
}
if cubeb::log_enabled() {
- if output_stream_params.is_some() {
- let output_att = *pa_stream_get_buffer_attr(stm.output_stream);
- log!("Output buffer attributes maxlength %u, tlength %u, \
- prebuf %u, minreq %u, fragsize %u",
+ if let Some(ref output_stream) = stm.output_stream {
+ let output_att = output_stream.get_buffer_attr();
+ log!("Output buffer attributes maxlength {}, tlength {}, \
+ prebuf {}, minreq {}, fragsize {}",
output_att.maxlength,
output_att.tlength,
output_att.prebuf,
@@ -202,10 +288,10 @@ impl<'ctx> Stream<'ctx> {
output_att.fragsize);
}
- if input_stream_params.is_some() {
- let input_att = *pa_stream_get_buffer_attr(stm.input_stream);
- log!("Input buffer attributes maxlength %u, tlength %u, \
- prebuf %u, minreq %u, fragsize %u",
+ if let Some(ref input_stream) = stm.input_stream {
+ let input_att = input_stream.get_buffer_attr();
+ log!("Input buffer attributes maxlength {}, tlength {}, \
+ prebuf {}, minreq {}, fragsize {}",
input_att.maxlength,
input_att.tlength,
input_att.prebuf,
@@ -219,224 +305,250 @@ impl<'ctx> Stream<'ctx> {
}
fn destroy(&mut self) {
- self.stream_cork(CorkState::cork());
+ self.cork(CorkState::cork());
- unsafe {
- pa_threaded_mainloop_lock(self.context.mainloop);
- if !self.output_stream.is_null() {
- if !self.drain_timer.is_null() {
- /* there's no pa_rttime_free, so use this instead. */
- let ma = pa_threaded_mainloop_get_api(self.context.mainloop);
- if !ma.is_null() {
- (*ma).time_free.unwrap()(self.drain_timer);
+ self.context.mainloop.lock();
+ {
+ match self.output_stream.take() {
+ Some(stm) => {
+ if !self.drain_timer.is_null() {
+ /* there's no pa_rttime_free, so use this instead. */
+ self.context
+ .mainloop
+ .get_api()
+ .time_free(self.drain_timer);
}
- }
-
- pa_stream_set_state_callback(self.output_stream, None, ptr::null_mut());
- pa_stream_set_write_callback(self.output_stream, None, ptr::null_mut());
- pa_stream_disconnect(self.output_stream);
- pa_stream_unref(self.output_stream);
+ stm.clear_state_callback();
+ stm.clear_write_callback();
+ let _ = stm.disconnect();
+ stm.unref();
+ },
+ _ => {},
+ }
+
+ match self.input_stream.take() {
+ Some(stm) => {
+ stm.clear_state_callback();
+ stm.clear_read_callback();
+ let _ = stm.disconnect();
+ stm.unref();
+ },
+ _ => {},
}
-
- if !self.input_stream.is_null() {
- pa_stream_set_state_callback(self.input_stream, None, ptr::null_mut());
- pa_stream_set_read_callback(self.input_stream, None, ptr::null_mut());
- pa_stream_disconnect(self.input_stream);
- pa_stream_unref(self.input_stream);
- }
- pa_threaded_mainloop_unlock(self.context.mainloop);
}
+ self.context.mainloop.unlock();
}
pub fn start(&mut self) -> i32 {
+ fn output_preroll(_: &pulse::MainloopApi, u: *mut c_void) {
+ let mut stm = unsafe { &mut *(u as *mut Stream) };
+ if !stm.shutdown {
+ let size = stm.output_stream
+ .as_ref()
+ .map_or(0, |s| s.writable_size().unwrap_or(0));
+ stm.trigger_user_callback(ptr::null_mut(), size);
+ }
+ }
+
self.shutdown = false;
- self.stream_cork(CorkState::uncork() | CorkState::notify());
+ self.cork(CorkState::uncork() | CorkState::notify());
- if !self.output_stream.is_null() && self.input_stream.is_null() {
- unsafe {
- /* On output only case need to manually call user cb once in order to make
- * things roll. This is done via a defer event in order to execute it
- * from PA server thread. */
- pa_threaded_mainloop_lock(self.context.mainloop);
- pa_mainloop_api_once(pa_threaded_mainloop_get_api(self.context.mainloop),
- Some(pulse_defer_event_cb),
- self as *mut _ as *mut _);
- pa_threaded_mainloop_unlock(self.context.mainloop);
- }
+ if self.output_stream.is_some() && self.input_stream.is_none() {
+ /* On output only case need to manually call user cb once in order to make
+ * things roll. This is done via a defer event in order to execute it
+ * from PA server thread. */
+ self.context.mainloop.lock();
+ self.context
+ .mainloop
+ .get_api()
+ .once(output_preroll, self as *mut _ as *mut _);
+ self.context.mainloop.unlock();
}
cubeb::OK
}
pub fn stop(&mut self) -> i32 {
- unsafe {
- pa_threaded_mainloop_lock(self.context.mainloop);
+ {
+ self.context.mainloop.lock();
self.shutdown = true;
// If draining is taking place wait to finish
while !self.drain_timer.is_null() {
- pa_threaded_mainloop_wait(self.context.mainloop);
+ self.context.mainloop.wait();
}
- pa_threaded_mainloop_unlock(self.context.mainloop);
+ self.context.mainloop.unlock();
}
- self.stream_cork(CorkState::cork() | CorkState::notify());
+ self.cork(CorkState::cork() | CorkState::notify());
cubeb::OK
}
pub fn position(&self) -> Result<u64> {
- if self.output_stream.is_null() {
- return Err(cubeb::ERROR);
- }
+ let in_thread = self.context.mainloop.in_thread();
- let position = unsafe {
- let in_thread = pa_threaded_mainloop_in_thread(self.context.mainloop);
-
- if in_thread == 0 {
- pa_threaded_mainloop_lock(self.context.mainloop);
- }
-
- let mut r_usec: pa_usec_t = Default::default();
- let r = pa_stream_get_time(self.output_stream, &mut r_usec);
- if in_thread == 0 {
- pa_threaded_mainloop_unlock(self.context.mainloop);
- }
-
- if r != 0 {
- return Err(cubeb::ERROR);
- }
+ if !in_thread {
+ self.context.mainloop.lock();
+ }
- let bytes = pa_usec_to_bytes(r_usec, &self.output_sample_spec);
- (bytes / pa_frame_size(&self.output_sample_spec)) as u64
+ let r = match self.output_stream {
+ None => Err(cubeb::ERROR),
+ Some(ref stm) => {
+ match stm.get_time() {
+ Ok(r_usec) => {
+ let bytes = r_usec.to_bytes(&self.output_sample_spec);
+ Ok((bytes / self.output_sample_spec.frame_size()) as u64)
+ },
+ Err(_) => Err(cubeb::ERROR),
+ }
+ },
};
- Ok(position)
- }
- pub fn latency(&self) -> Result<u32> {
- if self.output_stream.is_null() {
- return Err(cubeb::ERROR);
+ if !in_thread {
+ self.context.mainloop.unlock();
}
- let mut r_usec: pa_usec_t = 0;
- let mut negative: i32 = 0;
- let r = unsafe { pa_stream_get_latency(self.output_stream, &mut r_usec, &mut negative) };
+ r
+ }
- if r != 0 {
- return Err(cubeb::ERROR);
+ pub fn latency(&self) -> Result<u32> {
+ match self.output_stream {
+ None => Err(cubeb::ERROR),
+ Some(ref stm) => {
+ match stm.get_latency() {
+ Ok((r_usec, negative)) => {
+ debug_assert!(negative);
+ let latency = (r_usec * self.output_sample_spec.rate as pa_usec_t / PA_USEC_PER_SEC) as u32;
+ Ok(latency)
+ },
+ Err(_) => Err(cubeb::ERROR),
+ }
+ },
}
-
- debug_assert_eq!(negative, 0);
- let latency = (r_usec * self.output_sample_spec.rate as pa_usec_t / PA_USEC_PER_SEC) as u32;
-
- Ok(latency)
}
pub fn set_volume(&mut self, volume: f32) -> i32 {
- if self.output_stream.is_null() {
- return cubeb::ERROR;
- }
-
- unsafe {
- pa_threaded_mainloop_lock(self.context.mainloop);
-
- while self.context.default_sink_info.is_none() {
- pa_threaded_mainloop_wait(self.context.mainloop);
- }
-
- let mut cvol: pa_cvolume = Default::default();
-
- /* if the pulse daemon is configured to use flat volumes,
- * apply our own gain instead of changing the input volume on the sink. */
- let flags = {
- match self.context.default_sink_info {
- Some(ref info) => info.flags,
- _ => 0,
- }
- };
-
- if (flags & PA_SINK_FLAT_VOLUME) != 0 {
- self.volume = volume;
- } else {
- let ss = pa_stream_get_sample_spec(self.output_stream);
- let vol = pa_sw_volume_from_linear(volume as f64);
- pa_cvolume_set(&mut cvol, (*ss).channels as u32, vol);
-
- let index = pa_stream_get_index(self.output_stream);
+ match self.output_stream {
+ None => cubeb::ERROR,
+ Some(ref stm) => {
+ if let Some(ref context) = self.context.context {
+ self.context.mainloop.lock();
+
+ let mut cvol: pa_cvolume = Default::default();
+
+ /* if the pulse daemon is configured to use flat
+ * volumes, apply our own gain instead of changing
+ * the input volume on the sink. */
+ let flags = {
+ match self.context.default_sink_info {
+ Some(ref info) => info.flags,
+ _ => pulse::SinkFlags::empty(),
+ }
+ };
+
+ if flags.contains(pulse::SINK_FLAT_VOLUME) {
+ self.volume = volume;
+ } else {
+ let channels = stm.get_sample_spec().channels;
+ let vol = pulse::sw_volume_from_linear(volume as f64);
+ cvol.set(channels as u32, vol);
+
+ let index = stm.get_index();
+
+ let context_ptr = self.context as *const _ as *mut _;
+ if let Ok(o) = context.set_sink_input_volume(index, &cvol, context_success, context_ptr) {
+ self.context.operation_wait(stm, &o);
+ }
+ }
- let op = pa_context_set_sink_input_volume(self.context.context,
- index,
- &cvol,
- Some(volume_success),
- self as *mut _ as *mut _);
- if !op.is_null() {
- self.context.operation_wait(self.output_stream, op);
- pa_operation_unref(op);
+ self.context.mainloop.unlock();
+ cubeb::OK
+ } else {
+ cubeb::ERROR
}
- }
-
- pa_threaded_mainloop_unlock(self.context.mainloop);
+ },
}
- cubeb::OK
}
pub fn set_panning(&mut self, panning: f32) -> i32 {
- if self.output_stream.is_null() {
- return cubeb::ERROR;
- }
+ #[repr(C)]
+ struct SinkInputInfoResult<'a> {
+ pub cvol: pulse::CVolume,
+ pub mainloop: &'a pulse::ThreadedMainloop,
+ }
+
+ fn get_input_volume(_: &pulse::Context, info: *const pulse::SinkInputInfo, eol: i32, u: *mut c_void) {
+ let mut r = unsafe { &mut *(u as *mut SinkInputInfoResult) };
+ if eol == 0 {
+ let info = unsafe { *info };
+ r.cvol = info.volume;
+ }
+ r.mainloop.signal();
+ }
+
+ match self.output_stream {
+ None => cubeb::ERROR,
+ Some(ref stm) => {
+ if let Some(ref context) = self.context.context {
+ self.context.mainloop.lock();
+
+ let map = stm.get_channel_map();
+ if !map.can_balance() {
+ self.context.mainloop.unlock();
+ return cubeb::ERROR;
+ }
- unsafe {
- pa_threaded_mainloop_lock(self.context.mainloop);
+ let index = stm.get_index();
- let map = pa_stream_get_channel_map(self.output_stream);
- if pa_channel_map_can_balance(map) == 0 {
- pa_threaded_mainloop_unlock(self.context.mainloop);
- return cubeb::ERROR;
- }
+ let mut r = SinkInputInfoResult {
+ cvol: pulse::CVolume::default(),
+ mainloop: &self.context.mainloop,
+ };
- let index = pa_stream_get_index(self.output_stream);
+ if let Ok(o) = context.get_sink_input_info(index, get_input_volume, &mut r as *mut _ as *mut _) {
+ self.context.operation_wait(stm, &o);
+ }
- let mut cvol: pa_cvolume = Default::default();
- let mut r = SinkInputInfoResult {
- cvol: &mut cvol,
- mainloop: self.context.mainloop,
- };
+ r.cvol.set_balance(map, panning);
- let op = pa_context_get_sink_input_info(self.context.context,
- index,
- Some(sink_input_info_cb),
- &mut r as *mut _ as *mut _);
- if !op.is_null() {
- self.context.operation_wait(self.output_stream, op);
- pa_operation_unref(op);
- }
-
- pa_cvolume_set_balance(&mut cvol, map, panning);
-
- let op = pa_context_set_sink_input_volume(self.context.context,
- index,
- &cvol,
- Some(volume_success),
- self as *mut _ as *mut _);
- if !op.is_null() {
- self.context.operation_wait(self.output_stream, op);
- pa_operation_unref(op);
- }
+ let context_ptr = self.context as *const _ as *mut _;
+ if let Ok(o) = context.set_sink_input_volume(index, &r.cvol, context_success, context_ptr) {
+ self.context.operation_wait(stm, &o);
+ }
- pa_threaded_mainloop_unlock(self.context.mainloop);
- }
+ self.context.mainloop.unlock();
- cubeb::OK
+ cubeb::OK
+ } else {
+ cubeb::ERROR
+ }
+ },
+ }
}
pub fn current_device(&self) -> Result<Box<cubeb::Device>> {
if self.context.version_0_9_8 {
let mut dev = Box::new(cubeb::Device::default());
- if !self.input_stream.is_null() {
- dev.input_name = unsafe { pa_xstrdup(pa_stream_get_device_name(self.input_stream)) };
+ if self.input_stream.is_some() {
+ if let Some(ref stm) = self.input_stream {
+ dev.input_name = match stm.get_device_name() {
+ Ok(name) => name.to_owned().into_raw(),
+ Err(_) => {
+ return Err(cubeb::ERROR);
+ },
+ }
+ }
}
- if !self.output_stream.is_null() {
- dev.output_name = unsafe { pa_xstrdup(pa_stream_get_device_name(self.output_stream)) };
+ if !self.output_stream.is_some() {
+ if let Some(ref stm) = self.output_stream {
+ dev.output_name = match stm.get_device_name() {
+ Ok(name) => name.to_owned().into_raw(),
+ Err(_) => {
+ return Err(cubeb::ERROR);
+ },
+ }
+ }
}
Ok(dev)
@@ -445,51 +557,62 @@ impl<'ctx> Stream<'ctx> {
}
}
- fn pulse_stream_init(&mut self,
- stream_params: &cubeb::StreamParams,
- stream_name: *const c_char)
- -> Result<*mut pa_stream> {
+ fn stream_init(context: &pulse::Context,
+ stream_params: &cubeb::StreamParams,
+ stream_name: &CStr)
+ -> Result<pulse::Stream> {
- fn to_pulse_format(format: cubeb::SampleFormat) -> pa_sample_format_t {
+ fn to_pulse_format(format: cubeb::SampleFormat) -> pulse::SampleFormat {
match format {
- cubeb::SAMPLE_S16LE => PA_SAMPLE_S16LE,
- cubeb::SAMPLE_S16BE => PA_SAMPLE_S16BE,
- cubeb::SAMPLE_FLOAT32LE => PA_SAMPLE_FLOAT32LE,
- cubeb::SAMPLE_FLOAT32BE => PA_SAMPLE_FLOAT32BE,
- _ => panic!("Invalid format: {:?}", format),
+ cubeb::SAMPLE_S16LE => pulse::SampleFormat::Signed16LE,
+ cubeb::SAMPLE_S16BE => pulse::SampleFormat::Signed16BE,
+ cubeb::SAMPLE_FLOAT32LE => pulse::SampleFormat::Float32LE,
+ cubeb::SAMPLE_FLOAT32BE => pulse::SampleFormat::Float32BE,
+ _ => pulse::SampleFormat::Invalid,
}
}
let fmt = to_pulse_format(stream_params.format);
- if fmt == PA_SAMPLE_INVALID {
+ if fmt == pulse::SampleFormat::Invalid {
return Err(cubeb::ERROR_INVALID_FORMAT);
}
- let ss = pa_sample_spec {
+ let ss = pulse::SampleSpec {
channels: stream_params.channels as u8,
- format: fmt,
+ format: fmt.into(),
rate: stream_params.rate,
};
- let stream = if stream_params.layout == cubeb::LAYOUT_UNDEFINED {
- unsafe { pa_stream_new(self.context.context, stream_name, &ss, ptr::null_mut()) }
- } else {
- let cm = layout_to_channel_map(stream_params.layout);
- unsafe { pa_stream_new(self.context.context, stream_name, &ss, &cm) }
+ let cm: Option<pa_channel_map> = match stream_params.layout {
+ cubeb::LAYOUT_UNDEFINED => None,
+ _ => Some(layout_to_channel_map(stream_params.layout)),
};
- if !stream.is_null() {
- Ok(stream)
- } else {
- Err(cubeb::ERROR)
+ let stream = pulse::Stream::new(context, stream_name, &ss, cm.as_ref());
+
+ match stream {
+ None => Err(cubeb::ERROR),
+ Some(stm) => Ok(stm),
+ }
+ }
+
+ pub fn cork_stream(&self, stream: Option<&pulse::Stream>, state: CorkState) {
+ if let Some(stm) = stream {
+ if let Ok(o) = stm.cork(state.is_cork() as i32,
+ stream_success,
+ self as *const _ as *mut _) {
+ self.context.operation_wait(stream, &o);
+ }
}
}
- fn stream_cork(&mut self, state: CorkState) {
- unsafe { pa_threaded_mainloop_lock(self.context.mainloop) };
- self.context.pulse_stream_cork(self.output_stream, state);
- self.context.pulse_stream_cork(self.input_stream, state);
- unsafe { pa_threaded_mainloop_unlock(self.context.mainloop) };
+ fn cork(&mut self, state: CorkState) {
+ {
+ self.context.mainloop.lock();
+ self.cork_stream(self.output_stream.as_ref(), state);
+ self.cork_stream(self.input_stream.as_ref(), state);
+ self.context.mainloop.unlock()
+ }
if state.is_notify() {
self.state_change_callback(if state.is_cork() {
@@ -503,18 +626,9 @@ impl<'ctx> Stream<'ctx> {
fn update_timing_info(&self) -> bool {
let mut r = false;
- if !self.output_stream.is_null() {
- let o = unsafe {
- pa_stream_update_timing_info(self.output_stream,
- Some(stream_success_callback),
- self as *const _ as *mut _)
- };
-
- if !o.is_null() {
- r = self.context.operation_wait(self.output_stream, o);
- unsafe {
- pa_operation_unref(o);
- }
+ if let Some(ref stm) = self.output_stream {
+ if let Ok(o) = stm.update_timing_info(stream_success, self as *const _ as *mut _) {
+ r = self.context.operation_wait(stm, &o);
}
if !r {
@@ -522,18 +636,9 @@ impl<'ctx> Stream<'ctx> {
}
}
- if !self.input_stream.is_null() {
- let o = unsafe {
- pa_stream_update_timing_info(self.input_stream,
- Some(stream_success_callback),
- self as *const _ as *mut _)
- };
-
- if !o.is_null() {
- r = self.context.operation_wait(self.input_stream, o);
- unsafe {
- pa_operation_unref(o);
- }
+ if let Some(ref stm) = self.input_stream {
+ if let Ok(o) = stm.update_timing_info(stream_success, self as *const _ as *mut _) {
+ r = self.context.operation_wait(stm, &o);
}
}
@@ -547,232 +652,162 @@ impl<'ctx> Stream<'ctx> {
}
}
- fn wait_until_stream_ready(&self) -> bool {
- if !self.output_stream.is_null() && !wait_until_io_stream_ready(self.output_stream, self.context.mainloop) {
- return false;
- }
-
- if !self.input_stream.is_null() && !wait_until_io_stream_ready(self.input_stream, self.context.mainloop) {
- return false;
- }
-
- true
- }
-
- fn trigger_user_callback(&mut self, s: *mut pa_stream, input_data: *const c_void, nbytes: usize) {
- let frame_size = unsafe { pa_frame_size(&self.output_sample_spec) };
- debug_assert_eq!(nbytes % frame_size, 0);
-
- let mut buffer: *mut c_void = ptr::null_mut();
- let mut r: i32;
-
- let mut towrite = nbytes;
- let mut read_offset = 0usize;
- while towrite > 0 {
- let mut size = towrite;
- r = unsafe { pa_stream_begin_write(s, &mut buffer, &mut size) };
- // Note: this has failed running under rr on occassion - needs investigation.
- debug_assert_eq!(r, 0);
- debug_assert!(size > 0);
- debug_assert_eq!(size % frame_size, 0);
-
- logv!("Trigger user callback with output buffer size={}, read_offset={}",
- size,
- read_offset);
- let read_ptr = unsafe { (input_data as *const u8).offset(read_offset as isize) };
- let got = unsafe {
- self.data_callback.unwrap()(self as *const _ as *mut _,
- self.user_ptr,
- read_ptr as *const _ as *mut _,
- buffer,
- (size / frame_size) as c_long)
- };
- if got < 0 {
- unsafe {
- pa_stream_cancel_write(s);
- }
- self.shutdown = true;
- return;
- }
- // If more iterations move offset of read buffer
- if !input_data.is_null() {
- let in_frame_size = unsafe { pa_frame_size(&self.input_sample_spec) };
- read_offset += (size / frame_size) * in_frame_size;
+ fn wait_until_ready(&self) -> bool {
+ fn wait_until_io_stream_ready(stm: &pulse::Stream, mainloop: &pulse::ThreadedMainloop) -> bool {
+ if mainloop.is_null() {
+ return false;
}
- if self.volume != PULSE_NO_GAIN {
- let samples = (self.output_sample_spec.channels as usize * size / frame_size) as isize;
-
- if self.output_sample_spec.format == PA_SAMPLE_S16BE ||
- self.output_sample_spec.format == PA_SAMPLE_S16LE {
- let b = buffer as *mut i16;
- for i in 0..samples {
- unsafe { *b.offset(i) *= self.volume as i16 };
- }
- } else {
- let b = buffer as *mut f32;
- for i in 0..samples {
- unsafe { *b.offset(i) *= self.volume };
- }
+ loop {
+ let state = stm.get_state();
+ if !state.is_good() {
+ return false;
+ }
+ if state == pulse::StreamState::Ready {
+ break;
}
+ mainloop.wait();
}
- r = unsafe {
- pa_stream_write(s,
- buffer,
- got as usize * frame_size,
- None,
- 0,
- PA_SEEK_RELATIVE)
- };
- debug_assert_eq!(r, 0);
+ true
+ }
- if (got as usize) < size / frame_size {
- let mut latency: pa_usec_t = 0;
- let rr: i32 = unsafe { pa_stream_get_latency(s, &mut latency, ptr::null_mut()) };
- if rr == -(PA_ERR_NODATA as i32) {
- /* this needs a better guess. */
- latency = 100 * PA_USEC_PER_MSEC;
- }
- debug_assert!(r == 0 || r == -(PA_ERR_NODATA as i32));
- /* pa_stream_drain is useless, see PA bug# 866. this is a workaround. */
- /* arbitrary safety margin: double the current latency. */
- debug_assert!(self.drain_timer.is_null());
- self.drain_timer = unsafe {
- pa_context_rttime_new(self.context.context,
- pa_rtclock_now() + 2 * latency,
- Some(stream_drain_callback),
- self as *const _ as *mut _)
- };
- self.shutdown = true;
- return;
+ if let Some(ref stm) = self.output_stream {
+ if !wait_until_io_stream_ready(stm, &self.context.mainloop) {
+ return false;
}
-
- towrite -= size;
}
- debug_assert_eq!(towrite, 0);
- }
-}
-
-unsafe extern "C" fn stream_success_callback(_s: *mut pa_stream, _success: i32, u: *mut c_void) {
- let stm = &*(u as *mut Stream);
- pa_threaded_mainloop_signal(stm.context.mainloop, 0);
-}
-
-unsafe extern "C" fn stream_drain_callback(a: *mut pa_mainloop_api,
- e: *mut pa_time_event,
- _tv: *const timeval,
- u: *mut c_void) {
- let mut stm = &mut *(u as *mut Stream);
- debug_assert_eq!(stm.drain_timer, e);
- stm.state_change_callback(cubeb::STATE_DRAINED);
- /* there's no pa_rttime_free, so use this instead. */
- (*a).time_free.unwrap()(stm.drain_timer);
- stm.drain_timer = ptr::null_mut();
- pa_threaded_mainloop_signal(stm.context.mainloop, 0);
-}
-
-unsafe extern "C" fn stream_state_callback(s: *mut pa_stream, u: *mut c_void) {
- let stm = &mut *(u as *mut Stream);
- if !PA_STREAM_IS_GOOD(pa_stream_get_state(s)) {
- stm.state_change_callback(cubeb::STATE_ERROR);
- }
- pa_threaded_mainloop_signal(stm.context.mainloop, 0);
-}
-
-fn read_from_input(s: *mut pa_stream, buffer: *mut *const c_void, size: *mut usize) -> i32 {
- let readable_size = unsafe { pa_stream_readable_size(s) };
- if readable_size > 0 && unsafe { pa_stream_peek(s, buffer, size) } < 0 {
- return -1;
- }
-
- readable_size as i32
-}
+ if let Some(ref stm) = self.input_stream {
+ if !wait_until_io_stream_ready(stm, &self.context.mainloop) {
+ return false;
+ }
+ }
-unsafe extern "C" fn stream_write_callback(s: *mut pa_stream, nbytes: usize, u: *mut c_void) {
- logv!("Output callback to be written buffer size {}", nbytes);
- let mut stm = &mut *(u as *mut Stream);
- if stm.shutdown || stm.state != cubeb::STATE_STARTED {
- return;
+ true
}
- if stm.input_stream.is_null() {
- // Output/playback only operation.
- // Write directly to output
- debug_assert!(!stm.output_stream.is_null());
- stm.trigger_user_callback(s, ptr::null(), nbytes);
- }
-}
+ fn trigger_user_callback(&mut self, input_data: *const c_void, nbytes: usize) {
+ fn drained_cb(a: &pulse::MainloopApi, e: *mut pa_time_event, _tv: &pulse::TimeVal, u: *mut c_void) {
+ let mut stm = unsafe { &mut *(u as *mut Stream) };
+ debug_assert_eq!(stm.drain_timer, e);
+ stm.state_change_callback(cubeb::STATE_DRAINED);
+ /* there's no pa_rttime_free, so use this instead. */
+ a.time_free(stm.drain_timer);
+ stm.drain_timer = ptr::null_mut();
+ stm.context.mainloop.signal();
+ }
+
+ if let Some(ref stm) = self.output_stream {
+
+ let frame_size = self.output_sample_spec.frame_size();
+ debug_assert_eq!(nbytes % frame_size, 0);
+
+ let mut towrite = nbytes;
+ let mut read_offset = 0usize;
+ while towrite > 0 {
+ match stm.begin_write(towrite) {
+ Err(e) => {
+ panic!("Failed to write data: {}", e);
+ },
+ Ok((buffer, size)) => {
+ debug_assert!(size > 0);
+ debug_assert_eq!(size % frame_size, 0);
+
+ logv!("Trigger user callback with output buffer size={}, read_offset={}",
+ size,
+ read_offset);
+ let read_ptr = unsafe { (input_data as *const u8).offset(read_offset as isize) };
+ let got = unsafe {
+ self.data_callback.unwrap()(self as *const _ as *mut _,
+ self.user_ptr,
+ read_ptr as *const _ as *mut _,
+ buffer,
+ (size / frame_size) as c_long)
+ };
+ if got < 0 {
+ let _ = stm.cancel_write();
+ self.shutdown = true;
+ return;
+ }
+
+ // If more iterations move offset of read buffer
+ if !input_data.is_null() {
+ let in_frame_size = self.input_sample_spec.frame_size();
+ read_offset += (size / frame_size) * in_frame_size;
+ }
+
+ if self.volume != PULSE_NO_GAIN {
+ let samples = (self.output_sample_spec.channels as usize * size / frame_size) as isize;
+
+ if self.output_sample_spec.format == PA_SAMPLE_S16BE ||
+ self.output_sample_spec.format == PA_SAMPLE_S16LE {
+ let b = buffer as *mut i16;
+ for i in 0..samples {
+ unsafe { *b.offset(i) *= self.volume as i16 };
+ }
+ } else {
+ let b = buffer as *mut f32;
+ for i in 0..samples {
+ unsafe { *b.offset(i) *= self.volume };
+ }
+ }
+ }
+
+ let r = stm.write(buffer,
+ got as usize * frame_size,
+ 0,
+ pulse::SeekMode::Relative);
+ debug_assert!(r.is_ok());
+
+ if (got as usize) < size / frame_size {
+ let latency = match stm.get_latency() {
+ Ok((l, negative)) => {
+ assert_ne!(negative, true);
+ l
+ },
+ Err(e) => {
+ debug_assert_eq!(e, pulse::ErrorCode::from_error_code(PA_ERR_NODATA));
+ /* this needs a better guess. */
+ 100 * PA_USEC_PER_MSEC
+ },
+ };
+
+ /* pa_stream_drain is useless, see PA bug# 866. this is a workaround. */
+ /* arbitrary safety margin: double the current latency. */
+ debug_assert!(self.drain_timer.is_null());
+ let stream_ptr = self as *const _ as *mut _;
+ if let Some(ref context) = self.context.context {
+ self.drain_timer =
+ context.rttime_new(pulse::rtclock_now() + 2 * latency, drained_cb, stream_ptr);
+ }
+ self.shutdown = true;
+ return;
+ }
-unsafe extern "C" fn stream_read_callback(s: *mut pa_stream, nbytes: usize, u: *mut c_void) {
- logv!("Input callback buffer size {}", nbytes);
- let mut stm = &mut *(u as *mut Stream);
- if stm.shutdown {
- return;
- }
-
- let mut read_data: *const c_void = ptr::null();
- let mut read_size: usize = 0;
- while read_from_input(s, &mut read_data, &mut read_size) > 0 {
- /* read_data can be NULL in case of a hole. */
- if !read_data.is_null() {
- let in_frame_size = pa_frame_size(&stm.input_sample_spec);
- let read_frames = read_size / in_frame_size;
-
- if !stm.output_stream.is_null() {
- // input/capture + output/playback operation
- let out_frame_size = pa_frame_size(&stm.output_sample_spec);
- let write_size = read_frames * out_frame_size;
- // Offer full duplex data for writing
- let stream = stm.output_stream;
- stm.trigger_user_callback(stream, read_data, write_size);
- } else {
- // input/capture only operation. Call callback directly
- let got = stm.data_callback.unwrap()(stm as *mut _ as *mut _,
- stm.user_ptr,
- read_data,
- ptr::null_mut(),
- read_frames as c_long);
- if got < 0 || got as usize != read_frames {
- pa_stream_cancel_write(s);
- stm.shutdown = true;
- break;
+ towrite -= size;
+ },
}
}
- }
-
- if read_size > 0 {
- pa_stream_drop(s);
- }
-
- if stm.shutdown {
- return;
+ debug_assert_eq!(towrite, 0);
}
}
}
-fn wait_until_io_stream_ready(stream: *mut pa_stream, mainloop: *mut pa_threaded_mainloop) -> bool {
- if stream.is_null() || mainloop.is_null() {
- return false;
- }
-
- loop {
- let state = unsafe { pa_stream_get_state(stream) };
- if !PA_STREAM_IS_GOOD(state) {
- return false;
- }
- if state == PA_STREAM_READY {
- break;
- }
- unsafe { pa_threaded_mainloop_wait(mainloop) };
- }
+fn stream_success(_: &pulse::Stream, success: i32, u: *mut c_void) {
+ let stm = unsafe { &*(u as *mut Stream) };
+ debug_assert_ne!(success, 0);
+ stm.context.mainloop.signal();
+}
- true
+fn context_success(_: &pulse::Context, success: i32, u: *mut c_void) {
+ let ctx = unsafe { &*(u as *mut Context) };
+ debug_assert_ne!(success, 0);
+ ctx.mainloop.signal();
}
fn set_buffering_attribute(latency_frames: u32, sample_spec: &pa_sample_spec) -> pa_buffer_attr {
- let tlength = latency_frames * unsafe { pa_frame_size(sample_spec) } as u32;
+ let tlength = latency_frames * sample_spec.frame_size() as u32;
let minreq = tlength / 4;
let battr = pa_buffer_attr {
maxlength: u32::max_value(),
@@ -791,34 +826,3 @@ fn set_buffering_attribute(latency_frame
battr
}
-
-unsafe extern "C" fn pulse_defer_event_cb(_a: *mut pa_mainloop_api, u: *mut c_void) {
- let mut stm = &mut *(u as *mut Stream);
- if stm.shutdown {
- return;
- }
- let writable_size = pa_stream_writable_size(stm.output_stream);
- let stream = stm.output_stream;
- stm.trigger_user_callback(stream, ptr::null_mut(), writable_size);
-}
-
-#[repr(C)]
-struct SinkInputInfoResult {
- pub cvol: *mut pa_cvolume,
- pub mainloop: *mut pa_threaded_mainloop,
-}
-
-unsafe extern "C" fn sink_input_info_cb(_c: *mut pa_context, i: *const pa_sink_input_info, eol: i32, u: *mut c_void) {
- let info = &*i;
- let mut r = &mut *(u as *mut SinkInputInfoResult);
- if eol == 0 {
- *r.cvol = info.volume;
- }
- pa_threaded_mainloop_signal(r.mainloop, 0);
-}
-
-unsafe extern "C" fn volume_success(_c: *mut pa_context, success: i32, u: *mut c_void) {
- let stm = &*(u as *mut Stream);
- debug_assert_ne!(success, 0);
- pa_threaded_mainloop_signal(stm.context.mainloop, 0);
-}
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/capi.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/capi.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/capi.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/capi.rs 2017-08-04 13:37:46.387821728 +0200
@@ -5,6 +5,7 @@
use backend;
use cubeb;
+use std::ffi::CStr;
use std::os::raw::{c_char, c_void};
unsafe extern "C" fn capi_init(c: *mut *mut cubeb::Context, context_name: *const c_char) -> i32 {
@@ -114,21 +115,18 @@ unsafe extern "C" fn capi_stream_init(c:
state_callback: cubeb::StateCallback,
user_ptr: *mut c_void)
-> i32 {
+ fn try_stream_params_from(sp: *mut cubeb::StreamParams) -> Option<cubeb::StreamParams> {
+ if sp.is_null() { None } else { Some(unsafe { *sp }) }
+ }
+
let mut ctx = &mut *(c as *mut backend::Context);
+ let stream_name = CStr::from_ptr(stream_name);
match ctx.new_stream(stream_name,
input_device,
- if input_stream_params.is_null() {
- None
- } else {
- Some(*input_stream_params)
- },
+ try_stream_params_from(input_stream_params),
output_device,
- if output_stream_params.is_null() {
- None
- } else {
- Some(*output_stream_params)
- },
+ try_stream_params_from(output_stream_params),
latency_frames,
data_callback,
state_callback,
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/lib.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/lib.rs
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/lib.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/lib.rs 2017-08-04 13:37:46.387821728 +0200
@@ -8,6 +8,7 @@
#[macro_use]
extern crate cubeb_ffi as cubeb;
extern crate pulse_ffi;
+extern crate pulse;
extern crate semver;
mod capi;
diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/update.sh.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/update.sh
--- firefox-55.0/media/libcubeb/cubeb-pulse-rs/update.sh.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200
+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/update.sh 2017-08-04 13:37:46.383821740 +0200
@@ -13,6 +13,9 @@ cp -pr $1/cubeb-ffi/src/* cubeb-ffi/src/
test -d pulse-ffi/src || mkdir -p pulse-ffi/src
cp -pr $1/pulse-ffi/Cargo.toml pulse-ffi/
cp -pr $1/pulse-ffi/src/* pulse-ffi/src/
+test -d pulse-rs/src || mkdir -p pulse-rs/src
+cp -pr $1/pulse-rs/Cargo.toml pulse-rs/
+cp -pr $1/pulse-rs/src/* pulse-rs/src/
if [ -d $1/.git ]; then
rev=$(cd $1 && git rev-parse --verify HEAD)
diff -up firefox-55.0/toolkit/library/gtest/rust/Cargo.lock.cubeb-pulse-arm firefox-55.0/toolkit/library/gtest/rust/Cargo.lock
--- firefox-55.0/toolkit/library/gtest/rust/Cargo.lock.cubeb-pulse-arm 2017-08-04 13:37:46.388821725 +0200
+++ firefox-55.0/toolkit/library/gtest/rust/Cargo.lock 2017-08-04 13:59:15.592940994 +0200
@@ -252,6 +252,7 @@ name = "cubeb-pulse"
version = "0.0.1"
dependencies = [
"cubeb-ffi 0.0.1",
+ "pulse 0.1.0",
"pulse-ffi 0.1.0",
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -660,6 +661,14 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "pulse"
+version = "0.1.0"
+dependencies = [
+ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pulse-ffi 0.1.0",
+]
+
+[[package]]
name = "pulse-ffi"
version = "0.1.0"
dependencies = [
diff -up firefox-55.0/toolkit/library/rust/Cargo.lock.cubeb-pulse-arm firefox-55.0/toolkit/library/rust/Cargo.lock
--- firefox-55.0/toolkit/library/rust/Cargo.lock.cubeb-pulse-arm 2017-08-04 13:37:46.388821725 +0200
+++ firefox-55.0/toolkit/library/rust/Cargo.lock 2017-08-04 13:52:24.551163669 +0200
@@ -250,6 +250,7 @@ name = "cubeb-pulse"
version = "0.0.1"
dependencies = [
"cubeb-ffi 0.0.1",
+ "pulse 0.1.0",
"pulse-ffi 0.1.0",
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -647,6 +648,14 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "pulse"
+version = "0.1.0"
+dependencies = [
+ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pulse-ffi 0.1.0",
+]
+
+[[package]]
name = "pulse-ffi"
version = "0.1.0"
dependencies = [