зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1360060 - P3: device_collection_destroy for cubeb-pulse-rs. r=kinetik
MozReview-Commit-ID: Hvn12h4O4FE --HG-- extra : rebase_source : 9a689bcc516c1a3d363c2996bce67a083970aad9
This commit is contained in:
Родитель
d8f7d93bff
Коммит
839fad3c98
|
@ -4,59 +4,52 @@
|
|||
// 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)]
|
||||
|
@ -83,15 +76,12 @@ impl Default for Device {
|
|||
}
|
||||
}
|
||||
|
||||
#[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;
|
||||
|
@ -179,10 +169,10 @@ pub struct DeviceInfo {
|
|||
#[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,
|
||||
|
@ -228,8 +218,10 @@ pub struct Ops {
|
|||
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)>,
|
||||
|
@ -257,49 +249,32 @@ pub struct LayoutMap {
|
|||
}
|
||||
|
||||
// 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() },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
|
||||
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;
|
||||
|
||||
|
@ -51,12 +51,19 @@ fn channel_map_to_layout(cm: &pa_channel_map) -> cubeb::ChannelLayout {
|
|||
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,
|
||||
|
@ -67,6 +74,12 @@ pub struct Context {
|
|||
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>> {
|
||||
|
@ -80,7 +93,7 @@ impl Context {
|
|||
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 _,
|
||||
|
@ -98,7 +111,7 @@ impl 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 _,
|
||||
|
@ -119,11 +132,19 @@ impl Context {
|
|||
}
|
||||
|
||||
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.
|
||||
|
@ -131,10 +152,6 @@ impl Context {
|
|||
}
|
||||
|
||||
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() };
|
||||
}
|
||||
|
@ -175,26 +192,16 @@ impl Context {
|
|||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,18 +211,13 @@ impl Context {
|
|||
}
|
||||
|
||||
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 _;
|
||||
|
||||
|
@ -253,18 +255,43 @@ impl Context {
|
|||
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(),
|
||||
};
|
||||
|
||||
Ok(Box::into_raw(coll) as *mut cubeb::DeviceCollection)
|
||||
// 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 _);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_device_collection_changed(&mut self,
|
||||
|
@ -469,7 +496,6 @@ 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,
|
||||
|
@ -478,32 +504,34 @@ unsafe extern "C" fn server_info_callback(context: *mut pa_context, info: *const
|
|||
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 _);
|
||||
|
@ -600,7 +628,7 @@ unsafe extern "C" fn pulse_sink_info_cb(_context: *mut pa_context,
|
|||
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);
|
||||
}
|
||||
|
@ -666,7 +694,7 @@ unsafe extern "C" fn pulse_source_info_cb(_context: *mut pa_context,
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
mod context;
|
||||
mod cork_state;
|
||||
mod stream;
|
||||
mod var_array;
|
||||
|
||||
pub type Result<T> = ::std::result::Result<T, i32>;
|
||||
|
||||
|
|
|
@ -338,7 +338,7 @@ impl<'ctx> Stream<'ctx> {
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -346,7 +346,14 @@ impl<'ctx> Stream<'ctx> {
|
|||
|
||||
/* 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);
|
||||
|
@ -464,9 +471,12 @@ impl<'ctx> Stream<'ctx> {
|
|||
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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -76,7 +76,7 @@ unsafe extern "C" fn capi_get_preferred_channel_layout(c: *mut cubeb::Context,
|
|||
|
||||
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);
|
||||
|
||||
|
@ -89,6 +89,15 @@ unsafe extern "C" fn capi_enumerate_devices(c: *mut cubeb::Context,
|
|||
}
|
||||
}
|
||||
|
||||
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 _);
|
||||
}
|
||||
|
@ -219,6 +228,7 @@ pub const PULSE_OPS: cubeb::Ops = cubeb::Ops {
|
|||
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),
|
||||
|
|
Загрузка…
Ссылка в новой задаче