Bug 1687070 - mach vendor rust. r=cubeb-reviewers,kinetik

Differential Revision: https://phabricator.services.mozilla.com/D119955
This commit is contained in:
Paul Adenot 2021-08-02 15:46:09 +00:00
parent 2b7b90b50f
commit 52a4c47c98
25 changed files with 1413 additions and 1007 deletions

View File

@ -30,7 +30,7 @@ rev = "1bb484e96ae724309e3346968e8ffd4c25e61616"
[source."https://github.com/mozilla/cubeb-pulse-rs"]
git = "https://github.com/mozilla/cubeb-pulse-rs"
replace-with = "vendored-sources"
rev = "c87b50aebfa088c1ad30c74819d4e9829f88b2e3"
rev = "3ad5978575f501ab10b1753626f176f1bba3f584"
[source."https://github.com/mozilla/cubeb-coreaudio-rs"]
git = "https://github.com/mozilla/cubeb-coreaudio-rs"

6
Cargo.lock generated
View File

@ -1027,7 +1027,7 @@ dependencies = [
[[package]]
name = "cubeb-pulse"
version = "0.3.0"
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=c87b50aebfa088c1ad30c74819d4e9829f88b2e3#c87b50aebfa088c1ad30c74819d4e9829f88b2e3"
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=3ad5978575f501ab10b1753626f176f1bba3f584#3ad5978575f501ab10b1753626f176f1bba3f584"
dependencies = [
"cubeb-backend",
"pulse",
@ -3999,7 +3999,7 @@ dependencies = [
[[package]]
name = "pulse"
version = "0.3.0"
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=c87b50aebfa088c1ad30c74819d4e9829f88b2e3#c87b50aebfa088c1ad30c74819d4e9829f88b2e3"
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=3ad5978575f501ab10b1753626f176f1bba3f584#3ad5978575f501ab10b1753626f176f1bba3f584"
dependencies = [
"bitflags",
"pulse-ffi",
@ -4008,7 +4008,7 @@ dependencies = [
[[package]]
name = "pulse-ffi"
version = "0.1.0"
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=c87b50aebfa088c1ad30c74819d4e9829f88b2e3#c87b50aebfa088c1ad30c74819d4e9829f88b2e3"
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=3ad5978575f501ab10b1753626f176f1bba3f584#3ad5978575f501ab10b1753626f176f1bba3f584"
dependencies = [
"libc",
]

View File

@ -1 +1 @@
{"files":{".editorconfig":"bf047bd1da10cabb99eea666d1e57c321eba4716dccb3e4ed0e2c5fe3ca53858",".travis.yml":"0394e2adb041175457685cde5ee05ff04bdab8885fd8a62551f2ff43d9e48872","AUTHORS":"0e0ac930a68ce2f6b876126b195add177f0d3886facb9260f4d9b69f1988f0cc","Cargo.toml":"56e90cb82ec36ead07e551a28fc2455fa658fa8308c3d73f8d856d85bfcd2122","LICENSE":"44c6b5ae5ec3fe2fbc608b00e6f4896f4d2d5c7e525fcbaa3eaa3cf2f3d5a983","README.md":"e6a98ee5630b9ce1a096a2907d095454f2770e298a5b0976ab552cc53ca96cfc","src/backend/context.rs":"33d9fdf1504fe1ae43d301e288daf6eaeabeb47aa0ef86efa135c6d984425fc4","src/backend/cork_state.rs":"4a0f1afc7d9f333dac89218cc56d7d32fbffb487cd48c1c9a4e03d79cb3b5e28","src/backend/intern.rs":"374a9a3bd79fddc47739dda1dbfc5929aea5a91946794fe65fba3c8d130fbda9","src/backend/mod.rs":"06ce9250865abf0ea461f215b128470636d072a6776821efef3caf5a7b992fb9","src/backend/stream.rs":"b8700fffb4d1537bc2fd3f0e26e7bbb16bc6e7cc7a803723e06704610ca1f6f5","src/capi.rs":"b2c1be8128cadd36caa65c80950440f9d6f2aa0c24cc7bae6a9eaf6347ac454d","src/lib.rs":"7282560d84b134b09acfd8d6282600982e42fb3557f72454c535637cc26c7bf6"},"package":null}
{"files":{".editorconfig":"bf047bd1da10cabb99eea666d1e57c321eba4716dccb3e4ed0e2c5fe3ca53858",".github/workflows/build.yml":"95d0d2542c04f0c932f58591b92c3051db5c95657bf5f24b6a6110f7b667568d","AUTHORS":"0e0ac930a68ce2f6b876126b195add177f0d3886facb9260f4d9b69f1988f0cc","Cargo.toml":"56e90cb82ec36ead07e551a28fc2455fa658fa8308c3d73f8d856d85bfcd2122","LICENSE":"44c6b5ae5ec3fe2fbc608b00e6f4896f4d2d5c7e525fcbaa3eaa3cf2f3d5a983","README.md":"0079450bb4b013bac065ed1750851e461a3710ebad1f323817da1cb82db0bc4f","src/backend/context.rs":"8969b300850b56ace07abe570940e2099774bf0bf20325be1d3ec0f5f408c8ce","src/backend/cork_state.rs":"4a0f1afc7d9f333dac89218cc56d7d32fbffb487cd48c1c9a4e03d79cb3b5e28","src/backend/intern.rs":"11ca424e4eb77f8eb9fd5a6717d1e791facf9743156a8534f0016fcf64d57b0f","src/backend/mod.rs":"d5da05348bf1a7f65c85b14372964a49dc4849f0aee96c75e2c18b51fb03fcaf","src/backend/stream.rs":"deac28f4840dbeeb195deff8734d594e53fbca3b65545a54613e9e6fa22d7dfc","src/capi.rs":"fa0fa020f0d0efe55aa0fc3596405e8407bbe2cbe6c7a558345304e6da87994e","src/lib.rs":"b41bbdc562cbfb130ed7c1e53fe69944774f515705341d8ce48a2f82c8c0c2c5"},"package":null}

View File

@ -0,0 +1,44 @@
name: Build
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-20.04
continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: false
matrix:
rust: [stable]
experimental: [false]
include:
- rust: nightly
experimental: true
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Install Rust
run: rustup toolchain install ${{ matrix.rust }} --profile minimal --component rustfmt clippy
- name: Install Dependencies (Linux)
run: sudo apt-get install libpulse-dev
- name: Check format
shell: bash
run: rustup run ${{ matrix.rust }} cargo fmt --all -- --check
- name: Clippy
shell: bash
run: rustup run ${{ matrix.rust }} cargo clippy --all -- -D warnings
- name: Build
shell: bash
run: rustup run ${{ matrix.rust }} cargo build --all
- name: Test
shell: bash
run: rustup run ${{ matrix.rust }} cargo test --all

View File

@ -1,70 +0,0 @@
language: rust
cache: cargo
notifications:
email:
on_success: never
rust:
# Version 1.36 is the minimum version of rust supported by Gecko.
- 1.36.0
- stable
- nightly
env:
# default jobs with and without optional features.
-
- FEATURES=pulse-dlopen
# Invoke cargo with optional target or features switches.
script: >
cargo test
${TARGET:+--target ${TARGET}}
${FEATURES:+--features ${FEATURES}}
# Install cross target if necessary.
before_install:
if test -n "${TARGET}"; then rustup target add ${TARGET}; fi
addons: &apt_64
apt:
packages:
- libpulse-dev
matrix:
include:
# Add in 32-bit builds
- rust: 1.36.0
env:
- TARGET=i686-unknown-linux-gnu
addons: &apt_32
apt:
packages:
- gcc-multilib
- g++-multilib
- libpulse-dev:i386
- libglib2.0-dev:i386
- rust: 1.36.0
env:
- TARGET=i686-unknown-linux-gnu
- FEATURES=pulse-dlopen
addons: *apt_32
- rust: stable
env:
- TARGET=i686-unknown-linux-gnu
addons: *apt_32
- rust: stable
env:
- TARGET=i686-unknown-linux-gnu
- FEATURES=pulse-dlopen
addons: *apt_32
- rust: nightly
env:
- TARGET=i686-unknown-linux-gnu
addons: *apt_32
- rust: nightly
env:
- TARGET=i686-unknown-linux-gnu
- FEATURES=pulse-dlopen
addons: *apt_32
allow_failures:
- rust: nightly

View File

@ -2,5 +2,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)
[![Build Status](https://github.com/mozilla/cubeb-pulse-rs/actions/workflows/build.yml/badge.svg)](https://github.com/mozilla/cubeb-pulse-rs/actions/workflows/build.yml)

View File

@ -4,8 +4,10 @@
// accompanying file LICENSE for details.
use backend::*;
use cubeb_backend::{ffi, log_enabled, Context, ContextOps, DeviceCollectionRef, DeviceId,
DeviceType, Error, Ops, Result, Stream, StreamParams, StreamParamsRef};
use cubeb_backend::{
ffi, log_enabled, Context, ContextOps, DeviceCollectionRef, DeviceId, DeviceType, Error, Ops,
Result, Stream, StreamParams, StreamParamsRef,
};
use pulse::{self, ProplistExt};
use pulse_ffi::*;
use semver;
@ -92,17 +94,8 @@ impl PulseContext {
}))
}
fn server_info_cb(
context: &pulse::Context,
info: Option<&pulse::ServerInfo>,
u: *mut c_void,
) {
fn sink_info_cb(
_: &pulse::Context,
i: *const pulse::SinkInfo,
eol: i32,
u: *mut c_void,
) {
fn server_info_cb(context: &pulse::Context, info: Option<&pulse::ServerInfo>, u: *mut c_void) {
fn sink_info_cb(_: &pulse::Context, i: *const pulse::SinkInfo, eol: i32, u: *mut c_void) {
let ctx = unsafe { &mut *(u as *mut PulseContext) };
if eol == 0 {
let info = unsafe { &*i };
@ -110,7 +103,7 @@ impl PulseContext {
ctx.default_sink_info = Some(DefaultInfo {
sample_spec: info.sample_spec,
channel_map: info.channel_map,
flags: flags,
flags,
});
}
ctx.mainloop.signal();
@ -220,11 +213,13 @@ impl PulseContext {
}
}
} else if (f == pulse::SubscriptionEventFacility::Server)
&& (t == pulse::SubscriptionEventType::Change) {
&& (t == pulse::SubscriptionEventType::Change)
{
cubeb_log!("Server changed {}", index as i32);
let user_data: *mut c_void = ctx as *mut _ as *mut _;
if let Some(ref context) = ctx.context {
if let Err(e) = context.get_server_info(PulseContext::server_info_cb, user_data) {
if let Err(e) = context.get_server_info(PulseContext::server_info_cb, user_data)
{
cubeb_log!("get_server_info ignored failure: {}", e);
}
}
@ -335,14 +330,14 @@ impl ContextOps for PulseContext {
let device_id = ctx.devids.borrow_mut().add(info_name);
let friendly_name = info_description.into_raw();
let devinfo = ffi::cubeb_device_info {
device_id: device_id,
device_id,
devid: device_id as ffi::cubeb_devid,
friendly_name: friendly_name,
group_id: group_id,
vendor_name: vendor_name,
friendly_name,
group_id,
vendor_name,
device_type: ffi::CUBEB_DEVICE_TYPE_OUTPUT,
state: ctx.state_from_port(info.active_port),
preferred: preferred,
preferred,
format: ffi::CUBEB_DEVICE_FMT_ALL,
default_format: pulse_format_to_cubeb_format(info.sample_spec.format),
max_channels: u32::from(info.channel_map.channels),
@ -396,14 +391,14 @@ impl ContextOps for PulseContext {
let device_id = ctx.devids.borrow_mut().add(info_name);
let friendly_name = info_description.into_raw();
let devinfo = ffi::cubeb_device_info {
device_id: device_id,
device_id,
devid: device_id as ffi::cubeb_devid,
friendly_name: friendly_name,
group_id: group_id,
vendor_name: vendor_name,
friendly_name,
group_id,
vendor_name,
device_type: ffi::CUBEB_DEVICE_TYPE_INPUT,
state: ctx.state_from_port(info.active_port),
preferred: preferred,
preferred,
format: ffi::CUBEB_DEVICE_FMT_ALL,
default_format: pulse_format_to_cubeb_format(info.sample_spec.format),
max_channels: u32::from(info.channel_map.channels),
@ -506,7 +501,7 @@ impl ContextOps for PulseContext {
Ok(())
}
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
#[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))]
fn stream_init(
&mut self,
stream_name: Option<&CStr>,
@ -591,10 +586,7 @@ impl PulseContext {
}
self.context = {
let name = match self.context_name.as_ref() {
Some(s) => Some(s.as_ref()),
None => None,
};
let name = self.context_name.as_ref().map(|s| s.as_ref());
pulse::Context::new(&self.mainloop.get_api(), name)
};
@ -723,7 +715,7 @@ impl<'a> PulseDevListData<'a> {
default_sink_name: CString::default(),
default_source_name: CString::default(),
devinfo: Vec::new(),
context: context,
context,
}
}
}

View File

@ -8,7 +8,7 @@ use std::os::raw::c_char;
#[derive(Debug)]
pub struct Intern {
vec: Vec<Box<CString>>,
vec: Vec<CString>,
}
impl Intern {
@ -26,7 +26,7 @@ impl Intern {
}
}
self.vec.push(Box::new(string.to_owned()));
self.vec.push(string.to_owned());
self.vec.last().unwrap().as_ptr()
}
}

View File

@ -5,8 +5,8 @@
mod context;
mod cork_state;
mod stream;
mod intern;
mod stream;
pub use self::context::PulseContext;
use self::intern::Intern;

View File

@ -3,22 +3,24 @@
// 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_backend::{ffi, log_enabled, ChannelLayout, DeviceId, DeviceRef, Error, Result,
SampleFormat, StreamOps, StreamParamsRef, StreamPrefs};
use backend::*;
use cubeb_backend::{
ffi, log_enabled, ChannelLayout, DeviceId, DeviceRef, Error, Result, SampleFormat, StreamOps,
StreamParamsRef, StreamPrefs,
};
use pulse::{self, CVolumeExt, ChannelMapExt, SampleSpecExt, StreamLatency, USecExt};
use pulse_ffi::*;
use std::{mem, ptr};
use ringbuf::RingBuffer;
use std::ffi::{CStr, CString};
use std::os::raw::{c_long, c_void};
use std::slice;
use std::sync::atomic::{AtomicUsize, Ordering};
use ringbuf::RingBuffer;
use std::{mem, ptr};
use self::LinearInputBuffer::*;
use self::RingBufferConsumer::*;
use self::RingBufferProducer::*;
use self::LinearInputBuffer::*;
const PULSE_NO_GAIN: f32 = -1.0;
@ -101,12 +103,10 @@ fn default_layout_for_channels(ch: u32) -> ChannelLayout {
3 => ChannelLayout::_3F,
4 => ChannelLayout::QUAD,
5 => ChannelLayout::_3F2,
6 => ChannelLayout::_3F_LFE
| ChannelLayout::SIDE_LEFT
| ChannelLayout::SIDE_RIGHT,
6 => ChannelLayout::_3F_LFE | ChannelLayout::SIDE_LEFT | ChannelLayout::SIDE_RIGHT,
7 => ChannelLayout::_3F3R_LFE,
8 => ChannelLayout::_3F4_LFE,
_ => panic!("channel must be between 1 to 8.")
_ => panic!("channel must be between 1 to 8."),
}
}
@ -127,58 +127,63 @@ impl Drop for Device {
enum RingBufferConsumer {
IntegerRingBufferConsumer(ringbuf::Consumer<i16>),
FloatRingBufferConsumer(ringbuf::Consumer<f32>)
FloatRingBufferConsumer(ringbuf::Consumer<f32>),
}
enum RingBufferProducer {
IntegerRingBufferProducer(ringbuf::Producer<i16>),
FloatRingBufferProducer(ringbuf::Producer<f32>)
FloatRingBufferProducer(ringbuf::Producer<f32>),
}
enum LinearInputBuffer {
IntegerLinearInputBuffer(Vec<i16>),
FloatLinearInputBuffer(Vec<f32>)
FloatLinearInputBuffer(Vec<f32>),
}
struct BufferManager {
consumer: RingBufferConsumer,
producer: RingBufferProducer,
linear_input_buffer: LinearInputBuffer
linear_input_buffer: LinearInputBuffer,
}
impl BufferManager {
// When opening a duplex stream, the sample-spec are guaranteed to match. It's ok to have
// either the input or output sample-spec here.
fn new(input_buffer_size: usize, sample_spec: &pulse::SampleSpec) -> BufferManager {
if sample_spec.format == PA_SAMPLE_S16BE ||
sample_spec.format == PA_SAMPLE_S16LE {
let ring = RingBuffer::<i16>::new(input_buffer_size);
let (prod, cons) = ring.split();
return BufferManager {
producer: IntegerRingBufferProducer(prod),
consumer: IntegerRingBufferConsumer(cons),
linear_input_buffer: IntegerLinearInputBuffer(Vec::<i16>::with_capacity(input_buffer_size))
};
} else {
let ring = RingBuffer::<f32>::new(input_buffer_size);
let (prod, cons) = ring.split();
return BufferManager {
producer: FloatRingBufferProducer(prod),
consumer: FloatRingBufferConsumer(cons),
linear_input_buffer: FloatLinearInputBuffer(Vec::<f32>::with_capacity(input_buffer_size))
};
if sample_spec.format == PA_SAMPLE_S16BE || sample_spec.format == PA_SAMPLE_S16LE {
let ring = RingBuffer::<i16>::new(input_buffer_size);
let (prod, cons) = ring.split();
BufferManager {
producer: IntegerRingBufferProducer(prod),
consumer: IntegerRingBufferConsumer(cons),
linear_input_buffer: IntegerLinearInputBuffer(Vec::<i16>::with_capacity(
input_buffer_size,
)),
}
} else {
let ring = RingBuffer::<f32>::new(input_buffer_size);
let (prod, cons) = ring.split();
BufferManager {
producer: FloatRingBufferProducer(prod),
consumer: FloatRingBufferConsumer(cons),
linear_input_buffer: FloatLinearInputBuffer(Vec::<f32>::with_capacity(
input_buffer_size,
)),
}
}
}
fn push_input_data(&mut self, input_data: *const c_void, read_samples: usize) {
match &mut self.producer {
RingBufferProducer::FloatRingBufferProducer(p) => {
let input_data = unsafe { slice::from_raw_parts::<f32>(input_data as *const f32, read_samples) };
let input_data =
unsafe { slice::from_raw_parts::<f32>(input_data as *const f32, read_samples) };
// we don't do anything in particular if we can't push everything
p.push_slice(input_data);
}
RingBufferProducer::IntegerRingBufferProducer(p) => {
let input_data = unsafe { slice::from_raw_parts::<i16>(input_data as *const i16, read_samples) };
let input_data =
unsafe { slice::from_raw_parts::<i16>(input_data as *const i16, read_samples) };
p.push_slice(input_data);
}
}
@ -187,7 +192,9 @@ impl BufferManager {
fn pull_input_data(&mut self, input_data: *mut c_void, needed_samples: usize) {
match &mut self.consumer {
IntegerRingBufferConsumer(p) => {
let mut input: &mut[i16] = unsafe { slice::from_raw_parts_mut::<i16>(input_data as *mut i16, needed_samples) };
let mut input: &mut [i16] = unsafe {
slice::from_raw_parts_mut::<i16>(input_data as *mut i16, needed_samples)
};
let read = p.pop_slice(&mut input);
if read < needed_samples {
for i in 0..(needed_samples - read) {
@ -196,7 +203,9 @@ impl BufferManager {
}
}
FloatRingBufferConsumer(p) => {
let mut input: &mut[f32] = unsafe { slice::from_raw_parts_mut::<f32>(input_data as *mut f32, needed_samples) };
let mut input: &mut [f32] = unsafe {
slice::from_raw_parts_mut::<f32>(input_data as *mut f32, needed_samples)
};
let read = p.pop_slice(&mut input);
if read < needed_samples {
for i in 0..(needed_samples - read) {
@ -221,7 +230,7 @@ impl BufferManager {
}
self.pull_input_data(p, nsamples);
return p;
p
}
pub fn trim(&mut self, final_size: usize) {
@ -242,12 +251,8 @@ impl BufferManager {
}
pub fn available_samples(&mut self) -> usize {
match &self.linear_input_buffer {
LinearInputBuffer::IntegerLinearInputBuffer(b) => {
b.len()
}
LinearInputBuffer::FloatLinearInputBuffer(b) => {
b.len()
}
LinearInputBuffer::IntegerLinearInputBuffer(b) => b.len(),
LinearInputBuffer::FloatLinearInputBuffer(b) => b.len(),
}
}
}
@ -274,11 +279,11 @@ pub struct PulseStream<'ctx> {
shutdown: bool,
volume: f32,
state: ffi::cubeb_state,
input_buffer_manager: Option<BufferManager>
input_buffer_manager: Option<BufferManager>,
}
impl<'ctx> PulseStream<'ctx> {
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
#[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))]
pub fn new(
context: &'ctx PulseContext,
stream_name: Option<&CStr>,
@ -305,7 +310,7 @@ impl<'ctx> PulseStream<'ctx> {
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);
let readable_size = s.readable_size().map(|s| s as i32).unwrap_or(-1);
if readable_size > 0 && unsafe { s.peek(buffer, size).is_err() } {
return -1;
}
@ -329,7 +334,10 @@ impl<'ctx> PulseStream<'ctx> {
if stm.output_stream.is_some() {
// duplex stream: push the input data to the ring buffer.
stm.input_buffer_manager.as_mut().unwrap().push_input_data(read_data, read_samples);
stm.input_buffer_manager
.as_mut()
.unwrap()
.push_input_data(read_data, read_samples);
} else {
// input/capture only operation. Call callback directly
let got = unsafe {
@ -373,11 +381,13 @@ impl<'ctx> PulseStream<'ctx> {
let input_buffer_manager = stm.input_buffer_manager.as_mut().unwrap();
if stm.output_frame_count.fetch_add(nframes, Ordering::SeqCst) == 0 {
let buffered_input_frames = input_buffer_manager.available_samples() / stm.input_sample_spec.channels as usize;
let buffered_input_frames = input_buffer_manager.available_samples()
/ stm.input_sample_spec.channels as usize;
if buffered_input_frames > nframes {
// Trim the buffer to ensure minimal roundtrip latency
let popped_frames = buffered_input_frames - nframes;
input_buffer_manager.trim(nframes * stm.input_sample_spec.channels as usize);
input_buffer_manager
.trim(nframes * stm.input_sample_spec.channels as usize);
cubeb_log!("Dropping {} frames in input buffer.", popped_frames);
}
}
@ -393,12 +403,12 @@ impl<'ctx> PulseStream<'ctx> {
}
let mut stm = Box::new(PulseStream {
context: context,
context,
output_stream: None,
input_stream: None,
data_callback: data_callback,
state_callback: state_callback,
user_ptr: user_ptr,
data_callback,
state_callback,
user_ptr,
drain_timer: ptr::null_mut(),
output_sample_spec: pulse::SampleSpec::default(),
input_sample_spec: pulse::SampleSpec::default(),
@ -406,7 +416,7 @@ impl<'ctx> PulseStream<'ctx> {
shutdown: false,
volume: PULSE_NO_GAIN,
state: ffi::CUBEB_STATE_ERROR,
input_buffer_manager: None
input_buffer_manager: None,
});
if let Some(ref context) = stm.context.context {
@ -421,14 +431,15 @@ impl<'ctx> PulseStream<'ctx> {
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 buffer_size_bytes = latency_frames * stm.output_sample_spec.frame_size() as u32;
let buffer_size_bytes =
latency_frames * stm.output_sample_spec.frame_size() as u32;
let battr = pa_buffer_attr {
maxlength: u32::max_value(),
prebuf: u32::max_value(),
prebuf: 0,
fragsize: u32::max_value(),
tlength: buffer_size_bytes * 2,
minreq: buffer_size_bytes / 4
minreq: buffer_size_bytes / 4,
};
let device_name = super::try_cstr_from(output_device as *const _);
let mut stream_flags = pulse::StreamFlags::AUTO_TIMING_UPDATE
@ -438,16 +449,11 @@ impl<'ctx> PulseStream<'ctx> {
if device_name.is_some()
|| stream_params
.prefs()
.contains(StreamPrefs::DISABLE_DEVICE_SWITCHING) {
stream_flags |= pulse::StreamFlags::DONT_MOVE;
.contains(StreamPrefs::DISABLE_DEVICE_SWITCHING)
{
stream_flags |= pulse::StreamFlags::DONT_MOVE;
}
let _ = s.connect_playback(
device_name,
&battr,
stream_flags,
None,
None,
);
let _ = s.connect_playback(device_name, &battr, stream_flags, None, None);
stm.output_stream = Some(s);
}
@ -460,7 +466,7 @@ impl<'ctx> PulseStream<'ctx> {
}
// Set up input stream
if let Some(ref stream_params) = input_stream_params {
if let Some(stream_params) = input_stream_params {
match PulseStream::stream_init(context, stream_params, stream_name) {
Ok(s) => {
stm.input_sample_spec = *s.get_sample_spec();
@ -468,13 +474,14 @@ impl<'ctx> PulseStream<'ctx> {
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 buffer_size_bytes = latency_frames * stm.input_sample_spec.frame_size() as u32;
let buffer_size_bytes =
latency_frames * stm.input_sample_spec.frame_size() as u32;
let battr = pa_buffer_attr {
maxlength: u32::max_value(),
prebuf: u32::max_value(),
fragsize: buffer_size_bytes,
tlength: buffer_size_bytes,
minreq: buffer_size_bytes
minreq: buffer_size_bytes,
};
let device_name = super::try_cstr_from(input_device as *const _);
let mut stream_flags = pulse::StreamFlags::AUTO_TIMING_UPDATE
@ -484,14 +491,11 @@ impl<'ctx> PulseStream<'ctx> {
if device_name.is_some()
|| stream_params
.prefs()
.contains(StreamPrefs::DISABLE_DEVICE_SWITCHING) {
.contains(StreamPrefs::DISABLE_DEVICE_SWITCHING)
{
stream_flags |= pulse::StreamFlags::DONT_MOVE;
}
let _ = s.connect_record(
device_name,
&battr,
stream_flags,
);
let _ = s.connect_record(device_name, &battr, stream_flags);
stm.input_stream = Some(s);
}
@ -506,8 +510,12 @@ impl<'ctx> PulseStream<'ctx> {
// Duplex, set up the ringbuffer
if input_stream_params.is_some() && output_stream_params.is_some() {
// A bit more room in case of output underrun.
let buffer_size_bytes = 2 * latency_frames * stm.input_sample_spec.frame_size() as u32;
stm.input_buffer_manager = Some(BufferManager::new(buffer_size_bytes as usize, &stm.input_sample_spec))
let buffer_size_bytes =
2 * latency_frames * stm.input_sample_spec.frame_size() as u32;
stm.input_buffer_manager = Some(BufferManager::new(
buffer_size_bytes as usize,
&stm.input_sample_spec,
))
}
let r = if stm.wait_until_ready() {
@ -593,31 +601,9 @@ impl<'ctx> Drop for PulseStream<'ctx> {
impl<'ctx> StreamOps for PulseStream<'ctx> {
fn start(&mut self) -> Result<()> {
fn output_preroll(_: &pulse::MainloopApi, u: *mut c_void) {
let stm = unsafe { &mut *(u as *mut PulseStream) };
if !stm.shutdown {
let size = stm.output_stream
.as_ref()
.map_or(0, |s| s.writable_size().unwrap_or(0));
stm.trigger_user_callback(std::ptr::null(), size);
}
}
self.shutdown = false;
self.cork(CorkState::uncork() | CorkState::notify());
if self.output_stream.is_some() {
/* When doing output-only or duplex, we 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 *const _ as *mut _);
self.context.mainloop.unlock();
}
Ok(())
}
@ -626,9 +612,11 @@ impl<'ctx> StreamOps for PulseStream<'ctx> {
self.context.mainloop.lock();
self.shutdown = true;
// If draining is taking place wait to finish
cubeb_log!("Stream stop: waiting for drain.");
while !self.drain_timer.is_null() {
self.context.mainloop.wait();
}
cubeb_log!("Stream stop: waited for drain.");
self.context.mainloop.unlock();
}
self.cork(CorkState::cork() | CorkState::notify());
@ -691,9 +679,7 @@ impl<'ctx> StreamOps for PulseStream<'ctx> {
}
// Input stream can be negative only if it is attached to a
// monitor source device
Ok(StreamLatency::Negative(_)) => {
return Ok(0);
}
Ok(StreamLatency::Negative(_)) => Ok(0),
Err(_) => Err(Error::error()),
},
}
@ -752,13 +738,9 @@ impl<'ctx> StreamOps for PulseStream<'ctx> {
None => Err(Error::error()),
Some(ref stm) => {
self.context.mainloop.lock();
if let Ok(o) = stm.set_name(
name,
stream_success,
self as *const _ as *mut _
) {
self.context.operation_wait(stm, &o);
}
if let Ok(o) = stm.set_name(name, stream_success, self as *const _ as *mut _) {
self.context.operation_wait(stm, &o);
}
self.context.mainloop.unlock();
Ok(())
}
@ -844,15 +826,23 @@ impl<'ctx> PulseStream<'ctx> {
};
let cm: Option<pa_channel_map> = match stream_params.layout() {
ChannelLayout::UNDEFINED =>
ChannelLayout::UNDEFINED => {
if stream_params.channels() <= 8
&& pulse::ChannelMap::init_auto(stream_params.channels(), PA_CHANNEL_MAP_DEFAULT).is_none() {
&& pulse::ChannelMap::init_auto(
stream_params.channels(),
PA_CHANNEL_MAP_DEFAULT,
)
.is_none()
{
cubeb_log!("Layout undefined and PulseAudio's default layout has not been configured, guess one.");
Some(layout_to_channel_map(default_layout_for_channels(stream_params.channels())))
Some(layout_to_channel_map(default_layout_for_channels(
stream_params.channels(),
)))
} else {
cubeb_log!("Layout undefined, PulseAudio will use its default.");
None
},
}
}
_ => Some(layout_to_channel_map(stream_params.layout())),
};
@ -964,7 +954,6 @@ impl<'ctx> PulseStream<'ctx> {
true
}
#[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
fn trigger_user_callback(&mut self, input_data: *const c_void, nbytes: usize) {
fn drained_cb(
@ -973,6 +962,7 @@ impl<'ctx> PulseStream<'ctx> {
_tv: &pulse::TimeVal,
u: *mut c_void,
) {
cubeb_logv!("Drain finished callback.");
let stm = unsafe { &mut *(u as *mut PulseStream) };
debug_assert_eq!(stm.drain_timer, e);
stm.state_change_callback(ffi::CUBEB_STATE_DRAINED);
@ -1002,8 +992,7 @@ impl<'ctx> PulseStream<'ctx> {
size,
read_offset
);
let read_ptr =
unsafe { (input_data as *const u8).offset(read_offset as isize) };
let read_ptr = unsafe { (input_data as *const u8).add(read_offset) };
let got = unsafe {
self.data_callback.unwrap()(
self as *const _ as *mut _,
@ -1053,6 +1042,7 @@ impl<'ctx> PulseStream<'ctx> {
debug_assert!(r.is_ok());
if (got as usize) < size / frame_size {
cubeb_logv!("Draining {} < {}", got, size / frame_size);
let latency = match stm.get_latency() {
Ok(StreamLatency::Positive(l)) => l,
Ok(_) => {
@ -1118,9 +1108,9 @@ fn not_supported() -> Error {
#[cfg(all(test, not(feature = "pulse-dlopen")))]
mod test {
use super::layout_to_channel_map;
use cubeb_backend::ChannelLayout;
use pulse_ffi::*;
use super::layout_to_channel_map;
macro_rules! channel_tests {
{$($name: ident, $layout: ident => [ $($channels: ident),* ]),+} => {

View File

@ -7,7 +7,11 @@ use backend::PulseContext;
use cubeb_backend::{capi, ffi};
use std::os::raw::{c_char, c_int};
/// Entry point from C code.
/// # Safety
///
/// Entry point from C code. This function is unsafe because it dereferences
/// the given `c` and `context_name` pointers. The caller should ensure those
/// pointers are valid.
#[no_mangle]
pub unsafe extern "C" fn pulse_rust_init(
c: *mut *mut ffi::cubeb,

View File

@ -9,10 +9,10 @@
extern crate cubeb_backend;
extern crate pulse;
extern crate pulse_ffi;
extern crate semver;
extern crate ringbuf;
extern crate semver;
mod capi;
mod backend;
mod capi;
pub use capi::pulse_rust_init;

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"86bb1c8ebc438416c3a1f71b41494f19a85f698860b8c12d4875c8247f9c3664","src/ffi_funcs.rs":"8e79fc30a6ae800efdd026a7f29808abf039491fedac3491e22e0b1399b5c06b","src/ffi_types.rs":"fd6ca280be7601ae1990d4d0626fa9c4c6c9c958040c29e651764d06386d15c1","src/lib.rs":"edb03c6d9bcddc69a688160ffda0b8bdb69f1f87ccbc3e3b005574c9d5484991"},"package":null}
{"files":{"Cargo.toml":"86bb1c8ebc438416c3a1f71b41494f19a85f698860b8c12d4875c8247f9c3664","src/ffi_funcs.rs":"a16646c5e7c49e94b907a7a404cfcadf3007688005c689cca936f0c2ee2e28e6","src/ffi_types.rs":"2ca56bc3638a40d331e53117a5dd175d0a6e102b1e0eccb9c2adc565c6861a33","src/lib.rs":"6aff308de11954a067d0f6ef95bf3126aabb6d928a5191e91d9a38ebadba91c2"},"package":null}

File diff suppressed because it is too large Load Diff

View File

@ -54,7 +54,10 @@ pub type pa_context_state_t = c_int;
#[allow(non_snake_case)]
pub fn PA_CONTEXT_IS_GOOD(x: pa_context_state_t) -> bool {
x == PA_CONTEXT_CONNECTING || x == PA_CONTEXT_AUTHORIZING || x == PA_CONTEXT_SETTING_NAME || x == PA_CONTEXT_READY
x == PA_CONTEXT_CONNECTING
|| x == PA_CONTEXT_AUTHORIZING
|| x == PA_CONTEXT_SETTING_NAME
|| x == PA_CONTEXT_READY
}
pub const PA_STREAM_UNCONNECTED: c_int = 0;
@ -297,46 +300,63 @@ pub const PA_IO_EVENT_HANGUP: c_int = 4;
pub const PA_IO_EVENT_ERROR: c_int = 8;
pub type pa_io_event_flags_t = c_int;
pub enum pa_io_event { }
pub type pa_io_event_cb_t = Option<unsafe extern "C" fn(ea: *mut pa_mainloop_api,
e: *mut pa_io_event,
fd: c_int,
events: pa_io_event_flags_t,
userdata: *mut c_void)>;
pub type pa_io_event_destroy_cb_t = Option<unsafe extern "C" fn(a: *mut pa_mainloop_api,
e: *mut pa_io_event,
userdata: *mut c_void)>;
pub enum pa_time_event { }
pub type pa_time_event_cb_t = Option<unsafe extern "C" fn(a: *mut pa_mainloop_api,
e: *mut pa_time_event,
tv: *const timeval,
userdata: *mut c_void)>;
pub type pa_time_event_destroy_cb_t = Option<unsafe extern "C" fn(a: *mut pa_mainloop_api,
e: *mut pa_time_event,
userdata: *mut c_void)>;
pub enum pa_io_event {}
pub type pa_io_event_cb_t = Option<
unsafe extern "C" fn(
ea: *mut pa_mainloop_api,
e: *mut pa_io_event,
fd: c_int,
events: pa_io_event_flags_t,
userdata: *mut c_void,
),
>;
pub type pa_io_event_destroy_cb_t = Option<
unsafe extern "C" fn(a: *mut pa_mainloop_api, e: *mut pa_io_event, userdata: *mut c_void),
>;
pub enum pa_time_event {}
pub type pa_time_event_cb_t = Option<
unsafe extern "C" fn(
a: *mut pa_mainloop_api,
e: *mut pa_time_event,
tv: *const timeval,
userdata: *mut c_void,
),
>;
pub type pa_time_event_destroy_cb_t = Option<
unsafe extern "C" fn(a: *mut pa_mainloop_api, e: *mut pa_time_event, userdata: *mut c_void),
>;
pub enum pa_defer_event { }
pub type pa_defer_event_cb_t = Option<unsafe extern "C" fn(a: *mut pa_mainloop_api,
e: *mut pa_defer_event,
userdata: *mut c_void)>;
pub type pa_defer_event_destroy_cb_t = Option<unsafe extern "C" fn(a: *mut pa_mainloop_api,
e: *mut pa_defer_event,
userdata: *mut c_void)>;
pub type IoNewFn = Option<unsafe extern "C" fn(a: *mut pa_mainloop_api,
fd: c_int,
events: pa_io_event_flags_t,
cb: pa_io_event_cb_t,
userdata: *mut c_void)
-> *mut pa_io_event>;
pub type TimeNewFn = Option<unsafe extern "C" fn(a: *mut pa_mainloop_api,
tv: *const timeval,
cb: pa_time_event_cb_t,
userdata: *mut c_void)
-> *mut pa_time_event>;
pub type DeferNewFn = Option<unsafe extern "C" fn(a: *mut pa_mainloop_api,
cb: pa_defer_event_cb_t,
userdata: *mut c_void)
-> *mut pa_defer_event>;
pub enum pa_defer_event {}
pub type pa_defer_event_cb_t = Option<
unsafe extern "C" fn(a: *mut pa_mainloop_api, e: *mut pa_defer_event, userdata: *mut c_void),
>;
pub type pa_defer_event_destroy_cb_t = Option<
unsafe extern "C" fn(a: *mut pa_mainloop_api, e: *mut pa_defer_event, userdata: *mut c_void),
>;
pub type IoNewFn = Option<
unsafe extern "C" fn(
a: *mut pa_mainloop_api,
fd: c_int,
events: pa_io_event_flags_t,
cb: pa_io_event_cb_t,
userdata: *mut c_void,
) -> *mut pa_io_event,
>;
pub type TimeNewFn = Option<
unsafe extern "C" fn(
a: *mut pa_mainloop_api,
tv: *const timeval,
cb: pa_time_event_cb_t,
userdata: *mut c_void,
) -> *mut pa_time_event,
>;
pub type DeferNewFn = Option<
unsafe extern "C" fn(
a: *mut pa_mainloop_api,
cb: pa_defer_event_cb_t,
userdata: *mut c_void,
) -> *mut pa_defer_event,
>;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@ -345,15 +365,18 @@ pub struct pa_mainloop_api {
pub io_new: IoNewFn,
pub io_enable: Option<unsafe extern "C" fn(e: *mut pa_io_event, events: pa_io_event_flags_t)>,
pub io_free: Option<unsafe extern "C" fn(e: *mut pa_io_event)>,
pub io_set_destroy: Option<unsafe extern "C" fn(e: *mut pa_io_event, cb: pa_io_event_destroy_cb_t)>,
pub io_set_destroy:
Option<unsafe extern "C" fn(e: *mut pa_io_event, cb: pa_io_event_destroy_cb_t)>,
pub time_new: TimeNewFn,
pub time_restart: Option<unsafe extern "C" fn(e: *mut pa_time_event, tv: *const timeval)>,
pub time_free: Option<unsafe extern "C" fn(e: *mut pa_time_event)>,
pub time_set_destroy: Option<unsafe extern "C" fn(e: *mut pa_time_event, cb: pa_time_event_destroy_cb_t)>,
pub time_set_destroy:
Option<unsafe extern "C" fn(e: *mut pa_time_event, cb: pa_time_event_destroy_cb_t)>,
pub defer_new: DeferNewFn,
pub defer_enable: Option<unsafe extern "C" fn(e: *mut pa_defer_event, b: c_int)>,
pub defer_free: Option<unsafe extern "C" fn(e: *mut pa_defer_event)>,
pub defer_set_destroy: Option<unsafe extern "C" fn(e: *mut pa_defer_event, cb: pa_defer_event_destroy_cb_t)>,
pub defer_set_destroy:
Option<unsafe extern "C" fn(e: *mut pa_defer_event, cb: pa_defer_event_destroy_cb_t)>,
pub quit: Option<unsafe extern "C" fn(a: *mut pa_mainloop_api, retval: c_int)>,
}
@ -363,9 +386,10 @@ impl ::std::default::Default for pa_mainloop_api {
}
}
pub type pa_mainloop_api_once_cb_t = Option<unsafe extern "C" fn(m: *mut pa_mainloop_api, userdata: *mut c_void)>;
pub type pa_mainloop_api_once_cb_t =
Option<unsafe extern "C" fn(m: *mut pa_mainloop_api, userdata: *mut c_void)>;
pub enum pa_proplist { }
pub enum pa_proplist {}
pub const PA_UPDATE_SET: c_int = 0;
pub const PA_UPDATE_MERGE: c_int = 1;
@ -486,18 +510,23 @@ pub const PA_PROP_TYPE_STRING_ARRAY: c_int = 4;
pub const PA_PROP_TYPE_INVALID: c_int = -1;
pub type pa_prop_type_t = c_int;
pub enum pa_operation { }
pub type pa_operation_notify_cb_t = Option<unsafe extern "C" fn(o: *mut pa_operation, userdata: *mut c_void)>;
pub enum pa_operation {}
pub type pa_operation_notify_cb_t =
Option<unsafe extern "C" fn(o: *mut pa_operation, userdata: *mut c_void)>;
pub enum pa_context { }
pub type pa_context_notify_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context, userdata: *mut c_void)>;
pub type pa_context_success_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
success: c_int,
userdata: *mut c_void)>;
pub type pa_context_event_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
name: *const c_char,
p: *mut pa_proplist,
userdata: *mut c_void)>;
pub enum pa_context {}
pub type pa_context_notify_cb_t =
Option<unsafe extern "C" fn(c: *mut pa_context, userdata: *mut c_void)>;
pub type pa_context_success_cb_t =
Option<unsafe extern "C" fn(c: *mut pa_context, success: c_int, userdata: *mut c_void)>;
pub type pa_context_event_cb_t = Option<
unsafe extern "C" fn(
c: *mut pa_context,
name: *const c_char,
p: *mut pa_proplist,
userdata: *mut c_void,
),
>;
pub type pa_volume_t = u32;
@ -514,16 +543,21 @@ impl ::std::default::Default for pa_cvolume {
}
}
pub enum pa_stream { }
pub type pa_stream_success_cb_t = Option<unsafe extern "C" fn(s: *mut pa_stream,
success: c_int,
userdata: *mut c_void)>;
pub type pa_stream_request_cb_t = Option<unsafe extern "C" fn(p: *mut pa_stream, nbytes: usize, userdata: *mut c_void)>;
pub type pa_stream_notify_cb_t = Option<unsafe extern "C" fn(p: *mut pa_stream, userdata: *mut c_void)>;
pub type pa_stream_event_cb_t = Option<unsafe extern "C" fn(p: *mut pa_stream,
name: *const c_char,
pl: *mut pa_proplist,
userdata: *mut c_void)>;
pub enum pa_stream {}
pub type pa_stream_success_cb_t =
Option<unsafe extern "C" fn(s: *mut pa_stream, success: c_int, userdata: *mut c_void)>;
pub type pa_stream_request_cb_t =
Option<unsafe extern "C" fn(p: *mut pa_stream, nbytes: usize, userdata: *mut c_void)>;
pub type pa_stream_notify_cb_t =
Option<unsafe extern "C" fn(p: *mut pa_stream, userdata: *mut c_void)>;
pub type pa_stream_event_cb_t = Option<
unsafe extern "C" fn(
p: *mut pa_stream,
name: *const c_char,
pl: *mut pa_proplist,
userdata: *mut c_void,
),
>;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@ -575,10 +609,14 @@ impl ::std::default::Default for pa_sink_info {
}
}
pub type pa_sink_info_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
i: *const pa_sink_info,
eol: c_int,
userdata: *mut c_void)>;
pub type pa_sink_info_cb_t = Option<
unsafe extern "C" fn(
c: *mut pa_context,
i: *const pa_sink_info,
eol: c_int,
userdata: *mut c_void,
),
>;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@ -615,10 +653,14 @@ impl ::std::default::Default for pa_source_info {
}
}
pub type pa_source_info_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
i: *const pa_source_info,
eol: c_int,
userdata: *mut c_void)>;
pub type pa_source_info_cb_t = Option<
unsafe extern "C" fn(
c: *mut pa_context,
i: *const pa_source_info,
eol: c_int,
userdata: *mut c_void,
),
>;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@ -640,9 +682,9 @@ impl ::std::default::Default for pa_server_info {
}
}
pub type pa_server_info_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
i: *const pa_server_info,
userdata: *mut c_void)>;
pub type pa_server_info_cb_t = Option<
unsafe extern "C" fn(c: *mut pa_context, i: *const pa_server_info, userdata: *mut c_void),
>;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@ -661,11 +703,16 @@ impl ::std::default::Default for pa_module_info {
}
}
pub type pa_module_info_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
i: *const pa_module_info,
eol: c_int,
userdata: *mut c_void)>;
pub type pa_context_index_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context, idx: u32, userdata: *mut c_void)>;
pub type pa_module_info_cb_t = Option<
unsafe extern "C" fn(
c: *mut pa_context,
i: *const pa_module_info,
eol: c_int,
userdata: *mut c_void,
),
>;
pub type pa_context_index_cb_t =
Option<unsafe extern "C" fn(c: *mut pa_context, idx: u32, userdata: *mut c_void)>;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@ -683,10 +730,14 @@ impl ::std::default::Default for pa_client_info {
}
}
pub type pa_client_info_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
i: *const pa_client_info,
eol: c_int,
userdata: *mut c_void)>;
pub type pa_client_info_cb_t = Option<
unsafe extern "C" fn(
c: *mut pa_context,
i: *const pa_client_info,
eol: c_int,
userdata: *mut c_void,
),
>;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@ -765,10 +816,14 @@ impl ::std::default::Default for pa_card_info {
}
}
pub type pa_card_info_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
i: *const pa_card_info,
eol: c_int,
userdata: *mut c_void)>;
pub type pa_card_info_cb_t = Option<
unsafe extern "C" fn(
c: *mut pa_context,
i: *const pa_card_info,
eol: c_int,
userdata: *mut c_void,
),
>;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@ -799,10 +854,14 @@ impl ::std::default::Default for pa_sink_input_info {
}
}
pub type pa_sink_input_info_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
i: *const pa_sink_input_info,
eol: c_int,
userdata: *mut c_void)>;
pub type pa_sink_input_info_cb_t = Option<
unsafe extern "C" fn(
c: *mut pa_context,
i: *const pa_sink_input_info,
eol: c_int,
userdata: *mut c_void,
),
>;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@ -833,10 +892,14 @@ impl ::std::default::Default for pa_source_output_info {
}
}
pub type pa_source_output_info_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
i: *const pa_source_output_info,
eol: c_int,
userdata: *mut c_void)>;
pub type pa_source_output_info_cb_t = Option<
unsafe extern "C" fn(
c: *mut pa_context,
i: *const pa_source_output_info,
eol: c_int,
userdata: *mut c_void,
),
>;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@ -854,9 +917,8 @@ impl ::std::default::Default for pa_stat_info {
}
}
pub type pa_stat_info_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
i: *const pa_stat_info,
userdata: *mut c_void)>;
pub type pa_stat_info_cb_t =
Option<unsafe extern "C" fn(c: *mut pa_context, i: *const pa_stat_info, userdata: *mut c_void)>;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@ -879,10 +941,14 @@ impl ::std::default::Default for pa_sample_info {
}
}
pub type pa_sample_info_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
i: *const pa_sample_info,
eol: c_int,
userdata: *mut c_void)>;
pub type pa_sample_info_cb_t = Option<
unsafe extern "C" fn(
c: *mut pa_context,
i: *const pa_sample_info,
eol: c_int,
userdata: *mut c_void,
),
>;
pub const PA_AUTOLOAD_SINK: c_int = 0;
pub const PA_AUTOLOAD_SOURCE: c_int = 1;
@ -904,33 +970,47 @@ impl ::std::default::Default for pa_autoload_info {
}
}
pub type pa_autoload_info_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
i: *const pa_autoload_info,
eol: c_int,
userdata: *mut c_void)>;
pub type pa_context_subscribe_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
t: pa_subscription_event_type_t,
idx: u32,
userdata: *mut c_void)>;
pub type pa_context_play_sample_cb_t = Option<unsafe extern "C" fn(c: *mut pa_context,
idx: u32,
userdata: *mut c_void)>;
pub type pa_autoload_info_cb_t = Option<
unsafe extern "C" fn(
c: *mut pa_context,
i: *const pa_autoload_info,
eol: c_int,
userdata: *mut c_void,
),
>;
pub type pa_context_subscribe_cb_t = Option<
unsafe extern "C" fn(
c: *mut pa_context,
t: pa_subscription_event_type_t,
idx: u32,
userdata: *mut c_void,
),
>;
pub type pa_context_play_sample_cb_t =
Option<unsafe extern "C" fn(c: *mut pa_context, idx: u32, userdata: *mut c_void)>;
pub enum pa_threaded_mainloop { }
pub enum pollfd { }
pub enum pa_mainloop { }
pub enum pa_threaded_mainloop {}
pub enum pollfd {}
pub enum pa_mainloop {}
pub type pa_poll_func = Option<unsafe extern "C" fn(ufds: *mut pollfd,
nfds: c_ulong,
timeout: c_int,
userdata: *mut c_void)
-> c_int>;
pub enum pa_signal_event { }
pub type pa_poll_func = Option<
unsafe extern "C" fn(
ufds: *mut pollfd,
nfds: c_ulong,
timeout: c_int,
userdata: *mut c_void,
) -> c_int,
>;
pub enum pa_signal_event {}
pub type pa_signal_cb_t = Option<unsafe extern "C" fn(api: *mut pa_mainloop_api,
e: *mut pa_signal_event,
sig: c_int,
userdata: *mut c_void)>;
pub type pa_signal_destroy_cb_t = Option<unsafe extern "C" fn(api: *mut pa_mainloop_api,
e: *mut pa_signal_event,
userdata: *mut c_void)>;
pub type pa_signal_cb_t = Option<
unsafe extern "C" fn(
api: *mut pa_mainloop_api,
e: *mut pa_signal_event,
sig: c_int,
userdata: *mut c_void,
),
>;
pub type pa_signal_destroy_cb_t = Option<
unsafe extern "C" fn(api: *mut pa_mainloop_api, e: *mut pa_signal_event, userdata: *mut c_void),
>;

View File

@ -2,11 +2,11 @@
#[cfg(feature = "dlopen")]
extern crate libc;
mod ffi_types;
mod ffi_funcs;
mod ffi_types;
pub use ffi_types::*;
pub use ffi_funcs::*;
pub use ffi_types::*;
#[cfg(feature = "dlopen")]
pub unsafe fn open() -> Option<LibLoader> {

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"961d0d5d82f0d128d23dd753ad89beccdefdc0bc830ff646c785ee87eed261db","src/context.rs":"5e43131c0a989336e149b5408e0b362c0ef8176854785f98191f86b75ef5d76a","src/error.rs":"7be0ad689b6519a5be3771c29a102ff394bdc5ee46502d418bced90268e912dd","src/lib.rs":"8636d18c55b7ccd8e79d45a8d12ea84ba94b7aeef8ac3975292c94a28ed4a2b1","src/mainloop_api.rs":"b4a6c7e1a507490157c5b4a25af367cf810e1ef64c7a96f71575a15674d9b649","src/operation.rs":"c0d3e28ef7db52d60b19f931fe7bb44271127009b2e82693da2b7e342e804022","src/proplist.rs":"65bfc2b90f31bc3969aef69eb3e26b34ac657a2149f1b6515791403d752f3fc5","src/stream.rs":"7205d53d3aa5de7473339e6baa02bd32998e6ae15f76e8aa94420449354ba570","src/threaded_mainloop.rs":"958181a46363ded3ac8e0d9c9d912587cb6f9f26ae6f190881014adbda2d3211","src/util.rs":"d971486fd828b8b9d81db61a21a77960ea34a99a59b96fceaf77c2b84ed2accc"},"package":null}
{"files":{"Cargo.toml":"961d0d5d82f0d128d23dd753ad89beccdefdc0bc830ff646c785ee87eed261db","src/context.rs":"849333d1d3b443700ea13e07696c68b3fe7ad3c4ee136b17ea888c494e871812","src/error.rs":"7cca3f0b0a238743db01d707881eee0c7b5b2ba530d579b6a2bd82bc8dd7dd30","src/lib.rs":"52891e08b0cfbe434a63074a226bec16580cfeb96e2eeaf30079dd213657e6a2","src/mainloop_api.rs":"6374f8f62233277f4cf460b9978db0347a8829eb04f62101eaaa5533b6aca769","src/operation.rs":"c0d3e28ef7db52d60b19f931fe7bb44271127009b2e82693da2b7e342e804022","src/proplist.rs":"ce53f1e92fae51727aa564d371b1e0d59078f5cbbd655b39bc1c7741c8ba2f87","src/stream.rs":"ba14551ff34f6b23e94e450384487b3c35be75ac4456c22c14b36ade23282978","src/threaded_mainloop.rs":"057928b5b84b1ea8c839150840ccd88cb944b60ca0aa2ec5389aaa6676c8e505","src/util.rs":"1613909f460eb008b282801ac803dd28b4bfe59926c14fe030da6482fdacd70f"},"package":null}

View File

@ -3,13 +3,13 @@
// 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::mem::{forget, MaybeUninit};
use std::os::raw::{c_int, c_void};
use std::ptr;
use util::UnwrapCStr;
use *;
// A note about `wrapped` functions
//
@ -57,7 +57,7 @@ macro_rules! op_or_err {
} else {
Ok(unsafe { operation::from_raw_ptr(o) })
}
}}
}};
}
#[repr(C)]
@ -66,7 +66,8 @@ 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>>
where
OPT: Into<Option<&'a CStr>>,
{
let ptr = unsafe { ffi::pa_context_new(api.raw_mut(), name.unwrap_cstr()) };
if ptr.is_null() {
@ -94,13 +95,15 @@ impl Context {
}
pub fn set_state_callback<CB>(&self, _: CB, userdata: *mut c_void)
where CB: Fn(&Context, *mut c_void)
where
CB: Fn(&Context, *mut c_void),
{
assert_eq!(::std::mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, userdata: *mut c_void)
where F: Fn(&Context, *mut c_void)
where
F: Fn(&Context, *mut c_void),
{
let ctx = context::from_raw_ptr(c);
let cb = MaybeUninit::<F>::uninit();
@ -120,19 +123,26 @@ impl Context {
}
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")
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>>
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)
ffi::pa_context_connect(
self.raw_mut(),
server.into().unwrap_cstr(),
flags.into(),
api,
)
};
error_result!((), r)
}
@ -143,15 +153,16 @@ impl Context {
}
}
pub fn drain<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
where CB: Fn(&Context, *mut c_void)
where
CB: Fn(&Context, *mut c_void),
{
assert_eq!(::std::mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, userdata: *mut c_void)
where F: Fn(&Context, *mut c_void)
where
F: Fn(&Context, *mut c_void),
{
let ctx = context::from_raw_ptr(c);
let cb = MaybeUninit::<F>::uninit();
@ -161,21 +172,31 @@ impl Context {
result
}
op_or_err!(self,
ffi::pa_context_drain(self.raw_mut(), Some(wrapped::<CB>), userdata))
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)
pub fn rttime_new<CB>(
&self,
usec: USec,
_: CB,
userdata: *mut c_void,
) -> *mut ffi::pa_time_event
where
CB: Fn(&MainloopApi, *mut ffi::pa_time_event, &TimeVal, *mut c_void),
{
assert_eq!(::std::mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(a: *mut ffi::pa_mainloop_api,
e: *mut ffi::pa_time_event,
tv: *const TimeVal,
userdata: *mut c_void)
where F: Fn(&MainloopApi, *mut ffi::pa_time_event, &TimeVal, *mut c_void)
unsafe extern "C" fn wrapped<F>(
a: *mut ffi::pa_mainloop_api,
e: *mut ffi::pa_time_event,
tv: *const TimeVal,
userdata: *mut c_void,
) where
F: Fn(&MainloopApi, *mut ffi::pa_time_event, &TimeVal, *mut c_void),
{
let api = mainloop_api::from_raw_ptr(a);
let timeval = &*tv;
@ -190,19 +211,20 @@ impl Context {
}
pub fn get_server_info<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
where CB: Fn(&Context, Option<&ServerInfo>, *mut c_void)
where
CB: Fn(&Context, Option<&ServerInfo>, *mut c_void),
{
assert_eq!(::std::mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, i: *const ffi::pa_server_info, userdata: *mut c_void)
where F: Fn(&Context, Option<&ServerInfo>, *mut c_void)
unsafe extern "C" fn wrapped<F>(
c: *mut ffi::pa_context,
i: *const ffi::pa_server_info,
userdata: *mut c_void,
) where
F: Fn(&Context, Option<&ServerInfo>, *mut c_void),
{
let info = if i.is_null() {
None
} else {
Some(&*i)
};
let info = if i.is_null() { None } else { Some(&*i) };
let ctx = context::from_raw_ptr(c);
let cb = MaybeUninit::<F>::uninit();
let result = (*cb.as_ptr())(&ctx, info, userdata);
@ -211,11 +233,18 @@ impl Context {
result
}
op_or_err!(self,
ffi::pa_context_get_server_info(self.raw_mut(), Some(wrapped::<CB>), userdata))
op_or_err!(
self,
ffi::pa_context_get_server_info(self.raw_mut(), Some(wrapped::<CB>), userdata)
)
}
pub fn get_sink_info_by_name<'str, CS, CB>(&self, name: CS, _: CB, userdata: *mut c_void) -> Result<Operation>
pub fn get_sink_info_by_name<'str, CS, CB>(
&self,
name: CS,
_: CB,
userdata: *mut c_void,
) -> Result<Operation>
where
CB: Fn(&Context, *const SinkInfo, i32, *mut c_void),
CS: Into<Option<&'str CStr>>,
@ -223,11 +252,13 @@ impl Context {
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)
unsafe extern "C" fn wrapped<F>(
c: *mut ffi::pa_context,
info: *const ffi::pa_sink_info,
eol: c_int,
userdata: *mut c_void,
) where
F: Fn(&Context, *const SinkInfo, i32, *mut c_void),
{
let ctx = context::from_raw_ptr(c);
let cb = MaybeUninit::<F>::uninit();
@ -237,24 +268,31 @@ impl Context {
result
}
op_or_err!(self,
ffi::pa_context_get_sink_info_by_name(self.raw_mut(),
name.into().unwrap_cstr(),
Some(wrapped::<CB>),
userdata))
op_or_err!(
self,
ffi::pa_context_get_sink_info_by_name(
self.raw_mut(),
name.into().unwrap_cstr(),
Some(wrapped::<CB>),
userdata
)
)
}
pub fn get_sink_info_list<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
where CB: Fn(&Context, *const SinkInfo, i32, *mut c_void)
where
CB: Fn(&Context, *const SinkInfo, i32, *mut c_void),
{
assert_eq!(::std::mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context,
info: *const ffi::pa_sink_info,
eol: c_int,
userdata: *mut c_void)
where F: Fn(&Context, *const SinkInfo, i32, *mut c_void)
unsafe extern "C" fn wrapped<F>(
c: *mut ffi::pa_context,
info: *const ffi::pa_sink_info,
eol: c_int,
userdata: *mut c_void,
) where
F: Fn(&Context, *const SinkInfo, i32, *mut c_void),
{
let ctx = context::from_raw_ptr(c);
let cb = MaybeUninit::<F>::uninit();
@ -264,21 +302,31 @@ impl Context {
result
}
op_or_err!(self,
ffi::pa_context_get_sink_info_list(self.raw_mut(), Some(wrapped::<CB>), userdata))
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)
pub fn get_sink_input_info<CB>(
&self,
idx: u32,
_: CB,
userdata: *mut c_void,
) -> Result<Operation>
where
CB: Fn(&Context, *const SinkInputInfo, i32, *mut c_void),
{
assert_eq!(::std::mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context,
info: *const ffi::pa_sink_input_info,
eol: c_int,
userdata: *mut c_void)
where F: Fn(&Context, *const SinkInputInfo, i32, *mut c_void)
unsafe extern "C" fn wrapped<F>(
c: *mut ffi::pa_context,
info: *const ffi::pa_sink_input_info,
eol: c_int,
userdata: *mut c_void,
) where
F: Fn(&Context, *const SinkInputInfo, i32, *mut c_void),
{
let ctx = context::from_raw_ptr(c);
let cb = MaybeUninit::<F>::uninit();
@ -288,21 +336,26 @@ impl Context {
result
}
op_or_err!(self,
ffi::pa_context_get_sink_input_info(self.raw_mut(), idx, Some(wrapped::<CB>), userdata))
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)
where
CB: Fn(&Context, *const SourceInfo, i32, *mut c_void),
{
assert_eq!(::std::mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context,
info: *const ffi::pa_source_info,
eol: c_int,
userdata: *mut c_void)
where F: Fn(&Context, *const SourceInfo, i32, *mut c_void)
unsafe extern "C" fn wrapped<F>(
c: *mut ffi::pa_context,
info: *const ffi::pa_source_info,
eol: c_int,
userdata: *mut c_void,
) where
F: Fn(&Context, *const SourceInfo, i32, *mut c_void),
{
let ctx = context::from_raw_ptr(c);
let cb = MaybeUninit::<F>::uninit();
@ -312,23 +365,31 @@ impl Context {
result
}
op_or_err!(self,
ffi::pa_context_get_source_info_list(self.raw_mut(), Some(wrapped::<CB>), userdata))
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)
pub fn set_sink_input_volume<CB>(
&self,
idx: u32,
volume: &CVolume,
_: CB,
userdata: *mut c_void,
) -> Result<Operation>
where
CB: Fn(&Context, i32, *mut c_void),
{
assert_eq!(::std::mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, success: c_int, userdata: *mut c_void)
where F: Fn(&Context, i32, *mut c_void)
unsafe extern "C" fn wrapped<F>(
c: *mut ffi::pa_context,
success: c_int,
userdata: *mut c_void,
) where
F: Fn(&Context, i32, *mut c_void),
{
let ctx = context::from_raw_ptr(c);
let cb = MaybeUninit::<F>::uninit();
@ -338,18 +399,36 @@ impl Context {
result
}
op_or_err!(self,
ffi::pa_context_set_sink_input_volume(self.raw_mut(), idx, volume, Some(wrapped::<CB>), userdata))
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)
pub fn subscribe<CB>(
&self,
m: SubscriptionMask,
_: CB,
userdata: *mut c_void,
) -> Result<Operation>
where
CB: Fn(&Context, i32, *mut c_void),
{
assert_eq!(::std::mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, success: c_int, userdata: *mut c_void)
where F: Fn(&Context, i32, *mut c_void)
unsafe extern "C" fn wrapped<F>(
c: *mut ffi::pa_context,
success: c_int,
userdata: *mut c_void,
) where
F: Fn(&Context, i32, *mut c_void),
{
let ctx = context::from_raw_ptr(c);
let cb = MaybeUninit::<F>::uninit();
@ -359,8 +438,10 @@ impl Context {
result
}
op_or_err!(self,
ffi::pa_context_subscribe(self.raw_mut(), m.into(), Some(wrapped::<CB>), userdata))
op_or_err!(
self,
ffi::pa_context_subscribe(self.raw_mut(), m.into(), Some(wrapped::<CB>), userdata)
)
}
pub fn clear_subscribe_callback(&self) {
@ -370,20 +451,23 @@ impl Context {
}
pub fn set_subscribe_callback<CB>(&self, _: CB, userdata: *mut c_void)
where CB: Fn(&Context, SubscriptionEvent, u32, *mut c_void)
where
CB: Fn(&Context, SubscriptionEvent, u32, *mut c_void),
{
assert_eq!(::std::mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context,
t: ffi::pa_subscription_event_type_t,
idx: u32,
userdata: *mut c_void)
where F: Fn(&Context, SubscriptionEvent, u32, *mut c_void)
unsafe extern "C" fn wrapped<F>(
c: *mut ffi::pa_context,
t: ffi::pa_subscription_event_type_t,
idx: u32,
userdata: *mut c_void,
) where
F: Fn(&Context, SubscriptionEvent, u32, *mut c_void),
{
let ctx = context::from_raw_ptr(c);
let event = SubscriptionEvent::try_from(t)
.expect("pa_context_subscribe_cb_t passed invalid pa_subscription_event_type_t");
.expect("pa_context_subscribe_cb_t passed invalid pa_subscription_event_type_t");
let cb = MaybeUninit::<F>::uninit();
let result = (*cb.as_ptr())(&ctx, event, idx, userdata);
forget(ctx);

View File

@ -14,7 +14,7 @@ macro_rules! error_result {
} else {
Err(ErrorCode::from_error_result($err))
}
}
};
}
#[derive(Debug, PartialEq)]
@ -32,9 +32,7 @@ impl ErrorCode {
pub fn from_error_code(err: ffi::pa_error_code_t) -> Self {
debug_assert!(err > 0);
ErrorCode {
err: err,
}
ErrorCode { err: err }
}
fn desc(&self) -> &'static str {

View File

@ -86,10 +86,10 @@ impl ContextState {
// 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,
ContextState::Connecting
| ContextState::Authorizing
| ContextState::SettingName
| ContextState::Ready => true,
_ => false,
}
}
@ -216,7 +216,6 @@ impl Into<ffi::pa_device_type_t> for DeviceType {
}
}
#[repr(i32)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum StreamDirection {
@ -269,18 +268,29 @@ bitflags! {
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 {
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
@ -299,7 +309,7 @@ pub enum StreamLatency {
Negative(u64),
}
bitflags!{
bitflags! {
pub struct SubscriptionMask : u32 {
const SINK = ffi::PA_SUBSCRIPTION_MASK_SINK;
const SOURCE = ffi::PA_SUBSCRIPTION_MASK_SOURCE;
@ -358,7 +368,9 @@ pub enum SubscriptionEventType {
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 {
if (x & !(ffi::PA_SUBSCRIPTION_EVENT_TYPE_MASK | ffi::PA_SUBSCRIPTION_EVENT_FACILITY_MASK))
== 0
{
Some(SubscriptionEvent(x))
} else {
None
@ -415,11 +427,18 @@ bitflags! {
impl SinkFlags {
pub fn try_from(x: ffi::pa_sink_flags_t) -> Option<SinkFlags> {
if (x &
!(ffi::PA_SINK_NOFLAGS | ffi::PA_SINK_HW_VOLUME_CTRL | ffi::PA_SINK_LATENCY |
ffi::PA_SINK_HARDWARE | ffi::PA_SINK_NETWORK | ffi::PA_SINK_HW_MUTE_CTRL |
ffi::PA_SINK_DECIBEL_VOLUME | ffi::PA_SINK_DYNAMIC_LATENCY |
ffi::PA_SINK_FLAT_VOLUME | ffi::PA_SINK_SET_FORMATS)) == 0 {
if (x & !(ffi::PA_SINK_NOFLAGS
| ffi::PA_SINK_HW_VOLUME_CTRL
| ffi::PA_SINK_LATENCY
| ffi::PA_SINK_HARDWARE
| ffi::PA_SINK_NETWORK
| ffi::PA_SINK_HW_MUTE_CTRL
| ffi::PA_SINK_DECIBEL_VOLUME
| ffi::PA_SINK_DYNAMIC_LATENCY
| ffi::PA_SINK_FLAT_VOLUME
| ffi::PA_SINK_SET_FORMATS))
== 0
{
Some(unsafe { ::std::mem::transmute(x) })
} else {
None
@ -438,7 +457,7 @@ pub enum SinkState {
Unlinked = ffi::PA_SINK_UNLINKED,
}
bitflags!{
bitflags! {
pub struct SourceFlags: u32 {
const HW_VOLUME_CTRL = ffi::PA_SOURCE_HW_VOLUME_CTRL;
const LATENCY = ffi::PA_SOURCE_LATENCY;
@ -607,9 +626,8 @@ impl ChannelMapExt for ChannelMap {
}
fn init_auto(ch: u32, def: ffi::pa_channel_map_def_t) -> Option<ChannelMap> {
let mut cm = ChannelMap::default();
let r: *mut ffi::pa_channel_map = unsafe {
ffi::pa_channel_map_init_auto(&mut cm, ch, def)
};
let r: *mut ffi::pa_channel_map =
unsafe { ffi::pa_channel_map_init_auto(&mut cm, ch, def) };
if r.is_null() {
None
} else {

View File

@ -7,17 +7,18 @@ 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)>;
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)
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)
where
F: Fn(&MainloopApi, *mut c_void),
{
let api = from_raw_ptr(m);
let result = mem::transmute::<_, &F>(&())(&api, userdata);
@ -36,7 +37,8 @@ impl MainloopApi {
}
pub fn once<CB>(&self, cb: CB, userdata: *mut c_void)
where CB: Fn(&MainloopApi, *mut c_void)
where
CB: Fn(&MainloopApi, *mut c_void),
{
let wrapped = wrap_once_cb(cb);
unsafe {

View File

@ -11,7 +11,8 @@ pub struct Proplist(*mut ffi::pa_proplist);
impl Proplist {
pub fn gets<T>(&self, key: T) -> Option<&CStr>
where T: Into<Vec<u8>>
where
T: Into<Vec<u8>>,
{
let key = match CString::new(key) {
Ok(k) => k,

View File

@ -3,7 +3,6 @@
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
use ::*;
use context;
use ffi;
use operation;
@ -12,19 +11,28 @@ use std::mem::{self, forget, MaybeUninit};
use std::os::raw::{c_int, c_void};
use std::ptr;
use util::*;
use *;
#[derive(Debug)]
pub struct Stream(*mut ffi::pa_stream);
impl Stream {
pub fn new<'a, CM>(c: &Context, name: &::std::ffi::CStr, ss: &SampleSpec, map: CM) -> Option<Self>
where CM: Into<Option<&'a ChannelMap>>
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()))
ffi::pa_stream_new(
c.raw_mut(),
name.as_ptr(),
ss as *const _,
to_ptr(map.into()),
)
};
if ptr.is_null() {
None
@ -45,9 +53,8 @@ impl Stream {
}
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")
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> {
@ -87,38 +94,45 @@ impl Stream {
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>>
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))
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>>
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())
ffi::pa_stream_connect_record(
self.raw_mut(),
str_to_ptr(dev.into()),
to_ptr(attr.into()),
flags.into(),
)
};
error_result!((), r)
}
@ -140,8 +154,16 @@ impl Stream {
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()) };
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)
}
@ -182,13 +204,18 @@ impl Stream {
}
pub fn update_timing_info<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
where CB: Fn(&Stream, i32, *mut c_void)
where
CB: Fn(&Stream, i32, *mut c_void),
{
assert_eq!(mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(s: *mut ffi::pa_stream, success: c_int, userdata: *mut c_void)
where F: Fn(&Stream, i32, *mut c_void)
unsafe extern "C" fn wrapped<F>(
s: *mut ffi::pa_stream,
success: c_int,
userdata: *mut c_void,
) where
F: Fn(&Stream, i32, *mut c_void),
{
let mut stm = stream::from_raw_ptr(s);
let cb = MaybeUninit::<F>::uninit();
@ -198,7 +225,9 @@ impl Stream {
result
}
let r = unsafe { ffi::pa_stream_update_timing_info(self.raw_mut(), Some(wrapped::<CB>), userdata) };
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()
@ -217,13 +246,15 @@ impl Stream {
}
pub fn set_state_callback<CB>(&self, _: CB, userdata: *mut c_void)
where CB: Fn(&Stream, *mut c_void)
where
CB: Fn(&Stream, *mut c_void),
{
assert_eq!(mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(s: *mut ffi::pa_stream, userdata: *mut c_void)
where F: Fn(&Stream, *mut c_void)
where
F: Fn(&Stream, *mut c_void),
{
let mut stm = stream::from_raw_ptr(s);
let cb = MaybeUninit::<F>::uninit();
@ -245,13 +276,18 @@ impl Stream {
}
pub fn set_write_callback<CB>(&self, _: CB, userdata: *mut c_void)
where CB: Fn(&Stream, usize, *mut c_void)
where
CB: Fn(&Stream, usize, *mut c_void),
{
assert_eq!(mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(s: *mut ffi::pa_stream, nbytes: usize, userdata: *mut c_void)
where F: Fn(&Stream, usize, *mut c_void)
unsafe extern "C" fn wrapped<F>(
s: *mut ffi::pa_stream,
nbytes: usize,
userdata: *mut c_void,
) where
F: Fn(&Stream, usize, *mut c_void),
{
let mut stm = stream::from_raw_ptr(s);
let cb = MaybeUninit::<F>::uninit();
@ -273,13 +309,18 @@ impl Stream {
}
pub fn set_read_callback<CB>(&self, _: CB, userdata: *mut c_void)
where CB: Fn(&Stream, usize, *mut c_void)
where
CB: Fn(&Stream, usize, *mut c_void),
{
assert_eq!(mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(s: *mut ffi::pa_stream, nbytes: usize, userdata: *mut c_void)
where F: Fn(&Stream, usize, *mut c_void)
unsafe extern "C" fn wrapped<F>(
s: *mut ffi::pa_stream,
nbytes: usize,
userdata: *mut c_void,
) where
F: Fn(&Stream, usize, *mut c_void),
{
let mut stm = stream::from_raw_ptr(s);
let cb = MaybeUninit::<F>::uninit();
@ -295,13 +336,18 @@ impl Stream {
}
pub fn cork<CB>(&self, b: i32, _: CB, userdata: *mut c_void) -> Result<Operation>
where CB: Fn(&Stream, i32, *mut c_void)
where
CB: Fn(&Stream, i32, *mut c_void),
{
assert_eq!(mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(s: *mut ffi::pa_stream, success: c_int, userdata: *mut c_void)
where F: Fn(&Stream, i32, *mut c_void)
unsafe extern "C" fn wrapped<F>(
s: *mut ffi::pa_stream,
success: c_int,
userdata: *mut c_void,
) where
F: Fn(&Stream, i32, *mut c_void),
{
let mut stm = stream::from_raw_ptr(s);
let cb = MaybeUninit::<F>::uninit();
@ -368,13 +414,18 @@ impl Stream {
}
pub fn set_name<CB>(&self, name: &CStr, _: CB, userdata: *mut c_void) -> Result<Operation>
where CB: Fn(&Stream, i32, *mut c_void)
where
CB: Fn(&Stream, i32, *mut c_void),
{
assert_eq!(mem::size_of::<CB>(), 0);
// See: A note about `wrapped` functions
unsafe extern "C" fn wrapped<F>(s: *mut ffi::pa_stream, success: c_int, userdata: *mut c_void)
where F: Fn(&Stream, i32, *mut c_void)
unsafe extern "C" fn wrapped<F>(
s: *mut ffi::pa_stream,
success: c_int,
userdata: *mut c_void,
) where
F: Fn(&Stream, i32, *mut c_void),
{
let mut stm = stream::from_raw_ptr(s);
let cb = MaybeUninit::<F>::uninit();
@ -384,7 +435,9 @@ impl Stream {
result
}
let r = unsafe { ffi::pa_stream_set_name(self.raw_mut(), name.as_ptr(), Some(wrapped::<CB>), userdata) };
let r = unsafe {
ffi::pa_stream_set_name(self.raw_mut(), name.as_ptr(), Some(wrapped::<CB>), userdata)
};
if r.is_null() {
let err = if let Some(c) = self.get_context() {
c.errno()

View File

@ -3,11 +3,11 @@
// 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;
use ErrorCode;
use Result;
#[derive(Debug)]
pub struct ThreadedMainloop(*mut ffi::pa_threaded_mainloop);

View File

@ -12,7 +12,8 @@ pub trait UnwrapCStr {
}
impl<'a, U> UnwrapCStr for U
where U: Into<Option<&'a CStr>>
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 _)