2014-12-17 08:45:14 +00:00
|
|
|
/*!
|
|
|
|
# How to use cpal
|
|
|
|
|
|
|
|
In order to play a sound, first you need to create a `Voice`.
|
|
|
|
|
|
|
|
```no_run
|
2015-09-01 15:47:55 +00:00
|
|
|
// getting the default sound output of the system (can return `None` if nothing is supported)
|
|
|
|
let endpoint = cpal::get_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.get_supported_formats_list().unwrap().next().unwrap();
|
|
|
|
|
|
|
|
let mut voice = cpal::Voice::new(&endpoint, &format).unwrap();
|
2014-12-17 08:45:14 +00:00
|
|
|
```
|
|
|
|
|
2015-08-20 12:38:25 +00:00
|
|
|
Then you must send raw samples to it by calling `append_data`. You must take the number of channels
|
|
|
|
and samples rate into account when writing the data.
|
2014-12-17 08:45:14 +00:00
|
|
|
|
2015-08-20 12:38:25 +00:00
|
|
|
TODO: add example
|
2014-12-17 08:45:14 +00:00
|
|
|
|
|
|
|
**Important**: the `append_data` function can return a buffer shorter than what you requested.
|
|
|
|
This is the case if the device doesn't have enough space available. **It happens very often**,
|
|
|
|
this is not some obscure situation that can be ignored.
|
|
|
|
|
2014-12-22 13:16:47 +00:00
|
|
|
After you have submitted data for the first time, call `play`:
|
|
|
|
|
|
|
|
```no_run
|
2015-09-01 15:47:55 +00:00
|
|
|
# let mut voice: cpal::Voice = unsafe { std::mem::uninitialized() };
|
2014-12-22 13:16:47 +00:00
|
|
|
voice.play();
|
|
|
|
```
|
|
|
|
|
2014-12-17 08:45:14 +00:00
|
|
|
The audio device of the user will read the buffer that you sent, and play it. If the audio device
|
2014-12-22 13:16:47 +00:00
|
|
|
reaches the end of the data, it will stop playing. You must continuously fill the buffer by
|
2014-12-17 08:45:14 +00:00
|
|
|
calling `append_data` repeatedly if you don't want the audio to stop playing.
|
|
|
|
|
|
|
|
*/
|
2015-09-01 09:23:41 +00:00
|
|
|
#[macro_use]
|
|
|
|
extern crate lazy_static;
|
|
|
|
|
2014-12-17 07:47:19 +00:00
|
|
|
pub use samples_formats::{SampleFormat, Sample};
|
|
|
|
|
2015-09-10 16:37:37 +00:00
|
|
|
#[cfg(all(not(windows), not(unix)))]
|
|
|
|
use null as cpal_impl;
|
|
|
|
|
2015-09-01 12:17:57 +00:00
|
|
|
use std::fmt;
|
2015-09-01 09:23:41 +00:00
|
|
|
use std::error::Error;
|
2015-01-05 09:52:59 +00:00
|
|
|
use std::ops::{Deref, DerefMut};
|
|
|
|
|
2015-09-10 16:37:37 +00:00
|
|
|
mod null;
|
2014-12-17 07:47:19 +00:00
|
|
|
mod samples_formats;
|
2014-12-15 10:45:38 +00:00
|
|
|
|
2015-02-22 13:50:06 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2014-12-16 15:45:45 +00:00
|
|
|
#[path="alsa/mod.rs"]
|
2014-12-17 08:13:58 +00:00
|
|
|
mod cpal_impl;
|
2015-02-22 13:50:06 +00:00
|
|
|
|
2014-12-11 13:22:55 +00:00
|
|
|
#[cfg(windows)]
|
|
|
|
#[path="wasapi/mod.rs"]
|
2014-12-17 08:13:58 +00:00
|
|
|
mod cpal_impl;
|
2014-12-11 16:23:33 +00:00
|
|
|
|
2015-02-22 13:50:06 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
2015-02-28 18:50:29 +00:00
|
|
|
#[path="coreaudio/mod.rs"]
|
2015-02-22 13:50:06 +00:00
|
|
|
mod cpal_impl;
|
|
|
|
|
2015-09-01 09:23:41 +00:00
|
|
|
/// 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;
|
|
|
|
|
2015-09-01 11:53:54 +00:00
|
|
|
#[inline]
|
2015-09-01 09:23:41 +00:00
|
|
|
fn next(&mut self) -> Option<Endpoint> {
|
|
|
|
self.0.next().map(Endpoint)
|
|
|
|
}
|
|
|
|
|
2015-09-01 11:53:54 +00:00
|
|
|
#[inline]
|
2015-09-01 09:23:41 +00:00
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
|
|
self.0.size_hint()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return an iterator to the list of formats that are supported by the system.
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-01 09:23:41 +00:00
|
|
|
pub fn get_endpoints_list() -> EndpointsIterator {
|
|
|
|
EndpointsIterator(Default::default())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the default endpoint, or `None` if no device is available.
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-01 09:23:41 +00:00
|
|
|
pub fn get_default_endpoint() -> Option<Endpoint> {
|
|
|
|
cpal_impl::get_default_endpoint().map(Endpoint)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An opaque type that identifies an end point.
|
|
|
|
#[derive(Clone, PartialEq, Eq)]
|
|
|
|
pub struct Endpoint(cpal_impl::Endpoint);
|
|
|
|
|
2015-09-01 11:53:54 +00:00
|
|
|
impl Endpoint {
|
|
|
|
/// Returns an iterator that produces the list of formats that are supported by the backend.
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-01 12:17:57 +00:00
|
|
|
pub fn get_supported_formats_list(&self) -> Result<SupportedFormatsIterator,
|
|
|
|
FormatsEnumerationError>
|
|
|
|
{
|
|
|
|
Ok(SupportedFormatsIterator(try!(self.0.get_supported_formats_list())))
|
2015-09-01 11:53:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Number of channels.
|
|
|
|
pub type ChannelsCount = u16;
|
|
|
|
|
2015-09-10 09:44:19 +00:00
|
|
|
/// 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,
|
|
|
|
}
|
|
|
|
|
2015-09-01 11:53:54 +00:00
|
|
|
///
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
|
|
|
pub struct SamplesRate(pub u32);
|
|
|
|
|
|
|
|
/// Describes a format.
|
2015-09-10 09:44:19 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
2015-09-01 11:53:54 +00:00
|
|
|
pub struct Format {
|
2015-09-10 09:44:19 +00:00
|
|
|
pub channels: Vec<ChannelPosition>,
|
2015-09-01 11:53:54 +00:00
|
|
|
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<Format> {
|
|
|
|
self.0.next()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
|
|
self.0.size_hint()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-11 17:09:48 +00:00
|
|
|
/// Represents a buffer that must be filled with audio data.
|
|
|
|
///
|
2014-12-17 08:45:14 +00:00
|
|
|
/// You should destroy this object as soon as possible. Data is only committed when it
|
|
|
|
/// is destroyed.
|
2014-12-26 09:39:19 +00:00
|
|
|
#[must_use]
|
2015-03-30 09:06:46 +00:00
|
|
|
pub struct Buffer<'a, T: 'a> where T: Sample {
|
2014-12-15 14:29:59 +00:00
|
|
|
// also contains something, taken by `Drop`
|
2015-07-25 22:08:31 +00:00
|
|
|
target: Option<cpal_impl::Buffer<'a, T>>,
|
2014-12-15 14:29:59 +00:00
|
|
|
}
|
|
|
|
|
2015-08-20 12:38:25 +00:00
|
|
|
/// 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>),
|
2014-12-15 10:45:38 +00:00
|
|
|
}
|
2014-12-11 16:23:33 +00:00
|
|
|
|
2015-09-10 19:21:46 +00:00
|
|
|
impl<'a> UnknownTypeBuffer<'a> {
|
|
|
|
/// Returns the length of the buffer in number of samples.
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-10 19:21:46 +00:00
|
|
|
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(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-01 12:17:57 +00:00
|
|
|
/// 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 {
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-01 12:17:57 +00:00
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
|
|
write!(fmt, "{}", self.description())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Error for FormatsEnumerationError {
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-01 12:17:57 +00:00
|
|
|
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 {
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-01 12:17:57 +00:00
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
|
|
write!(fmt, "{}", self.description())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Error for CreationError {
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-09-01 12:17:57 +00:00
|
|
|
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."
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-20 12:38:25 +00:00
|
|
|
/// Controls a sound output. A typical application has one `Voice` for each sound
|
|
|
|
/// it wants to output.
|
|
|
|
///
|
|
|
|
/// A voice must be periodically filled with new data by calling `append_data`, or the sound
|
|
|
|
/// will stop playing.
|
|
|
|
///
|
|
|
|
/// Each `Voice` is bound to a specific number of channels, samples rate, and samples format,
|
|
|
|
/// which can be retreived by calling `get_channels`, `get_samples_rate` and `get_samples_format`.
|
|
|
|
/// If you call `append_data` with values different than these, then cpal will automatically
|
|
|
|
/// perform a conversion on your data.
|
|
|
|
///
|
|
|
|
/// If you have the possibility, you should try to match the format of the voice.
|
|
|
|
pub struct Voice(cpal_impl::Voice);
|
|
|
|
|
2014-12-17 08:16:26 +00:00
|
|
|
impl Voice {
|
2014-12-17 08:13:58 +00:00
|
|
|
/// Builds a new channel.
|
2015-09-01 11:53:54 +00:00
|
|
|
#[inline]
|
2015-09-01 12:17:57 +00:00
|
|
|
pub fn new(endpoint: &Endpoint, format: &Format) -> Result<Voice, CreationError> {
|
2015-09-01 11:53:54 +00:00
|
|
|
let channel = try!(cpal_impl::Voice::new(&endpoint.0, format));
|
2015-09-01 09:23:41 +00:00
|
|
|
Ok(Voice(channel))
|
2014-12-11 16:23:33 +00:00
|
|
|
}
|
|
|
|
|
2014-12-11 17:09:48 +00:00
|
|
|
/// Returns the number of channels.
|
|
|
|
///
|
2014-12-17 08:45:14 +00:00
|
|
|
/// You can add data with any number of channels, but matching the voice's native format
|
|
|
|
/// will lead to better performances.
|
2015-09-01 11:53:54 +00:00
|
|
|
#[inline]
|
2014-12-11 18:02:04 +00:00
|
|
|
pub fn get_channels(&self) -> ChannelsCount {
|
2014-12-11 16:23:33 +00:00
|
|
|
self.0.get_channels()
|
|
|
|
}
|
|
|
|
|
2014-12-11 18:07:58 +00:00
|
|
|
/// Returns the number of samples that are played per second.
|
|
|
|
///
|
2014-12-17 08:45:14 +00:00
|
|
|
/// You can add data with any samples rate, but matching the voice's native format
|
|
|
|
/// will lead to better performances.
|
2015-09-01 11:53:54 +00:00
|
|
|
#[inline]
|
2014-12-15 10:45:38 +00:00
|
|
|
pub fn get_samples_rate(&self) -> SamplesRate {
|
|
|
|
self.0.get_samples_rate()
|
2014-12-11 18:07:58 +00:00
|
|
|
}
|
|
|
|
|
2014-12-17 08:45:14 +00:00
|
|
|
/// Returns the format of the samples that are accepted by the backend.
|
2014-12-11 18:07:58 +00:00
|
|
|
///
|
2014-12-17 08:45:14 +00:00
|
|
|
/// You can add data of any format, but matching the voice's native format
|
|
|
|
/// will lead to better performances.
|
2015-09-01 11:53:54 +00:00
|
|
|
#[inline]
|
2014-12-11 18:07:58 +00:00
|
|
|
pub fn get_samples_format(&self) -> SampleFormat {
|
|
|
|
self.0.get_samples_format()
|
|
|
|
}
|
|
|
|
|
2014-12-17 08:45:14 +00:00
|
|
|
/// Adds some PCM data to the voice's buffer.
|
2014-12-11 17:09:48 +00:00
|
|
|
///
|
2015-08-20 12:38:25 +00:00
|
|
|
/// This function indirectly returns a `Buffer` object that must be filled with the audio data.
|
2014-12-17 08:45:14 +00:00
|
|
|
/// The size of the buffer being returned depends on the current state of the backend
|
2015-08-20 12:38:25 +00:00
|
|
|
/// and can't be known in advance. However it is never greater than `max_samples`.
|
2014-12-17 08:45:14 +00:00
|
|
|
///
|
2015-08-20 12:38:25 +00:00
|
|
|
/// You must fill the buffer *entirely*, so do not set `max_samples` to a value greater
|
2014-12-17 08:45:14 +00:00
|
|
|
/// than the amount of data available to you.
|
|
|
|
///
|
|
|
|
/// Channels are interleaved. For example if you have two channels, you must write
|
|
|
|
/// the first sample of the first channel, then the first sample of the second channel,
|
|
|
|
/// then the second sample of the first channel, then the second sample of the second
|
|
|
|
/// channel, etc.
|
|
|
|
///
|
2014-12-15 15:26:55 +00:00
|
|
|
/// ## Panic
|
|
|
|
///
|
2015-08-20 12:38:25 +00:00
|
|
|
/// Panics if `max_samples` is 0.
|
2014-12-15 15:26:55 +00:00
|
|
|
///
|
2015-09-11 08:55:29 +00:00
|
|
|
#[inline]
|
2015-08-20 12:38:25 +00:00
|
|
|
pub fn append_data(&mut self, max_samples: usize) -> UnknownTypeBuffer {
|
|
|
|
assert!(max_samples != 0);
|
|
|
|
|
|
|
|
match self.get_samples_format() {
|
|
|
|
SampleFormat::U16 => UnknownTypeBuffer::U16(Buffer {
|
|
|
|
target: Some(self.0.append_data(max_samples))
|
|
|
|
}),
|
|
|
|
SampleFormat::I16 => UnknownTypeBuffer::I16(Buffer {
|
|
|
|
target: Some(self.0.append_data(max_samples))
|
|
|
|
}),
|
|
|
|
SampleFormat::F32 => UnknownTypeBuffer::F32(Buffer {
|
|
|
|
target: Some(self.0.append_data(max_samples))
|
|
|
|
}),
|
2014-12-15 10:45:38 +00:00
|
|
|
}
|
2014-12-11 16:23:33 +00:00
|
|
|
}
|
2014-12-22 13:16:47 +00:00
|
|
|
|
|
|
|
/// 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.
|
2015-09-01 11:53:54 +00:00
|
|
|
#[inline]
|
2014-12-22 13:16:47 +00:00
|
|
|
pub fn play(&mut self) {
|
|
|
|
self.0.play()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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.
|
2015-09-01 11:53:54 +00:00
|
|
|
#[inline]
|
2014-12-22 13:16:47 +00:00
|
|
|
pub fn pause(&mut self) {
|
|
|
|
self.0.pause()
|
|
|
|
}
|
2015-09-10 19:03:40 +00:00
|
|
|
|
|
|
|
/// Returns true if the voice has finished reading all the data you sent to it.
|
|
|
|
#[inline]
|
|
|
|
pub fn underflowed(&self) -> bool {
|
|
|
|
self.0.underflowed()
|
|
|
|
}
|
2014-12-11 16:23:33 +00:00
|
|
|
}
|
|
|
|
|
2015-03-30 09:06:46 +00:00
|
|
|
impl<'a, T> Deref for Buffer<'a, T> where T: Sample {
|
2015-01-05 09:52:59 +00:00
|
|
|
type Target = [T];
|
|
|
|
|
2015-09-01 11:53:54 +00:00
|
|
|
#[inline]
|
2014-12-15 15:32:13 +00:00
|
|
|
fn deref(&self) -> &[T] {
|
|
|
|
panic!("It is forbidden to read from the audio buffer");
|
2014-12-11 16:23:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-30 09:06:46 +00:00
|
|
|
impl<'a, T> DerefMut for Buffer<'a, T> where T: Sample {
|
2015-09-01 11:53:54 +00:00
|
|
|
#[inline]
|
2014-12-15 15:32:13 +00:00
|
|
|
fn deref_mut(&mut self) -> &mut [T] {
|
2015-08-20 12:38:25 +00:00
|
|
|
self.target.as_mut().unwrap().get_buffer()
|
2014-12-15 10:45:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T> Drop for Buffer<'a, T> where T: Sample {
|
2015-09-01 11:53:54 +00:00
|
|
|
#[inline]
|
2014-12-15 10:45:38 +00:00
|
|
|
fn drop(&mut self) {
|
2014-12-15 15:32:13 +00:00
|
|
|
self.target.take().unwrap().finish();
|
2014-12-11 16:23:33 +00:00
|
|
|
}
|
|
|
|
}
|