//! 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; /// The `Device` type yielded by the host. type Device: DeviceTrait; /// The event loop type used by the `Host` type EventLoop: EventLoopTrait; /// 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; /// The default input audio device on the system. /// /// Returns `None` if no input device is available. fn default_input_device(&self) -> Option; /// The default output audio device on the system. /// /// Returns `None` if no output device is available. fn default_output_device(&self) -> Option; /// 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, DevicesError> { fn supports_input(device: &D) -> bool { device.supported_input_formats() .map(|mut iter| iter.next().is_some()) .unwrap_or(false) } Ok(self.devices()?.filter(supports_input::)) } /// 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, DevicesError> { fn supports_output(device: &D) -> bool { device.supported_output_formats() .map(|mut iter| iter.next().is_some()) .unwrap_or(false) } Ok(self.devices()?.filter(supports_output::)) } } /// 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; /// The iterator type yielding supported output stream formats. type SupportedOutputFormats: Iterator; /// The human-readable name of the device. fn name(&self) -> Result; /// 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; /// 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; /// The default input stream format for the device. fn default_input_format(&self) -> Result; /// The default output stream format for the device. fn default_output_format(&self) -> Result; } /// 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; /// 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; /// 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(&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 + std::hash::Hash + PartialEq + Eq {}