Bug 1440538 - P1: Remove local cubeb-rs. r=kinetik

MozReview-Commit-ID: GGYFzavnUV4

--HG--
extra : rebase_source : 38bf861e2258dd0cfd4e9255095a4567b4362a8c
This commit is contained in:
Dan Glastonbury 2018-02-22 12:49:32 +10:00
parent 3b389b3cc1
commit a006d86faa
33 changed files with 0 additions and 4056 deletions

View File

@ -1,6 +0,0 @@
[workspace]
members = [
"cubeb-core",
"cubeb-api",
"cubeb-backend"
]

View File

@ -1,13 +0,0 @@
Copyright © 2017 Mozilla Foundation
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@ -1,8 +0,0 @@
The source from this directory was copied from the cubeb-rs
git repository using the update.sh script. The only changes
made were those applied by update.sh and the addition of
Makefile.in build files for the Mozilla build system.
The cubeb-rs git repository is: https://github.com/djg/cubeb-rs.git
The git commit ID used was c7e5ef006dede18158582246bddafbb51f832078 (2018-01-25 11:35:14 +1000)

View File

@ -1,22 +0,0 @@
[package]
name = "cubeb"
version = "0.3.2"
authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
license = "ISC"
readme = "README.md"
keywords = ["cubeb"]
repository = "https://github.com/djg/cubeb-rs"
homepage = "https://github.com/djg/cubeb-rs"
description = """
Bindings to libcubeb for interacting with system audio from rust.
"""
categories = ["api-bindings"]
[badges]
travis-ci = { repository = "djg/cubeb-rs" }
appveyor = { repository = "djg/cubeb-rs" }
[dependencies]
cubeb-core = { path = "../cubeb-core" }
libcubeb-sys = { path = "libcubeb-sys" }

View File

@ -1,26 +0,0 @@
# cubeb-rs
[![Build Status](https://travis-ci.org/djg/cubeb-rs.svg?branch=master)](https://travis-ci.org/djg/cubeb-rs)
[Documentation](https://docs.rs/cubeb)
cubeb bindings for Rust
```toml
[dependencies]
cubeb = "0.1"
```
## Building cubeb-rs
First, you'll need to install _CMake_. Afterwards, just run:
```sh
$ git clone https://github.com/djg/cubeb-rs
$ cd cubeb-rs
$ cargo build
```
# License
`cubeb-rs` is distributed under an ISC-style license. See LICENSE for details.

View File

@ -1,30 +0,0 @@
use cubeb::{Context, Result};
use std::env;
use std::io::{self, Write};
pub fn init(ctx_name: &str) -> Result<Context> {
let backend = match env::var("CUBEB_BACKEND") {
Ok(s) => Some(s),
Err(_) => None,
};
let ctx = Context::init(ctx_name, None);
if let Ok(ref ctx) = ctx {
if let Some(ref backend) = backend {
let ctx_backend = ctx.backend_id();
if backend != ctx_backend {
let stderr = io::stderr();
let mut handle = stderr.lock();
writeln!(
handle,
"Requested backend `{}', got `{}'",
backend,
ctx_backend
).unwrap();
}
}
}
ctx
}

View File

@ -1,133 +0,0 @@
// Copyright © 2011 Mozilla Foundation
// Copyright © 2015 Haakon Sporsheim <haakon.sporsheim@telenordigital.com>
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
//! libcubeb enumerate device test/example.
//! Prints out a list of input/output devices connected to the system.
extern crate cubeb;
mod common;
use std::error::Error;
fn print_device_info(info: &cubeb::DeviceInfo) {
let devtype = if info.device_type().contains(cubeb::DEVICE_TYPE_INPUT) {
"input"
} else if info.device_type().contains(cubeb::DEVICE_TYPE_OUTPUT) {
"output"
} else {
"unknown?"
};
let devstate = match info.state() {
cubeb::DeviceState::Disabled => "disabled",
cubeb::DeviceState::Unplugged => "unplugged",
cubeb::DeviceState::Enabled => "enabled",
};
let devdeffmt = match info.default_format() {
cubeb::DEVICE_FMT_S16LE => "S16LE",
cubeb::DEVICE_FMT_S16BE => "S16BE",
cubeb::DEVICE_FMT_F32LE => "F32LE",
cubeb::DEVICE_FMT_F32BE => "F32BE",
_ => "unknown?",
};
let mut devfmts = "".to_string();
if info.format().contains(cubeb::DEVICE_FMT_S16LE) {
devfmts = format!("{} S16LE", devfmts);
}
if info.format().contains(cubeb::DEVICE_FMT_S16BE) {
devfmts = format!("{} S16BE", devfmts);
}
if info.format().contains(cubeb::DEVICE_FMT_F32LE) {
devfmts = format!("{} F32LE", devfmts);
}
if info.format().contains(cubeb::DEVICE_FMT_F32BE) {
devfmts = format!("{} F32BE", devfmts);
}
if let Some(device_id) = info.device_id() {
let preferred = if info.preferred().is_empty() {
""
} else {
" (PREFERRED)"
};
println!("dev: \"{}\"{}", device_id, preferred);
}
if let Some(friendly_name) = info.friendly_name() {
println!("\tName: \"{}\"", friendly_name);
}
if let Some(group_id) = info.group_id() {
println!("\tGroup: \"{}\"", group_id);
}
if let Some(vendor_name) = info.vendor_name() {
println!("\tVendor: \"{}\"", vendor_name);
}
println!("\tType: {}", devtype);
println!("\tState: {}", devstate);
println!("\tCh: {}", info.max_channels());
println!(
"\tFormat: {} (0x{:x}) (default: {})",
&devfmts[1..],
info.format(),
devdeffmt
);
println!(
"\tRate: {} - {} (default: {})",
info.min_rate(),
info.max_rate(),
info.default_rate()
);
println!(
"\tLatency: lo {} frames, hi {} frames",
info.latency_lo(),
info.latency_hi()
);
}
fn main() {
let ctx = common::init("Cubeb audio test").expect("Failed to create cubeb context");
println!("Enumerating input devices for backend {}", ctx.backend_id());
let devices = match ctx.enumerate_devices(cubeb::DEVICE_TYPE_INPUT) {
Ok(devices) => devices,
Err(e) if e.code() == cubeb::ErrorCode::NotSupported => {
println!("Device enumeration not support for this backend.");
return;
},
Err(e) => {
println!("Error enumerating devices: {}", e.description());
return;
},
};
println!("Found {} input devices", devices.len());
for d in devices.iter() {
print_device_info(d);
}
println!(
"Enumerating output devices for backend {}",
ctx.backend_id()
);
let devices = match ctx.enumerate_devices(cubeb::DEVICE_TYPE_OUTPUT) {
Ok(devices) => devices,
Err(e) => {
println!("Error enumerating devices: {}", e.description());
return;
},
};
println!("Found {} output devices", devices.len());
for d in devices.iter() {
print_device_info(d);
}
}

View File

@ -1,74 +0,0 @@
// Copyright © 2011 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
//! libcubeb api/function test. Plays a simple tone.
extern crate cubeb;
mod common;
use cubeb::SampleType;
use std::f32::consts::PI;
use std::thread;
use std::time::Duration;
const SAMPLE_FREQUENCY: u32 = 48000;
const STREAM_FORMAT: cubeb::SampleFormat = cubeb::SampleFormat::S16LE;
// store the phase of the generated waveform
struct Tone {
position: isize
}
impl cubeb::StreamCallback for Tone {
type Frame = cubeb::MonoFrame<i16>;
fn data_callback(&mut self, _: &[cubeb::MonoFrame<i16>], output: &mut [cubeb::MonoFrame<i16>]) -> isize {
// generate our test tone on the fly
for f in output.iter_mut() {
// North American dial tone
let t1 = (2.0 * PI * 350.0 * self.position as f32 / SAMPLE_FREQUENCY as f32).sin();
let t2 = (2.0 * PI * 440.0 * self.position as f32 / SAMPLE_FREQUENCY as f32).sin();
f.m = i16::from_float(0.5 * (t1 + t2));
self.position += 1;
}
output.len() as isize
}
fn state_callback(&mut self, state: cubeb::State) {
println!("stream {:?}", state);
}
}
fn main() {
let ctx = common::init("Cubeb tone example").expect("Failed to create cubeb context");
let params = cubeb::StreamParamsBuilder::new()
.format(STREAM_FORMAT)
.rate(SAMPLE_FREQUENCY)
.channels(1)
.layout(cubeb::ChannelLayout::Mono)
.take();
let stream_init_opts = cubeb::StreamInitOptionsBuilder::new()
.stream_name("Cubeb tone (mono)")
.output_stream_param(&params)
.latency(4096)
.take();
let stream = ctx.stream_init(
&stream_init_opts,
Tone {
position: 0
}
).expect("Failed to create cubeb stream");
stream.start().unwrap();
thread::sleep(Duration::from_millis(500));
stream.stop().unwrap();
}

View File

@ -1,14 +0,0 @@
[package]
name = "libcubeb-sys"
version = "0.1.0"
authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
repository = "https://github.com/djg/cubeb-rs"
license = "ISC"
description = "Native bindings to the cubeb library"
[lib]
name = "libcubeb_sys"
path = "lib.rs"
[dependencies]
cubeb-core = { path = "../../cubeb-core" }

View File

@ -1,105 +0,0 @@
#![allow(non_camel_case_types)]
extern crate cubeb_core;
use cubeb_core::ffi::{cubeb, cubeb_channel_layout, cubeb_data_callback,
cubeb_device, cubeb_device_changed_callback,
cubeb_device_collection,
cubeb_device_collection_changed_callback, cubeb_device_type,
cubeb_devid, cubeb_log_callback, cubeb_log_level,
cubeb_state_callback, cubeb_stream, cubeb_stream_params};
use std::os::raw::{c_char, c_float, c_int, c_uint, c_void};
extern "C" {
pub fn cubeb_init(
context: *mut *mut cubeb,
context_name: *const c_char,
backend_name: *const c_char,
) -> c_int;
pub fn cubeb_get_backend_id(context: *mut cubeb) -> *const c_char;
pub fn cubeb_get_max_channel_count(
context: *mut cubeb,
max_channels: *mut c_uint,
) -> c_int;
pub fn cubeb_get_min_latency(
context: *mut cubeb,
params: *const cubeb_stream_params,
latency_frames: *mut c_uint,
) -> c_int;
pub fn cubeb_get_preferred_sample_rate(
context: *mut cubeb,
rate: *mut c_uint,
) -> c_int;
pub fn cubeb_get_preferred_channel_layout(
context: *mut cubeb,
layout: *mut cubeb_channel_layout,
) -> c_int;
pub fn cubeb_destroy(context: *mut cubeb);
pub fn cubeb_stream_init(
context: *mut cubeb,
stream: *mut *mut cubeb_stream,
stream_name: *const c_char,
input_device: cubeb_devid,
input_stream_params: *const cubeb_stream_params,
output_device: cubeb_devid,
output_stream_params: *const cubeb_stream_params,
latency_frames: c_uint,
data_callback: cubeb_data_callback,
state_callback: cubeb_state_callback,
user_ptr: *mut c_void,
) -> c_int;
pub fn cubeb_stream_destroy(stream: *mut cubeb_stream);
pub fn cubeb_stream_start(stream: *mut cubeb_stream) -> c_int;
pub fn cubeb_stream_stop(stream: *mut cubeb_stream) -> c_int;
pub fn cubeb_stream_reset_default_device(stream: *mut cubeb_stream) -> c_int;
pub fn cubeb_stream_get_position(
stream: *mut cubeb_stream,
position: *mut u64,
) -> c_int;
pub fn cubeb_stream_get_latency(
stream: *mut cubeb_stream,
latency: *mut c_uint,
) -> c_int;
pub fn cubeb_stream_set_volume(
stream: *mut cubeb_stream,
volume: c_float,
) -> c_int;
pub fn cubeb_stream_set_panning(
stream: *mut cubeb_stream,
panning: c_float,
) -> c_int;
pub fn cubeb_stream_get_current_device(
stream: *mut cubeb_stream,
device: *mut *const cubeb_device,
) -> c_int;
pub fn cubeb_stream_device_destroy(
stream: *mut cubeb_stream,
devices: *const cubeb_device,
) -> c_int;
pub fn cubeb_stream_register_device_changed_callback(
stream: *mut cubeb_stream,
device_changed_callback: cubeb_device_changed_callback,
) -> c_int;
pub fn cubeb_enumerate_devices(
context: *mut cubeb,
devtype: cubeb_device_type,
collection: *mut cubeb_device_collection,
) -> c_int;
pub fn cubeb_device_collection_destroy(
context: *mut cubeb,
collection: *mut cubeb_device_collection,
) -> c_int;
pub fn cubeb_register_device_collection_changed(
context: *mut cubeb,
devtype: cubeb_device_type,
callback: cubeb_device_collection_changed_callback,
user_ptr: *mut c_void,
) -> c_int;
pub fn cubeb_set_log_callback(
log_level: cubeb_log_level,
log_callback: cubeb_log_callback,
) -> c_int;
pub static g_cubeb_log_level: cubeb_log_level;
pub static g_cubeb_log_callback: Option<cubeb_log_callback>;
}

View File

@ -1,145 +0,0 @@
use Error;
use std::os::raw::c_int;
macro_rules! call {
(sys::$p:ident ($($e:expr),*)) => (
sys::$p($(::call::convert(&$e)),*)
)
}
macro_rules! try_call {
(sys::$p:ident ($($e:expr),*)) => ({
match ::call::try(sys::$p($(::call::convert(&$e)),*)) {
Ok(o) => o,
Err(e) => { return Err(e) }
}
})
}
pub fn try(ret: c_int) -> Result<c_int, Error> {
match ret {
n if n < 0 => Err(unsafe { Error::from_raw(n) }),
n => Ok(n),
}
}
#[doc(hidden)]
pub trait Convert<T> {
fn convert(&self) -> T;
}
pub fn convert<T, U>(u: &U) -> T
where
U: Convert<T>,
{
u.convert()
}
mod impls {
use call::Convert;
use cubeb_core::{ChannelLayout, LogLevel, SampleFormat, State};
use ffi;
use std::ffi::CString;
use std::os::raw::c_char;
use std::ptr;
impl<T: Copy> Convert<T> for T {
fn convert(&self) -> T {
*self
}
}
impl<'a, T> Convert<*const T> for &'a T {
fn convert(&self) -> *const T {
&**self as *const _
}
}
impl<'a, T> Convert<*mut T> for &'a mut T {
fn convert(&self) -> *mut T {
&**self as *const _ as *mut _
}
}
impl<T> Convert<*const T> for *mut T {
fn convert(&self) -> *const T {
*self as *const T
}
}
impl Convert<*const c_char> for CString {
fn convert(&self) -> *const c_char {
self.as_ptr()
}
}
impl<T, U: Convert<*const T>> Convert<*const T> for Option<U> {
fn convert(&self) -> *const T {
self.as_ref().map(|s| s.convert()).unwrap_or(ptr::null())
}
}
impl Convert<ffi::cubeb_sample_format> for SampleFormat {
#[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
fn convert(&self) -> ffi::cubeb_sample_format {
match *self {
SampleFormat::S16LE => ffi::CUBEB_SAMPLE_S16LE,
SampleFormat::S16BE => ffi::CUBEB_SAMPLE_S16BE,
SampleFormat::S16NE => ffi::CUBEB_SAMPLE_S16NE,
SampleFormat::Float32LE => ffi::CUBEB_SAMPLE_FLOAT32LE,
SampleFormat::Float32BE => ffi::CUBEB_SAMPLE_FLOAT32BE,
SampleFormat::Float32NE => ffi::CUBEB_SAMPLE_FLOAT32NE,
}
}
}
impl Convert<ffi::cubeb_log_level> for LogLevel {
fn convert(&self) -> ffi::cubeb_log_level {
match *self {
LogLevel::Disabled => ffi::CUBEB_LOG_DISABLED,
LogLevel::Normal => ffi::CUBEB_LOG_NORMAL,
LogLevel::Verbose => ffi::CUBEB_LOG_VERBOSE,
}
}
}
impl Convert<ffi::cubeb_channel_layout> for ChannelLayout {
fn convert(&self) -> ffi::cubeb_channel_layout {
match *self {
ChannelLayout::Undefined => ffi::CUBEB_LAYOUT_UNDEFINED,
ChannelLayout::DualMono => ffi::CUBEB_LAYOUT_DUAL_MONO,
ChannelLayout::DualMonoLfe => ffi::CUBEB_LAYOUT_DUAL_MONO_LFE,
ChannelLayout::Mono => ffi::CUBEB_LAYOUT_MONO,
ChannelLayout::MonoLfe => ffi::CUBEB_LAYOUT_MONO_LFE,
ChannelLayout::Stereo => ffi::CUBEB_LAYOUT_STEREO,
ChannelLayout::StereoLfe => ffi::CUBEB_LAYOUT_STEREO_LFE,
ChannelLayout::Layout3F => ffi::CUBEB_LAYOUT_3F,
ChannelLayout::Layout3FLfe => ffi::CUBEB_LAYOUT_3F_LFE,
ChannelLayout::Layout2F1 => ffi::CUBEB_LAYOUT_2F1,
ChannelLayout::Layout2F1Lfe => ffi::CUBEB_LAYOUT_2F1_LFE,
ChannelLayout::Layout3F1 => ffi::CUBEB_LAYOUT_3F1,
ChannelLayout::Layout3F1Lfe => ffi::CUBEB_LAYOUT_3F1_LFE,
ChannelLayout::Layout2F2 => ffi::CUBEB_LAYOUT_2F2,
ChannelLayout::Layout2F2Lfe => ffi::CUBEB_LAYOUT_2F2_LFE,
ChannelLayout::Layout3F2 => ffi::CUBEB_LAYOUT_3F2,
ChannelLayout::Layout3F2Lfe => ffi::CUBEB_LAYOUT_3F2_LFE,
ChannelLayout::Layout3F3RLfe => ffi::CUBEB_LAYOUT_3F3R_LFE,
ChannelLayout::Layout3F4Lfe => ffi::CUBEB_LAYOUT_3F4_LFE,
}
}
}
impl Convert<ffi::cubeb_state> for State {
fn convert(&self) -> ffi::cubeb_state {
{
match *self {
State::Started => ffi::CUBEB_STATE_STARTED,
State::Stopped => ffi::CUBEB_STATE_STOPPED,
State::Drained => ffi::CUBEB_STATE_DRAINED,
State::Error => ffi::CUBEB_STATE_ERROR,
}
}
}
}
}

View File

@ -1,148 +0,0 @@
use {ChannelLayout, DeviceCollection, DeviceType, Result, Stream, StreamInitOptions, StreamParams};
use {ffi, sys};
use Binding;
use dev_coll;
use std::{ptr, str};
use std::ffi::CString;
use stream::{StreamCallback, stream_init};
use util::{opt_bytes, opt_cstr};
pub struct Context {
raw: *mut ffi::cubeb
}
impl Context {
pub fn init(context_name: &str, backend_name: Option<&str>) -> Result<Context> {
let mut context: *mut ffi::cubeb = ptr::null_mut();
let context_name = try!(CString::new(context_name));
let backend_name = try!(opt_cstr(backend_name));
unsafe {
try_call!(sys::cubeb_init(&mut context, context_name, backend_name));
Ok(Binding::from_raw(context))
}
}
pub fn backend_id(&self) -> &str {
str::from_utf8(self.backend_id_bytes()).unwrap()
}
pub fn backend_id_bytes(&self) -> &[u8] {
unsafe { opt_bytes(self, call!(sys::cubeb_get_backend_id(self.raw))).unwrap() }
}
pub fn max_channel_count(&self) -> Result<u32> {
let mut channel_count = 0u32;
unsafe {
try_call!(sys::cubeb_get_max_channel_count(
self.raw,
&mut channel_count
));
}
Ok(channel_count)
}
pub fn min_latency(&self, params: &StreamParams) -> Result<u32> {
let mut latency = 0u32;
unsafe {
try_call!(sys::cubeb_get_min_latency(
self.raw,
params.raw(),
&mut latency
));
}
Ok(latency)
}
pub fn preferred_sample_rate(&self) -> Result<u32> {
let mut rate = 0u32;
unsafe {
try_call!(sys::cubeb_get_preferred_sample_rate(self.raw, &mut rate));
}
Ok(rate)
}
pub fn preferred_channel_layout(&self) -> Result<ChannelLayout> {
let mut layout: ffi::cubeb_channel_layout = ffi::CUBEB_LAYOUT_UNDEFINED;
unsafe {
try_call!(sys::cubeb_get_preferred_channel_layout(
self.raw,
&mut layout
));
}
macro_rules! check( ($($raw:ident => $real:ident),*) => (
$(if layout == ffi::$raw {
Ok(ChannelLayout::$real)
}) else *
else {
panic!("unknown channel layout: {}", layout)
}
));
check!(
CUBEB_LAYOUT_UNDEFINED => Undefined,
CUBEB_LAYOUT_DUAL_MONO => DualMono,
CUBEB_LAYOUT_DUAL_MONO_LFE => DualMonoLfe,
CUBEB_LAYOUT_MONO => Mono,
CUBEB_LAYOUT_MONO_LFE => MonoLfe,
CUBEB_LAYOUT_STEREO => Stereo,
CUBEB_LAYOUT_STEREO_LFE => StereoLfe,
CUBEB_LAYOUT_3F => Layout3F,
CUBEB_LAYOUT_3F_LFE => Layout3FLfe,
CUBEB_LAYOUT_2F1 => Layout2F1,
CUBEB_LAYOUT_2F1_LFE => Layout2F1Lfe,
CUBEB_LAYOUT_3F1 => Layout3F1,
CUBEB_LAYOUT_3F1_LFE => Layout3F1Lfe,
CUBEB_LAYOUT_2F2 => Layout2F2,
CUBEB_LAYOUT_2F2_LFE => Layout2F2Lfe,
CUBEB_LAYOUT_3F2 => Layout3F2,
CUBEB_LAYOUT_3F2_LFE => Layout3F2Lfe,
CUBEB_LAYOUT_3F3R_LFE => Layout3F3RLfe,
CUBEB_LAYOUT_3F4_LFE => Layout3F4Lfe
)
}
/// Initialize a stream associated with the supplied application context.
pub fn stream_init<CB>(&self, opts: &StreamInitOptions, cb: CB) -> Result<Stream<CB>>
where
CB: StreamCallback,
{
stream_init(self, opts, cb)
}
pub fn enumerate_devices(&self, devtype: DeviceType) -> Result<DeviceCollection> {
dev_coll::enumerate(self, devtype)
}
/*
pub fn register_device_collection_changed(
&self,
devtype: DeviceType,
callback: &mut DeviceCollectionChangedCb,
user_ptr: *mut c_void,
) -> Result<()> {
unsafe {
try_call!(sys::cubeb_register_device_collection_changed(self.raw, devtype, cb));
}
Ok(())
}
*/
}
impl Binding for Context {
type Raw = *mut ffi::cubeb;
unsafe fn from_raw(raw: *mut ffi::cubeb) -> Self {
Self {
raw: raw
}
}
fn raw(&self) -> Self::Raw {
self.raw
}
}
impl Drop for Context {
fn drop(&mut self) {
unsafe { sys::cubeb_destroy(self.raw) }
}
}

View File

@ -1,61 +0,0 @@
//! Bindings to libcubeb's raw `cubeb_device_collection` type
use {Binding, Context};
use cubeb_core::{DeviceInfo, DeviceType, Result};
use ffi;
use std::{ptr, slice};
use std::ops::Deref;
use sys;
/// A collection of `DeviceInfo` used by libcubeb
pub struct DeviceCollection<'coll, 'ctx> {
coll: &'coll [DeviceInfo],
ctx: &'ctx Context
}
impl<'coll, 'ctx> DeviceCollection<'coll, 'ctx> {
fn new(ctx: &'ctx Context, devtype: DeviceType) -> Result<DeviceCollection> {
let mut coll = ffi::cubeb_device_collection {
device: ptr::null(),
count: 0
};
let devices = unsafe {
try_call!(sys::cubeb_enumerate_devices(
ctx.raw(),
devtype.bits(),
&mut coll
));
slice::from_raw_parts(coll.device as *const _, coll.count)
};
Ok(DeviceCollection {
coll: devices,
ctx: ctx
})
}
}
impl<'coll, 'ctx> Deref for DeviceCollection<'coll, 'ctx> {
type Target = [DeviceInfo];
fn deref(&self) -> &[DeviceInfo] {
self.coll
}
}
impl<'coll, 'ctx> Drop for DeviceCollection<'coll, 'ctx> {
fn drop(&mut self) {
let mut coll = ffi::cubeb_device_collection {
device: self.coll.as_ptr() as *const _,
count: self.coll.len()
};
unsafe {
call!(sys::cubeb_device_collection_destroy(
self.ctx.raw(),
&mut coll
));
}
}
}
pub fn enumerate(ctx: &Context, devtype: DeviceType) -> Result<DeviceCollection> {
DeviceCollection::new(ctx, devtype)
}

View File

@ -1,48 +0,0 @@
use ffi;
use std::marker;
use std::str;
use util::opt_bytes;
/// Audio device description
pub struct Device<'a> {
raw: *const ffi::cubeb_device,
_marker: marker::PhantomData<&'a ffi::cubeb_device>
}
impl<'a> Device<'a> {
/// Gets the output device name.
///
/// May return `None` if there is no output device.
pub fn output_name(&self) -> Option<&str> {
self.output_name_bytes().map(|b| str::from_utf8(b).unwrap())
}
fn output_name_bytes(&self) -> Option<&[u8]> {
unsafe { opt_bytes(self, (*self.raw).output_name) }
}
/// Gets the input device name.
///
/// May return `None` if there is no input device.
pub fn input_name(&self) -> Option<&str> {
self.input_name_bytes().map(|b| str::from_utf8(b).unwrap())
}
fn input_name_bytes(&self) -> Option<&[u8]> {
unsafe { opt_bytes(self, (*self.raw).input_name) }
}
}
impl<'a> Binding for Device<'a> {
type Raw = *const ffi::cubeb_device;
unsafe fn from_raw(raw: *const ffi::cubeb_device) -> Device<'a> {
Device {
raw: raw,
_marker: marker::PhantomData
}
}
fn raw(&self) -> *const ffi::cubeb_device {
self.raw
}
}

View File

@ -1,37 +0,0 @@
//! Frame utilities
use ChannelLayout;
/// A `Frame` is a collection of samples which have a a specific
/// layout represented by `ChannelLayout`
pub trait Frame {
fn layout() -> ChannelLayout;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// A monaural frame.
pub struct MonoFrame<T> {
/// Mono channel
pub m: T
}
impl<T> Frame for MonoFrame<T> {
fn layout() -> ChannelLayout {
ChannelLayout::Mono
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// A stereo frame.
pub struct StereoFrame<T> {
/// Left channel
pub l: T,
/// Right channel
pub r: T
}
impl<T> Frame for StereoFrame<T> {
fn layout() -> ChannelLayout {
ChannelLayout::Stereo
}
}

View File

@ -1,47 +0,0 @@
//! # libcubeb bindings for rust
//!
//! This library contains bindings to the [cubeb][1] C library which
//! is used to interact with system audio. The library itself is a
//! work in progress and is likely lacking documentation and test.
//!
//! [1]: https://github.com/kinetiknz/cubeb/
//!
//! The cubeb-rs library exposes the user API of libcubeb. It doesn't
//! expose the internal interfaces, so isn't suitable for extending
//! libcubeb. See [cubeb-pulse-rs][2] for an example of extending
//! libcubeb via implementing a cubeb backend in rust.
extern crate cubeb_core;
extern crate libcubeb_sys as sys;
#[macro_use]
mod call;
mod context;
mod dev_coll;
mod frame;
mod log;
mod stream;
mod util;
pub use context::Context;
// Re-export cubeb_core types
pub use cubeb_core::{ChannelLayout, Device, DeviceFormat, DeviceId, DeviceInfo,
DeviceState, DeviceType, Error, ErrorCode, LogLevel, Result,
SampleFormat, State, StreamParams, StreamPrefs};
pub use cubeb_core::{DEVICE_FMT_F32BE, DEVICE_FMT_F32LE, DEVICE_FMT_S16BE,
DEVICE_FMT_S16LE};
pub use cubeb_core::{DEVICE_PREF_ALL, DEVICE_PREF_MULTIMEDIA, DEVICE_PREF_NONE,
DEVICE_PREF_NOTIFICATION, DEVICE_PREF_VOICE};
pub use cubeb_core::{DEVICE_TYPE_INPUT, DEVICE_TYPE_OUTPUT, DEVICE_TYPE_UNKNOWN};
pub use cubeb_core::{STREAM_PREF_LOOPBACK, STREAM_PREF_NONE};
use cubeb_core::binding::Binding;
use cubeb_core::ffi;
pub use dev_coll::DeviceCollection;
pub use frame::{Frame, MonoFrame, StereoFrame};
pub use log::*;
pub use stream::{SampleType, Stream, StreamCallback, StreamInitOptions,
StreamInitOptionsBuilder, StreamParamsBuilder};
pub type DeviceChangedCb<'a> = FnMut() + 'a;
pub type DeviceCollectionChangedCb<'a> = FnMut(Context) + 'a;

View File

@ -1,71 +0,0 @@
// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
use LogLevel;
use sys;
#[macro_export]
macro_rules! log_internal {
($level: expr, $msg: expr) => {
#[allow(unused_unsafe)]
unsafe {
if $level as i32 <= $crate::sys::g_cubeb_log_level {
if let Some(log_callback) = $crate::sys::g_cubeb_log_callback {
let cstr = ::std::ffi::CString::new(concat!("%s:%d: ", $msg, "\n")).unwrap();
log_callback(cstr.as_ptr(), file!(), line!());
}
}
}
};
($level: expr, $fmt: expr, $($arg:tt)+) => {
#[allow(unused_unsafe)]
unsafe {
if $level as i32 <= $crate::sys::g_cubeb_log_level {
if let Some(log_callback) = $crate::sys::g_cubeb_log_callback {
let cstr = ::std::ffi::CString::new(concat!("%s:%d: ", $fmt, "\n")).unwrap();
log_callback(cstr.as_ptr(), file!(), line!(), $($arg)+);
}
}
}
}
}
#[macro_export]
macro_rules! logv {
($msg: expr) => (log_internal!($crate::LogLevel::Verbose, $msg));
($fmt: expr, $($arg: tt)+) => (log_internal!($crate::LogLevel::Verbose, $fmt, $($arg)*));
}
#[macro_export]
macro_rules! log {
($msg: expr) => (log_internal!($crate::LogLevel::Normal, $msg));
($fmt: expr, $($arg: tt)+) => (log_internal!($crate::LogLevel::Normal, $fmt, $($arg)*));
}
pub fn log_enabled() -> bool {
unsafe { sys::g_cubeb_log_level != LogLevel::Disabled as _ }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_normal_logging() {
log!("This is log at normal level");
log!("Formatted log %d", 1);
}
#[test]
fn test_verbose_logging() {
logv!("This is a log at verbose level");
logv!("Formatted log %d", 1);
}
#[test]
fn test_logging_disabled_by_default() {
assert!(!log_enabled());
}
}

View File

@ -1,669 +0,0 @@
//! Stream Functions
//!
//! # Example
//! ```no_run
//! extern crate cubeb;
//! use std::time::Duration;
//! use std::thread;
//!
//! struct SquareWave {
//! phase_inc: f32,
//! phase: f32,
//! volume: f32
//! }
//!
//! impl cubeb::StreamCallback for SquareWave {
//! type Frame = cubeb::MonoFrame<f32>;
//!
//! fn data_callback(&mut self, _: &[cubeb::MonoFrame<f32>], output: &mut [cubeb::MonoFrame<f32>]) -> isize {
//! // Generate a square wave
//! for x in output.iter_mut() {
//! x.m = if self.phase < 0.5 {
//! self.volume
//! } else {
//! -self.volume
//! };
//! self.phase = (self.phase + self.phase_inc) % 1.0;
//! }
//!
//! output.len() as isize
//! }
//!
//! fn state_callback(&mut self, state: cubeb::State) { println!("stream {:?}", state); }
//! }
//!
//! fn main() {
//! let ctx = cubeb::Context::init("Cubeb tone example", None).unwrap();
//!
//! let params = cubeb::StreamParamsBuilder::new()
//! .format(cubeb::SampleFormat::Float32LE)
//! .rate(44100)
//! .channels(1)
//! .layout(cubeb::ChannelLayout::Mono)
//! .prefs(cubeb::STREAM_PREF_NONE)
//! .take();
//!
//! let stream_init_opts = cubeb::StreamInitOptionsBuilder::new()
//! .stream_name("Cubeb Square Wave")
//! .output_stream_param(&params)
//! .latency(4096)
//! .take();
//!
//! let stream = ctx.stream_init(
//! &stream_init_opts,
//! SquareWave {
//! phase_inc: 440.0 / 44100.0,
//! phase: 0.0,
//! volume: 0.25
//! }).unwrap();
//!
//! // Start playback
//! stream.start().unwrap();
//!
//! // Play for 1/2 second
//! thread::sleep(Duration::from_millis(500));
//!
//! // Shutdown
//! stream.stop().unwrap();
//! }
//! ```
use {Binding, ChannelLayout, Context, Device, DeviceId, Error, Result,
SampleFormat, State, StreamParams, StreamPrefs};
use STREAM_PREF_NONE;
use ffi;
use std::ptr;
use std::ffi::CString;
use std::os::raw::{c_long, c_void};
use sys;
use util::IntoCString;
/// An extension trait which allows the implementation of converting
/// void* buffers from libcubeb-sys into rust slices of the appropriate
/// type.
pub trait SampleType: Send + Copy {
/// Type of the sample
fn format() -> SampleFormat;
/// Map f32 in range [-1,1] to sample type
fn from_float(f32) -> Self;
}
impl SampleType for i16 {
fn format() -> SampleFormat {
SampleFormat::S16NE
}
fn from_float(x: f32) -> i16 {
(x * f32::from(i16::max_value())) as i16
}
}
impl SampleType for f32 {
fn format() -> SampleFormat {
SampleFormat::Float32NE
}
fn from_float(x: f32) -> f32 {
x
}
}
pub trait StreamCallback: Send + 'static
{
type Frame;
// This should return a Result<usize,Error>
fn data_callback(&mut self, &[Self::Frame], &mut [Self::Frame]) -> isize;
fn state_callback(&mut self, state: State);
}
///
pub struct StreamParamsBuilder {
format: SampleFormat,
rate: u32,
channels: u32,
layout: ChannelLayout,
prefs: StreamPrefs
}
impl Default for StreamParamsBuilder {
fn default() -> Self {
Self::new()
}
}
impl StreamParamsBuilder {
pub fn new() -> Self {
Self {
format: SampleFormat::S16NE,
rate: 0,
channels: 0,
layout: ChannelLayout::Undefined,
prefs: STREAM_PREF_NONE
}
}
pub fn format(&mut self, format: SampleFormat) -> &mut Self {
self.format = format;
self
}
pub fn rate(&mut self, rate: u32) -> &mut Self {
self.rate = rate;
self
}
pub fn channels(&mut self, channels: u32) -> &mut Self {
self.channels = channels;
self
}
pub fn layout(&mut self, layout: ChannelLayout) -> &mut Self {
self.layout = layout;
self
}
pub fn prefs(&mut self, prefs: StreamPrefs) -> &mut Self {
self.prefs = prefs;
self
}
#[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
pub fn take(&self) -> StreamParams {
// Convert native endian types to matching format
let raw_sample_format = match self.format {
SampleFormat::S16LE => ffi::CUBEB_SAMPLE_S16LE,
SampleFormat::S16BE => ffi::CUBEB_SAMPLE_S16BE,
SampleFormat::S16NE => ffi::CUBEB_SAMPLE_S16NE,
SampleFormat::Float32LE => ffi::CUBEB_SAMPLE_FLOAT32LE,
SampleFormat::Float32BE => ffi::CUBEB_SAMPLE_FLOAT32BE,
SampleFormat::Float32NE => ffi::CUBEB_SAMPLE_FLOAT32NE,
};
unsafe {
Binding::from_raw(&ffi::cubeb_stream_params {
format: raw_sample_format,
rate: self.rate,
channels: self.channels,
layout: self.layout as ffi::cubeb_channel_layout,
prefs: self.prefs.bits()
} as *const _)
}
}
}
///
pub struct Stream<CB>
where
CB: StreamCallback,
{
raw: *mut ffi::cubeb_stream,
cbs: Box<CB>
}
impl<CB> Stream<CB>
where
CB: StreamCallback,
{
fn init(context: &Context, opts: &StreamInitOptions, cb: CB) -> Result<Stream<CB>> {
let mut stream: *mut ffi::cubeb_stream = ptr::null_mut();
let cbs = Box::new(cb);
unsafe {
let input_stream_params = opts.input_stream_params
.as_ref()
.map(|s| s.raw())
.unwrap_or(ptr::null());
let output_stream_params = opts.output_stream_params
.as_ref()
.map(|s| s.raw())
.unwrap_or(ptr::null());
let user_ptr: *mut c_void = &*cbs as *const _ as *mut _;
try_call!(sys::cubeb_stream_init(
context.raw(),
&mut stream,
opts.stream_name,
opts.input_device.raw(),
input_stream_params,
opts.output_device.raw(),
output_stream_params,
opts.latency_frames,
Stream::<CB>::data_cb_c,
Stream::<CB>::state_cb_c,
user_ptr
));
}
Ok(Stream {
raw: stream,
cbs: cbs
})
}
// start playback.
pub fn start(&self) -> Result<()> {
unsafe {
try_call!(sys::cubeb_stream_start(self.raw));
}
Ok(())
}
// Stop playback.
pub fn stop(&self) -> Result<()> {
unsafe {
try_call!(sys::cubeb_stream_stop(self.raw));
}
Ok(())
}
pub fn reset_default_device(&self) -> Result<()> {
unsafe {
try_call!(sys::cubeb_stream_reset_default_device(self.raw));
}
Ok(())
}
// Get the current stream playback position.
pub fn position(&self) -> Result<u64> {
let mut position: u64 = 0;
unsafe {
try_call!(sys::cubeb_stream_get_position(self.raw, &mut position));
}
Ok(position)
}
pub fn latency(&self) -> Result<u32> {
let mut latency: u32 = 0;
unsafe {
try_call!(sys::cubeb_stream_get_latency(self.raw, &mut latency));
}
Ok(latency)
}
pub fn set_volume(&self, volume: f32) -> Result<()> {
unsafe {
try_call!(sys::cubeb_stream_set_volume(self.raw, volume));
}
Ok(())
}
pub fn set_panning(&self, panning: f32) -> Result<()> {
unsafe {
try_call!(sys::cubeb_stream_set_panning(self.raw, panning));
}
Ok(())
}
pub fn current_device(&self) -> Result<Device> {
let mut device_ptr: *const ffi::cubeb_device = ptr::null();
unsafe {
try_call!(sys::cubeb_stream_get_current_device(
self.raw,
&mut device_ptr
));
Binding::from_raw_opt(device_ptr).ok_or_else(|| Error::from_raw(ffi::CUBEB_ERROR))
}
}
pub fn destroy_device(&self, device: Device) -> Result<()> {
unsafe {
try_call!(sys::cubeb_stream_device_destroy(self.raw, device.raw()));
}
Ok(())
}
/*
pub fn register_device_changed_callback(&self, device_changed_cb: &mut DeviceChangedCb) -> Result<(), Error> {
unsafe { try_call!(sys::cubeb_stream_register_device_changed_callback(self.raw, ...)); }
Ok(())
}
*/
// C callable callbacks
extern "C" fn data_cb_c(
_: *mut ffi::cubeb_stream,
user_ptr: *mut c_void,
input_buffer: *const c_void,
output_buffer: *mut c_void,
nframes: c_long,
) -> c_long {
use std::slice::{from_raw_parts, from_raw_parts_mut};
unsafe {
let cbs = &mut *(user_ptr as *mut CB);
let input: &[CB::Frame] = if input_buffer.is_null() {
&[]
} else {
from_raw_parts(input_buffer as *const _, nframes as usize)
};
let output: &mut [CB::Frame] = if output_buffer.is_null() {
&mut []
} else {
from_raw_parts_mut(output_buffer as *mut _, nframes as usize)
};
cbs.data_callback(input, output) as c_long
}
}
extern "C" fn state_cb_c(_: *mut ffi::cubeb_stream, user_ptr: *mut c_void, state: ffi::cubeb_state) {
let state = match state {
ffi::CUBEB_STATE_STARTED => State::Started,
ffi::CUBEB_STATE_STOPPED => State::Stopped,
ffi::CUBEB_STATE_DRAINED => State::Drained,
ffi::CUBEB_STATE_ERROR => State::Error,
n => panic!("unknown state: {}", n),
};
unsafe {
let cbs = &mut *(user_ptr as *mut CB);
cbs.state_callback(state);
};
}
}
impl<CB> Drop for Stream<CB>
where
CB: StreamCallback,
{
fn drop(&mut self) {
unsafe {
sys::cubeb_stream_destroy(self.raw);
}
}
}
#[doc(hidden)]
pub fn stream_init<CB>(context: &Context, opts: &StreamInitOptions, cb: CB) -> Result<Stream<CB>>
where
CB: StreamCallback,
{
Stream::init(context, opts, cb)
}
pub struct StreamInitOptions {
pub stream_name: Option<CString>,
pub input_device: DeviceId,
pub input_stream_params: Option<StreamParams>,
pub output_device: DeviceId,
pub output_stream_params: Option<StreamParams>,
pub latency_frames: u32
}
impl StreamInitOptions {
pub fn new() -> Self {
StreamInitOptions {
stream_name: None,
input_device: DeviceId::default(),
input_stream_params: None,
output_device: DeviceId::default(),
output_stream_params: None,
latency_frames: 0
}
}
}
impl Default for StreamInitOptions {
fn default() -> Self {
Self::new()
}
}
/// Structure describing options about how stream should be initialized.
pub struct StreamInitOptionsBuilder {
opts: StreamInitOptions
}
impl Default for StreamInitOptionsBuilder {
fn default() -> Self {
Self::new()
}
}
impl StreamInitOptionsBuilder {
pub fn new() -> Self {
StreamInitOptionsBuilder {
opts: Default::default()
}
}
pub fn stream_name<S>(&mut self, name: S) -> &mut Self
where
S: IntoCString,
{
self.opts.stream_name = Some(name.into_c_string().unwrap());
self
}
pub fn input_device(&mut self, id: DeviceId) -> &mut Self {
self.opts.input_device = id;
self
}
pub fn input_stream_param(&mut self, param: &StreamParams) -> &mut Self {
self.opts.input_stream_params = Some(*param);
self
}
pub fn output_device(&mut self, id: DeviceId) -> &mut Self {
self.opts.output_device = id;
self
}
pub fn output_stream_param(&mut self, param: &StreamParams) -> &mut Self {
self.opts.output_stream_params = Some(*param);
self
}
pub fn latency(&mut self, latency: u32) -> &mut Self {
self.opts.latency_frames = latency;
self
}
pub fn take(&mut self) -> StreamInitOptions {
use std::mem::replace;
replace(&mut self.opts, Default::default())
}
}
#[cfg(test)]
mod tests {
use {StreamParamsBuilder, ffi};
use cubeb_core::binding::Binding;
#[test]
fn stream_params_builder_channels() {
let params = StreamParamsBuilder::new().channels(2).take();
assert_eq!(params.channels(), 2);
}
#[test]
fn stream_params_builder_format() {
macro_rules! check(
($($real:ident),*) => (
$(let params = StreamParamsBuilder::new()
.format(super::SampleFormat::$real)
.take();
assert_eq!(params.format(), super::SampleFormat::$real);
)*
) );
check!(S16LE, S16BE, Float32LE, Float32BE);
}
#[test]
fn stream_params_builder_format_native_endian() {
let params = StreamParamsBuilder::new()
.format(super::SampleFormat::S16NE)
.take();
assert_eq!(
params.format(),
if cfg!(target_endian = "little") {
super::SampleFormat::S16LE
} else {
super::SampleFormat::S16BE
}
);
let params = StreamParamsBuilder::new()
.format(super::SampleFormat::Float32NE)
.take();
assert_eq!(
params.format(),
if cfg!(target_endian = "little") {
super::SampleFormat::Float32LE
} else {
super::SampleFormat::Float32BE
}
);
}
#[test]
fn stream_params_builder_layout() {
macro_rules! check(
($($real:ident),*) => (
$(let params = StreamParamsBuilder::new()
.layout(super::ChannelLayout::$real)
.take();
assert_eq!(params.layout(), super::ChannelLayout::$real);
)*
) );
check!(
Undefined,
DualMono,
DualMonoLfe,
Mono,
MonoLfe,
Stereo,
StereoLfe,
Layout3F,
Layout3FLfe,
Layout2F1,
Layout2F1Lfe,
Layout3F1,
Layout3F1Lfe,
Layout2F2,
Layout2F2Lfe,
Layout3F2,
Layout3F3RLfe,
Layout3F4Lfe
);
}
#[test]
fn stream_params_builder_rate() {
let params = StreamParamsBuilder::new().rate(44100).take();
assert_eq!(params.rate(), 44100);
}
#[test]
fn stream_params_builder_to_raw_channels() {
let params = StreamParamsBuilder::new().channels(2).take();
let raw = unsafe { &*params.raw() };
assert_eq!(raw.channels, 2);
}
#[test]
fn stream_params_builder_to_raw_format() {
macro_rules! check(
($($real:ident => $raw:ident),*) => (
$(let params = super::StreamParamsBuilder::new()
.format(super::SampleFormat::$real)
.take();
let raw = unsafe { &*params.raw() };
assert_eq!(raw.format, ffi::$raw);
)*
) );
check!(S16LE => CUBEB_SAMPLE_S16LE,
S16BE => CUBEB_SAMPLE_S16BE,
Float32LE => CUBEB_SAMPLE_FLOAT32LE,
Float32BE => CUBEB_SAMPLE_FLOAT32BE);
}
#[test]
fn stream_params_builder_format_to_raw_native_endian() {
let params = StreamParamsBuilder::new()
.format(super::SampleFormat::S16NE)
.take();
let raw = unsafe { &*params.raw() };
assert_eq!(
raw.format,
if cfg!(target_endian = "little") {
ffi::CUBEB_SAMPLE_S16LE
} else {
ffi::CUBEB_SAMPLE_S16BE
}
);
let params = StreamParamsBuilder::new()
.format(super::SampleFormat::Float32NE)
.take();
let raw = unsafe { &*params.raw() };
assert_eq!(
raw.format,
if cfg!(target_endian = "little") {
ffi::CUBEB_SAMPLE_FLOAT32LE
} else {
ffi::CUBEB_SAMPLE_FLOAT32BE
}
);
}
#[test]
fn stream_params_builder_to_raw_layout() {
macro_rules! check(
($($real:ident => $raw:ident),*) => (
$(let params = super::StreamParamsBuilder::new()
.layout(super::ChannelLayout::$real)
.take();
let raw = unsafe { &*params.raw() };
assert_eq!(raw.layout, ffi::$raw);
)*
) );
check!(Undefined => CUBEB_LAYOUT_UNDEFINED,
DualMono => CUBEB_LAYOUT_DUAL_MONO,
DualMonoLfe => CUBEB_LAYOUT_DUAL_MONO_LFE,
Mono => CUBEB_LAYOUT_MONO,
MonoLfe => CUBEB_LAYOUT_MONO_LFE,
Stereo => CUBEB_LAYOUT_STEREO,
StereoLfe => CUBEB_LAYOUT_STEREO_LFE,
Layout3F => CUBEB_LAYOUT_3F,
Layout3FLfe => CUBEB_LAYOUT_3F_LFE,
Layout2F1 => CUBEB_LAYOUT_2F1,
Layout2F1Lfe => CUBEB_LAYOUT_2F1_LFE,
Layout3F1 => CUBEB_LAYOUT_3F1,
Layout3F1Lfe => CUBEB_LAYOUT_3F1_LFE,
Layout2F2 => CUBEB_LAYOUT_2F2,
Layout2F2Lfe => CUBEB_LAYOUT_2F2_LFE,
Layout3F2 => CUBEB_LAYOUT_3F2,
Layout3F2Lfe => CUBEB_LAYOUT_3F2_LFE,
Layout3F3RLfe => CUBEB_LAYOUT_3F3R_LFE,
Layout3F4Lfe => CUBEB_LAYOUT_3F4_LFE);
}
#[test]
fn stream_params_builder_to_raw_rate() {
let params = StreamParamsBuilder::new().rate(44100).take();
let raw = unsafe { &*params.raw() };
assert_eq!(raw.rate, 44100);
}
#[test]
fn stream_params_builder_prefs_default() {
use cubeb_core::STREAM_PREF_NONE;
let params = StreamParamsBuilder::new().take();
assert_eq!(params.prefs(), STREAM_PREF_NONE);
}
#[test]
fn stream_params_builder_prefs() {
use cubeb_core::STREAM_PREF_LOOPBACK;
let params = StreamParamsBuilder::new()
.prefs(STREAM_PREF_LOOPBACK)
.take();
assert_eq!(params.prefs(), STREAM_PREF_LOOPBACK);
}
}

View File

@ -1,72 +0,0 @@
// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
use cubeb_core::Error;
use ffi;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
/// A class of types that can be converted to C strings.
///
/// These types are represented internally as byte slices and it is quite rare
/// for them to contain an interior 0 byte.
pub trait IntoCString {
/// Consume this container, converting it into a CString
fn into_c_string(self) -> Result<CString, Error>;
}
impl<'a, T: IntoCString + Clone> IntoCString for &'a T {
fn into_c_string(self) -> Result<CString, Error> {
self.clone().into_c_string()
}
}
impl<'a> IntoCString for &'a str {
fn into_c_string(self) -> Result<CString, Error> {
match CString::new(self) {
Ok(s) => Ok(s),
Err(_) => Err(unsafe { Error::from_raw(ffi::CUBEB_ERROR) }),
}
}
}
impl IntoCString for String {
fn into_c_string(self) -> Result<CString, Error> {
match CString::new(self.into_bytes()) {
Ok(s) => Ok(s),
Err(_) => Err(unsafe { Error::from_raw(ffi::CUBEB_ERROR) }),
}
}
}
impl IntoCString for CString {
fn into_c_string(self) -> Result<CString, Error> {
Ok(self)
}
}
impl IntoCString for Vec<u8> {
fn into_c_string(self) -> Result<CString, Error> {
Ok(try!(CString::new(self)))
}
}
pub unsafe fn opt_bytes<T>(_anchor: &T, c: *const c_char) -> Option<&[u8]> {
if c.is_null() {
None
} else {
Some(CStr::from_ptr(c).to_bytes())
}
}
pub fn opt_cstr<T>(o: Option<T>) -> Result<Option<CString>, Error>
where
T: IntoCString,
{
match o {
Some(s) => s.into_c_string().map(Some),
None => Ok(None),
}
}

View File

@ -1,20 +0,0 @@
[package]
name = "cubeb-backend"
version = "0.2.0"
authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
license = "ISC"
keywords = ["cubeb"]
repository = "https://github.com/djg/cubeb-rs"
homepage = "https://github.com/djg/cubeb-rs"
description = """
Bindings to libcubeb internals to facilitate implementing cubeb backends in rust.
"""
categories = ["api-bindings"]
[badges]
travis-ci = { repository = "djg/cubeb-rs" }
appveyor = { repository = "djg/cubeb-rs" }
[dependencies]
cubeb-core = { path = "../cubeb-core" }

View File

@ -1,297 +0,0 @@
// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details
use {Context, Stream};
use cubeb_core::{DeviceId, DeviceType, StreamParams, ffi};
use cubeb_core::binding::Binding;
use std::ffi::CStr;
use std::os::raw::{c_char, c_int, c_void};
// Helper macro for unwrapping `Result` values from rust-api calls
// while returning early with a c-api error code if the value of the
// expression is `Err`.
macro_rules! _try(
($e:expr) => (match $e {
Ok(e) => e,
Err(e) => return e.raw_code()
})
);
#[macro_export]
macro_rules! capi_new(
($ctx:ident, $stm:ident) => (
Ops {
init: Some($crate::capi::capi_init::<$ctx>),
get_backend_id: Some($crate::capi::capi_get_backend_id::<$ctx>),
get_max_channel_count: Some($crate::capi::capi_get_max_channel_count::<$ctx>),
get_min_latency: Some($crate::capi::capi_get_min_latency::<$ctx>),
get_preferred_sample_rate: Some($crate::capi::capi_get_preferred_sample_rate::<$ctx>),
get_preferred_channel_layout: Some($crate::capi::capi_get_preferred_channel_layout::<$ctx>),
enumerate_devices: Some($crate::capi::capi_enumerate_devices::<$ctx>),
device_collection_destroy: Some($crate::capi::capi_device_collection_destroy::<$ctx>),
destroy: Some($crate::capi::capi_destroy::<$ctx>),
stream_init: Some($crate::capi::capi_stream_init::<$ctx>),
stream_destroy: Some($crate::capi::capi_stream_destroy::<$stm>),
stream_start: Some($crate::capi::capi_stream_start::<$stm>),
stream_stop: Some($crate::capi::capi_stream_stop::<$stm>),
stream_reset_default_device: Some($crate::capi::capi_stream_reset_default_device::<$stm>),
stream_get_position: Some($crate::capi::capi_stream_get_position::<$stm>),
stream_get_latency: Some($crate::capi::capi_stream_get_latency::<$stm>),
stream_set_volume: Some($crate::capi::capi_stream_set_volume::<$stm>),
stream_set_panning: Some($crate::capi::capi_stream_set_panning::<$stm>),
stream_get_current_device: Some($crate::capi::capi_stream_get_current_device::<$stm>),
stream_device_destroy: Some($crate::capi::capi_stream_device_destroy::<$stm>),
stream_register_device_changed_callback: None,
register_device_collection_changed: Some($crate::capi::capi_register_device_collection_changed::<$ctx>)
}));
pub unsafe extern "C" fn capi_init<CTX: Context>(
c: *mut *mut ffi::cubeb,
context_name: *const c_char,
) -> c_int {
let anchor = &();
let context_name = opt_cstr(anchor, context_name);
*c = _try!(CTX::init(context_name));
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_get_backend_id<CTX: Context>(
c: *mut ffi::cubeb,
) -> *const c_char {
let ctx = &mut *(c as *mut CTX);
ctx.backend_id().as_ptr()
}
pub unsafe extern "C" fn capi_get_max_channel_count<CTX: Context>(
c: *mut ffi::cubeb,
max_channels: *mut u32,
) -> c_int {
let ctx = &mut *(c as *mut CTX);
*max_channels = _try!(ctx.max_channel_count());
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_get_min_latency<CTX: Context>(
c: *mut ffi::cubeb,
param: ffi::cubeb_stream_params,
latency_frames: *mut u32,
) -> c_int {
let ctx = &mut *(c as *mut CTX);
let param = StreamParams::from_raw(&param);
*latency_frames = _try!(ctx.min_latency(&param));
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_get_preferred_sample_rate<CTX: Context>(
c: *mut ffi::cubeb,
rate: *mut u32,
) -> c_int {
let ctx = &mut *(c as *mut CTX);
*rate = _try!(ctx.preferred_sample_rate());
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_get_preferred_channel_layout<CTX: Context>(
c: *mut ffi::cubeb,
layout: *mut ffi::cubeb_channel_layout,
) -> c_int {
let ctx = &mut *(c as *mut CTX);
*layout = _try!(ctx.preferred_channel_layout()) as _;
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_enumerate_devices<CTX: Context>(
c: *mut ffi::cubeb,
devtype: ffi::cubeb_device_type,
collection: *mut ffi::cubeb_device_collection,
) -> c_int {
let ctx = &mut *(c as *mut CTX);
let devtype = DeviceType::from_bits_truncate(devtype);
*collection = _try!(ctx.enumerate_devices(devtype));
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_device_collection_destroy<CTX: Context>(
c: *mut ffi::cubeb,
collection: *mut ffi::cubeb_device_collection,
) -> c_int {
let ctx = &mut *(c as *mut CTX);
ctx.device_collection_destroy(collection);
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_destroy<CTX>(c: *mut ffi::cubeb) {
let _: Box<CTX> = Box::from_raw(c as *mut _);
}
pub unsafe extern "C" fn capi_stream_init<CTX: Context>(
c: *mut ffi::cubeb,
s: *mut *mut ffi::cubeb_stream,
stream_name: *const c_char,
input_device: ffi::cubeb_devid,
input_stream_params: *const ffi::cubeb_stream_params,
output_device: ffi::cubeb_devid,
output_stream_params: *const ffi::cubeb_stream_params,
latency_frames: u32,
data_callback: ffi::cubeb_data_callback,
state_callback: ffi::cubeb_state_callback,
user_ptr: *mut c_void,
) -> c_int {
let ctx = &*(c as *const CTX);
let anchor = &(); // for lifetime of stream_name as CStr
let input_device = DeviceId::from_raw(input_device);
let input_stream_params = input_stream_params.as_opt_ref();
let output_device = DeviceId::from_raw(output_device);
let output_stream_params = output_stream_params.as_opt_ref();
*s = _try!(ctx.stream_init(
opt_cstr(anchor, stream_name),
input_device,
input_stream_params,
output_device,
output_stream_params,
latency_frames,
data_callback,
state_callback,
user_ptr
));
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_stream_destroy<STM>(s: *mut ffi::cubeb_stream) {
let _ = Box::from_raw(s as *mut STM);
}
pub unsafe extern "C" fn capi_stream_start<STM: Stream>(
s: *mut ffi::cubeb_stream,
) -> c_int {
let stm = &*(s as *const STM);
_try!(stm.start());
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_stream_stop<STM: Stream>(
s: *mut ffi::cubeb_stream,
) -> c_int {
let stm = &*(s as *const STM);
_try!(stm.stop());
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_stream_reset_default_device<STM: Stream>(
s: *mut ffi::cubeb_stream,
) -> c_int {
let stm = &mut *(s as *mut STM);
_try!(stm.reset_default_device());
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_stream_get_position<STM: Stream>(
s: *mut ffi::cubeb_stream,
position: *mut u64,
) -> c_int {
let stm = &mut *(s as *mut STM);
*position = _try!(stm.position());
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_stream_get_latency<STM: Stream>(
s: *mut ffi::cubeb_stream,
latency: *mut u32,
) -> c_int {
let stm = &mut *(s as *mut STM);
*latency = _try!(stm.latency());
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_stream_set_volume<STM: Stream>(
s: *mut ffi::cubeb_stream,
volume: f32,
) -> c_int {
let stm = &mut *(s as *mut STM);
_try!(stm.set_volume(volume));
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_stream_set_panning<STM: Stream>(
s: *mut ffi::cubeb_stream,
panning: f32,
) -> c_int {
let stm = &mut *(s as *mut STM);
_try!(stm.set_panning(panning));
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_stream_get_current_device<STM: Stream>(
s: *mut ffi::cubeb_stream,
device: *mut *const ffi::cubeb_device,
) -> i32 {
let stm = &mut *(s as *mut STM);
*device = _try!(stm.current_device());
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_stream_device_destroy<STM: Stream>(
s: *mut ffi::cubeb_stream,
device: *const ffi::cubeb_device,
) -> c_int {
let stm = &mut *(s as *mut STM);
let _ = stm.device_destroy(device);
ffi::CUBEB_OK
}
pub unsafe extern "C" fn capi_register_device_collection_changed<CTX: Context>(
c: *mut ffi::cubeb,
devtype: ffi::cubeb_device_type,
collection_changed_callback: ffi::cubeb_device_collection_changed_callback,
user_ptr: *mut c_void,
) -> i32 {
let ctx = &*(c as *const CTX);
let devtype = DeviceType::from_bits_truncate(devtype);
_try!(ctx.register_device_collection_changed(
devtype,
collection_changed_callback,
user_ptr
));
ffi::CUBEB_OK
}
trait AsOptRef<'a, T: 'a> {
fn as_opt_ref(self) -> Option<&'a T>;
}
impl<'a, T> AsOptRef<'a, T> for *const T
where
T: 'a,
{
fn as_opt_ref(self) -> Option<&'a T> {
if self.is_null() {
None
} else {
Some(unsafe { &*self })
}
}
}
fn opt_cstr<T>(_anchor: &T, ptr: *const c_char) -> Option<&CStr> {
if ptr.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(ptr) })
}
}

View File

@ -1,241 +0,0 @@
// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
#![allow(non_camel_case_types)]
use cubeb_core::ffi;
use std::fmt::{self, Debug};
use std::os::raw::{c_char, c_int, c_long, c_uint, c_void};
macro_rules! cubeb_enum {
(pub enum $name:ident { $($variants:tt)* }) => {
pub type $name = i32;
cubeb_enum!(gen, $name, 0, $($variants)*);
};
(pub enum $name:ident: $t:ty { $($variants:tt)* }) => {
pub type $name = $t;
cubeb_enum!(gen, $name, 0, $($variants)*);
};
(gen, $name:ident, $val:expr, $variant:ident, $($rest:tt)*) => {
pub const $variant: $name = $val;
cubeb_enum!(gen, $name, $val+1, $($rest)*);
};
(gen, $name:ident, $val:expr, $variant:ident = $e:expr, $($rest:tt)*) => {
pub const $variant: $name = $e;
cubeb_enum!(gen, $name, $e+1, $($rest)*);
};
(gen, $name:ident, $val:expr, ) => {}
}
// cubeb_internal.h
#[repr(C)]
pub struct cubeb_layout_map {
name: *const c_char,
channels: c_uint,
layout: ffi::cubeb_channel_layout
}
pub type InitFn =
unsafe extern fn(context: *mut *mut ffi::cubeb, context_name: *const c_char) -> c_int;
pub type GetBackendIdFn =
unsafe extern fn(context: *mut ffi::cubeb) -> *const c_char;
pub type GetMaxChannelCountFn =
unsafe extern fn(context: *mut ffi::cubeb, max_channels: *mut u32) -> c_int;
pub type GetMinLatencyFn =
unsafe extern fn(context: *mut ffi::cubeb,
params: ffi::cubeb_stream_params,
latency_ms: *mut u32) -> c_int;
pub type GetPreferredSampleRateFn =
unsafe extern fn(context: *mut ffi::cubeb, rate: *mut u32) -> c_int;
pub type GetPreferredChannelLayoutFn =
unsafe extern fn(context: *mut ffi::cubeb, layout: *mut ffi::cubeb_channel_layout) -> c_int;
pub type EnumerateDevicesFn =
unsafe extern fn(context: *mut ffi::cubeb, devtype: ffi::cubeb_device_type,
collection: *mut ffi::cubeb_device_collection) -> c_int;
pub type DeviceCollectionDestroyFn =
unsafe extern fn(context: *mut ffi::cubeb,
collection: *mut ffi::cubeb_device_collection) -> c_int;
pub type DestroyFn =
unsafe extern "C" fn(context: *mut ffi::cubeb);
pub type StreamInitFn =
unsafe extern fn(context: *mut ffi::cubeb,
stream: *mut *mut ffi::cubeb_stream,
stream_name: *const c_char,
input_device: ffi::cubeb_devid,
input_stream_params: *const ffi::cubeb_stream_params,
output_device: ffi::cubeb_devid,
output_stream_params: *const ffi::cubeb_stream_params,
latency: u32,
data_callback: ffi::cubeb_data_callback,
state_callback: ffi::cubeb_state_callback,
user_ptr: *mut c_void) -> c_int;
pub type StreamDestroyFn =
unsafe extern "C" fn(stream: *mut ffi::cubeb_stream);
pub type StreamStartFn =
unsafe extern fn(stream: *mut ffi::cubeb_stream) -> c_int;
pub type StreamStopFn =
unsafe extern fn(stream: *mut ffi::cubeb_stream) -> c_int;
pub type StreamResetDefaultDeviceFn =
unsafe extern fn(stream: *mut ffi::cubeb_stream) -> c_int;
pub type StreamGetPositionFn =
unsafe extern fn(stream: *mut ffi::cubeb_stream, position: *mut u64) -> c_int;
pub type StreamGetLatencyFn =
unsafe extern fn(stream: *mut ffi::cubeb_stream, latency: *mut u32) -> c_int;
pub type StreamSetVolumeFn =
unsafe extern fn(stream: *mut ffi::cubeb_stream, volumes: f32) -> c_int;
pub type StreamSetPanningFn =
unsafe extern fn(stream: *mut ffi::cubeb_stream, panning: f32) -> c_int;
pub type StreamGetCurrentDeviceFn =
unsafe extern fn(stream: *mut ffi::cubeb_stream,
device: *mut *const ffi::cubeb_device) -> c_int;
pub type StreamDeviceDestroyFn =
unsafe extern fn(stream: *mut ffi::cubeb_stream,
device: *const ffi::cubeb_device) -> c_int;
pub type StreamRegisterDeviceChangedCallbackFn =
unsafe extern fn(stream: *mut ffi::cubeb_stream,
device_changed_callback: ffi::cubeb_device_changed_callback) -> c_int;
pub type RegisterDeviceCollectionChangedFn =
unsafe extern fn(context: *mut ffi::cubeb,
devtype: ffi::cubeb_device_type,
callback: ffi::cubeb_device_collection_changed_callback,
user_ptr: *mut c_void) -> c_int;
#[repr(C)]
pub struct Ops {
pub init: Option<InitFn>,
pub get_backend_id: Option<GetBackendIdFn>,
pub get_max_channel_count: Option<GetMaxChannelCountFn>,
pub get_min_latency: Option<GetMinLatencyFn>,
pub get_preferred_sample_rate: Option<
unsafe extern fn(context: *mut ffi::cubeb, rate: *mut u32) -> c_int>,
pub get_preferred_channel_layout: Option<
unsafe extern fn(context: *mut ffi::cubeb,
layout: *mut ffi::cubeb_channel_layout)
-> c_int>,
pub enumerate_devices: Option<
unsafe extern fn(context: *mut ffi::cubeb,
devtype: ffi::cubeb_device_type,
collection: *mut ffi::cubeb_device_collection)
-> c_int>,
pub device_collection_destroy: Option<
unsafe extern fn(context: *mut ffi::cubeb,
collection: *mut ffi::cubeb_device_collection)
-> c_int>,
pub destroy: Option<unsafe extern "C" fn(context: *mut ffi::cubeb)>,
pub stream_init: Option<StreamInitFn>,
pub stream_destroy: Option<unsafe extern "C" fn(stream: *mut ffi::cubeb_stream)>,
pub stream_start: Option<
unsafe extern fn(stream: *mut ffi::cubeb_stream) -> c_int>,
pub stream_stop: Option<
unsafe extern fn(stream: *mut ffi::cubeb_stream) -> c_int>,
pub stream_reset_default_device: Option<
unsafe extern fn(stream: *mut ffi::cubeb_stream) -> c_int>,
pub stream_get_position: Option<
unsafe extern fn(stream: *mut ffi::cubeb_stream,
position: *mut u64)
-> c_int>,
pub stream_get_latency: Option<
unsafe extern fn(stream: *mut ffi::cubeb_stream,
latency: *mut u32)
-> c_int>,
pub stream_set_volume: Option<
unsafe extern fn(stream: *mut ffi::cubeb_stream, volumes: f32)
-> c_int>,
pub stream_set_panning: Option<
unsafe extern fn(stream: *mut ffi::cubeb_stream, panning: f32)
-> c_int>,
pub stream_get_current_device: Option<
unsafe extern fn(stream: *mut ffi::cubeb_stream,
device: *mut *const ffi::cubeb_device)
-> c_int>,
pub stream_device_destroy: Option<
unsafe extern fn(stream: *mut ffi::cubeb_stream,
device: *const ffi::cubeb_device)
-> c_int>,
pub stream_register_device_changed_callback: Option<
unsafe extern fn(stream: *mut ffi::cubeb_stream,
device_changed_callback:
ffi::cubeb_device_changed_callback)
-> c_int>,
pub register_device_collection_changed: Option<
RegisterDeviceCollectionChangedFn>
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct LayoutMap {
pub name: *const c_char,
pub channels: u32,
pub layout: ffi::cubeb_channel_layout
}
// cubeb_mixer.h
cubeb_enum! {
pub enum cubeb_channel {
// These need to match cubeb_channel
CHANNEL_INVALID = -1,
CHANNEL_MONO = 0,
CHANNEL_LEFT,
CHANNEL_RIGHT,
CHANNEL_CENTER,
CHANNEL_LS,
CHANNEL_RS,
CHANNEL_RLS,
CHANNEL_RCENTER,
CHANNEL_RRS,
CHANNEL_LFE,
CHANNEL_UNMAPPED,
CHANNEL_MAX = 256,
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct cubeb_channel_map {
pub channels: c_uint,
pub map: [cubeb_channel; CHANNEL_MAX as usize]
}
impl Debug for cubeb_channel_map {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("cubeb_channel_map")
.field("channels", &self.channels)
.field("map", &self.map.iter().take(self.channels as usize))
.finish()
}
}
extern "C" {
pub fn cubeb_channel_map_to_layout(
channel_map: *const cubeb_channel_map,
) -> ffi::cubeb_channel_layout;
pub fn cubeb_should_upmix(
stream: *const ffi::cubeb_stream_params,
mixer: *const ffi::cubeb_stream_params,
) -> bool;
pub fn cubeb_should_downmix(
stream: *const ffi::cubeb_stream_params,
mixer: *const ffi::cubeb_stream_params,
) -> bool;
pub fn cubeb_downmix_float(
input: *const f32,
inframes: c_long,
output: *mut f32,
in_channels: u32,
out_channels: u32,
in_layout: ffi::cubeb_channel_layout,
out_layout: ffi::cubeb_channel_layout,
);
pub fn cubeb_upmix_float(
input: *const f32,
inframes: c_long,
output: *mut f32,
in_channels: u32,
out_channels: u32,
);
pub static CHANNEL_INDEX_TO_ORDER: [[cubeb_channel; CHANNEL_MAX as usize];
ffi::CUBEB_LAYOUT_MAX as usize];
}

View File

@ -1,13 +0,0 @@
// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
extern crate cubeb_core;
pub mod ffi;
pub mod capi;
mod traits;
pub use ffi::Ops;
pub use traits::{Context, Stream};

View File

@ -1,61 +0,0 @@
// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
use cubeb_core::{DeviceId, DeviceType, Result, StreamParams};
use cubeb_core::ffi;
use std::ffi::CStr;
use std::os::raw::c_void;
pub trait Context {
fn init(context_name: Option<&CStr>) -> Result<*mut ffi::cubeb>;
fn backend_id(&self) -> &'static CStr;
fn max_channel_count(&self) -> Result<u32>;
fn min_latency(&self, params: &StreamParams) -> Result<u32>;
fn preferred_sample_rate(&self) -> Result<u32>;
fn preferred_channel_layout(&self) -> Result<ffi::cubeb_channel_layout>;
fn enumerate_devices(
&self,
devtype: DeviceType,
) -> Result<ffi::cubeb_device_collection>;
fn device_collection_destroy(
&self,
collection: *mut ffi::cubeb_device_collection,
);
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
fn stream_init(
&self,
stream_name: Option<&CStr>,
input_device: DeviceId,
input_stream_params: Option<&ffi::cubeb_stream_params>,
output_device: DeviceId,
output_stream_params: Option<&ffi::cubeb_stream_params>,
latency_frames: u32,
data_callback: ffi::cubeb_data_callback,
state_callback: ffi::cubeb_state_callback,
user_ptr: *mut c_void,
) -> Result<*mut ffi::cubeb_stream>;
fn register_device_collection_changed(
&self,
devtype: DeviceType,
cb: ffi::cubeb_device_collection_changed_callback,
user_ptr: *mut c_void,
) -> Result<()>;
}
pub trait Stream {
fn start(&self) -> Result<()>;
fn stop(&self) -> Result<()>;
fn reset_default_device(&self) -> Result<()>;
fn position(&self) -> Result<u64>;
fn latency(&self) -> Result<u32>;
fn set_volume(&self, volume: f32) -> Result<()>;
fn set_panning(&self, panning: f32) -> Result<()>;
fn current_device(&self) -> Result<*const ffi::cubeb_device>;
fn device_destroy(&self, device: *const ffi::cubeb_device) -> Result<()>;
fn register_device_changed_callback(
&self,
device_changed_callback: ffi::cubeb_device_changed_callback,
) -> Result<()>;
}

View File

@ -1,268 +0,0 @@
// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details
#[macro_use]
extern crate cubeb_backend;
extern crate cubeb_core;
use cubeb_backend::{Context, Ops, Stream};
use cubeb_core::{ChannelLayout, DeviceId, DeviceType, Result, StreamParams, ffi};
use std::ffi::CStr;
use std::os::raw::c_void;
use std::ptr;
pub const OPS: Ops = capi_new!(TestContext, TestStream);
struct TestContext {
pub ops: *const Ops
}
impl Context for TestContext {
fn init(_context_name: Option<&CStr>) -> Result<*mut ffi::cubeb> {
let ctx = Box::new(TestContext {
ops: &OPS as *const _
});
Ok(Box::into_raw(ctx) as *mut _)
}
fn backend_id(&self) -> &'static CStr {
unsafe { CStr::from_ptr(b"remote\0".as_ptr() as *const _) }
}
fn max_channel_count(&self) -> Result<u32> {
Ok(0u32)
}
fn min_latency(&self, _params: &StreamParams) -> Result<u32> {
Ok(0u32)
}
fn preferred_sample_rate(&self) -> Result<u32> {
Ok(0u32)
}
fn preferred_channel_layout(&self) -> Result<ffi::cubeb_channel_layout> {
Ok(ChannelLayout::Mono as _)
}
fn enumerate_devices(
&self,
_devtype: DeviceType,
) -> Result<ffi::cubeb_device_collection> {
Ok(ffi::cubeb_device_collection {
device: 0xDEADBEEF as *const _,
count: usize::max_value()
})
}
fn device_collection_destroy(
&self,
collection: *mut ffi::cubeb_device_collection,
) {
let mut coll = unsafe { &mut *collection };
assert_eq!(coll.device, 0xDEADBEEF as *const _);
assert_eq!(coll.count, usize::max_value());
coll.device = ptr::null_mut();
coll.count = 0;
}
fn stream_init(
&self,
_stream_name: Option<&CStr>,
_input_device: DeviceId,
_input_stream_params: Option<&ffi::cubeb_stream_params>,
_output_device: DeviceId,
_output_stream_params: Option<&ffi::cubeb_stream_params>,
_latency_frame: u32,
_data_callback: ffi::cubeb_data_callback,
_state_callback: ffi::cubeb_state_callback,
_user_ptr: *mut c_void,
) -> Result<*mut ffi::cubeb_stream> {
Ok(ptr::null_mut())
}
fn register_device_collection_changed(
&self,
_dev_type: DeviceType,
_collection_changed_callback: ffi::cubeb_device_collection_changed_callback,
_user_ptr: *mut c_void,
) -> Result<()> {
Ok(())
}
}
struct TestStream {}
impl Stream for TestStream {
fn start(&self) -> Result<()> {
Ok(())
}
fn stop(&self) -> Result<()> {
Ok(())
}
fn reset_default_device(&self) -> Result<()> {
Ok(())
}
fn position(&self) -> Result<u64> {
Ok(0u64)
}
fn latency(&self) -> Result<u32> {
Ok(0u32)
}
fn set_volume(&self, volume: f32) -> Result<()> {
assert_eq!(volume, 0.5);
Ok(())
}
fn set_panning(&self, panning: f32) -> Result<()> {
assert_eq!(panning, 0.5);
Ok(())
}
fn current_device(&self) -> Result<*const ffi::cubeb_device> {
Ok(0xDEADBEEF as *const _)
}
fn device_destroy(&self, device: *const ffi::cubeb_device) -> Result<()> {
assert_eq!(device, 0xDEADBEEF as *const _);
Ok(())
}
fn register_device_changed_callback(
&self,
_: ffi::cubeb_device_changed_callback,
) -> Result<()> {
Ok(())
}
}
#[test]
fn test_ops_context_init() {
let mut c: *mut ffi::cubeb = ptr::null_mut();
assert_eq!(
unsafe { OPS.init.unwrap()(&mut c, ptr::null()) },
ffi::CUBEB_OK
);
}
#[test]
fn test_ops_context_max_channel_count() {
let c: *mut ffi::cubeb = ptr::null_mut();
let mut max_channel_count = u32::max_value();
assert_eq!(
unsafe { OPS.get_max_channel_count.unwrap()(c, &mut max_channel_count) },
ffi::CUBEB_OK
);
assert_eq!(max_channel_count, 0);
}
#[test]
fn test_ops_context_min_latency() {
let c: *mut ffi::cubeb = ptr::null_mut();
let params: ffi::cubeb_stream_params = unsafe { ::std::mem::zeroed() };
let mut latency = u32::max_value();
assert_eq!(
unsafe { OPS.get_min_latency.unwrap()(c, params, &mut latency) },
ffi::CUBEB_OK
);
assert_eq!(latency, 0);
}
#[test]
fn test_ops_context_preferred_sample_rate() {
let c: *mut ffi::cubeb = ptr::null_mut();
let mut rate = u32::max_value();
assert_eq!(
unsafe { OPS.get_preferred_sample_rate.unwrap()(c, &mut rate) },
ffi::CUBEB_OK
);
assert_eq!(rate, 0);
}
#[test]
fn test_ops_context_preferred_channel_layout() {
let c: *mut ffi::cubeb = ptr::null_mut();
let mut layout = ChannelLayout::Undefined;
assert_eq!(
unsafe {
OPS.get_preferred_channel_layout.unwrap()(
c,
&mut layout as *mut _ as *mut _
)
},
ffi::CUBEB_OK
);
assert_eq!(layout, ChannelLayout::Mono);
}
#[test]
fn test_ops_context_enumerate_devices() {
let c: *mut ffi::cubeb = ptr::null_mut();
let mut coll = ffi::cubeb_device_collection {
device: ptr::null(),
count: 0
};
assert_eq!(
unsafe { OPS.enumerate_devices.unwrap()(c, 0, &mut coll) },
ffi::CUBEB_OK
);
assert_eq!(coll.device, 0xDEADBEEF as *const _);
assert_eq!(coll.count, usize::max_value())
}
#[test]
fn test_ops_context_device_collection_destroy() {
let c: *mut ffi::cubeb = ptr::null_mut();
let mut coll = ffi::cubeb_device_collection {
device: 0xDEADBEEF as *const _,
count: usize::max_value()
};
assert_eq!(
unsafe { OPS.device_collection_destroy.unwrap()(c, &mut coll) },
ffi::CUBEB_OK
);
assert_eq!(coll.device, ptr::null_mut());
assert_eq!(coll.count, 0);
}
// stream_init: Some($crate::capi::capi_stream_init::<$ctx>),
// stream_destroy: Some($crate::capi::capi_stream_destroy::<$stm>),
// stream_start: Some($crate::capi::capi_stream_start::<$stm>),
// stream_stop: Some($crate::capi::capi_stream_stop::<$stm>),
// stream_get_position: Some($crate::capi::capi_stream_get_position::<$stm>),
#[test]
fn test_ops_stream_latency() {
let s: *mut ffi::cubeb_stream = ptr::null_mut();
let mut latency = u32::max_value();
assert_eq!(
unsafe { OPS.stream_get_latency.unwrap()(s, &mut latency) },
ffi::CUBEB_OK
);
assert_eq!(latency, 0);
}
#[test]
fn test_ops_stream_set_volume() {
let s: *mut ffi::cubeb_stream = ptr::null_mut();
unsafe {
OPS.stream_set_volume.unwrap()(s, 0.5);
}
}
#[test]
fn test_ops_stream_set_panning() {
let s: *mut ffi::cubeb_stream = ptr::null_mut();
unsafe {
OPS.stream_set_panning.unwrap()(s, 0.5);
}
}
#[test]
fn test_ops_stream_current_device() {
let s: *mut ffi::cubeb_stream = ptr::null_mut();
let mut device: *const ffi::cubeb_device = ptr::null();
assert_eq!(
unsafe { OPS.stream_get_current_device.unwrap()(s, &mut device) },
ffi::CUBEB_OK
);
assert_eq!(device, 0xDEADBEEF as *const _);
}
#[test]
fn test_ops_stream_device_destroy() {
let s: *mut ffi::cubeb_stream = ptr::null_mut();
unsafe {
OPS.stream_device_destroy.unwrap()(s, 0xDEADBEEF as *const _);
}
}

View File

@ -1,15 +0,0 @@
[package]
name = "cubeb-core"
version = "0.1.0"
authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
license = "ISC"
keywords = ["cubeb"]
repository = "https://github.com/djg/cubeb-rs"
homepage = "https://github.com/djg/cubeb-rs"
description = """
Common types and definitions for cubeb rust and C bindings.
"""
categories = ["api-bindings"]
[dependencies]
bitflags = "0.9"

View File

@ -1,41 +0,0 @@
// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
#[doc(hidden)]
pub trait IsNullPtr {
fn is_ptr_null(&self) -> bool;
}
impl<T> IsNullPtr for *const T {
fn is_ptr_null(&self) -> bool {
self.is_null()
}
}
impl<T> IsNullPtr for *mut T {
fn is_ptr_null(&self) -> bool {
self.is_null()
}
}
#[doc(hidden)]
pub trait Binding: Sized {
type Raw;
unsafe fn from_raw(raw: Self::Raw) -> Self;
fn raw(&self) -> Self::Raw;
unsafe fn from_raw_opt<T>(raw: T) -> Option<Self>
where
T: Copy + IsNullPtr,
Self: Binding<Raw = T>,
{
if raw.is_ptr_null() {
None
} else {
Some(Binding::from_raw(raw))
}
}
}

View File

@ -1,132 +0,0 @@
use ErrorCode;
use ffi;
use std::error;
use std::ffi::NulError;
use std::fmt;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Error {
code: ErrorCode
}
impl Error {
pub fn new() -> Error {
Error {
code: ErrorCode::Error
}
}
pub unsafe fn from_raw(code: ffi::cubeb_error_code) -> Error {
let code = match code {
ffi::CUBEB_ERROR_INVALID_FORMAT => ErrorCode::InvalidFormat,
ffi::CUBEB_ERROR_INVALID_PARAMETER => ErrorCode::InvalidParameter,
ffi::CUBEB_ERROR_NOT_SUPPORTED => ErrorCode::NotSupported,
ffi::CUBEB_ERROR_DEVICE_UNAVAILABLE => ErrorCode::DeviceUnavailable,
// Everything else is just the generic error
_ => ErrorCode::Error,
};
Error {
code: code
}
}
pub fn code(&self) -> ErrorCode {
self.code
}
pub fn raw_code(&self) -> ffi::cubeb_error_code {
match self.code {
ErrorCode::Error => ffi::CUBEB_ERROR,
ErrorCode::InvalidFormat => ffi::CUBEB_ERROR_INVALID_FORMAT,
ErrorCode::InvalidParameter => ffi::CUBEB_ERROR_INVALID_PARAMETER,
ErrorCode::NotSupported => ffi::CUBEB_ERROR_NOT_SUPPORTED,
ErrorCode::DeviceUnavailable => ffi::CUBEB_ERROR_DEVICE_UNAVAILABLE,
}
}
}
impl Default for Error {
fn default() -> Self {
Error::new()
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match self.code {
ErrorCode::Error => "Error",
ErrorCode::InvalidFormat => "Invalid format",
ErrorCode::InvalidParameter => "Invalid parameter",
ErrorCode::NotSupported => "Not supported",
ErrorCode::DeviceUnavailable => "Device unavailable",
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::error::Error;
write!(f, "{}", self.description())
}
}
impl From<ErrorCode> for Error {
fn from(code: ErrorCode) -> Error {
Error {
code: code
}
}
}
impl From<NulError> for Error {
fn from(_: NulError) -> Error {
unsafe { Error::from_raw(ffi::CUBEB_ERROR) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use ffi;
#[test]
fn test_from_raw() {
macro_rules! test {
( $($raw:ident => $err:ident),* ) => {{
$(
let e = unsafe { Error::from_raw(ffi::$raw) };
assert_eq!(e.raw_code(), ffi::$raw);
assert_eq!(e.code(), ErrorCode::$err);
)*
}};
}
test!(CUBEB_ERROR => Error,
CUBEB_ERROR_INVALID_FORMAT => InvalidFormat,
CUBEB_ERROR_INVALID_PARAMETER => InvalidParameter,
CUBEB_ERROR_NOT_SUPPORTED => NotSupported,
CUBEB_ERROR_DEVICE_UNAVAILABLE => DeviceUnavailable
);
}
#[test]
fn test_from_error_code() {
macro_rules! test {
( $($raw:ident => $err:ident),* ) => {{
$(
let e = Error::from(ErrorCode::$err);
assert_eq!(e.raw_code(), ffi::$raw);
assert_eq!(e.code(), ErrorCode::$err);
)*
}};
}
test!(CUBEB_ERROR => Error,
CUBEB_ERROR_INVALID_FORMAT => InvalidFormat,
CUBEB_ERROR_INVALID_PARAMETER => InvalidParameter,
CUBEB_ERROR_NOT_SUPPORTED => NotSupported,
CUBEB_ERROR_DEVICE_UNAVAILABLE => DeviceUnavailable
);
}
}

View File

@ -1,538 +0,0 @@
// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
#![allow(non_camel_case_types)]
use std::os::raw::{c_char, c_int, c_long, c_uint, c_void};
macro_rules! cubeb_enum {
(pub enum $name:ident { $($variants:tt)* }) => {
#[cfg(target_env = "msvc")]
pub type $name = i32;
#[cfg(not(target_env = "msvc"))]
pub type $name = u32;
cubeb_enum!(gen, $name, 0, $($variants)*);
};
(pub enum $name:ident: $t:ty { $($variants:tt)* }) => {
pub type $name = $t;
cubeb_enum!(gen, $name, 0, $($variants)*);
};
(gen, $name:ident, $val:expr, $variant:ident, $($rest:tt)*) => {
pub const $variant: $name = $val;
cubeb_enum!(gen, $name, $val+1, $($rest)*);
};
(gen, $name:ident, $val:expr, $variant:ident = $e:expr, $($rest:tt)*) => {
pub const $variant: $name = $e;
cubeb_enum!(gen, $name, $e+1, $($rest)*);
};
(gen, $name:ident, $val:expr, ) => {}
}
pub enum cubeb {}
pub enum cubeb_stream {}
cubeb_enum! {
pub enum cubeb_sample_format {
CUBEB_SAMPLE_S16LE,
CUBEB_SAMPLE_S16BE,
CUBEB_SAMPLE_FLOAT32LE,
CUBEB_SAMPLE_FLOAT32BE,
}
}
#[cfg(target_endian = "big")]
pub const CUBEB_SAMPLE_S16NE: cubeb_sample_format = CUBEB_SAMPLE_S16BE;
#[cfg(target_endian = "big")]
pub const CUBEB_SAMPLE_FLOAT32NE: cubeb_sample_format = CUBEB_SAMPLE_FLOAT32BE;
#[cfg(target_endian = "little")]
pub const CUBEB_SAMPLE_S16NE: cubeb_sample_format = CUBEB_SAMPLE_S16LE;
#[cfg(target_endian = "little")]
pub const CUBEB_SAMPLE_FLOAT32NE: cubeb_sample_format = CUBEB_SAMPLE_FLOAT32LE;
pub type cubeb_devid = *const c_void;
cubeb_enum! {
pub enum cubeb_log_level: c_int {
CUBEB_LOG_DISABLED = 0,
CUBEB_LOG_NORMAL = 1,
CUBEB_LOG_VERBOSE = 2,
}
}
cubeb_enum! {
pub enum cubeb_channel_layout: c_int {
CUBEB_LAYOUT_UNDEFINED,
CUBEB_LAYOUT_DUAL_MONO,
CUBEB_LAYOUT_DUAL_MONO_LFE,
CUBEB_LAYOUT_MONO,
CUBEB_LAYOUT_MONO_LFE,
CUBEB_LAYOUT_STEREO,
CUBEB_LAYOUT_STEREO_LFE,
CUBEB_LAYOUT_3F,
CUBEB_LAYOUT_3F_LFE,
CUBEB_LAYOUT_2F1,
CUBEB_LAYOUT_2F1_LFE,
CUBEB_LAYOUT_3F1,
CUBEB_LAYOUT_3F1_LFE,
CUBEB_LAYOUT_2F2,
CUBEB_LAYOUT_2F2_LFE,
CUBEB_LAYOUT_3F2,
CUBEB_LAYOUT_3F2_LFE,
CUBEB_LAYOUT_3F3R_LFE,
CUBEB_LAYOUT_3F4_LFE,
CUBEB_LAYOUT_MAX,
}
}
cubeb_enum! {
pub enum cubeb_stream_prefs: c_int {
CUBEB_STREAM_PREF_NONE = 0x00,
CUBEB_STREAM_PREF_LOOPBACK = 0x01,
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct cubeb_stream_params {
pub format: cubeb_sample_format,
pub rate: c_uint,
pub channels: c_uint,
pub layout: cubeb_channel_layout,
pub prefs: cubeb_stream_prefs
}
#[repr(C)]
#[derive(Debug)]
pub struct cubeb_device {
pub output_name: *const c_char,
pub input_name: *const c_char
}
cubeb_enum! {
pub enum cubeb_state: c_int {
CUBEB_STATE_STARTED,
CUBEB_STATE_STOPPED,
CUBEB_STATE_DRAINED,
CUBEB_STATE_ERROR,
}
}
cubeb_enum! {
pub enum cubeb_error_code: c_int {
CUBEB_OK = 0,
CUBEB_ERROR = -1,
CUBEB_ERROR_INVALID_FORMAT = -2,
CUBEB_ERROR_INVALID_PARAMETER = -3,
CUBEB_ERROR_NOT_SUPPORTED = -4,
CUBEB_ERROR_DEVICE_UNAVAILABLE = -5,
}
}
cubeb_enum! {
pub enum cubeb_device_type {
CUBEB_DEVICE_TYPE_UNKNOWN,
CUBEB_DEVICE_TYPE_INPUT,
CUBEB_DEVICE_TYPE_OUTPUT,
}
}
cubeb_enum! {
pub enum cubeb_device_state {
CUBEB_DEVICE_STATE_DISABLED,
CUBEB_DEVICE_STATE_UNPLUGGED,
CUBEB_DEVICE_STATE_ENABLED,
}
}
cubeb_enum! {
pub enum cubeb_device_fmt {
CUBEB_DEVICE_FMT_S16LE = 0x0010,
CUBEB_DEVICE_FMT_S16BE = 0x0020,
CUBEB_DEVICE_FMT_F32LE = 0x1000,
CUBEB_DEVICE_FMT_F32BE = 0x2000,
}
}
#[cfg(target_endian = "big")]
pub const CUBEB_DEVICE_FMT_S16NE: cubeb_device_fmt = CUBEB_DEVICE_FMT_S16BE;
#[cfg(target_endian = "big")]
pub const CUBEB_DEVICE_FMT_F32NE: cubeb_device_fmt = CUBEB_DEVICE_FMT_F32BE;
#[cfg(target_endian = "little")]
pub const CUBEB_DEVICE_FMT_S16NE: cubeb_device_fmt = CUBEB_DEVICE_FMT_S16LE;
#[cfg(target_endian = "little")]
pub const CUBEB_DEVICE_FMT_F32NE: cubeb_device_fmt = CUBEB_DEVICE_FMT_F32LE;
pub const CUBEB_DEVICE_FMT_S16_MASK: cubeb_device_fmt = (CUBEB_DEVICE_FMT_S16LE | CUBEB_DEVICE_FMT_S16BE);
pub const CUBEB_DEVICE_FMT_F32_MASK: cubeb_device_fmt = (CUBEB_DEVICE_FMT_F32LE | CUBEB_DEVICE_FMT_F32BE);
pub const CUBEB_DEVICE_FMT_ALL: cubeb_device_fmt = (CUBEB_DEVICE_FMT_S16_MASK | CUBEB_DEVICE_FMT_F32_MASK);
cubeb_enum! {
pub enum cubeb_device_pref {
CUBEB_DEVICE_PREF_NONE = 0x00,
CUBEB_DEVICE_PREF_MULTIMEDIA = 0x01,
CUBEB_DEVICE_PREF_VOICE = 0x02,
CUBEB_DEVICE_PREF_NOTIFICATION = 0x04,
CUBEB_DEVICE_PREF_ALL = 0x0F,
}
}
#[repr(C)]
#[derive(Debug)]
pub struct cubeb_device_info {
pub devid: cubeb_devid,
pub device_id: *const c_char,
pub friendly_name: *const c_char,
pub group_id: *const c_char,
pub vendor_name: *const c_char,
pub device_type: cubeb_device_type,
pub state: cubeb_device_state,
pub preferred: cubeb_device_pref,
pub format: cubeb_device_fmt,
pub default_format: cubeb_device_fmt,
pub max_channels: c_uint,
pub default_rate: c_uint,
pub max_rate: c_uint,
pub min_rate: c_uint,
pub latency_lo: c_uint,
pub latency_hi: c_uint
}
#[repr(C)]
#[derive(Debug)]
pub struct cubeb_device_collection {
pub device: *const cubeb_device_info,
pub count: usize
}
pub type cubeb_data_callback = extern "C" fn(*mut cubeb_stream,
*mut c_void,
*const c_void,
*mut c_void,
c_long)
-> c_long;
pub type cubeb_state_callback = extern "C" fn(*mut cubeb_stream, *mut c_void, cubeb_state);
pub type cubeb_device_changed_callback = extern "C" fn(*mut c_void);
pub type cubeb_device_collection_changed_callback = extern "C" fn(*mut cubeb, *mut c_void);
pub type cubeb_log_callback = extern "C" fn(*const c_char, ...);
#[cfg(test)]
mod test {
use std::mem::{align_of, size_of};
#[test]
fn test_layout_cubeb_stream_params() {
use super::cubeb_stream_params;
assert_eq!(
size_of::<cubeb_stream_params>(),
20usize,
concat!("Size of: ", stringify!(cubeb_stream_params))
);
assert_eq!(
align_of::<cubeb_stream_params>(),
4usize,
concat!("Alignment of ", stringify!(cubeb_stream_params))
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_stream_params)).format as *const _ as usize },
0usize,
concat!(
"Alignment of field: ",
stringify!(cubeb_stream_params),
"::",
stringify!(format)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_stream_params)).rate as *const _ as usize },
4usize,
concat!(
"Alignment of field: ",
stringify!(cubeb_stream_params),
"::",
stringify!(rate)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_stream_params)).channels as *const _ as usize },
8usize,
concat!(
"Alignment of field: ",
stringify!(cubeb_stream_params),
"::",
stringify!(channels)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_stream_params)).layout as *const _ as usize },
12usize,
concat!(
"Alignment of field: ",
stringify!(cubeb_stream_params),
"::",
stringify!(layout)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_stream_params)).prefs as *const _ as usize },
16usize,
concat!(
"Alignment of field: ",
stringify!(cubeb_stream_params),
"::",
stringify!(prefs)
)
);
}
#[test]
fn test_layout_cubeb_device() {
use super::cubeb_device;
assert_eq!(
size_of::<cubeb_device>(),
2 * size_of::<usize>(),
concat!("Size of: ", stringify!(cubeb_device))
);
assert_eq!(
align_of::<cubeb_device>(),
align_of::<usize>(),
concat!("Alignment of ", stringify!(cubeb_device))
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device)).output_name as *const _ as usize },
0usize,
concat!(
"Alignment of field: ",
stringify!(cubeb_device),
"::",
stringify!(output_name)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device)).input_name as *const _ as usize },
size_of::<usize>(),
concat!(
"Alignment of field: ",
stringify!(cubeb_device),
"::",
stringify!(input_name)
)
);
}
#[test]
fn test_layout_cubeb_device_info() {
use super::cubeb_device_info;
let psize: usize = size_of::<usize>();
assert_eq!(
size_of::<cubeb_device_info>(),
(5 * psize + 44 + psize - 1) / psize * psize,
concat!("Size of: ", stringify!(cubeb_device_info))
);
assert_eq!(
align_of::<cubeb_device_info>(),
align_of::<usize>(),
concat!("Alignment of ", stringify!(cubeb_device_info))
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).devid as *const _ as usize },
0usize,
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(devid)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).device_id as *const _ as usize },
size_of::<usize>(),
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(device_id)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).friendly_name as *const _ as usize },
2 * size_of::<usize>(),
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(friendly_name)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).group_id as *const _ as usize },
3 * size_of::<usize>(),
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(group_id)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).vendor_name as *const _ as usize },
4 * size_of::<usize>(),
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(vendor_name)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).device_type as *const _ as usize },
5 * size_of::<usize>() + 0,
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(type_)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).state as *const _ as usize },
5 * size_of::<usize>() + 4,
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(state)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).preferred as *const _ as usize },
5 * size_of::<usize>() + 8,
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(preferred)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).format as *const _ as usize },
5 * size_of::<usize>() + 12,
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(format)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).default_format as *const _ as usize },
5 * size_of::<usize>() + 16,
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(default_format)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).max_channels as *const _ as usize },
5 * size_of::<usize>() + 20,
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(max_channels)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).default_rate as *const _ as usize },
5 * size_of::<usize>() + 24,
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(default_rate)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).max_rate as *const _ as usize },
5 * size_of::<usize>() + 28,
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(max_rate)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).min_rate as *const _ as usize },
5 * size_of::<usize>() + 32,
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(min_rate)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).latency_lo as *const _ as usize },
5 * size_of::<usize>() + 36,
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(latency_lo)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_info)).latency_hi as *const _ as usize },
5 * size_of::<usize>() + 40,
concat!(
"Alignment of field: ",
stringify!(cubeb_device_info),
"::",
stringify!(latency_hi)
)
);
}
#[test]
fn test_layout_cubeb_device_collection() {
use super::cubeb_device_collection;
assert_eq!(
size_of::<cubeb_device_collection>(),
2 * size_of::<usize>(),
concat!("Size of: ", stringify!(cubeb_device_collection))
);
assert_eq!(
align_of::<cubeb_device_collection>(),
align_of::<usize>(),
concat!("Alignment of ", stringify!(cubeb_device_collection))
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_collection)).device as *const _ as usize },
0usize,
concat!(
"Alignment of field: ",
stringify!(cubeb_device_collection),
"::",
stringify!(device)
)
);
assert_eq!(
unsafe { &(*(0 as *const cubeb_device_collection)).count as *const _ as usize },
size_of::<usize>(),
concat!(
"Alignment of field: ",
stringify!(cubeb_device_collection),
"::",
stringify!(count)
)
);
}
}

View File

@ -1,617 +0,0 @@
// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
#[macro_use]
extern crate bitflags;
pub mod ffi;
pub mod binding;
mod error;
mod util;
use binding::Binding;
pub use error::Error;
use std::{marker, ptr, str};
use util::opt_bytes;
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
pub enum SampleFormat {
S16LE,
S16BE,
S16NE,
Float32LE,
Float32BE,
Float32NE
}
impl From<ffi::cubeb_sample_format> for SampleFormat {
fn from(x: ffi::cubeb_sample_format) -> SampleFormat {
match x {
ffi::CUBEB_SAMPLE_S16LE => SampleFormat::S16LE,
ffi::CUBEB_SAMPLE_S16BE => SampleFormat::S16BE,
ffi::CUBEB_SAMPLE_FLOAT32LE => SampleFormat::Float32LE,
ffi::CUBEB_SAMPLE_FLOAT32BE => SampleFormat::Float32BE,
// TODO: Implement TryFrom
_ => SampleFormat::S16NE,
}
}
}
/// An opaque handle used to refer to a particular input or output device
/// across calls.
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
pub struct DeviceId {
raw: ffi::cubeb_devid
}
impl Binding for DeviceId {
type Raw = ffi::cubeb_devid;
unsafe fn from_raw(raw: Self::Raw) -> DeviceId {
DeviceId {
raw: raw
}
}
fn raw(&self) -> Self::Raw {
self.raw
}
}
impl Default for DeviceId {
fn default() -> Self {
DeviceId {
raw: ptr::null()
}
}
}
/// Level (verbosity) of logging for a particular cubeb context.
#[derive(PartialEq, Eq, Clone, Debug, Copy, PartialOrd, Ord)]
pub enum LogLevel {
/// Logging disabled
Disabled,
/// Logging lifetime operation (creation/destruction).
Normal,
/// Verbose logging of callbacks, can have performance implications.
Verbose
}
/// SMPTE channel layout (also known as wave order)
///
/// ---------------------------------------------------
/// Name | Channels
/// ---------------------------------------------------
/// DUAL-MONO | L R
/// DUAL-MONO-LFE | L R LFE
/// MONO | M
/// MONO-LFE | M LFE
/// STEREO | L R
/// STEREO-LFE | L R LFE
/// 3F | L R C
/// 3F-LFE | L R C LFE
/// 2F1 | L R S
/// 2F1-LFE | L R LFE S
/// 3F1 | L R C S
/// 3F1-LFE | L R C LFE S
/// 2F2 | L R LS RS
/// 2F2-LFE | L R LFE LS RS
/// 3F2 | L R C LS RS
/// 3F2-LFE | L R C LFE LS RS
/// 3F3R-LFE | L R C LFE RC LS RS
/// 3F4-LFE | L R C LFE RLS RRS LS RS
/// ---------------------------------------------------
///
/// The abbreviation of channel name is defined in following table:
/// ---------------------------
/// Abbr | Channel name
/// ---------------------------
/// M | Mono
/// L | Left
/// R | Right
/// C | Center
/// LS | Left Surround
/// RS | Right Surround
/// RLS | Rear Left Surround
/// RC | Rear Center
/// RRS | Rear Right Surround
/// LFE | Low Frequency Effects
/// ---------------------------
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
pub enum ChannelLayout {
/// Indicate the speaker's layout is undefined.
Undefined,
DualMono,
DualMonoLfe,
Mono,
MonoLfe,
Stereo,
StereoLfe,
Layout3F,
Layout3FLfe,
Layout2F1,
Layout2F1Lfe,
Layout3F1,
Layout3F1Lfe,
Layout2F2,
Layout2F2Lfe,
Layout3F2,
Layout3F2Lfe,
Layout3F3RLfe,
Layout3F4Lfe
}
impl From<ffi::cubeb_channel_layout> for ChannelLayout {
fn from(x: ffi::cubeb_channel_layout) -> ChannelLayout {
match x {
ffi::CUBEB_LAYOUT_DUAL_MONO => ChannelLayout::DualMono,
ffi::CUBEB_LAYOUT_DUAL_MONO_LFE => ChannelLayout::DualMonoLfe,
ffi::CUBEB_LAYOUT_MONO => ChannelLayout::Mono,
ffi::CUBEB_LAYOUT_MONO_LFE => ChannelLayout::MonoLfe,
ffi::CUBEB_LAYOUT_STEREO => ChannelLayout::Stereo,
ffi::CUBEB_LAYOUT_STEREO_LFE => ChannelLayout::StereoLfe,
ffi::CUBEB_LAYOUT_3F => ChannelLayout::Layout3F,
ffi::CUBEB_LAYOUT_3F_LFE => ChannelLayout::Layout3FLfe,
ffi::CUBEB_LAYOUT_2F1 => ChannelLayout::Layout2F1,
ffi::CUBEB_LAYOUT_2F1_LFE => ChannelLayout::Layout2F1Lfe,
ffi::CUBEB_LAYOUT_3F1 => ChannelLayout::Layout3F1,
ffi::CUBEB_LAYOUT_3F1_LFE => ChannelLayout::Layout3F1Lfe,
ffi::CUBEB_LAYOUT_2F2 => ChannelLayout::Layout2F2,
ffi::CUBEB_LAYOUT_2F2_LFE => ChannelLayout::Layout2F2Lfe,
ffi::CUBEB_LAYOUT_3F2 => ChannelLayout::Layout3F2,
ffi::CUBEB_LAYOUT_3F2_LFE => ChannelLayout::Layout3F2Lfe,
ffi::CUBEB_LAYOUT_3F3R_LFE => ChannelLayout::Layout3F3RLfe,
ffi::CUBEB_LAYOUT_3F4_LFE => ChannelLayout::Layout3F4Lfe,
// TODO: Implement TryFrom
// Everything else is just undefined.
_ => ChannelLayout::Undefined,
}
}
}
/// Miscellaneous stream preferences.
bitflags! {
pub struct StreamPrefs: ffi::cubeb_stream_prefs {
const STREAM_PREF_NONE = ffi::CUBEB_STREAM_PREF_NONE;
const STREAM_PREF_LOOPBACK = ffi::CUBEB_STREAM_PREF_LOOPBACK;
}
}
/// Stream format initialization parameters.
#[derive(Clone, Copy)]
pub struct StreamParams {
raw: ffi::cubeb_stream_params
}
impl StreamParams {
pub fn format(&self) -> SampleFormat {
macro_rules! check( ($($raw:ident => $real:ident),*) => (
$(if self.raw.format == ffi::$raw {
SampleFormat::$real
}) else *
else {
panic!("unknown sample format: {}", self.raw.format)
}
) );
check!(
CUBEB_SAMPLE_S16LE => S16LE,
CUBEB_SAMPLE_S16BE => S16BE,
CUBEB_SAMPLE_FLOAT32LE => Float32LE,
CUBEB_SAMPLE_FLOAT32BE => Float32BE
)
}
pub fn rate(&self) -> u32 {
self.raw.rate as u32
}
pub fn channels(&self) -> u32 {
self.raw.channels as u32
}
pub fn layout(&self) -> ChannelLayout {
macro_rules! check( ($($raw:ident => $real:ident),*) => (
$(if self.raw.layout == ffi::$raw {
ChannelLayout::$real
}) else *
else {
panic!("unknown channel layout: {}", self.raw.layout)
}
) );
check!(CUBEB_LAYOUT_UNDEFINED => Undefined,
CUBEB_LAYOUT_DUAL_MONO => DualMono,
CUBEB_LAYOUT_DUAL_MONO_LFE => DualMonoLfe,
CUBEB_LAYOUT_MONO => Mono,
CUBEB_LAYOUT_MONO_LFE => MonoLfe,
CUBEB_LAYOUT_STEREO => Stereo,
CUBEB_LAYOUT_STEREO_LFE => StereoLfe,
CUBEB_LAYOUT_3F => Layout3F,
CUBEB_LAYOUT_3F_LFE => Layout3FLfe,
CUBEB_LAYOUT_2F1 => Layout2F1,
CUBEB_LAYOUT_2F1_LFE => Layout2F1Lfe,
CUBEB_LAYOUT_3F1 => Layout3F1,
CUBEB_LAYOUT_3F1_LFE => Layout3F1Lfe,
CUBEB_LAYOUT_2F2 => Layout2F2,
CUBEB_LAYOUT_2F2_LFE => Layout2F2Lfe,
CUBEB_LAYOUT_3F2 => Layout3F2,
CUBEB_LAYOUT_3F2_LFE => Layout3F2Lfe,
CUBEB_LAYOUT_3F3R_LFE => Layout3F3RLfe,
CUBEB_LAYOUT_3F4_LFE => Layout3F4Lfe)
}
pub fn prefs(&self) -> StreamPrefs {
StreamPrefs::from_bits(self.raw.prefs).unwrap()
}
}
impl Binding for StreamParams {
type Raw = *const ffi::cubeb_stream_params;
unsafe fn from_raw(raw: *const ffi::cubeb_stream_params) -> Self {
Self {
raw: *raw
}
}
fn raw(&self) -> Self::Raw {
&self.raw as Self::Raw
}
}
/// Audio device description
#[derive(Copy, Clone, Debug)]
pub struct Device<'a> {
raw: *const ffi::cubeb_device,
_marker: marker::PhantomData<&'a ffi::cubeb_device>
}
impl<'a> Device<'a> {
/// Gets the output device name.
///
/// May return `None` if there is no output device.
pub fn output_name(&self) -> Option<&str> {
self.output_name_bytes().map(|b| str::from_utf8(b).unwrap())
}
pub fn output_name_bytes(&self) -> Option<&[u8]> {
unsafe { opt_bytes(self, (*self.raw).output_name) }
}
/// Gets the input device name.
///
/// May return `None` if there is no input device.
pub fn input_name(&self) -> Option<&str> {
self.input_name_bytes().map(|b| str::from_utf8(b).unwrap())
}
pub fn input_name_bytes(&self) -> Option<&[u8]> {
unsafe { opt_bytes(self, (*self.raw).input_name) }
}
}
impl<'a> Binding for Device<'a> {
type Raw = *const ffi::cubeb_device;
unsafe fn from_raw(raw: *const ffi::cubeb_device) -> Device<'a> {
Device {
raw: raw,
_marker: marker::PhantomData
}
}
fn raw(&self) -> *const ffi::cubeb_device {
self.raw
}
}
/// Stream states signaled via `state_callback`.
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
pub enum State {
/// Stream started.
Started,
/// Stream stopped.
Stopped,
/// Stream drained.
Drained,
/// Stream disabled due to error.
Error
}
/// An enumeration of possible errors that can happen when working with cubeb.
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
pub enum ErrorCode {
/// GenericError
Error,
/// Requested format is invalid
InvalidFormat,
/// Requested parameter is invalid
InvalidParameter,
/// Requested operation is not supported
NotSupported,
/// Requested device is unavailable
DeviceUnavailable
}
/// Whether a particular device is an input device (e.g. a microphone), or an
/// output device (e.g. headphones).
bitflags! {
pub struct DeviceType: ffi::cubeb_device_type {
const DEVICE_TYPE_UNKNOWN = ffi::CUBEB_DEVICE_TYPE_UNKNOWN as _;
const DEVICE_TYPE_INPUT = ffi::CUBEB_DEVICE_TYPE_INPUT as _;
const DEVICE_TYPE_OUTPUT = ffi::CUBEB_DEVICE_TYPE_OUTPUT as _;
}
}
/// The state of a device.
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
pub enum DeviceState {
/// The device has been disabled at the system level.
Disabled,
/// The device is enabled, but nothing is plugged into it.
Unplugged,
/// The device is enabled.
Enabled
}
/// Architecture specific sample type.
bitflags! {
pub struct DeviceFormat: ffi::cubeb_device_fmt {
const DEVICE_FMT_S16LE = ffi::CUBEB_DEVICE_FMT_S16LE;
const DEVICE_FMT_S16BE = ffi::CUBEB_DEVICE_FMT_S16BE;
const DEVICE_FMT_F32LE = ffi::CUBEB_DEVICE_FMT_F32LE;
const DEVICE_FMT_F32BE = ffi::CUBEB_DEVICE_FMT_F32BE;
}
}
/// Channel type for a `cubeb_stream`. Depending on the backend and platform
/// used, this can control inter-stream interruption, ducking, and volume
/// control.
bitflags! {
pub struct DevicePref: ffi::cubeb_device_pref {
const DEVICE_PREF_NONE = ffi::CUBEB_DEVICE_PREF_NONE;
const DEVICE_PREF_MULTIMEDIA = ffi::CUBEB_DEVICE_PREF_MULTIMEDIA;
const DEVICE_PREF_VOICE = ffi::CUBEB_DEVICE_PREF_VOICE;
const DEVICE_PREF_NOTIFICATION = ffi::CUBEB_DEVICE_PREF_NOTIFICATION;
const DEVICE_PREF_ALL = ffi::CUBEB_DEVICE_PREF_ALL;
}
}
/// This structure holds the characteristics of an input or output
/// audio device. It is obtained using `enumerate_devices`, which
/// returns these structures via `device_collection` and must be
/// destroyed via `device_collection_destroy`.
pub struct DeviceInfo {
raw: ffi::cubeb_device_info
}
impl DeviceInfo {
pub fn raw(&self) -> &ffi::cubeb_device_info {
&self.raw
}
/// Device identifier handle.
pub fn devid(&self) -> DeviceId {
unsafe { Binding::from_raw(self.raw.devid) }
}
/// Device identifier which might be presented in a UI.
pub fn device_id(&self) -> Option<&str> {
self.device_id_bytes().and_then(|s| str::from_utf8(s).ok())
}
pub fn device_id_bytes(&self) -> Option<&[u8]> {
unsafe { opt_bytes(self, self.raw.device_id) }
}
/// Friendly device name which might be presented in a UI.
pub fn friendly_name(&self) -> Option<&str> {
self.friendly_name_bytes().and_then(
|s| str::from_utf8(s).ok()
)
}
pub fn friendly_name_bytes(&self) -> Option<&[u8]> {
unsafe { opt_bytes(self, self.raw.friendly_name) }
}
/// Two devices have the same group identifier if they belong to
/// the same physical device; for example a headset and
/// microphone.
pub fn group_id(&self) -> Option<&str> {
self.group_id_bytes().and_then(|s| str::from_utf8(s).ok())
}
pub fn group_id_bytes(&self) -> Option<&[u8]> {
unsafe { opt_bytes(self, self.raw.group_id) }
}
/// Optional vendor name, may be NULL.
pub fn vendor_name(&self) -> Option<&str> {
self.vendor_name_bytes().and_then(
|s| str::from_utf8(s).ok()
)
}
pub fn vendor_name_bytes(&self) -> Option<&[u8]> {
unsafe { opt_bytes(self, self.raw.vendor_name) }
}
/// Type of device (Input/Output).
pub fn device_type(&self) -> DeviceType {
DeviceType::from_bits_truncate(self.raw.device_type)
}
/// State of device disabled/enabled/unplugged.
pub fn state(&self) -> DeviceState {
let state = self.raw.state;
macro_rules! check( ($($raw:ident => $real:ident),*) => (
$(if state == ffi::$raw {
DeviceState::$real
}) else *
else {
panic!("unknown device state: {}", state)
}
));
check!(CUBEB_DEVICE_STATE_DISABLED => Disabled,
CUBEB_DEVICE_STATE_UNPLUGGED => Unplugged,
CUBEB_DEVICE_STATE_ENABLED => Enabled)
}
/// Preferred device.
pub fn preferred(&self) -> DevicePref {
DevicePref::from_bits(self.raw.preferred).unwrap()
}
/// Sample format supported.
pub fn format(&self) -> DeviceFormat {
DeviceFormat::from_bits(self.raw.format).unwrap()
}
/// The default sample format for this device.
pub fn default_format(&self) -> DeviceFormat {
DeviceFormat::from_bits(self.raw.default_format).unwrap()
}
/// Channels.
pub fn max_channels(&self) -> u32 {
self.raw.max_channels
}
/// Default/Preferred sample rate.
pub fn default_rate(&self) -> u32 {
self.raw.default_rate
}
/// Maximum sample rate supported.
pub fn max_rate(&self) -> u32 {
self.raw.max_rate
}
/// Minimum sample rate supported.
pub fn min_rate(&self) -> u32 {
self.raw.min_rate
}
/// Lowest possible latency in frames.
pub fn latency_lo(&self) -> u32 {
self.raw.latency_lo
}
/// Higest possible latency in frames.
pub fn latency_hi(&self) -> u32 {
self.raw.latency_hi
}
}
pub type Result<T> = ::std::result::Result<T, Error>;
#[cfg(test)]
mod tests {
use binding::Binding;
use std::mem;
#[test]
fn stream_params_raw_channels() {
let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
raw.channels = 2;
let params = unsafe { super::StreamParams::from_raw(&raw as *const _) };
assert_eq!(params.channels(), 2);
}
#[test]
fn stream_params_raw_format() {
let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
macro_rules! check(
($($raw:ident => $real:ident),*) => (
$(raw.format = super::ffi::$raw;
let params = unsafe {
super::StreamParams::from_raw(&raw as *const _)
};
assert_eq!(params.format(), super::SampleFormat::$real);
)*
) );
check!(CUBEB_SAMPLE_S16LE => S16LE,
CUBEB_SAMPLE_S16BE => S16BE,
CUBEB_SAMPLE_FLOAT32LE => Float32LE,
CUBEB_SAMPLE_FLOAT32BE => Float32BE);
}
#[test]
fn stream_params_raw_format_native_endian() {
let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
raw.format = super::ffi::CUBEB_SAMPLE_S16NE;
let params = unsafe { super::StreamParams::from_raw(&raw as *const _) };
assert_eq!(
params.format(),
if cfg!(target_endian = "little") {
super::SampleFormat::S16LE
} else {
super::SampleFormat::S16BE
}
);
raw.format = super::ffi::CUBEB_SAMPLE_FLOAT32NE;
let params = unsafe { super::StreamParams::from_raw(&raw as *const _) };
assert_eq!(
params.format(),
if cfg!(target_endian = "little") {
super::SampleFormat::Float32LE
} else {
super::SampleFormat::Float32BE
}
);
}
#[test]
fn stream_params_raw_layout() {
let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
macro_rules! check(
($($raw:ident => $real:ident),*) => (
$(raw.layout = super::ffi::$raw;
let params = unsafe {
super::StreamParams::from_raw(&raw as *const _)
};
assert_eq!(params.layout(), super::ChannelLayout::$real);
)*
) );
check!(CUBEB_LAYOUT_UNDEFINED => Undefined,
CUBEB_LAYOUT_DUAL_MONO => DualMono,
CUBEB_LAYOUT_DUAL_MONO_LFE => DualMonoLfe,
CUBEB_LAYOUT_MONO => Mono,
CUBEB_LAYOUT_MONO_LFE => MonoLfe,
CUBEB_LAYOUT_STEREO => Stereo,
CUBEB_LAYOUT_STEREO_LFE => StereoLfe,
CUBEB_LAYOUT_3F => Layout3F,
CUBEB_LAYOUT_3F_LFE => Layout3FLfe,
CUBEB_LAYOUT_2F1 => Layout2F1,
CUBEB_LAYOUT_2F1_LFE => Layout2F1Lfe,
CUBEB_LAYOUT_3F1 => Layout3F1,
CUBEB_LAYOUT_3F1_LFE => Layout3F1Lfe,
CUBEB_LAYOUT_2F2 => Layout2F2,
CUBEB_LAYOUT_2F2_LFE => Layout2F2Lfe,
CUBEB_LAYOUT_3F2 => Layout3F2,
CUBEB_LAYOUT_3F2_LFE => Layout3F2Lfe,
CUBEB_LAYOUT_3F3R_LFE => Layout3F3RLfe,
CUBEB_LAYOUT_3F4_LFE => Layout3F4Lfe);
}
#[test]
fn stream_params_raw_rate() {
let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
raw.rate = 44100;
let params = unsafe { super::StreamParams::from_raw(&raw as *const _) };
assert_eq!(params.rate(), 44100);
}
#[test]
fn stream_params_raw_prefs() {
use STREAM_PREF_LOOPBACK;
let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
raw.prefs = STREAM_PREF_LOOPBACK.bits();
let params = unsafe { super::StreamParams::from_raw(&raw as *const _) };
assert_eq!(params.prefs(), STREAM_PREF_LOOPBACK);
}
}

View File

@ -1,15 +0,0 @@
// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license. See the
// accompanying file LICENSE for details.
use std::ffi::CStr;
use std::os::raw::c_char;
pub unsafe fn opt_bytes<T>(_anchor: &T, c: *const c_char) -> Option<&[u8]> {
if c.is_null() {
None
} else {
Some(CStr::from_ptr(c).to_bytes())
}
}

View File

@ -1,34 +0,0 @@
From 1fca45f284d78a8df5e86779aab92173f69557a0 Mon Sep 17 00:00:00 2001
From: Dan Glastonbury <dan.glastonbury@gmail.com>
Date: Mon, 6 Nov 2017 15:00:48 +1000
Subject: remove-cubeb-build.patch
MozReview-Commit-ID: bymdNMfAjE
diff --git a/media/cubeb-rs/cubeb-api/libcubeb-sys/Cargo.toml b/media/cubeb-rs/cubeb-api/libcubeb-sys/Cargo.toml
index 523c352..6ed4d34 100644
--- a/media/cubeb-rs/cubeb-api/libcubeb-sys/Cargo.toml
+++ b/media/cubeb-rs/cubeb-api/libcubeb-sys/Cargo.toml
@@ -6,17 +6,9 @@ repository = "https://github.com/djg/cubeb-rs"
license = "ISC"
description = "Native bindings to the cubeb library"
-links = "cubeb"
-build = "build.rs"
-
[lib]
name = "libcubeb_sys"
path = "lib.rs"
[dependencies]
-cubeb-core = { path = "../../cubeb-core" }
-
-[build-dependencies]
-pkg-config = "0.3"
-cmake = "0.1.2"
-gcc = "0.3"
+cubeb-core = { path = "../../cubeb-core" }
\ No newline at end of file
--
2.10.2

View File

@ -1,35 +0,0 @@
# Usage: sh update.sh <upstream_src_directory>
set -e
cp -p $1/LICENSE .
cp -p $1/Cargo.toml .
for dir in cubeb-api cubeb-backend cubeb-core; do
test -d $dir/src || mkdir -p $dir/src
cp -pr $1/$dir/Cargo.toml $dir/
cp -pr $1/$dir/src/* $dir/src/
done
test -d cubeb-api/libcubeb-sys || mkdir -p cubeb-api/libcubeb-sys
cp -p $1/cubeb-api/libcubeb-sys/Cargo.toml cubeb-api/libcubeb-sys/
cp -p $1/cubeb-api/libcubeb-sys/lib.rs cubeb-api/libcubeb-sys/
if [ -d $1/.git ]; then
rev=$(cd $1 && git rev-parse --verify HEAD)
date=$(cd $1 && git show -s --format=%ci HEAD)
dirty=$(cd $1 && git diff-index --name-only HEAD)
fi
if [ -n "$rev" ]; then
version=$rev
if [ -n "$dirty" ]; then
version=$version-dirty
echo "WARNING: updating from a dirty git repository."
fi
sed -i.bak -e "/The git commit ID used was/ s/[0-9a-f]\{40\}\(-dirty\)\{0,1\} .\{1,100\}/$version ($date)/" README_MOZILLA
rm README_MOZILLA.bak
else
echo "Remember to update README_MOZILLA with the version details."
fi
echo "Applying remote-cubeb-build.patch on top of $rev"
patch -p3 < remove-cubeb-build.patch