Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 11 additions & 15 deletions cubeb-api/examples/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
use cubeb::{Context, Result};
use std::env;
use std::ffi::CString;
use std::io::{self, Write};

pub fn init<T: Into<Vec<u8>>>(ctx_name: T) -> Result<Context> {
let backend = match env::var("CUBEB_BACKEND") {
Ok(s) => Some(s),
Err(_) => None,
};
// allow user to select backend via env var
let backend = env::var("CUBEB_BACKEND").ok();

// a little dance to convert to `Option<&CStr>`
let backend_c = backend.clone().map(|s| CString::new(s).unwrap());
let backend_c = backend_c.as_ref().map(|c| c.as_c_str());

// setup context
let ctx_name = CString::new(ctx_name).unwrap();
let ctx = Context::init(Some(ctx_name.as_c_str()), None);
let ctx = Context::init(Some(ctx_name.as_c_str()), backend_c);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a small functional change, we actually try to select the provided backend.
FYI, on my Mac, I can only get audiounit to work, is audiounit-rust not provided by default?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not by default no, cubeb can be built without a rust toolchain. It's at https://github.com/mozilla/cubeb-coreaudio-rs/, https://github.com/mozilla/cubeb-coreaudio-rs/blob/trailblazer/build-audiounit-rust-in-cubeb.sh has the steps to build it, but really it's just cloning it in the src/ directory of the cubeb dir, and building cubeb with -DBUILD_RUST_LIBS="ON"


// alert when the prefered backend was not available
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();
eprintln!("Requested backend `{}', got `{}'", backend, ctx_backend);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions cubeb-api/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use std::ffi::CString;
use {Context, Result};

/// Initialize a new cubeb [`Context`]
///
/// See the documentation for [`Context::init`] for more info
pub fn init<T: Into<Vec<u8>>>(name: T) -> Result<Context> {
let name = CString::new(name)?;

Expand Down
18 changes: 18 additions & 0 deletions cubeb-core/src/builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@
use ffi;
use {ChannelLayout, SampleFormat, StreamParams, StreamPrefs};

/// Builder for stream format initialization parameters
///
/// ```
/// let params = cubeb_core::StreamParamsBuilder::new()
/// .format(cubeb_core::SampleFormat::Float32LE)
/// .rate(44_100)
/// .channels(1)
/// .layout(cubeb_core::ChannelLayout::MONO)
/// .prefs(cubeb_core::StreamPrefs::NONE)
/// .take();
/// ```
#[derive(Debug)]
pub struct StreamParamsBuilder(ffi::cubeb_stream_params);

Expand All @@ -24,31 +34,39 @@ impl StreamParamsBuilder {
Default::default()
}

/// Requested sample format. One of [`SampleFormat`]
pub fn format(mut self, format: SampleFormat) -> Self {
self.0.format = format.into();
self
}

/// Requested sample rate. Valid range is [1000, 192000].
pub fn rate(mut self, rate: u32) -> Self {
self.0.rate = rate;
self
}

/// Requested channel count. Valid range is [1, 8].
pub fn channels(mut self, channels: u32) -> Self {
self.0.channels = channels;
self
}

/// Requested channel layout.
///
/// This must be consistent with the provided channels. [`ChannelLayout::UNDEFINED`] if unknown
pub fn layout(mut self, layout: ChannelLayout) -> Self {
self.0.layout = layout.into();
self
}

/// Requested preferences (loopback, voice, device switching)
pub fn prefs(mut self, prefs: StreamPrefs) -> Self {
self.0.prefs = prefs.bits();
self
}

/// Build the stream initialization parameters
pub fn take(&self) -> StreamParams {
StreamParams::from(self.0)
}
Expand Down
1 change: 0 additions & 1 deletion cubeb-core/src/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use ffi;
bitflags! {
/// Some common layout definitions
pub struct ChannelLayout: ffi::cubeb_channel_layout {
///
const FRONT_LEFT = ffi::CHANNEL_FRONT_LEFT;
const FRONT_RIGHT = ffi::CHANNEL_FRONT_RIGHT;
const FRONT_CENTER = ffi::CHANNEL_FRONT_CENTER;
Expand Down
86 changes: 86 additions & 0 deletions cubeb-core/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,73 @@ macro_rules! as_ptr {
ffi_type_heap! {
type CType = ffi::cubeb;
fn drop = ffi::cubeb_destroy;

/// Application context
///
/// # Usage
///
/// ```no_run
/// use cubeb_core::{Context, Result};
/// use std::env;
/// use std::ffi::CString;
///
/// // allow user to select backend via env var
/// let backend = env::var("CUBEB_BACKEND").ok();
///
/// // a little dance to convert to `Option<&CStr>`
/// let backend_c = backend.clone().map(|s| CString::new(s).unwrap());
/// let backend_c = backend_c.as_ref().map(|c| c.as_c_str());
///
/// // setup context
/// let ctx_name = CString::new("Cubeb test context").unwrap();
/// let ctx = Context::init(Some(ctx_name.as_c_str()), backend_c);
///
/// // alert when the prefered backend was not available
/// if let Ok(ref ctx) = ctx {
/// if let Some(ref backend) = backend {
/// let ctx_backend = ctx.backend_id();
/// if backend != ctx_backend {
/// eprintln!("Requested backend `{}', got `{}'", backend, ctx_backend);
/// }
/// }
/// }
/// ```
///
/// See [`Context::init`] for allowed values for the backend selection.
pub struct Context;

/// Reference to a [`Context`]
pub struct ContextRef;
}

impl Context {
/// Initialize an application context.
///
/// This will perform any library or application scoped initialization.
///
/// # Arguments
///
/// - context_name (optional): A name for the context. Depending on the platform this can
/// appear in different locations.
/// - backend_name (optional): The name of the cubeb backend user desires to select. Accepted
/// values are listed below. When `None`, a default ordering is used for backend choice.
///
/// Available backend names:
/// - pulse
/// - pulse-rust
/// - jack
/// - alsa
/// - audiounit
/// - audiounit-rust
/// - wasapi
/// - winmm
/// - sndio
/// - sun
/// - opensl
/// - oss
/// - aaudio
/// - audiotrack
/// - kai
pub fn init(context_name: Option<&CStr>, backend_name: Option<&CStr>) -> Result<Context> {
let mut context: *mut ffi::cubeb = ptr::null_mut();
let context_name = as_ptr!(context_name);
Expand All @@ -36,14 +98,17 @@ impl Context {
}

impl ContextRef {
/// String identifying this context's current backend
pub fn backend_id(&self) -> &str {
str::from_utf8(self.backend_id_bytes()).unwrap()
}

/// Raw bytes identifying this context's current backend
pub fn backend_id_bytes(&self) -> &[u8] {
unsafe { opt_bytes(ffi::cubeb_get_backend_id(self.as_ptr())).unwrap() }
}

/// The maximum possible number of channels.
pub fn max_channel_count(&self) -> Result<u32> {
let mut channel_count = 0u32;
unsafe {
Expand All @@ -55,6 +120,13 @@ impl ContextRef {
Ok(channel_count)
}

/// The minimal supported latency value, in frames
///
/// This is guaranteed to work when creating a stream for the specified sample rate. This is
/// platform, hardware and backend dependent.
///
/// On some backends, the minimum achievable latency depends on the characteristics of the
/// stream.
pub fn min_latency(&self, params: &StreamParamsRef) -> Result<u32> {
let mut latency = 0u32;
unsafe {
Expand All @@ -67,6 +139,10 @@ impl ContextRef {
Ok(latency)
}

/// The preferred sample rate for this backend
///
/// This is hardware and platform dependent, and can avoid resampling, and/or trigger
/// fastpaths.
pub fn preferred_sample_rate(&self) -> Result<u32> {
let mut rate = 0u32;
unsafe {
Expand All @@ -78,6 +154,10 @@ impl ContextRef {
Ok(rate)
}

/// Initialize an application context.
///
/// For a safe variant, have a look at the `StreamBuilder` in `cubeb_api`
///
/// # Safety
///
/// This function is unsafe because it dereferences the given `data_callback`, `state_callback`, and `user_ptr` pointers.
Expand Down Expand Up @@ -117,6 +197,9 @@ impl ContextRef {
Ok(Stream::from_ptr(stm))
}

/// Returns enumerated devices
///
/// See `examples/devices.rs` in `cubeb_api` for example usage
pub fn enumerate_devices(&self, devtype: DeviceType) -> Result<DeviceCollection> {
let mut coll = ffi::cubeb_device_collection::default();
unsafe {
Expand All @@ -129,6 +212,9 @@ impl ContextRef {
Ok(DeviceCollection::init_with_ctx(self, coll))
}

/// Registers a callback which is called when the system detects a new device or a device is
/// removed.
///
/// # Safety
///
/// This function is unsafe because it dereferences the given `callback` and `user_ptr` pointers.
Expand Down
15 changes: 10 additions & 5 deletions cubeb-core/src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,13 @@ bitflags! {
pub type DeviceId = ffi::cubeb_devid;

ffi_type_heap! {
/// Audio device description
type CType = ffi::cubeb_device;

/// Audio device description
#[derive(Debug)]
pub struct Device;

/// Reference to a [`Device`]
pub struct DeviceRef;
}

Expand Down Expand Up @@ -92,12 +95,14 @@ impl DeviceRef {
}

ffi_type_stack! {
/// 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`.
type CType = ffi::cubeb_device_info;

/// Characteristics of an input or output audio device.
///
/// It is obtained using [`enumerate_devices`](crate::ContextRef::enumerate_devices).
pub struct DeviceInfo;

/// Reference to a [`DeviceInfo`]
pub struct DeviceInfoRef;
}

Expand Down
3 changes: 2 additions & 1 deletion cubeb-core/src/device_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use ffi_types;
use std::{ops, slice};
use {ContextRef, DeviceInfo};

/// A collection of `DeviceInfo` used by libcubeb
type CType = ffi::cubeb_device_collection;

/// A collection of `DeviceInfo` used by libcubeb
#[derive(Debug)]
pub struct DeviceCollection<'ctx>(CType, &'ctx ContextRef);

Expand Down Expand Up @@ -52,6 +52,7 @@ impl<'ctx> ::std::convert::AsRef<DeviceCollectionRef> for DeviceCollection<'ctx>
}
}

/// Reference to a [`DeviceCollection`]
pub struct DeviceCollectionRef(ffi_types::Opaque);

impl DeviceCollectionRef {
Expand Down
1 change: 1 addition & 0 deletions cubeb-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub enum ErrorCode {
DeviceUnavailable,
}

/// Possible errors that can happen when working with cubeb.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Error {
code: ErrorCode,
Expand Down
7 changes: 7 additions & 0 deletions cubeb-core/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@

use ffi;

/// Sample format enumeration
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
pub enum SampleFormat {
/// 16bit signed integer little endian
S16LE,
/// 16bit signed integer big endian
S16BE,
/// 32bit float little endian
Float32LE,
/// 32bit float big endian
Float32BE,
// Maps to the platform native endian
/// 16bit signed integer native endian - maps to flatform specific type
S16NE,
/// 32bit float native endian - maps to flatform specific type
Float32NE,
}

Expand Down
1 change: 1 addition & 0 deletions cubeb-core/src/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ impl From<ffi::cubeb_log_level> for LogLevel {
}
}

/// Check if logging is enabled (disabled by default)
pub fn log_enabled() -> bool {
unsafe { ffi::g_cubeb_log_level != LogLevel::Disabled as _ }
}
Expand Down
Loading