Refactor `Host` and related traits into a new `traits` module
This is a draft implementation of #294. I'll leave this open for feedback and potentially better trait naming suggestions or better solutions in general! cc @ishitatsuyuki
This commit is contained in:
parent
36dee482bd
commit
5e4f384992
|
@ -1,7 +1,7 @@
|
|||
extern crate cpal;
|
||||
extern crate failure;
|
||||
|
||||
use cpal::{Device, EventLoop, Host};
|
||||
use cpal::traits::{DeviceTrait, EventLoopTrait, HostTrait};
|
||||
|
||||
fn main() -> Result<(), failure::Error> {
|
||||
let host = cpal::default_host();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
extern crate cpal;
|
||||
extern crate failure;
|
||||
|
||||
use cpal::{Device, Host};
|
||||
use cpal::traits::{DeviceTrait, HostTrait};
|
||||
|
||||
fn main() -> Result<(), failure::Error> {
|
||||
println!("Supported hosts:\n {:?}", cpal::ALL_HOSTS);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
extern crate cpal;
|
||||
extern crate failure;
|
||||
|
||||
use cpal::{Device, EventLoop, Host};
|
||||
use cpal::traits::{DeviceTrait, EventLoopTrait, HostTrait};
|
||||
|
||||
const LATENCY_MS: f32 = 150.0;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ extern crate cpal;
|
|||
extern crate failure;
|
||||
extern crate hound;
|
||||
|
||||
use cpal::{Device, EventLoop, Host};
|
||||
use cpal::traits::{DeviceTrait, EventLoopTrait, HostTrait};
|
||||
|
||||
fn main() -> Result<(), failure::Error> {
|
||||
// Use the default host for working with audio devices.
|
||||
|
|
|
@ -7,12 +7,9 @@ use ChannelCount;
|
|||
use BackendSpecificError;
|
||||
use BuildStreamError;
|
||||
use DefaultFormatError;
|
||||
use Device as DeviceTrait;
|
||||
use DeviceNameError;
|
||||
use DevicesError;
|
||||
use EventLoop as EventLoopTrait;
|
||||
use Format;
|
||||
use Host as HostTrait;
|
||||
use PauseStreamError;
|
||||
use PlayStreamError;
|
||||
use SampleFormat;
|
||||
|
@ -21,10 +18,10 @@ use SupportedFormatsError;
|
|||
use StreamData;
|
||||
use StreamDataResult;
|
||||
use StreamError;
|
||||
use StreamId as StreamIdTrait;
|
||||
use SupportedFormat;
|
||||
use UnknownTypeInputBuffer;
|
||||
use UnknownTypeOutputBuffer;
|
||||
use traits::{DeviceTrait, EventLoopTrait, HostTrait, StreamIdTrait};
|
||||
|
||||
use std::{cmp, ffi, mem, ptr};
|
||||
use std::sync::Mutex;
|
||||
|
|
|
@ -5,12 +5,9 @@ use ChannelCount;
|
|||
use BackendSpecificError;
|
||||
use BuildStreamError;
|
||||
use DefaultFormatError;
|
||||
use Device as DeviceTrait;
|
||||
use DeviceNameError;
|
||||
use DevicesError;
|
||||
use EventLoop as EventLoopTrait;
|
||||
use Format;
|
||||
use Host as HostTrait;
|
||||
use PauseStreamError;
|
||||
use PlayStreamError;
|
||||
use SupportedFormatsError;
|
||||
|
@ -18,10 +15,10 @@ use SampleFormat;
|
|||
use SampleRate;
|
||||
use StreamData;
|
||||
use StreamDataResult;
|
||||
use StreamId as StreamIdTrait;
|
||||
use SupportedFormat;
|
||||
use UnknownTypeInputBuffer;
|
||||
use UnknownTypeOutputBuffer;
|
||||
use traits::{DeviceTrait, EventLoopTrait, HostTrait, StreamIdTrait};
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::fmt;
|
||||
|
|
|
@ -10,20 +10,17 @@ use stdweb::web::set_timeout;
|
|||
|
||||
use BuildStreamError;
|
||||
use DefaultFormatError;
|
||||
use Device as DeviceTrait;
|
||||
use DeviceNameError;
|
||||
use DevicesError;
|
||||
use EventLoop as EventLoopTrait;
|
||||
use Format;
|
||||
use Host as HostTrait;
|
||||
use PauseStreamError;
|
||||
use PlayStreamError;
|
||||
use SupportedFormatsError;
|
||||
use StreamData;
|
||||
use StreamDataResult;
|
||||
use StreamId as StreamIdTrait;
|
||||
use SupportedFormat;
|
||||
use UnknownTypeOutputBuffer;
|
||||
use traits::{DeviceTrait, EventLoopTrait, HostTrait, StreamIdTrait};
|
||||
|
||||
/// The default emscripten host type.
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -2,18 +2,15 @@
|
|||
|
||||
use BuildStreamError;
|
||||
use DefaultFormatError;
|
||||
use Device as DeviceTrait;
|
||||
use DevicesError;
|
||||
use DeviceNameError;
|
||||
use EventLoop as EventLoopTrait;
|
||||
use Format;
|
||||
use Host as HostTrait;
|
||||
use PauseStreamError;
|
||||
use PlayStreamError;
|
||||
use StreamDataResult;
|
||||
use SupportedFormatsError;
|
||||
use StreamId as StreamIdTrait;
|
||||
use SupportedFormat;
|
||||
use traits::{DeviceTrait, EventLoopTrait, HostTrait, StreamIdTrait};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Devices;
|
||||
|
|
|
@ -3,19 +3,16 @@ extern crate winapi;
|
|||
use BackendSpecificError;
|
||||
use BuildStreamError;
|
||||
use DefaultFormatError;
|
||||
use Device as DeviceTrait;
|
||||
use DeviceNameError;
|
||||
use DevicesError;
|
||||
use EventLoop as EventLoopTrait;
|
||||
use Format;
|
||||
use Host as HostTrait;
|
||||
use PlayStreamError;
|
||||
use PauseStreamError;
|
||||
use StreamDataResult;
|
||||
use StreamId as StreamIdTrait;
|
||||
use SupportedFormatsError;
|
||||
use self::winapi::um::winnt::HRESULT;
|
||||
use std::io::Error as IoError;
|
||||
use traits::{DeviceTrait, EventLoopTrait, HostTrait, StreamIdTrait};
|
||||
pub use self::device::{Device, Devices, SupportedInputFormats, SupportedOutputFormats, default_input_device, default_output_device};
|
||||
pub use self::stream::{EventLoop, StreamId};
|
||||
|
||||
|
|
203
src/lib.rs
203
src/lib.rs
|
@ -18,7 +18,7 @@
|
|||
//! `EventLoop`:
|
||||
//!
|
||||
//! ```
|
||||
//! use cpal::Host;
|
||||
//! use cpal::traits::HostTrait;
|
||||
//! let host = cpal::default_host();
|
||||
//! let event_loop = host.event_loop();
|
||||
//! ```
|
||||
|
@ -30,7 +30,7 @@
|
|||
//! stream type on the system.
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use cpal::Host;
|
||||
//! # use cpal::traits::HostTrait;
|
||||
//! # let host = cpal::default_host();
|
||||
//! let device = host.default_output_device().expect("no output device available");
|
||||
//! ```
|
||||
|
@ -46,7 +46,7 @@
|
|||
//! > has been disconnected.
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use cpal::{Device, Host};
|
||||
//! use cpal::traits::{DeviceTrait, HostTrait};
|
||||
//! # let host = cpal::default_host();
|
||||
//! # let device = host.default_output_device().unwrap();
|
||||
//! let mut supported_formats_range = device.supported_output_formats()
|
||||
|
@ -59,7 +59,7 @@
|
|||
//! Now that we have everything for the stream, we can create it from our event loop:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use cpal::{Device, EventLoop, Host};
|
||||
//! use cpal::traits::{DeviceTrait, EventLoopTrait, HostTrait};
|
||||
//! # let host = cpal::default_host();
|
||||
//! # let event_loop = host.event_loop();
|
||||
//! # let device = host.default_output_device().unwrap();
|
||||
|
@ -73,7 +73,7 @@
|
|||
//! Now we must start the stream. This is done with the `play_stream()` method on the event loop.
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use cpal::{EventLoop, Host};
|
||||
//! # use cpal::traits::{EventLoopTrait, HostTrait};
|
||||
//! # let host = cpal::default_host();
|
||||
//! # let event_loop = host.event_loop();
|
||||
//! # let stream_id = unimplemented!();
|
||||
|
@ -83,7 +83,7 @@
|
|||
//! Now everything is ready! We call `run()` on the `event_loop` to begin processing.
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use cpal::{EventLoop, Host};
|
||||
//! # use cpal::traits::{EventLoopTrait, HostTrait};
|
||||
//! # let host = cpal::default_host();
|
||||
//! # let event_loop = host.event_loop();
|
||||
//! event_loop.run(move |_stream_id, _stream_result| {
|
||||
|
@ -103,7 +103,8 @@
|
|||
//! In this example, we simply fill the given output buffer with zeroes.
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use cpal::{EventLoop, Host, StreamData, UnknownTypeOutputBuffer};
|
||||
//! use cpal::{StreamData, UnknownTypeOutputBuffer};
|
||||
//! use cpal::traits::{EventLoopTrait, HostTrait};
|
||||
//! # let host = cpal::default_host();
|
||||
//! # let event_loop = host.event_loop();
|
||||
//! event_loop.run(move |stream_id, stream_result| {
|
||||
|
@ -148,7 +149,10 @@ extern crate lazy_static;
|
|||
#[macro_use]
|
||||
extern crate stdweb;
|
||||
|
||||
pub use platform::{ALL_HOSTS, HostId, available_hosts, default_host, host_from_id};
|
||||
pub use platform::{
|
||||
ALL_HOSTS, Device, EventLoop, Host, HostId, StreamId, available_hosts,
|
||||
default_host, host_from_id,
|
||||
};
|
||||
pub use samples_formats::{Sample, SampleFormat};
|
||||
|
||||
use failure::Fail;
|
||||
|
@ -157,188 +161,7 @@ use std::ops::{Deref, DerefMut};
|
|||
mod host;
|
||||
pub mod platform;
|
||||
mod samples_formats;
|
||||
|
||||
/// A **Host** provides access to the available audio devices on the system.
|
||||
///
|
||||
/// Each platform may have a number of available hosts depending on the system, each with their own
|
||||
/// pros and cons.
|
||||
///
|
||||
/// For example, WASAPI is the standard audio host API that ships with the Windows operating
|
||||
/// system. However, due to historical limitations with respect to performance and flexibility,
|
||||
/// Steinberg created the ASIO API providing better audio device support for pro audio and
|
||||
/// low-latency applications. As a result, it is common for some devices and device capabilities to
|
||||
/// only be available via ASIO, while others are only available via WASAPI.
|
||||
///
|
||||
/// Another great example is the Linux platform. While the ALSA host API is the lowest-level API
|
||||
/// available to almost all distributions of Linux, its flexibility is limited as it requires that
|
||||
/// each process have exclusive access to the devices with which they establish streams. PulseAudio
|
||||
/// is another popular host API that aims to solve this issue by providing user-space mixing,
|
||||
/// however it has its own limitations w.r.t. low-latency and high-performance audio applications.
|
||||
/// JACK is yet another host API that is more suitable to pro-audio applications, however it is
|
||||
/// less readily available by default in many Linux distributions and is known to be tricky to
|
||||
/// setup.
|
||||
pub trait Host {
|
||||
/// The type used for enumerating available devices by the host.
|
||||
type Devices: Iterator<Item = Self::Device>;
|
||||
/// The `Device` type yielded by the host.
|
||||
type Device: Device;
|
||||
/// The event loop type used by the `Host`
|
||||
type EventLoop: EventLoop<Device = Self::Device>;
|
||||
|
||||
/// Whether or not the host is available on the system.
|
||||
fn is_available() -> bool;
|
||||
|
||||
/// An iterator yielding all `Device`s currently available to the host on the system.
|
||||
///
|
||||
/// Can be empty if the system does not support audio in general.
|
||||
fn devices(&self) -> Result<Self::Devices, DevicesError>;
|
||||
|
||||
/// The default input audio device on the system.
|
||||
///
|
||||
/// Returns `None` if no input device is available.
|
||||
fn default_input_device(&self) -> Option<Self::Device>;
|
||||
|
||||
/// The default output audio device on the system.
|
||||
///
|
||||
/// Returns `None` if no output device is available.
|
||||
fn default_output_device(&self) -> Option<Self::Device>;
|
||||
|
||||
/// Initialise the event loop, ready for managing audio streams.
|
||||
fn event_loop(&self) -> Self::EventLoop;
|
||||
|
||||
/// An iterator yielding all `Device`s currently available to the system that support one or more
|
||||
/// input stream formats.
|
||||
///
|
||||
/// Can be empty if the system does not support audio input.
|
||||
fn input_devices(&self) -> Result<InputDevices<Self::Devices>, DevicesError> {
|
||||
fn supports_input<D: Device>(device: &D) -> bool {
|
||||
device.supported_input_formats()
|
||||
.map(|mut iter| iter.next().is_some())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
Ok(self.devices()?.filter(supports_input::<Self::Device>))
|
||||
}
|
||||
|
||||
/// An iterator yielding all `Device`s currently available to the system that support one or more
|
||||
/// output stream formats.
|
||||
///
|
||||
/// Can be empty if the system does not support audio output.
|
||||
fn output_devices(&self) -> Result<OutputDevices<Self::Devices>, DevicesError> {
|
||||
fn supports_output<D: Device>(device: &D) -> bool {
|
||||
device.supported_output_formats()
|
||||
.map(|mut iter| iter.next().is_some())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
Ok(self.devices()?.filter(supports_output::<Self::Device>))
|
||||
}
|
||||
}
|
||||
|
||||
/// A device that is capable of audio input and/or output.
|
||||
///
|
||||
/// Please note that `Device`s may become invalid if they get disconnected. Therefore all the
|
||||
/// methods that involve a device return a `Result` allowing the user to handle this case.
|
||||
pub trait Device {
|
||||
/// The iterator type yielding supported input stream formats.
|
||||
type SupportedInputFormats: Iterator<Item = SupportedFormat>;
|
||||
/// The iterator type yielding supported output stream formats.
|
||||
type SupportedOutputFormats: Iterator<Item = SupportedFormat>;
|
||||
|
||||
/// The human-readable name of the device.
|
||||
fn name(&self) -> Result<String, DeviceNameError>;
|
||||
|
||||
/// An iterator yielding formats that are supported by the backend.
|
||||
///
|
||||
/// Can return an error if the device is no longer valid (eg. it has been disconnected).
|
||||
fn supported_input_formats(&self) -> Result<Self::SupportedInputFormats, SupportedFormatsError>;
|
||||
|
||||
/// An iterator yielding output stream formats that are supported by the device.
|
||||
///
|
||||
/// Can return an error if the device is no longer valid (eg. it has been disconnected).
|
||||
fn supported_output_formats(&self) -> Result<Self::SupportedOutputFormats, SupportedFormatsError>;
|
||||
|
||||
/// The default input stream format for the device.
|
||||
fn default_input_format(&self) -> Result<Format, DefaultFormatError>;
|
||||
|
||||
/// The default output stream format for the device.
|
||||
fn default_output_format(&self) -> Result<Format, DefaultFormatError>;
|
||||
}
|
||||
|
||||
/// Collection of streams managed together.
|
||||
///
|
||||
/// Created with the `Host::event_loop` method.
|
||||
pub trait EventLoop {
|
||||
/// The `Device` type yielded by the host.
|
||||
type Device: Device;
|
||||
/// The type used to uniquely distinguish between streams.
|
||||
type StreamId: StreamId;
|
||||
|
||||
/// Creates a new input stream that will run from the given device and with the given format.
|
||||
///
|
||||
/// On success, returns an identifier for the stream.
|
||||
///
|
||||
/// Can return an error if the device is no longer valid, or if the input stream format is not
|
||||
/// supported by the device.
|
||||
fn build_input_stream(
|
||||
&self,
|
||||
device: &Self::Device,
|
||||
format: &Format,
|
||||
) -> Result<Self::StreamId, BuildStreamError>;
|
||||
|
||||
/// Creates a new output stream that will play on the given device and with the given format.
|
||||
///
|
||||
/// On success, returns an identifier for the stream.
|
||||
///
|
||||
/// Can return an error if the device is no longer valid, or if the output stream format is not
|
||||
/// supported by the device.
|
||||
fn build_output_stream(
|
||||
&self,
|
||||
device: &Self::Device,
|
||||
format: &Format,
|
||||
) -> Result<Self::StreamId, BuildStreamError>;
|
||||
|
||||
/// Instructs the audio device that it should start playing the stream with the given ID.
|
||||
///
|
||||
/// Has no effect is the stream was already playing.
|
||||
///
|
||||
/// Only call this after you have submitted some data, otherwise you may hear some glitches.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// If the stream does not exist, this function can either panic or be a no-op.
|
||||
fn play_stream(&self, stream: Self::StreamId) -> Result<(), PlayStreamError>;
|
||||
|
||||
/// Instructs the audio device that it should stop playing the stream with the given ID.
|
||||
///
|
||||
/// Has no effect is the stream was already paused.
|
||||
///
|
||||
/// If you call `play` afterwards, the playback will resume where it was.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// If the stream does not exist, this function can either panic or be a no-op.
|
||||
fn pause_stream(&self, stream: Self::StreamId) -> Result<(), PauseStreamError>;
|
||||
|
||||
/// Destroys an existing stream.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// If the stream does not exist, this function can either panic or be a no-op.
|
||||
fn destroy_stream(&self, stream: Self::StreamId);
|
||||
|
||||
/// Takes control of the current thread and begins the stream processing.
|
||||
///
|
||||
/// > **Note**: Since it takes control of the thread, this method is best called on a separate
|
||||
/// > thread.
|
||||
///
|
||||
/// Whenever a stream needs to be fed some data, the closure passed as parameter is called.
|
||||
/// You can call the other methods of `EventLoop` without getting a deadlock.
|
||||
fn run<F>(&self, callback: F) -> !
|
||||
where
|
||||
F: FnMut(Self::StreamId, StreamDataResult) + Send;
|
||||
}
|
||||
|
||||
/// The set of required bounds for host `StreamId` types.
|
||||
pub trait StreamId: Clone + std::fmt::Debug + PartialEq + Eq {}
|
||||
pub mod traits;
|
||||
|
||||
/// A host's device iterator yielding only *input* devices.
|
||||
pub type InputDevices<I> = std::iter::Filter<I, fn(&<I as Iterator>::Item) -> bool>;
|
||||
|
|
|
@ -199,7 +199,7 @@ macro_rules! impl_platform_host {
|
|||
}
|
||||
}
|
||||
|
||||
impl crate::Device for Device {
|
||||
impl crate::traits::DeviceTrait for Device {
|
||||
type SupportedInputFormats = SupportedInputFormats;
|
||||
type SupportedOutputFormats = SupportedOutputFormats;
|
||||
|
||||
|
@ -252,7 +252,7 @@ macro_rules! impl_platform_host {
|
|||
}
|
||||
}
|
||||
|
||||
impl crate::EventLoop for EventLoop {
|
||||
impl crate::traits::EventLoopTrait for EventLoop {
|
||||
type StreamId = StreamId;
|
||||
type Device = Device;
|
||||
|
||||
|
@ -335,7 +335,7 @@ macro_rules! impl_platform_host {
|
|||
}
|
||||
}
|
||||
|
||||
impl crate::Host for Host {
|
||||
impl crate::traits::HostTrait for Host {
|
||||
type Devices = Devices;
|
||||
type Device = Device;
|
||||
type EventLoop = EventLoop;
|
||||
|
@ -385,7 +385,7 @@ macro_rules! impl_platform_host {
|
|||
}
|
||||
}
|
||||
|
||||
impl crate::StreamId for StreamId {}
|
||||
impl crate::traits::StreamIdTrait for StreamId {}
|
||||
|
||||
$(
|
||||
impl From<crate::host::$host_mod::Device> for Device {
|
||||
|
@ -423,7 +423,7 @@ macro_rules! impl_platform_host {
|
|||
pub fn available_hosts() -> Vec<HostId> {
|
||||
let mut host_ids = vec![];
|
||||
$(
|
||||
if <crate::host::$host_mod::Host as crate::Host>::is_available() {
|
||||
if <crate::host::$host_mod::Host as crate::traits::HostTrait>::is_available() {
|
||||
host_ids.push(HostId::$HostVariant);
|
||||
}
|
||||
)*
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
//! The suite of traits allowing CPAL to abstract over hosts, devices, event loops and stream IDs.
|
||||
|
||||
use {
|
||||
BuildStreamError,
|
||||
DefaultFormatError,
|
||||
DeviceNameError,
|
||||
DevicesError,
|
||||
Format,
|
||||
InputDevices,
|
||||
OutputDevices,
|
||||
PauseStreamError,
|
||||
PlayStreamError,
|
||||
StreamDataResult,
|
||||
SupportedFormat,
|
||||
SupportedFormatsError,
|
||||
};
|
||||
|
||||
/// A **Host** provides access to the available audio devices on the system.
|
||||
///
|
||||
/// Each platform may have a number of available hosts depending on the system, each with their own
|
||||
/// pros and cons.
|
||||
///
|
||||
/// For example, WASAPI is the standard audio host API that ships with the Windows operating
|
||||
/// system. However, due to historical limitations with respect to performance and flexibility,
|
||||
/// Steinberg created the ASIO API providing better audio device support for pro audio and
|
||||
/// low-latency applications. As a result, it is common for some devices and device capabilities to
|
||||
/// only be available via ASIO, while others are only available via WASAPI.
|
||||
///
|
||||
/// Another great example is the Linux platform. While the ALSA host API is the lowest-level API
|
||||
/// available to almost all distributions of Linux, its flexibility is limited as it requires that
|
||||
/// each process have exclusive access to the devices with which they establish streams. PulseAudio
|
||||
/// is another popular host API that aims to solve this issue by providing user-space mixing,
|
||||
/// however it has its own limitations w.r.t. low-latency and high-performance audio applications.
|
||||
/// JACK is yet another host API that is more suitable to pro-audio applications, however it is
|
||||
/// less readily available by default in many Linux distributions and is known to be tricky to
|
||||
/// setup.
|
||||
pub trait HostTrait {
|
||||
/// The type used for enumerating available devices by the host.
|
||||
type Devices: Iterator<Item = Self::Device>;
|
||||
/// The `Device` type yielded by the host.
|
||||
type Device: DeviceTrait;
|
||||
/// The event loop type used by the `Host`
|
||||
type EventLoop: EventLoopTrait<Device = Self::Device>;
|
||||
|
||||
/// Whether or not the host is available on the system.
|
||||
fn is_available() -> bool;
|
||||
|
||||
/// An iterator yielding all `Device`s currently available to the host on the system.
|
||||
///
|
||||
/// Can be empty if the system does not support audio in general.
|
||||
fn devices(&self) -> Result<Self::Devices, DevicesError>;
|
||||
|
||||
/// The default input audio device on the system.
|
||||
///
|
||||
/// Returns `None` if no input device is available.
|
||||
fn default_input_device(&self) -> Option<Self::Device>;
|
||||
|
||||
/// The default output audio device on the system.
|
||||
///
|
||||
/// Returns `None` if no output device is available.
|
||||
fn default_output_device(&self) -> Option<Self::Device>;
|
||||
|
||||
/// Initialise the event loop, ready for managing audio streams.
|
||||
fn event_loop(&self) -> Self::EventLoop;
|
||||
|
||||
/// An iterator yielding all `Device`s currently available to the system that support one or more
|
||||
/// input stream formats.
|
||||
///
|
||||
/// Can be empty if the system does not support audio input.
|
||||
fn input_devices(&self) -> Result<InputDevices<Self::Devices>, DevicesError> {
|
||||
fn supports_input<D: DeviceTrait>(device: &D) -> bool {
|
||||
device.supported_input_formats()
|
||||
.map(|mut iter| iter.next().is_some())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
Ok(self.devices()?.filter(supports_input::<Self::Device>))
|
||||
}
|
||||
|
||||
/// An iterator yielding all `Device`s currently available to the system that support one or more
|
||||
/// output stream formats.
|
||||
///
|
||||
/// Can be empty if the system does not support audio output.
|
||||
fn output_devices(&self) -> Result<OutputDevices<Self::Devices>, DevicesError> {
|
||||
fn supports_output<D: DeviceTrait>(device: &D) -> bool {
|
||||
device.supported_output_formats()
|
||||
.map(|mut iter| iter.next().is_some())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
Ok(self.devices()?.filter(supports_output::<Self::Device>))
|
||||
}
|
||||
}
|
||||
|
||||
/// A device that is capable of audio input and/or output.
|
||||
///
|
||||
/// Please note that `Device`s may become invalid if they get disconnected. Therefore all the
|
||||
/// methods that involve a device return a `Result` allowing the user to handle this case.
|
||||
pub trait DeviceTrait {
|
||||
/// The iterator type yielding supported input stream formats.
|
||||
type SupportedInputFormats: Iterator<Item = SupportedFormat>;
|
||||
/// The iterator type yielding supported output stream formats.
|
||||
type SupportedOutputFormats: Iterator<Item = SupportedFormat>;
|
||||
|
||||
/// The human-readable name of the device.
|
||||
fn name(&self) -> Result<String, DeviceNameError>;
|
||||
|
||||
/// An iterator yielding formats that are supported by the backend.
|
||||
///
|
||||
/// Can return an error if the device is no longer valid (eg. it has been disconnected).
|
||||
fn supported_input_formats(&self) -> Result<Self::SupportedInputFormats, SupportedFormatsError>;
|
||||
|
||||
/// An iterator yielding output stream formats that are supported by the device.
|
||||
///
|
||||
/// Can return an error if the device is no longer valid (eg. it has been disconnected).
|
||||
fn supported_output_formats(&self) -> Result<Self::SupportedOutputFormats, SupportedFormatsError>;
|
||||
|
||||
/// The default input stream format for the device.
|
||||
fn default_input_format(&self) -> Result<Format, DefaultFormatError>;
|
||||
|
||||
/// The default output stream format for the device.
|
||||
fn default_output_format(&self) -> Result<Format, DefaultFormatError>;
|
||||
}
|
||||
|
||||
/// Collection of streams managed together.
|
||||
///
|
||||
/// Created with the `Host::event_loop` method.
|
||||
pub trait EventLoopTrait {
|
||||
/// The `Device` type yielded by the host.
|
||||
type Device: DeviceTrait;
|
||||
/// The type used to uniquely distinguish between streams.
|
||||
type StreamId: StreamIdTrait;
|
||||
|
||||
/// Creates a new input stream that will run from the given device and with the given format.
|
||||
///
|
||||
/// On success, returns an identifier for the stream.
|
||||
///
|
||||
/// Can return an error if the device is no longer valid, or if the input stream format is not
|
||||
/// supported by the device.
|
||||
fn build_input_stream(
|
||||
&self,
|
||||
device: &Self::Device,
|
||||
format: &Format,
|
||||
) -> Result<Self::StreamId, BuildStreamError>;
|
||||
|
||||
/// Creates a new output stream that will play on the given device and with the given format.
|
||||
///
|
||||
/// On success, returns an identifier for the stream.
|
||||
///
|
||||
/// Can return an error if the device is no longer valid, or if the output stream format is not
|
||||
/// supported by the device.
|
||||
fn build_output_stream(
|
||||
&self,
|
||||
device: &Self::Device,
|
||||
format: &Format,
|
||||
) -> Result<Self::StreamId, BuildStreamError>;
|
||||
|
||||
/// Instructs the audio device that it should start playing the stream with the given ID.
|
||||
///
|
||||
/// Has no effect is the stream was already playing.
|
||||
///
|
||||
/// Only call this after you have submitted some data, otherwise you may hear some glitches.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// If the stream does not exist, this function can either panic or be a no-op.
|
||||
fn play_stream(&self, stream: Self::StreamId) -> Result<(), PlayStreamError>;
|
||||
|
||||
/// Instructs the audio device that it should stop playing the stream with the given ID.
|
||||
///
|
||||
/// Has no effect is the stream was already paused.
|
||||
///
|
||||
/// If you call `play` afterwards, the playback will resume where it was.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// If the stream does not exist, this function can either panic or be a no-op.
|
||||
fn pause_stream(&self, stream: Self::StreamId) -> Result<(), PauseStreamError>;
|
||||
|
||||
/// Destroys an existing stream.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// If the stream does not exist, this function can either panic or be a no-op.
|
||||
fn destroy_stream(&self, stream: Self::StreamId);
|
||||
|
||||
/// Takes control of the current thread and begins the stream processing.
|
||||
///
|
||||
/// > **Note**: Since it takes control of the thread, this method is best called on a separate
|
||||
/// > thread.
|
||||
///
|
||||
/// Whenever a stream needs to be fed some data, the closure passed as parameter is called.
|
||||
/// You can call the other methods of `EventLoop` without getting a deadlock.
|
||||
fn run<F>(&self, callback: F) -> !
|
||||
where
|
||||
F: FnMut(Self::StreamId, StreamDataResult) + Send;
|
||||
}
|
||||
|
||||
/// The set of required bounds for host `StreamId` types.
|
||||
pub trait StreamIdTrait: Clone + std::fmt::Debug + PartialEq + Eq {}
|
Loading…
Reference in New Issue