#![recursion_limit = "512"]
#[cfg(target_os = "windows")]
#[macro_use]
extern crate lazy_static;
#[cfg(target_os = "emscripten")]
#[macro_use]
extern crate stdweb;
pub use samples_formats::{Sample, SampleFormat};
#[cfg(not(any(windows, target_os = "linux", target_os = "freebsd",
target_os = "macos", target_os = "ios", target_os = "emscripten")))]
use null as cpal_impl;
use std::error::Error;
use std::fmt;
use std::iter;
use std::ops::{Deref, DerefMut};
mod null;
mod samples_formats;
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
#[path = "alsa/mod.rs"]
mod cpal_impl;
#[cfg(windows)]
#[path = "wasapi/mod.rs"]
mod cpal_impl;
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[path = "coreaudio/mod.rs"]
mod cpal_impl;
#[cfg(target_os = "emscripten")]
#[path = "emscripten/mod.rs"]
mod cpal_impl;
#[derive(Clone, PartialEq, Eq)]
pub struct Device(cpal_impl::Device);
pub struct EventLoop(cpal_impl::EventLoop);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StreamId(cpal_impl::StreamId);
pub type ChannelCount = u16;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct SampleRate(pub u32);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Format {
pub channels: ChannelCount,
pub sample_rate: SampleRate,
pub data_type: SampleFormat,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SupportedFormat {
pub channels: ChannelCount,
pub min_sample_rate: SampleRate,
pub max_sample_rate: SampleRate,
pub data_type: SampleFormat,
}
pub enum StreamData<'a> {
Input {
buffer: UnknownTypeInputBuffer<'a>,
},
Output {
buffer: UnknownTypeOutputBuffer<'a>,
},
}
pub struct InputBuffer<'a, T: 'a>
where
T: Sample,
{
buffer: Option<cpal_impl::InputBuffer<'a, T>>,
}
#[must_use]
pub struct OutputBuffer<'a, T: 'a>
where
T: Sample,
{
target: Option<cpal_impl::OutputBuffer<'a, T>>,
}
pub enum UnknownTypeInputBuffer<'a> {
U16(InputBuffer<'a, u16>),
I16(InputBuffer<'a, i16>),
F32(InputBuffer<'a, f32>),
}
pub enum UnknownTypeOutputBuffer<'a> {
U16(OutputBuffer<'a, u16>),
I16(OutputBuffer<'a, i16>),
F32(OutputBuffer<'a, f32>),
}
pub struct Devices(cpal_impl::Devices);
pub type InputDevices = iter::Filter<Devices, fn(&Device) -> bool>;
pub type OutputDevices = iter::Filter<Devices, fn(&Device) -> bool>;
pub struct SupportedInputFormats(cpal_impl::SupportedInputFormats);
pub struct SupportedOutputFormats(cpal_impl::SupportedOutputFormats);
#[derive(Debug)]
pub enum FormatsEnumerationError {
DeviceNotAvailable,
}
#[derive(Debug)]
pub enum DefaultFormatError {
DeviceNotAvailable,
StreamTypeNotSupported,
}
#[derive(Debug)]
pub enum CreationError {
DeviceNotAvailable,
FormatNotSupported,
}
#[inline]
pub fn devices() -> Devices {
Devices(Default::default())
}
pub fn input_devices() -> InputDevices {
fn supports_input(device: &Device) -> bool {
device.supported_input_formats()
.map(|mut iter| iter.next().is_some())
.unwrap_or(false)
}
devices().filter(supports_input)
}
pub fn output_devices() -> OutputDevices {
fn supports_output(device: &Device) -> bool {
device.supported_output_formats()
.map(|mut iter| iter.next().is_some())
.unwrap_or(false)
}
devices().filter(supports_output)
}
pub fn default_input_device() -> Option<Device> {
cpal_impl::default_input_device().map(Device)
}
pub fn default_output_device() -> Option<Device> {
cpal_impl::default_output_device().map(Device)
}
impl Device {
#[inline]
pub fn name(&self) -> String {
self.0.name()
}
#[inline]
pub fn supported_input_formats(&self) -> Result<SupportedInputFormats, FormatsEnumerationError> {
Ok(SupportedInputFormats(self.0.supported_input_formats()?))
}
#[inline]
pub fn supported_output_formats(&self) -> Result<SupportedOutputFormats, FormatsEnumerationError> {
Ok(SupportedOutputFormats(self.0.supported_output_formats()?))
}
#[inline]
pub fn default_input_format(&self) -> Result<Format, DefaultFormatError> {
self.0.default_input_format()
}
#[inline]
pub fn default_output_format(&self) -> Result<Format, DefaultFormatError> {
self.0.default_output_format()
}
}
impl EventLoop {
#[inline]
pub fn new() -> EventLoop {
EventLoop(cpal_impl::EventLoop::new())
}
#[inline]
pub fn build_input_stream(
&self,
device: &Device,
format: &Format,
) -> Result<StreamId, CreationError>
{
self.0.build_input_stream(&device.0, format).map(StreamId)
}
#[inline]
pub fn build_output_stream(
&self,
device: &Device,
format: &Format,
) -> Result<StreamId, CreationError>
{
self.0.build_output_stream(&device.0, format).map(StreamId)
}
#[inline]
pub fn play_stream(&self, stream: StreamId) {
self.0.play_stream(stream.0)
}
#[inline]
pub fn pause_stream(&self, stream: StreamId) {
self.0.pause_stream(stream.0)
}
#[inline]
pub fn destroy_stream(&self, stream_id: StreamId) {
self.0.destroy_stream(stream_id.0)
}
#[inline]
pub fn run<F>(&self, mut callback: F) -> !
where F: FnMut(StreamId, StreamData) + Send
{
self.0.run(move |id, data| callback(StreamId(id), data))
}
}
impl SupportedFormat {
#[inline]
pub fn with_max_sample_rate(self) -> Format {
Format {
channels: self.channels,
sample_rate: self.max_sample_rate,
data_type: self.data_type,
}
}
pub fn cmp_default_heuristics(&self, other: &Self) -> std::cmp::Ordering {
use std::cmp::Ordering::Equal;
use SampleFormat::{F32, I16, U16};
let cmp_stereo = (self.channels == 2).cmp(&(other.channels == 2));
if cmp_stereo != Equal {
return cmp_stereo;
}
let cmp_mono = (self.channels == 1).cmp(&(other.channels == 1));
if cmp_mono != Equal {
return cmp_mono;
}
let cmp_channels = self.channels.cmp(&other.channels);
if cmp_channels != Equal {
return cmp_channels;
}
let cmp_f32 = (self.data_type == F32).cmp(&(other.data_type == F32));
if cmp_f32 != Equal {
return cmp_f32;
}
let cmp_i16 = (self.data_type == I16).cmp(&(other.data_type == I16));
if cmp_i16 != Equal {
return cmp_i16;
}
let cmp_u16 = (self.data_type == U16).cmp(&(other.data_type == U16));
if cmp_u16 != Equal {
return cmp_u16;
}
const HZ_44100: SampleRate = SampleRate(44_100);
let r44100_in_self = self.min_sample_rate <= HZ_44100
&& HZ_44100 <= self.max_sample_rate;
let r44100_in_other = other.min_sample_rate <= HZ_44100
&& HZ_44100 <= other.max_sample_rate;
let cmp_r44100 = r44100_in_self.cmp(&r44100_in_other);
if cmp_r44100 != Equal {
return cmp_r44100;
}
self.max_sample_rate.cmp(&other.max_sample_rate)
}
}
impl<'a, T> Deref for InputBuffer<'a, T>
where T: Sample
{
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
self.buffer.as_ref().unwrap().buffer()
}
}
impl<'a, T> Drop for InputBuffer<'a, T>
where T: Sample
{
#[inline]
fn drop(&mut self) {
self.buffer.take().unwrap().finish();
}
}
impl<'a, T> Deref for OutputBuffer<'a, T>
where T: Sample
{
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
panic!("It is forbidden to read from the audio buffer");
}
}
impl<'a, T> DerefMut for OutputBuffer<'a, T>
where T: Sample
{
#[inline]
fn deref_mut(&mut self) -> &mut [T] {
self.target.as_mut().unwrap().buffer()
}
}
impl<'a, T> Drop for OutputBuffer<'a, T>
where T: Sample
{
#[inline]
fn drop(&mut self) {
self.target.take().unwrap().finish();
}
}
impl<'a> UnknownTypeInputBuffer<'a> {
#[inline]
pub fn len(&self) -> usize {
match self {
&UnknownTypeInputBuffer::U16(ref buf) => buf.len(),
&UnknownTypeInputBuffer::I16(ref buf) => buf.len(),
&UnknownTypeInputBuffer::F32(ref buf) => buf.len(),
}
}
}
impl<'a> UnknownTypeOutputBuffer<'a> {
#[inline]
pub fn len(&self) -> usize {
match self {
&UnknownTypeOutputBuffer::U16(ref buf) => buf.target.as_ref().unwrap().len(),
&UnknownTypeOutputBuffer::I16(ref buf) => buf.target.as_ref().unwrap().len(),
&UnknownTypeOutputBuffer::F32(ref buf) => buf.target.as_ref().unwrap().len(),
}
}
}
impl From<Format> for SupportedFormat {
#[inline]
fn from(format: Format) -> SupportedFormat {
SupportedFormat {
channels: format.channels,
min_sample_rate: format.sample_rate,
max_sample_rate: format.sample_rate,
data_type: format.data_type,
}
}
}
impl Iterator for Devices {
type Item = Device;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(Device)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl Iterator for SupportedInputFormats {
type Item = SupportedFormat;
#[inline]
fn next(&mut self) -> Option<SupportedFormat> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl Iterator for SupportedOutputFormats {
type Item = SupportedFormat;
#[inline]
fn next(&mut self) -> Option<SupportedFormat> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl fmt::Display for FormatsEnumerationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", self.description())
}
}
impl Error for FormatsEnumerationError {
#[inline]
fn description(&self) -> &str {
match self {
&FormatsEnumerationError::DeviceNotAvailable => {
"The requested device is no longer available (for example, it has been unplugged)."
},
}
}
}
impl fmt::Display for CreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", self.description())
}
}
impl Error for CreationError {
#[inline]
fn description(&self) -> &str {
match self {
&CreationError::DeviceNotAvailable => {
"The requested device is no longer available (for example, it has been unplugged)."
},
&CreationError::FormatNotSupported => {
"The requested samples format is not supported by the device."
},
}
}
}
impl fmt::Display for DefaultFormatError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", self.description())
}
}
impl Error for DefaultFormatError {
#[inline]
fn description(&self) -> &str {
match self {
&DefaultFormatError::DeviceNotAvailable => {
CreationError::DeviceNotAvailable.description()
},
&DefaultFormatError::StreamTypeNotSupported => {
"The requested stream type is not supported by the device."
},
}
}
}
#[cfg(target_os = "windows")]
const COMMON_SAMPLE_RATES: &'static [SampleRate] = &[
SampleRate(5512),
SampleRate(8000),
SampleRate(11025),
SampleRate(16000),
SampleRate(22050),
SampleRate(32000),
SampleRate(44100),
SampleRate(48000),
SampleRate(64000),
SampleRate(88200),
SampleRate(96000),
SampleRate(176400),
SampleRate(192000),
];