/*! # How to use cpal In order to play a sound, first you need to create an `EventLoop` and a voice. ```no_run // getting the default sound output of the system (can return `None` if nothing is supported) let endpoint = cpal::default_endpoint().unwrap(); // note that the user can at any moment disconnect the device, therefore all operations return // a `Result` to handle this situation // getting a format for the PCM let format = endpoint.supported_formats().unwrap().next().unwrap(); let event_loop = cpal::EventLoop::new(); let voice_id = event_loop.build_voice(&endpoint, &format).unwrap(); event_loop.play(voice_id); ``` `voice_id` is an identifier for the voice can be used to control the play/pause of the output. Once that's done, you can call `run()` on the `event_loop`. ```no_run # let event_loop = cpal::EventLoop::new(); event_loop.run(move |_voice_id, _buffer| { // write data to `buffer` here }); ``` Calling `run()` will block the thread forever, so it's usually best done in a separate thread. While `run()` is running, the audio device of the user will call the callbacks you registered from time to time. */ #[macro_use] extern crate lazy_static; pub use samples_formats::{Sample, SampleFormat}; #[cfg(all(not(windows), not(target_os = "linux"), not(target_os = "freebsd"), not(target_os = "macos"), not(target_os = "ios"), not(target_os = "emscripten")))] use null as cpal_impl; use std::error::Error; use std::fmt; 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; /// An iterator for the list of formats that are supported by the backend. pub struct EndpointsIterator(cpal_impl::EndpointsIterator); impl Iterator for EndpointsIterator { type Item = Endpoint; #[inline] fn next(&mut self) -> Option { self.0.next().map(Endpoint) } #[inline] fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } } /// Return an iterator to the list of formats that are supported by the system. #[inline] pub fn endpoints() -> EndpointsIterator { EndpointsIterator(Default::default()) } /// Deprecated. Use `endpoints()` instead. #[inline] #[deprecated] pub fn get_endpoints_list() -> EndpointsIterator { EndpointsIterator(Default::default()) } /// Return the default endpoint, or `None` if no device is available. #[inline] pub fn default_endpoint() -> Option { cpal_impl::default_endpoint().map(Endpoint) } /// Deprecated. Use `default_endpoint()` instead. #[inline] #[deprecated] pub fn get_default_endpoint() -> Option { default_endpoint() } /// An opaque type that identifies an end point. #[derive(Clone, PartialEq, Eq)] pub struct Endpoint(cpal_impl::Endpoint); impl Endpoint { /// Returns an iterator that produces the list of formats that are supported by the backend. #[inline] pub fn supported_formats(&self) -> Result { Ok(SupportedFormatsIterator(self.0.supported_formats()?)) } /// Deprecated. Use `supported_formats` instead. #[inline] #[deprecated] pub fn get_supported_formats_list( &self) -> Result { self.supported_formats() } /// Returns the name of the endpoint. #[inline] pub fn name(&self) -> String { self.0.name() } /// Deprecated. Use `name()` instead. #[deprecated] #[inline] pub fn get_name(&self) -> String { self.name() } } /// Number of channels. pub type ChannelsCount = u16; /// Possible position of a channel. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum ChannelPosition { FrontLeft, FrontRight, FrontCenter, LowFrequency, BackLeft, BackRight, FrontLeftOfCenter, FrontRightOfCenter, BackCenter, SideLeft, SideRight, TopCenter, TopFrontLeft, TopFrontCenter, TopFrontRight, TopBackLeft, TopBackCenter, TopBackRight, } /// #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct SamplesRate(pub u32); /// Describes a format. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Format { pub channels: Vec, pub samples_rate: SamplesRate, pub data_type: SampleFormat, } /// An iterator that produces a list of formats supported by the endpoint. pub struct SupportedFormatsIterator(cpal_impl::SupportedFormatsIterator); impl Iterator for SupportedFormatsIterator { type Item = Format; #[inline] fn next(&mut self) -> Option { self.0.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } } pub struct EventLoop(cpal_impl::EventLoop); impl EventLoop { /// Initializes a new events loop. #[inline] pub fn new() -> EventLoop { EventLoop(cpal_impl::EventLoop::new()) } /// Creates a new voice that will play on the given endpoint and with the given format. /// /// On success, returns an identifier for the voice. #[inline] pub fn build_voice(&self, endpoint: &Endpoint, format: &Format) -> Result { self.0.build_voice(&endpoint.0, format).map(VoiceId) } /// Destroys an existing voice. /// /// # Panic /// /// If the voice doesn't exist, this function can either panic or be a no-op. /// #[inline] pub fn destroy_voice(&self, voice_id: VoiceId) { self.0.destroy_voice(voice_id.0) } /// Takes control of the current thread and processes the sounds. /// /// Whenever a voice needs to be fed some data, the closure passed as parameter is called. /// **Note**: Calling other methods of the events loop from the callback will most likely /// deadlock. Don't do that. Maybe this will change in the future. #[inline] pub fn run(&self, mut callback: F) -> ! where F: FnMut(VoiceId, UnknownTypeBuffer) { self.0.run(move |id, buf| callback(VoiceId(id), buf)) } /// Sends a command to the audio device that it should start playing. /// /// Has no effect is the voice was already playing. /// /// Only call this after you have submitted some data, otherwise you may hear /// some glitches. /// /// # Panic /// /// If the voice doesn't exist, this function can either panic or be a no-op. /// #[inline] pub fn play(&self, voice: VoiceId) { self.0.play(voice.0) } /// Sends a command to the audio device that it should stop playing. /// /// Has no effect is the voice was already paused. /// /// If you call `play` afterwards, the playback will resume exactly where it was. /// /// # Panic /// /// If the voice doesn't exist, this function can either panic or be a no-op. /// #[inline] pub fn pause(&self, voice: VoiceId) { self.0.pause(voice.0) } } /// Identifier of a voice in an events loop. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct VoiceId(cpal_impl::VoiceId); /// This is the struct that is provided to you by cpal when you want to write samples to a buffer. /// /// Since the type of data is only known at runtime, you have to fill the right buffer. pub enum UnknownTypeBuffer<'a> { /// Samples whose format is `u16`. U16(Buffer<'a, u16>), /// Samples whose format is `i16`. I16(Buffer<'a, i16>), /// Samples whose format is `f32`. F32(Buffer<'a, f32>), } impl<'a> UnknownTypeBuffer<'a> { /// Returns the length of the buffer in number of samples. #[inline] pub fn len(&self) -> usize { match self { &UnknownTypeBuffer::U16(ref buf) => buf.target.as_ref().unwrap().len(), &UnknownTypeBuffer::I16(ref buf) => buf.target.as_ref().unwrap().len(), &UnknownTypeBuffer::F32(ref buf) => buf.target.as_ref().unwrap().len(), } } } /// Error that can happen when enumerating the list of supported formats. #[derive(Debug)] pub enum FormatsEnumerationError { /// The device no longer exists. This can happen if the device is disconnected while the /// program is running. DeviceNotAvailable, } 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)." }, } } } /// Error that can happen when creating a `Voice`. #[derive(Debug)] pub enum CreationError { /// The device no longer exists. This can happen if the device is disconnected while the /// program is running. DeviceNotAvailable, /// The required format is not supported. FormatNotSupported, } 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." }, } } } /// Represents a buffer that must be filled with audio data. /// /// You should destroy this object as soon as possible. Data is only committed when it /// is destroyed. #[must_use] pub struct Buffer<'a, T: 'a> where T: Sample { // Always contains something, taken by `Drop` // TODO: change that target: Option>, } impl<'a, T> Deref for Buffer<'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 Buffer<'a, T> where T: Sample { #[inline] fn deref_mut(&mut self) -> &mut [T] { self.target.as_mut().unwrap().buffer() } } impl<'a, T> Drop for Buffer<'a, T> where T: Sample { #[inline] fn drop(&mut self) { self.target.take().unwrap().finish(); } }