--- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs
+++ b/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs
@@ -1,67 +1,60 @@
// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
use std::default::Default;
-use std::os::raw::{c_char, c_long, c_void};
+use std::os::raw::{c_char, c_int, c_long, c_uint, c_void};
use std::ptr;
pub enum Context {}
pub enum Stream {}
-// TODO endian check
-#[repr(C)]
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct SampleFormat(i32);
-
// These need to match cubeb_sample_format
-pub const SAMPLE_S16LE: SampleFormat = SampleFormat(0);
-pub const SAMPLE_S16BE: SampleFormat = SampleFormat(1);
-pub const SAMPLE_FLOAT32LE: SampleFormat = SampleFormat(2);
-pub const SAMPLE_FLOAT32BE: SampleFormat = SampleFormat(3);
+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;
#[cfg(target_endian = "little")]
-pub const SAMPLE_S16NE: SampleFormat = SAMPLE_S16LE;
+pub const SAMPLE_S16NE: c_int = SAMPLE_S16LE;
#[cfg(target_endian = "little")]
-pub const SAMPLE_FLOAT32NE: SampleFormat = SAMPLE_FLOAT32LE;
+pub const SAMPLE_FLOAT32NE: c_int = SAMPLE_FLOAT32LE;
#[cfg(target_endian = "big")]
-pub const SAMPLE_S16NE: SampleFormat = SAMPLE_S16BE;
+pub const SAMPLE_S16NE: c_int = SAMPLE_S16BE;
#[cfg(target_endian = "big")]
-pub const SAMPLE_FLOAT32NE: SampleFormat = SAMPLE_FLOAT32BE;
+pub const SAMPLE_FLOAT32NE: c_int = SAMPLE_FLOAT32BE;
pub type DeviceId = *const c_void;
-#[repr(C)]
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct ChannelLayout(i32);
-
// These need to match cubeb_channel_layout
-pub const LAYOUT_UNDEFINED: ChannelLayout = ChannelLayout(0);
-pub const LAYOUT_DUAL_MONO: ChannelLayout = ChannelLayout(1);
-pub const LAYOUT_DUAL_MONO_LFE: ChannelLayout = ChannelLayout(2);
-pub const LAYOUT_MONO: ChannelLayout = ChannelLayout(3);
-pub const LAYOUT_MONO_LFE: ChannelLayout = ChannelLayout(4);
-pub const LAYOUT_STEREO: ChannelLayout = ChannelLayout(5);
-pub const LAYOUT_STEREO_LFE: ChannelLayout = ChannelLayout(6);
-pub const LAYOUT_3F: ChannelLayout = ChannelLayout(7);
-pub const LAYOUT_3F_LFE: ChannelLayout = ChannelLayout(8);
-pub const LAYOUT_2F1: ChannelLayout = ChannelLayout(9);
-pub const LAYOUT_2F1_LFE: ChannelLayout = ChannelLayout(10);
-pub const LAYOUT_3F1: ChannelLayout = ChannelLayout(11);
-pub const LAYOUT_3F1_LFE: ChannelLayout = ChannelLayout(12);
-pub const LAYOUT_2F2: ChannelLayout = ChannelLayout(13);
-pub const LAYOUT_2F2_LFE: ChannelLayout = ChannelLayout(14);
-pub const LAYOUT_3F2: ChannelLayout = ChannelLayout(15);
-pub const LAYOUT_3F2_LFE: ChannelLayout = ChannelLayout(16);
-pub const LAYOUT_3F3R_LFE: ChannelLayout = ChannelLayout(17);
-pub const LAYOUT_3F4_LFE: ChannelLayout = ChannelLayout(18);
-pub const LAYOUT_MAX: ChannelLayout = ChannelLayout(19);
+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;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct StreamParams {
pub format: SampleFormat,
pub rate: u32,
pub channels: u32,
pub layout: ChannelLayout,
@@ -78,25 +71,22 @@ impl Default for Device {
fn default() -> Self {
Device {
output_name: ptr::null_mut(),
input_name: ptr::null_mut(),
}
}
}
-#[repr(C)]
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct State(i32);
-
// These need to match cubeb_state
-pub const STATE_STARTED: State = State(0);
-pub const STATE_STOPPED: State = State(1);
-pub const STATE_DRAINED: State = State(2);
-pub const STATE_ERROR: State = State(3);
+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 OK: i32 = 0;
pub const ERROR: i32 = -1;
pub const ERROR_INVALID_FORMAT: i32 = -2;
pub const ERROR_INVALID_PARAMETER: i32 = -3;
pub const ERROR_NOT_SUPPORTED: i32 = -4;
pub const ERROR_DEVICE_UNAVAILABLE: i32 = -5;
@@ -174,20 +164,20 @@ pub struct DeviceInfo {
pub min_rate: u32,
pub latency_lo: u32,
pub latency_hi: u32,
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct DeviceCollection {
+ /// Array of device info.
+ pub device: *const DeviceInfo,
/// Device count in collection.
- pub count: u32,
- /// Array of pointers to device info.
- pub device: [*const DeviceInfo; 0],
+ pub count: usize,
}
pub type DataCallback = Option<unsafe extern "C" fn(stream: *mut Stream,
user_ptr: *mut c_void,
input_buffer: *const c_void,
output_buffer: *mut c_void,
nframes: c_long)
-> c_long>;
@@ -223,18 +213,20 @@ pub struct Ops {
params: StreamParams,
latency_ms: *mut u32)
-> i32>,
pub get_preferred_sample_rate: Option<unsafe extern "C" fn(context: *mut Context, rate: *mut u32) -> i32>,
pub get_preferred_channel_layout:
Option<unsafe extern "C" fn(context: *mut Context, layout: *mut ChannelLayout) -> i32>,
pub enumerate_devices: Option<unsafe extern "C" fn(context: *mut Context,
devtype: DeviceType,
- collection: *mut *mut DeviceCollection)
+ collection: *mut DeviceCollection)
-> i32>,
+ pub device_collection_destroy:
+ Option<unsafe extern "C" fn(context: *mut Context, collection: *mut DeviceCollection) -> i32>,
pub destroy: Option<unsafe extern "C" fn(context: *mut Context)>,
pub stream_init: StreamInitFn,
pub stream_destroy: Option<unsafe extern "C" fn(stream: *mut Stream)>,
pub stream_start: Option<unsafe extern "C" fn(stream: *mut Stream) -> i32>,
pub stream_stop: Option<unsafe extern "C" fn(stream: *mut Stream) -> i32>,
pub stream_get_position: Option<unsafe extern "C" fn(stream: *mut Stream, position: *mut u64) -> i32>,
pub stream_get_latency: Option<unsafe extern "C" fn(stream: *mut Stream, latency: *mut u32) -> i32>,
pub stream_set_volume: Option<unsafe extern "C" fn(stream: *mut Stream, volumes: f32) -> i32>,
@@ -252,59 +244,42 @@ pub struct Ops {
#[derive(Clone, Copy, Debug)]
pub struct LayoutMap {
pub name: *const c_char,
pub channels: u32,
pub layout: ChannelLayout,
}
// cubeb_mixer.h
-#[repr(C)]
-#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct Channel(i32);
-impl Into<i32> for Channel {
- fn into(self) -> i32 {
- self.0
- }
-}
// These need to match cubeb_channel
-pub const CHANNEL_INVALID: Channel = Channel(-1);
-pub const CHANNEL_MONO: Channel = Channel(0);
-pub const CHANNEL_LEFT: Channel = Channel(1);
-pub const CHANNEL_RIGHT: Channel = Channel(2);
-pub const CHANNEL_CENTER: Channel = Channel(3);
-pub const CHANNEL_LS: Channel = Channel(4);
-pub const CHANNEL_RS: Channel = Channel(5);
-pub const CHANNEL_RLS: Channel = Channel(6);
-pub const CHANNEL_RCENTER: Channel = Channel(7);
-pub const CHANNEL_RRS: Channel = Channel(8);
-pub const CHANNEL_LFE: Channel = Channel(9);
-pub const CHANNEL_MAX: Channel = Channel(10);
+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;
#[repr(C)]
-#[derive(Clone, Copy, Debug)]
pub struct ChannelMap {
- pub channels: u32,
- pub map: [Channel; 10],
+ pub channels: c_uint,
+ pub map: [Channel; 256],
}
impl ::std::default::Default for ChannelMap {
fn default() -> Self {
ChannelMap {
channels: 0,
- map: [CHANNEL_INVALID,
- CHANNEL_INVALID,
- CHANNEL_INVALID,
- CHANNEL_INVALID,
- CHANNEL_INVALID,
- CHANNEL_INVALID,
- CHANNEL_INVALID,
- CHANNEL_INVALID,
- CHANNEL_INVALID,
- CHANNEL_INVALID],
+ map: unsafe { ::std::mem::zeroed() },
}
}
}
extern "C" {
pub fn cubeb_channel_map_to_layout(channel_map: *const ChannelMap) -> ChannelLayout;
pub fn cubeb_should_upmix(stream: *const StreamParams, mixer: *const StreamParams) -> bool;
pub fn cubeb_should_downmix(stream: *const StreamParams, mixer: *const StreamParams) -> bool;
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs
@@ -1,22 +1,22 @@
// 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 backend::var_array::VarArray;
use capi::PULSE_OPS;
use cubeb;
use pulse_ffi::*;
use semver;
use std::default::Default;
use std::ffi::CStr;
+use std::mem;
use std::os::raw::{c_char, c_int, c_void};
use std::ptr;
macro_rules! dup_str {
($Dst: expr, $Src: expr) => {
if !$Dst.is_null() {
pa_xfree($Dst as *mut _);
}
@@ -47,45 +47,58 @@ fn channel_map_to_layout(cm: &pa_channel
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]);
}
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,
+}
+
+#[derive(Debug)]
pub struct Context {
pub ops: *const cubeb::Ops,
pub mainloop: *mut pa_threaded_mainloop,
pub context: *mut pa_context,
- pub default_sink_info: *mut pa_sink_info,
+ pub default_sink_info: Option<DefaultInfo>,
pub context_name: *const c_char,
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,
}
+impl Drop for Context {
+ fn drop(&mut self) {
+ self.destroy();
+ }
+}
+
impl Context {
#[cfg(feature = "pulse-dlopen")]
fn _new(name: *const i8) -> Result<Box<Self>> {
let libpulse = unsafe { open() };
if libpulse.is_none() {
return Err(cubeb::ERROR);
}
let ctx = Box::new(Context {
ops: &PULSE_OPS,
libpulse: libpulse.unwrap(),
mainloop: unsafe { pa_threaded_mainloop_new() },
context: 0 as *mut _,
- default_sink_info: 0 as *mut _,
+ default_sink_info: None,
context_name: name,
collection_changed_callback: None,
collection_changed_user_ptr: 0 as *mut _,
error: true,
version_0_9_8: false,
version_2_0_0: false,
});
@@ -93,17 +106,17 @@ impl Context {
}
#[cfg(not(feature = "pulse-dlopen"))]
fn _new(name: *const i8) -> Result<Box<Self>> {
Ok(Box::new(Context {
ops: &PULSE_OPS,
mainloop: unsafe { pa_threaded_mainloop_new() },
context: 0 as *mut _,
- default_sink_info: 0 as *mut _,
+ default_sink_info: None,
context_name: name,
collection_changed_callback: None,
collection_changed_user_ptr: 0 as *mut _,
error: true,
version_0_9_8: false,
version_2_0_0: false,
}))
}
@@ -114,32 +127,36 @@ impl Context {
unsafe { pa_threaded_mainloop_start(ctx.mainloop) };
if ctx.pulse_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);
- pa_context_get_server_info(ctx.context,
- Some(server_info_callback),
- ctx.as_mut() as *mut Context as *mut _);
+ 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);
+ }
pa_threaded_mainloop_unlock(ctx.mainloop);
+ assert!(ctx.default_sink_info.is_some());
}
// Return the result.
Ok(ctx)
}
pub fn destroy(&mut self) {
- if !self.default_sink_info.is_null() {
- let _ = unsafe { Box::from_raw(self.default_sink_info) };
- }
-
if !self.context.is_null() {
unsafe { self.pulse_context_destroy() };
}
if !self.mainloop.is_null() {
unsafe {
pa_threaded_mainloop_stop(self.mainloop);
pa_threaded_mainloop_free(self.mainloop);
@@ -170,57 +187,42 @@ impl Context {
output_stream_params,
latency_frames,
data_callback,
state_callback,
user_ptr)
}
pub fn max_channel_count(&self) -> Result<u32> {
- unsafe {
- pa_threaded_mainloop_lock(self.mainloop);
- while self.default_sink_info.is_null() {
- pa_threaded_mainloop_wait(self.mainloop);
- }
- pa_threaded_mainloop_unlock(self.mainloop);
-
- Ok((*self.default_sink_info).channel_map.channels as u32)
+ match self.default_sink_info {
+ Some(ref info) => Ok(info.channel_map.channels as u32),
+ None => Err(cubeb::ERROR),
}
}
pub fn preferred_sample_rate(&self) -> Result<u32> {
- unsafe {
- pa_threaded_mainloop_lock(self.mainloop);
- while self.default_sink_info.is_null() {
- pa_threaded_mainloop_wait(self.mainloop);
- }
- pa_threaded_mainloop_unlock(self.mainloop);
-
- Ok((*self.default_sink_info).sample_spec.rate)
+ match self.default_sink_info {
+ Some(ref info) => Ok(info.sample_spec.rate),
+ None => Err(cubeb::ERROR),
}
}
pub fn min_latency(&self, params: &cubeb::StreamParams) -> Result<u32> {
// According to PulseAudio developers, this is a safe minimum.
Ok(25 * params.rate / 1000)
}
pub fn preferred_channel_layout(&self) -> Result<cubeb::ChannelLayout> {
- unsafe {
- pa_threaded_mainloop_lock(self.mainloop);
- while self.default_sink_info.is_null() {
- pa_threaded_mainloop_wait(self.mainloop);
- }
- pa_threaded_mainloop_unlock(self.mainloop);
-
- Ok(channel_map_to_layout(&(*self.default_sink_info).channel_map))
+ match self.default_sink_info {
+ Some(ref info) => Ok(channel_map_to_layout(&info.channel_map)),
+ None => Err(cubeb::ERROR),
}
}
- pub fn enumerate_devices(&self, devtype: cubeb::DeviceType) -> Result<*mut cubeb::DeviceCollection> {
+ 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 _;
unsafe {
pa_threaded_mainloop_lock(self.mainloop);
let o = pa_context_get_server_info(self.context,
Some(pulse_server_info_cb),
@@ -248,28 +250,53 @@ impl Context {
self.operation_wait(ptr::null_mut(), o);
pa_operation_unref(o);
}
}
pa_threaded_mainloop_unlock(self.mainloop);
}
- // TODO: This is dodgy - Need to account for padding between count
- // and device array in C code on 64-bit platforms. Using an extra
- // pointer instead of the header size to achieve this.
- let mut coll: Box<VarArray<*const cubeb::DeviceInfo>> = VarArray::with_length(user_data.devinfo.len());
- for (e1, e2) in user_data
- .devinfo
- .drain(..)
- .zip(coll.as_mut_slice().iter_mut()) {
- *e2 = e1;
+ // Extract the array of cubeb_device_info from
+ // PulseDevListData and convert it into C representation.
+ let mut tmp = Vec::new();
+ mem::swap(&mut user_data.devinfo, &mut tmp);
+ let devices = tmp.into_boxed_slice();
+ let coll = cubeb::DeviceCollection {
+ device: devices.as_ptr(),
+ count: devices.len(),
+ };
+
+ // Giving away the memory owned by devices. Don't free it!
+ mem::forget(devices);
+ Ok(coll)
+ }
+
+ 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() {
+ pa_xfree(dev.device_id as *mut _);
+ }
+ if !dev.group_id.is_null() {
+ pa_xfree(dev.group_id as *mut _);
+ }
+ if !dev.vendor_name.is_null() {
+ pa_xfree(dev.vendor_name as *mut _);
+ }
+ if !dev.friendly_name.is_null() {
+ pa_xfree(dev.friendly_name as *mut _);
+ }
+ }
}
-
- Ok(Box::into_raw(coll) as *mut cubeb::DeviceCollection)
}
pub fn register_device_collection_changed(&mut self,
devtype: cubeb::DeviceType,
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) {
@@ -464,51 +491,52 @@ impl Context {
cubeb::DeviceState::Enabled
}
} else {
cubeb::DeviceState::Enabled
}
}
}
-
// 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 {
- if !ctx.default_sink_info.is_null() {
- let _ = Box::from_raw(ctx.default_sink_info);
- }
- ctx.default_sink_info = Box::into_raw(Box::new(*info));
+ 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);
}
- pa_context_get_sink_info_by_name(context,
- (*info).default_sink_name,
- Some(sink_info_callback),
- u);
+ 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,
- devinfo: Vec<*const cubeb::DeviceInfo>,
+ devinfo: Vec<cubeb::DeviceInfo>,
context: *mut Context,
}
impl Drop for PulseDevListData {
fn drop(&mut self) {
- for elem in &mut self.devinfo {
- let _ = unsafe { Box::from_raw(elem) };
- }
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 _);
@@ -595,17 +623,17 @@ unsafe extern "C" fn pulse_sink_info_cb(
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(Box::into_raw(Box::new(devinfo)));
+ 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) {
@@ -661,17 +689,17 @@ unsafe extern "C" fn pulse_source_info_c
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(Box::into_raw(Box::new(devinfo)));
+ 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());
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs
@@ -1,15 +1,14 @@
// 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 var_array;
pub type Result<T> = ::std::result::Result<T, i32>;
pub use self::context::Context;
pub use self::stream::Device;
pub use self::stream::Stream;
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
@@ -333,25 +333,32 @@ impl<'ctx> Stream<'ctx> {
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_null() {
+ 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. */
- if ((*self.context.default_sink_info).flags & PA_SINK_FLAT_VOLUME) != 0 {
+ 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);
@@ -459,19 +466,22 @@ impl<'ctx> Stream<'ctx> {
}
let ss = pa_sample_spec {
channels: stream_params.channels as u8,
format: fmt,
rate: stream_params.rate,
};
- let cm = layout_to_channel_map(stream_params.layout);
-
- let stream = unsafe { pa_stream_new(self.context.context, stream_name, &ss, &cm) };
+ 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) }
+ };
if !stream.is_null() {
Ok(stream)
} else {
Err(cubeb::ERROR)
}
}
deleted file mode 100644
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/var_array.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-/// A C-style variable length array implemented as one allocation with
-/// a prepended header.
-
-// Copyright © 2017 Mozilla Foundation
-//
-// This program is made available under an ISC-style license. See the
-// accompanying file LICENSE for details.
-
-use pulse_ffi::pa_xrealloc;
-use std::ptr;
-
-#[repr(C)]
-#[derive(Debug)]
-pub struct VarArray<T> {
- len: u32,
- data: [T; 0],
-}
-
-impl<T> VarArray<T> {
- pub fn len(&self) -> usize {
- self.len as usize
- }
-
- unsafe fn _realloc(ptr: Option<Box<Self>>, count: usize) -> Box<Self> {
- use std::mem::{size_of, transmute};
-
- let size = size_of::<Self>() + count * size_of::<T>();
- let raw_ptr = match ptr {
- Some(box_ptr) => Box::into_raw(box_ptr) as *mut u8,
- None => ptr::null_mut(),
- };
- let mem = pa_xrealloc(raw_ptr as *mut _, size);
- let mut result: Box<Self> = transmute(mem);
- result.len = count as u32;
- result
- }
-
- pub fn with_length(len: usize) -> Box<VarArray<T>> {
- unsafe { Self::_realloc(None, len) }
- }
-
- pub fn as_mut_slice(&mut self) -> &mut [T] {
- use std::slice::from_raw_parts_mut;
-
- unsafe { from_raw_parts_mut(&self.data as *const _ as *mut _, self.len()) }
- }
-}
-
-impl<T> Drop for VarArray<T> {
- fn drop(&mut self) {
- let ptr = self as *mut Self;
- unsafe {
- Self::_realloc(Some(Box::from_raw(ptr)), 0);
- }
- }
-}
--- a/media/libcubeb/cubeb-pulse-rs/src/capi.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/capi.rs
@@ -71,29 +71,38 @@ unsafe extern "C" fn capi_get_preferred_
cubeb::OK
},
Err(e) => e,
}
}
unsafe extern "C" fn capi_enumerate_devices(c: *mut cubeb::Context,
devtype: cubeb::DeviceType,
- collection: *mut *mut cubeb::DeviceCollection)
+ collection: *mut cubeb::DeviceCollection)
-> i32 {
let ctx = &*(c as *mut backend::Context);
match ctx.enumerate_devices(devtype) {
Ok(dc) => {
*collection = dc;
cubeb::OK
},
Err(e) => e,
}
}
+unsafe extern "C" fn capi_device_collection_destroy(c: *mut cubeb::Context,
+ collection: *mut cubeb::DeviceCollection)
+ -> i32 {
+ let ctx = &*(c as *mut backend::Context);
+
+ ctx.device_collection_destroy(collection);
+ cubeb::OK
+}
+
unsafe extern "C" fn capi_destroy(c: *mut cubeb::Context) {
let _: Box<backend::Context> = Box::from_raw(c as *mut _);
}
unsafe extern "C" fn capi_stream_init(c: *mut cubeb::Context,
s: *mut *mut cubeb::Stream,
stream_name: *const c_char,
input_device: cubeb::DeviceId,
@@ -214,16 +223,17 @@ unsafe extern "C" fn capi_register_devic
pub const PULSE_OPS: cubeb::Ops = cubeb::Ops {
init: Some(capi_init),
get_backend_id: Some(capi_get_backend_id),
get_max_channel_count: Some(capi_get_max_channel_count),
get_min_latency: Some(capi_get_min_latency),
get_preferred_sample_rate: Some(capi_get_preferred_sample_rate),
get_preferred_channel_layout: Some(capi_get_preferred_channel_layout),
enumerate_devices: Some(capi_enumerate_devices),
+ device_collection_destroy: Some(capi_device_collection_destroy),
destroy: Some(capi_destroy),
stream_init: Some(capi_stream_init),
stream_destroy: Some(capi_stream_destroy),
stream_start: Some(capi_stream_start),
stream_stop: Some(capi_stream_stop),
stream_get_position: Some(capi_stream_get_position),
stream_get_latency: Some(capi_stream_get_latency),
stream_set_volume: Some(capi_stream_set_volume),