cubeb-sys 0.34.1

Native bindings to the cubeb library
Documentation
// Copyright © 2017-2018 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details.

use callbacks::cubeb_device_collection_changed_callback;
use context::cubeb;
use std::ffi::CStr;
use std::os::raw::{c_char, c_int, c_uint, c_void};
use std::{fmt, mem, ptr};

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;

fn fmt_device_fmt(f: &cubeb_device_fmt) -> &'static str {
    match *f {
        CUBEB_DEVICE_FMT_S16LE => "S16LE",
        CUBEB_DEVICE_FMT_S16BE => "S16BE",
        CUBEB_DEVICE_FMT_F32LE => "F32LE",
        CUBEB_DEVICE_FMT_F32BE => "F32BE",
        CUBEB_DEVICE_FMT_S16_MASK => "S16LE | S16BE",
        CUBEB_DEVICE_FMT_F32_MASK => "F32LE | F32BE",
        CUBEB_DEVICE_FMT_ALL => "S16LE | S16BE | F32LE | F32BE",
        _ => "Unexpected device format",
    }
}

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,
    }
}

fn fmt_device_pref(p: &cubeb_device_pref) -> &'static str {
    match *p {
        CUBEB_DEVICE_PREF_NONE => "None",
        CUBEB_DEVICE_PREF_MULTIMEDIA => "Multimedia",
        CUBEB_DEVICE_PREF_VOICE => "Voice",
        CUBEB_DEVICE_PREF_NOTIFICATION => "Notification",
        CUBEB_DEVICE_PREF_ALL => "All",
        _ => "Unexpected",
    }
}

cubeb_enum! {
    pub enum cubeb_device_state {
        CUBEB_DEVICE_STATE_DISABLED,
        CUBEB_DEVICE_STATE_UNPLUGGED,
        CUBEB_DEVICE_STATE_ENABLED,
    }
}

fn fmt_device_state(s: &cubeb_device_state) -> &'static str {
    match *s {
        CUBEB_DEVICE_STATE_DISABLED => "Disabled",
        CUBEB_DEVICE_STATE_UNPLUGGED => "Unplugged",
        CUBEB_DEVICE_STATE_ENABLED => "Enabled",
        _ => "Unexpected",
    }
}

cubeb_enum! {
    pub enum cubeb_device_type {
        CUBEB_DEVICE_TYPE_UNKNOWN,
        CUBEB_DEVICE_TYPE_INPUT,
        CUBEB_DEVICE_TYPE_OUTPUT,
    }
}

fn fmt_device_type(t: &cubeb_device_type) -> &'static str {
    match *t {
        CUBEB_DEVICE_TYPE_UNKNOWN => "Unknown",
        CUBEB_DEVICE_TYPE_INPUT => "Input",
        CUBEB_DEVICE_TYPE_OUTPUT => "Output",
        t if t == CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT => "Input+Output",
        _ => "Unexpected",
    }
}

pub type cubeb_devid = *const c_void;

#[repr(C)]
pub struct cubeb_device {
    pub output_name: *mut c_char,
    pub input_name: *mut c_char,
}

// Explicit Debug impl to work around bug in ctest
impl Default for cubeb_device {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

impl fmt::Debug for cubeb_device {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("cubeb_device")
            .field("output_name", &self.output_name)
            .field("input_name", &self.input_name)
            .finish()
    }
}

#[repr(C)]
pub struct cubeb_device_collection {
    pub device: *mut cubeb_device_info,
    pub count: usize,
}

impl Default for cubeb_device_collection {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

impl fmt::Debug for cubeb_device_collection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let devices = ptr::slice_from_raw_parts(self.device, self.count);
        let devices = unsafe { &*devices };
        let mut dbg = f.debug_list();
        for d in devices {
            dbg.entry(d);
        }
        dbg.finish()
    }
}

#[repr(C)]
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,
}

impl Default for cubeb_device_info {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

impl fmt::Debug for cubeb_device_info {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fn optional_c_str(c_str: *const c_char) -> Option<*const c_char> {
            (unsafe { c_str.as_ref() }).map(ptr::from_ref)
        }
        f.debug_struct("cubeb_device_info")
            .field("devid", &(self.devid as u32))
            .field(
                "device_id",
                &optional_c_str(self.device_id).map(|p| unsafe { CStr::from_ptr(p) }),
            )
            .field(
                "friendly_name",
                &optional_c_str(self.friendly_name).map(|p| unsafe { CStr::from_ptr(p) }),
            )
            .field(
                "group_id",
                &optional_c_str(self.group_id).map(|p| unsafe { CStr::from_ptr(p) }),
            )
            .field(
                "vendor_name",
                &optional_c_str(self.vendor_name).map(|p| unsafe { CStr::from_ptr(p) }),
            )
            .field("device_type", &fmt_device_type(&self.device_type))
            .field("state", &fmt_device_state(&self.state))
            .field("preferred", &fmt_device_pref(&self.preferred))
            .field("format", &fmt_device_fmt(&self.format))
            .field("default_format", &fmt_device_fmt(&self.default_format))
            .field("max_channels", &self.max_channels)
            .field("default_rate", &self.default_rate)
            .field("max_rate", &self.max_rate)
            .field("min_rate", &self.min_rate)
            .field("latency_lo", &self.latency_lo)
            .field("latency_hi", &self.latency_hi)
            .finish()
    }
}

extern "C" {
    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;
}