Bug 1399009 - Update cubeb-pulse-rs to a386d91... r?kinetik draft
authorDan Glastonbury <dan.glastonbury@gmail.com>
Tue, 12 Sep 2017 15:31:18 +1000
changeset 662838 fc0e08d189d703e39063c3cee9f134107adc952a
parent 662738 bda524beac249b64aa36016800502a34073bf35a
child 730983 88f2c6c8e3e1dadf996f61a45468f84557c42505
push id79203
push userbmo:dglastonbury@mozilla.com
push dateTue, 12 Sep 2017 05:37:21 +0000
reviewerskinetik
bugs1399009
milestone57.0a1
Bug 1399009 - Update cubeb-pulse-rs to a386d91... r?kinetik MozReview-Commit-ID: BnJpMCuDPOf
media/libcubeb/cubeb-pulse-rs/README_MOZILLA
media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs
media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs
media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs
media/libcubeb/cubeb-pulse-rs/src/backend/context.rs
media/libcubeb/cubeb-pulse-rs/src/backend/intern.rs
media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs
media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
--- a/media/libcubeb/cubeb-pulse-rs/README_MOZILLA
+++ b/media/libcubeb/cubeb-pulse-rs/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the cubeb-pulse-rs
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The cubeb-pulse-rs git repository is: https://github.com/djg/cubeb-pulse-rs.git
 
-The git commit ID used was 3b8cfba161cec66bee6a755bce102466baa92ddb (2017-07-07 14:57:07 +1000)
+The git commit ID used was a386d91d7f34e6d3a949ee4fa44e848e29634587 (2017-09-05 13:34:32 +1000)
--- a/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs
+++ b/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs
@@ -1,12 +1,13 @@
 // This code is generated.
 
 use super::*;
 
+#[cfg(feature = "dlopen")]
 macro_rules! cstr {
   ($x:expr) => { concat!($x, "\0").as_bytes().as_ptr() as *const c_char }
 }
 
 #[cfg(not(feature = "dlopen"))]
 mod static_fns {
     use super::*;
     use std::os::raw::{c_char, c_double, c_float, c_int, c_uint, c_void};
--- a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs
+++ b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs
@@ -289,16 +289,21 @@ impl StreamFlags {
 }
 
 impl Into<ffi::pa_stream_flags_t> for StreamFlags {
     fn into(self) -> ffi::pa_stream_flags_t {
         self.bits() as ffi::pa_stream_flags_t
     }
 }
 
+pub enum StreamLatency {
+    Positive(u64),
+    Negative(u64),
+}
+
 bitflags!{
     pub 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,
--- a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs
+++ b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs
@@ -324,21 +324,28 @@ impl Stream {
     }
 
     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)> {
+    pub fn get_latency(&self) -> Result<StreamLatency> {
         let mut usec: u64 = 0;
         let mut negative: i32 = 0;
         let r = unsafe { ffi::pa_stream_get_latency(self.raw_mut(), &mut usec, &mut negative) };
-        error_result!((usec, negative != 0), r)
+        error_result!(
+            if negative == 0 {
+                StreamLatency::Positive(usec)
+            } else {
+                StreamLatency::Negative(usec)
+            },
+            r
+        )
     }
 
     pub fn get_sample_spec(&self) -> &SampleSpec {
         unsafe {
             let ptr = ffi::pa_stream_get_sample_spec(self.raw_mut());
             debug_assert!(!ptr.is_null());
             &*ptr
         }
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs
@@ -9,16 +9,17 @@ use cubeb;
 use pulse::{self, ProplistExt};
 use pulse_ffi::*;
 use semver;
 use std::default::Default;
 use std::ffi::{CStr, CString};
 use std::mem;
 use std::os::raw::{c_char, c_void};
 use std::ptr;
+use std::cell::RefCell;
 
 fn pa_channel_to_cubeb_channel(channel: pulse::ChannelPosition) -> cubeb::Channel {
     use pulse::ChannelPosition;
     assert_ne!(channel, ChannelPosition::Invalid);
     match channel {
         ChannelPosition::Mono => cubeb::CHANNEL_MONO,
         ChannelPosition::FrontLeft => cubeb::CHANNEL_LEFT,
         ChannelPosition::FrontRight => cubeb::CHANNEL_RIGHT,
@@ -60,16 +61,17 @@ pub struct Context {
     pub context_name: Option<CString>,
     pub collection_changed_callback: cubeb::DeviceCollectionChangedCallback,
     pub collection_changed_user_ptr: *mut c_void,
     pub error: bool,
     pub version_2_0_0: bool,
     pub version_0_9_8: bool,
     #[cfg(feature = "pulse-dlopen")]
     pub libpulse: LibLoader,
+    devids: RefCell<Intern>,
 }
 
 impl Drop for Context {
     fn drop(&mut self) {
         self.destroy();
     }
 }
 
@@ -88,16 +90,17 @@ impl Context {
                                context: None,
                                default_sink_info: None,
                                context_name: name,
                                collection_changed_callback: None,
                                collection_changed_user_ptr: ptr::null_mut(),
                                error: true,
                                version_0_9_8: false,
                                version_2_0_0: false,
+                               devids: RefCell::new(Intern::new()),
                            });
 
         Ok(ctx)
     }
 
     #[cfg(not(feature = "pulse-dlopen"))]
     fn _new(name: Option<CString>) -> Result<Box<Self>> {
         Ok(Box::new(Context {
@@ -106,16 +109,17 @@ impl Context {
                         context: None,
                         default_sink_info: None,
                         context_name: name,
                         collection_changed_callback: None,
                         collection_changed_user_ptr: ptr::null_mut(),
                         error: true,
                         version_0_9_8: false,
                         version_2_0_0: false,
+                        devids: RefCell::new(Intern::new()),
                     }))
     }
 
     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 {
@@ -243,28 +247,27 @@ impl Context {
                 _ => 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_name = unsafe { CStr::from_ptr(info.name) };
             let info_description = unsafe { CStr::from_ptr(info.description) }.to_owned();
 
-            let preferred = if info_name == list_data.default_sink_name {
+            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 device_id = ctx.devids.borrow_mut().add(info_name);
             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,
@@ -300,27 +303,27 @@ impl Context {
                 _ => 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_name = unsafe { CStr::from_ptr(info.name) };
             let info_description = unsafe { CStr::from_ptr(info.description) }.to_owned();
 
-            let preferred = if info_name == list_data.default_source_name {
+            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 device_id = ctx.devids.borrow_mut().add(info_name);
             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,
@@ -354,23 +357,23 @@ impl Context {
 
         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 {
+            if devtype.contains(cubeb::DEVICE_TYPE_OUTPUT) {
                 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 {
+            if devtype.contains(cubeb::DEVICE_TYPE_INPUT) {
                 if let Ok(o) = context.get_source_info_list(add_input_device, &mut user_data as *mut _ as *mut _) {
                     self.operation_wait(None, &o);
                 }
             }
 
             self.mainloop.unlock();
         }
 
@@ -392,19 +395,16 @@ impl Context {
     pub fn device_collection_destroy(&self, collection: *mut cubeb::DeviceCollection) {
         debug_assert!(!collection.is_null());
         unsafe {
             let coll = *collection;
             let mut devices = Vec::from_raw_parts(coll.device as *mut cubeb::DeviceInfo,
                                                   coll.count,
                                                   coll.count);
             for dev in devices.iter_mut() {
-                if !dev.device_id.is_null() {
-                    let _ = CString::from_raw(dev.device_id as *mut _);
-                }
                 if !dev.group_id.is_null() {
                     let _ = CString::from_raw(dev.group_id as *mut _);
                 }
                 if !dev.vendor_name.is_null() {
                     let _ = CString::from_raw(dev.vendor_name as *mut _);
                 }
                 if !dev.friendly_name.is_null() {
                     let _ = CString::from_raw(dev.friendly_name as *mut _);
new file mode 100644
--- /dev/null
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/intern.rs
@@ -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 std::ffi::{CStr, CString};
+use std::os::raw::c_char;
+
+#[derive(Debug)]
+pub struct Intern {
+    vec: Vec<Box<CString>>
+}
+
+impl Intern {
+    pub fn new() -> Intern {
+        Intern {
+            vec: Vec::new()
+        }
+    }
+
+    pub fn add(&mut self, string: &CStr) -> *const c_char {
+        fn eq(s1: &CStr, s2: &CStr) -> bool { s1 == s2 }
+        for s in &self.vec {
+            if eq(s, string) {
+                return s.as_ptr();
+            }
+        }
+
+        self.vec.push(Box::new(string.to_owned()));
+        self.vec.last().unwrap().as_ptr()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::ffi::CStr;
+    use super::Intern;
+
+    #[test]
+    fn intern() {
+        fn cstr(str: &[u8]) -> &CStr {
+            CStr::from_bytes_with_nul(str).unwrap()
+        }
+
+        let mut intern = Intern::new();
+
+        let foo_ptr = intern.add(cstr(b"foo\0"));
+        let bar_ptr = intern.add(cstr(b"bar\0"));
+        assert!(!foo_ptr.is_null());
+        assert!(!bar_ptr.is_null());
+        assert!(foo_ptr != bar_ptr);
+
+        assert!(foo_ptr == intern.add(cstr(b"foo\0")));
+        assert!(foo_ptr != intern.add(cstr(b"fo\0")));
+        assert!(foo_ptr != intern.add(cstr(b"fool\0")));
+        assert!(foo_ptr != intern.add(cstr(b"not foo\0")));
+    }
+}
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs
@@ -1,22 +1,24 @@
 // Copyright © 2017 Mozilla Foundation
 //
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
 mod context;
 mod cork_state;
 mod stream;
+mod intern;
 
 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;
+use self::intern::Intern;
 
 // 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) }) }
 }
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
@@ -1,17 +1,17 @@
 // Copyright © 2017 Mozilla Foundation
 //
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
 use backend::*;
 use backend::cork_state::CorkState;
 use cubeb;
-use pulse::{self, CVolumeExt, ChannelMapExt, SampleSpecExt, USecExt};
+use pulse::{self, CVolumeExt, ChannelMapExt, SampleSpecExt, StreamLatency, USecExt};
 use pulse_ffi::*;
 use std::ffi::{CStr, CString};
 use std::os::raw::{c_long, c_void};
 use std::ptr;
 
 const PULSE_NO_GAIN: f32 = -1.0;
 
 fn cubeb_channel_to_pa_channel(channel: cubeb::Channel) -> pa_channel_position_t {
@@ -410,21 +410,23 @@ impl<'ctx> Stream<'ctx> {
         r
     }
 
     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);
+                    Ok(StreamLatency::Positive(r_usec)) => {
                         let latency = (r_usec * self.output_sample_spec.rate as pa_usec_t / PA_USEC_PER_SEC) as u32;
                         Ok(latency)
                     },
+                    Ok(_) => {
+                        panic!("Can not handle negative latency values.");
+                    },
                     Err(_) => Err(cubeb::ERROR),
                 }
             },
         }
     }
 
     pub fn set_volume(&mut self, volume: f32) -> i32 {
         match self.output_stream {
@@ -757,19 +759,19 @@ impl<'ctx> Stream<'ctx> {
                         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
+                                Ok(StreamLatency::Positive(l)) => l,
+                                Ok(_) => {
+                                    panic!("Can not handle negative latency values.");
                                 },
                                 Err(e) => {
                                     debug_assert_eq!(e, pulse::ErrorCode::from_error_code(PA_ERR_NODATA));
                                     /* this needs a better guess. */
                                     100 * PA_USEC_PER_MSEC
                                 },
                             };