Remove EventLoop and port the ALSA backend

This commit is contained in:
Tatsuyuki Ishi 2019-07-09 15:47:33 +09:00 committed by mitchmindtree
parent 700bef79d9
commit c97d1dd3fa
8 changed files with 519 additions and 951 deletions

View File

@ -1,37 +1,34 @@
extern crate anyhow;
extern crate cpal;
use cpal::traits::{DeviceTrait, EventLoopTrait, HostTrait};
use cpal::traits::{DeviceTrait, StreamTrait, HostTrait};
fn main() -> Result<(), anyhow::Error> {
let host = cpal::default_host();
let device = host.default_output_device().expect("failed to find a default output device");
let format = device.default_output_format()?;
let event_loop = host.event_loop();
let stream_id = event_loop.build_output_stream(&device, &format)?;
event_loop.play_stream(stream_id.clone())?;
let sample_rate = format.sample_rate.0 as f32;
let channels = format.channels;
let mut sample_clock = 0f32;
// Produce a sinusoid of maximum amplitude.
let mut next_value = || {
let mut next_value = move || {
sample_clock = (sample_clock + 1.0) % sample_rate;
(sample_clock * 440.0 * 2.0 * 3.141592 / sample_rate).sin()
};
event_loop.run(move |id, result| {
let stream = device.build_output_stream(&format, move |result| {
let data = match result {
Ok(data) => data,
Err(err) => {
eprintln!("an error occurred on stream {:?}: {}", id, err);
eprintln!("an error occurred on stream: {}", err);
return;
}
};
match data {
cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::U16(mut buffer) } => {
for sample in buffer.chunks_mut(format.channels as usize) {
for sample in buffer.chunks_mut(channels as usize) {
let value = ((next_value() * 0.5 + 0.5) * std::u16::MAX as f32) as u16;
for out in sample.iter_mut() {
*out = value;
@ -39,7 +36,7 @@ fn main() -> Result<(), anyhow::Error> {
}
},
cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::I16(mut buffer) } => {
for sample in buffer.chunks_mut(format.channels as usize) {
for sample in buffer.chunks_mut(channels as usize) {
let value = (next_value() * std::i16::MAX as f32) as i16;
for out in sample.iter_mut() {
*out = value;
@ -47,7 +44,7 @@ fn main() -> Result<(), anyhow::Error> {
}
},
cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::F32(mut buffer) } => {
for sample in buffer.chunks_mut(format.channels as usize) {
for sample in buffer.chunks_mut(channels as usize) {
let value = next_value();
for out in sample.iter_mut() {
*out = value;
@ -56,5 +53,10 @@ fn main() -> Result<(), anyhow::Error> {
},
_ => (),
}
});
})?;
stream.play()?;
std::thread::sleep(std::time::Duration::from_millis(1000));
Ok(())
}

View File

@ -10,18 +10,21 @@ extern crate anyhow;
extern crate cpal;
extern crate ringbuf;
use cpal::traits::{DeviceTrait, EventLoopTrait, HostTrait};
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use ringbuf::RingBuffer;
const LATENCY_MS: f32 = 150.0;
fn main() -> Result<(), anyhow::Error> {
let host = cpal::default_host();
let event_loop = host.event_loop();
// Default devices.
let input_device = host.default_input_device().expect("failed to get default input device");
let output_device = host.default_output_device().expect("failed to get default output device");
let input_device = host
.default_input_device()
.expect("failed to get default input device");
let output_device = host
.default_output_device()
.expect("failed to get default output device");
println!("Using default input device: \"{}\"", input_device.name()?);
println!("Using default output device: \"{}\"", output_device.name()?);
@ -29,12 +32,6 @@ fn main() -> Result<(), anyhow::Error> {
let mut format = input_device.default_input_format()?;
format.data_type = cpal::SampleFormat::F32;
// Build streams.
println!("Attempting to build both streams with `{:?}`.", format);
let input_stream_id = event_loop.build_input_stream(&input_device, &format)?;
let output_stream_id = event_loop.build_output_stream(&output_device, &format)?;
println!("Successfully built streams.");
// Create a delay in case the input and output devices aren't synced.
let latency_frames = (LATENCY_MS / 1_000.0) * format.sample_rate.0 as f32;
let latency_samples = latency_frames as usize * format.channels as usize;
@ -50,59 +47,78 @@ fn main() -> Result<(), anyhow::Error> {
producer.push(0.0).unwrap();
}
// Play the streams.
println!("Starting the input and output streams with `{}` milliseconds of latency.", LATENCY_MS);
event_loop.play_stream(input_stream_id.clone())?;
event_loop.play_stream(output_stream_id.clone())?;
// Build streams.
println!("Attempting to build both streams with `{:?}`.", format);
let input_stream = input_device.build_input_stream(&format, move |result| {
let data = match result {
Ok(data) => data,
Err(err) => {
eprintln!("an error occurred on input stream: {}", err);
return;
},
};
// Run the event loop on a separate thread.
std::thread::spawn(move || {
event_loop.run(move |id, result| {
let data = match result {
Ok(data) => data,
Err(err) => {
eprintln!("an error occurred on stream {:?}: {}", id, err);
return;
match data {
cpal::StreamData::Input {
buffer: cpal::UnknownTypeInputBuffer::F32(buffer),
} => {
let mut output_fell_behind = false;
for &sample in buffer.iter() {
if producer.push(sample).is_err() {
output_fell_behind = true;
}
}
};
if output_fell_behind {
eprintln!("output stream fell behind: try increasing latency");
}
},
_ => panic!("Expected input with f32 data"),
}
})?;
let output_stream = output_device.build_output_stream(&format, move |result| {
let data = match result {
Ok(data) => data,
Err(err) => {
eprintln!("an error occurred on output stream: {}", err);
return;
},
};
match data {
cpal::StreamData::Output {
buffer: cpal::UnknownTypeOutputBuffer::F32(mut buffer),
} => {
let mut input_fell_behind = None;
for sample in buffer.iter_mut() {
*sample = match consumer.pop() {
Ok(s) => s,
Err(err) => {
input_fell_behind = Some(err);
0.0
},
};
}
if let Some(err) = input_fell_behind {
eprintln!("input stream fell behind: {:?}: try increasing latency", err);
}
},
_ => panic!("Expected output with f32 data"),
}
})?;
println!("Successfully built streams.");
match data {
cpal::StreamData::Input { buffer: cpal::UnknownTypeInputBuffer::F32(buffer) } => {
assert_eq!(id, input_stream_id);
let mut output_fell_behind = false;
for &sample in buffer.iter() {
if producer.push(sample).is_err() {
output_fell_behind = true;
}
}
if output_fell_behind {
eprintln!("output stream fell behind: try increasing latency");
}
},
cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::F32(mut buffer) } => {
assert_eq!(id, output_stream_id);
let mut input_fell_behind = None;
for sample in buffer.iter_mut() {
*sample = match consumer.pop() {
Ok(s) => s,
Err(err) => {
input_fell_behind = Some(err);
0.0
},
};
}
if let Some(_) = input_fell_behind {
eprintln!("input stream fell behind: try increasing latency");
}
},
_ => panic!("we're expecting f32 data"),
}
});
});
// Play the streams.
println!(
"Starting the input and output streams with `{}` milliseconds of latency.",
LATENCY_MS
);
input_stream.play()?;
output_stream.play()?;
// Run for 3 seconds before closing.
println!("Playing for 3 seconds... ");
std::thread::sleep(std::time::Duration::from_secs(3));
drop(input_stream);
drop(output_stream);
println!("Done!");
Ok(())
}

View File

@ -6,21 +6,21 @@ extern crate anyhow;
extern crate cpal;
extern crate hound;
use cpal::traits::{DeviceTrait, EventLoopTrait, HostTrait};
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
fn main() -> Result<(), anyhow::Error> {
// Use the default host for working with audio devices.
let host = cpal::default_host();
// Setup the default input device and stream with the default input format.
let device = host.default_input_device().expect("Failed to get default input device");
let device = host
.default_input_device()
.expect("Failed to get default input device");
println!("Default input device: {}", device.name()?);
let format = device.default_input_format().expect("Failed to get default input format");
let format = device
.default_input_format()
.expect("Failed to get default input format");
println!("Default input format: {:?}", format);
let event_loop = host.event_loop();
let stream_id = event_loop.build_input_stream(&device, &format)?;
event_loop.play_stream(stream_id)?;
// The WAV file we're recording to.
const PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/recorded.wav");
let spec = wav_spec_from_format(&format);
@ -29,63 +29,62 @@ fn main() -> Result<(), anyhow::Error> {
// A flag to indicate that recording is in progress.
println!("Begin recording...");
let recording = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true));
// Run the input stream on a separate thread.
let writer_2 = writer.clone();
let recording_2 = recording.clone();
std::thread::spawn(move || {
event_loop.run(move |id, event| {
let data = match event {
Ok(data) => data,
Err(err) => {
eprintln!("an error occurred on stream {:?}: {}", id, err);
return;
}
};
// If we're done recording, return early.
if !recording_2.load(std::sync::atomic::Ordering::Relaxed) {
let stream = device.build_input_stream(&format, move |event| {
let data = match event {
Ok(data) => data,
Err(err) => {
eprintln!("an error occurred on stream: {}", err);
return;
}
// Otherwise write to the wav writer.
match data {
cpal::StreamData::Input { buffer: cpal::UnknownTypeInputBuffer::U16(buffer) } => {
if let Ok(mut guard) = writer_2.try_lock() {
if let Some(writer) = guard.as_mut() {
for sample in buffer.iter() {
let sample = cpal::Sample::to_i16(sample);
writer.write_sample(sample).ok();
}
},
};
// Otherwise write to the wav writer.
match data {
cpal::StreamData::Input {
buffer: cpal::UnknownTypeInputBuffer::U16(buffer),
} => {
if let Ok(mut guard) = writer_2.try_lock() {
if let Some(writer) = guard.as_mut() {
for sample in buffer.iter() {
let sample = cpal::Sample::to_i16(sample);
writer.write_sample(sample).ok();
}
}
},
cpal::StreamData::Input { buffer: cpal::UnknownTypeInputBuffer::I16(buffer) } => {
if let Ok(mut guard) = writer_2.try_lock() {
if let Some(writer) = guard.as_mut() {
for &sample in buffer.iter() {
writer.write_sample(sample).ok();
}
}
},
cpal::StreamData::Input {
buffer: cpal::UnknownTypeInputBuffer::I16(buffer),
} => {
if let Ok(mut guard) = writer_2.try_lock() {
if let Some(writer) = guard.as_mut() {
for &sample in buffer.iter() {
writer.write_sample(sample).ok();
}
}
},
cpal::StreamData::Input { buffer: cpal::UnknownTypeInputBuffer::F32(buffer) } => {
if let Ok(mut guard) = writer_2.try_lock() {
if let Some(writer) = guard.as_mut() {
for &sample in buffer.iter() {
writer.write_sample(sample).ok();
}
}
},
cpal::StreamData::Input {
buffer: cpal::UnknownTypeInputBuffer::F32(buffer),
} => {
if let Ok(mut guard) = writer_2.try_lock() {
if let Some(writer) = guard.as_mut() {
for &sample in buffer.iter() {
writer.write_sample(sample).ok();
}
}
},
_ => (),
}
});
});
}
},
_ => (),
}
})?;
stream.play()?;
// Let recording go for roughly three seconds.
std::thread::sleep(std::time::Duration::from_secs(3));
recording.store(false, std::sync::atomic::Ordering::Relaxed);
drop(stream);
writer.lock().unwrap().take().unwrap().finalize()?;
println!("Recording {} complete!", PATH);
Ok(())

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@ use PlayStreamError;
use StreamDataResult;
use SupportedFormatsError;
use SupportedFormat;
use traits::{DeviceTrait, EventLoopTrait, HostTrait, StreamIdTrait};
use traits::{DeviceTrait, HostTrait, StreamTrait};
#[derive(Default)]
pub struct Devices;
@ -23,7 +23,7 @@ pub struct EventLoop;
pub struct Host;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StreamId;
pub struct Stream;
pub struct SupportedInputFormats;
pub struct SupportedOutputFormats;
@ -49,6 +49,7 @@ impl EventLoop {
impl DeviceTrait for Device {
type SupportedInputFormats = SupportedInputFormats;
type SupportedOutputFormats = SupportedOutputFormats;
type Stream = Stream;
#[inline]
fn name(&self) -> Result<String, DeviceNameError> {
@ -74,49 +75,22 @@ impl DeviceTrait for Device {
fn default_output_format(&self) -> Result<Format, DefaultFormatError> {
unimplemented!()
}
}
impl EventLoopTrait for EventLoop {
type Device = Device;
type StreamId = StreamId;
#[inline]
fn run<F>(&self, _callback: F) -> !
where F: FnMut(StreamId, StreamDataResult)
{
loop { /* TODO: don't spin */ }
}
#[inline]
fn build_input_stream(&self, _: &Device, _: &Format) -> Result<StreamId, BuildStreamError> {
Err(BuildStreamError::DeviceNotAvailable)
}
#[inline]
fn build_output_stream(&self, _: &Device, _: &Format) -> Result<StreamId, BuildStreamError> {
Err(BuildStreamError::DeviceNotAvailable)
}
#[inline]
fn destroy_stream(&self, _: StreamId) {
fn build_input_stream<F>(&self, format: &Format, callback: F) -> Result<Self::Stream, BuildStreamError>
where F: FnMut(StreamDataResult) + Send + 'static {
unimplemented!()
}
#[inline]
fn play_stream(&self, _: StreamId) -> Result<(), PlayStreamError> {
panic!()
}
#[inline]
fn pause_stream(&self, _: StreamId) -> Result<(), PauseStreamError> {
panic!()
/// Create an output stream.
fn build_output_stream<F>(&self, format: &Format, callback: F) -> Result<Self::Stream, BuildStreamError>
where F: FnMut(StreamDataResult) + Send + 'static{
unimplemented!()
}
}
impl HostTrait for Host {
type Device = Device;
type Devices = Devices;
type EventLoop = EventLoop;
fn is_available() -> bool {
false
@ -133,13 +107,17 @@ impl HostTrait for Host {
fn default_output_device(&self) -> Option<Device> {
None
}
fn event_loop(&self) -> Self::EventLoop {
EventLoop::new()
}
}
impl StreamIdTrait for StreamId {}
impl StreamTrait for Stream {
fn play(&self) -> Result<(), PlayStreamError> {
unimplemented!()
}
fn pause(&self) -> Result<(), PauseStreamError> {
unimplemented!()
}
}
impl Iterator for Devices {
type Item = Device;

View File

@ -151,11 +151,10 @@ extern crate thiserror;
pub use error::*;
pub use platform::{
ALL_HOSTS, Device, Devices, EventLoop, Host, HostId, SupportedInputFormats,
SupportedOutputFormats, StreamId, available_hosts, default_host, host_from_id,
ALL_HOSTS, available_hosts, default_host, Device, Devices, Host, host_from_id,
HostId, Stream, SupportedInputFormats, SupportedOutputFormats,
};
pub use samples_formats::{Sample, SampleFormat};
use std::ops::{Deref, DerefMut};
mod error;

View File

@ -58,14 +58,9 @@ macro_rules! impl_platform_host {
/// type.
pub struct Devices(DevicesInner);
/// The **EventLoop** implementation associated with the platform's dynamically dispatched
/// The **Stream** implementation associated with the platform's dynamically dispatched
/// **Host** type.
pub struct EventLoop(EventLoopInner);
/// The **StreamId** implementation associated with the platform's dynamically dispatched
/// **Host** type.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct StreamId(StreamIdInner);
pub struct Stream(StreamInner);
/// The **SupportedInputFormats** iterator associated with the platform's dynamically
/// dispatched **Host** type.
@ -95,22 +90,15 @@ macro_rules! impl_platform_host {
)*
}
enum EventLoopInner {
$(
$HostVariant(crate::host::$host_mod::EventLoop),
)*
}
enum HostInner {
$(
$HostVariant(crate::host::$host_mod::Host),
)*
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
enum StreamIdInner {
enum StreamInner {
$(
$HostVariant(crate::host::$host_mod::StreamId),
$HostVariant(crate::host::$host_mod::Stream),
)*
}
@ -212,6 +200,7 @@ macro_rules! impl_platform_host {
impl crate::traits::DeviceTrait for Device {
type SupportedInputFormats = SupportedInputFormats;
type SupportedOutputFormats = SupportedOutputFormats;
type Stream = Stream;
fn name(&self) -> Result<String, crate::DeviceNameError> {
match self.0 {
@ -260,96 +249,25 @@ macro_rules! impl_platform_host {
)*
}
}
}
impl crate::traits::EventLoopTrait for EventLoop {
type StreamId = StreamId;
type Device = Device;
#[allow(unreachable_patterns)]
fn build_input_stream(
&self,
device: &Self::Device,
format: &crate::Format,
) -> Result<Self::StreamId, crate::BuildStreamError> {
match (&self.0, &device.0) {
$(
(&EventLoopInner::$HostVariant(ref e), &DeviceInner::$HostVariant(ref d)) => {
e.build_input_stream(d, format)
.map(StreamIdInner::$HostVariant)
.map(StreamId)
}
)*
_ => panic!("tried to build a stream with a device from another host"),
}
}
#[allow(unreachable_patterns)]
fn build_output_stream(
&self,
device: &Self::Device,
format: &crate::Format,
) -> Result<Self::StreamId, crate::BuildStreamError> {
match (&self.0, &device.0) {
$(
(&EventLoopInner::$HostVariant(ref e), &DeviceInner::$HostVariant(ref d)) => {
e.build_output_stream(d, format)
.map(StreamIdInner::$HostVariant)
.map(StreamId)
}
)*
_ => panic!("tried to build a stream with a device from another host"),
}
}
#[allow(unreachable_patterns)]
fn play_stream(&self, stream: Self::StreamId) -> Result<(), crate::PlayStreamError> {
match (&self.0, stream.0) {
$(
(&EventLoopInner::$HostVariant(ref e), StreamIdInner::$HostVariant(ref s)) => {
e.play_stream(s.clone())
}
)*
_ => panic!("tried to play a stream with an ID associated with another host"),
}
}
#[allow(unreachable_patterns)]
fn pause_stream(&self, stream: Self::StreamId) -> Result<(), crate::PauseStreamError> {
match (&self.0, stream.0) {
$(
(&EventLoopInner::$HostVariant(ref e), StreamIdInner::$HostVariant(ref s)) => {
e.pause_stream(s.clone())
}
)*
_ => panic!("tried to pause a stream with an ID associated with another host"),
}
}
#[allow(unreachable_patterns)]
fn destroy_stream(&self, stream: Self::StreamId) {
match (&self.0, stream.0) {
$(
(&EventLoopInner::$HostVariant(ref e), StreamIdInner::$HostVariant(ref s)) => {
e.destroy_stream(s.clone())
}
)*
_ => panic!("tried to destroy a stream with an ID associated with another host"),
}
}
fn run<F>(&self, mut callback: F) -> !
where
F: FnMut(Self::StreamId, crate::StreamDataResult) + Send
{
fn build_input_stream<F>(&self, format: &crate::Format, callback: F) -> Result<Self::Stream, crate::BuildStreamError>
where F: FnMut(crate::StreamDataResult) + Send + 'static {
match self.0 {
$(
EventLoopInner::$HostVariant(ref e) => {
e.run(|id, result| {
let result = result;
callback(StreamId(StreamIdInner::$HostVariant(id)), result);
});
},
DeviceInner::$HostVariant(ref d) => d.build_input_stream(format, callback)
.map(StreamInner::$HostVariant)
.map(Stream),
)*
}
}
fn build_output_stream<F>(&self, format: &crate::Format, callback: F) -> Result<Self::Stream, crate::BuildStreamError>
where F: FnMut(crate::StreamDataResult) + Send + 'static {
match self.0 {
$(
DeviceInner::$HostVariant(ref d) => d.build_output_stream(format, callback)
.map(StreamInner::$HostVariant)
.map(Stream),
)*
}
}
@ -358,7 +276,6 @@ macro_rules! impl_platform_host {
impl crate::traits::HostTrait for Host {
type Devices = Devices;
type Device = Device;
type EventLoop = EventLoop;
fn is_available() -> bool {
$( crate::host::$host_mod::Host::is_available() ||)* false
@ -393,20 +310,30 @@ macro_rules! impl_platform_host {
)*
}
}
}
fn event_loop(&self) -> Self::EventLoop {
impl crate::traits::StreamTrait for Stream {
fn play(&self) -> Result<(), crate::PlayStreamError> {
match self.0 {
$(
HostInner::$HostVariant(ref h) => {
EventLoop(EventLoopInner::$HostVariant(h.event_loop()))
StreamInner::$HostVariant(ref s) => {
s.play()
}
)*
}
}
fn pause(&self) -> Result<(), crate::PauseStreamError> {
match self.0 {
$(
StreamInner::$HostVariant(ref s) => {
s.pause()
}
)*
}
}
}
impl crate::traits::StreamIdTrait for StreamId {}
$(
impl From<crate::host::$host_mod::Device> for Device {
fn from(h: crate::host::$host_mod::Device) -> Self {
@ -420,21 +347,15 @@ macro_rules! impl_platform_host {
}
}
impl From<crate::host::$host_mod::EventLoop> for EventLoop {
fn from(h: crate::host::$host_mod::EventLoop) -> Self {
EventLoop(EventLoopInner::$HostVariant(h))
}
}
impl From<crate::host::$host_mod::Host> for Host {
fn from(h: crate::host::$host_mod::Host) -> Self {
Host(HostInner::$HostVariant(h))
}
}
impl From<crate::host::$host_mod::StreamId> for StreamId {
fn from(h: crate::host::$host_mod::StreamId) -> Self {
StreamId(StreamIdInner::$HostVariant(h))
impl From<crate::host::$host_mod::Stream> for Stream {
fn from(h: crate::host::$host_mod::Stream) -> Self {
Stream(StreamInner::$HostVariant(h))
}
}
)*
@ -471,9 +392,8 @@ mod platform_impl {
pub use crate::host::alsa::{
Device as AlsaDevice,
Devices as AlsaDevices,
EventLoop as AlsaEventLoop,
Host as AlsaHost,
StreamId as AlsaStreamId,
Stream as AlsaStream,
SupportedInputFormats as AlsaSupportedInputFormats,
SupportedOutputFormats as AlsaSupportedOutputFormats,
};

View File

@ -39,8 +39,6 @@ pub trait HostTrait {
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;
@ -60,9 +58,6 @@ pub trait HostTrait {
/// 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.
///
@ -99,6 +94,8 @@ pub trait DeviceTrait {
type SupportedInputFormats: Iterator<Item = SupportedFormat>;
/// The iterator type yielding supported output stream formats.
type SupportedOutputFormats: Iterator<Item = SupportedFormat>;
/// The stream type created by `build_input_stream` and `build_output_stream`.
type Stream: StreamTrait;
/// The human-readable name of the device.
fn name(&self) -> Result<String, DeviceNameError>;
@ -118,81 +115,19 @@ pub trait DeviceTrait {
/// The default output stream format for the device.
fn default_output_format(&self) -> Result<Format, DefaultFormatError>;
/// Create an input stream.
fn build_input_stream<F>(&self, format: &Format, callback: F) -> Result<Self::Stream, BuildStreamError>
where F: FnMut(StreamDataResult) + Send + 'static;
/// Create an output stream.
fn build_output_stream<F>(&self, format: &Format, callback: F) -> Result<Self::Stream, BuildStreamError>
where F: FnMut(StreamDataResult) + Send + 'static;
}
/// 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;
/// A stream created from `Device`, with methods to control playback.
pub trait StreamTrait {
fn play(&self) -> Result<(), PlayStreamError>;
/// 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;
fn pause(&self) -> Result<(), PauseStreamError>;
}
/// The set of required bounds for host `StreamId` types.
pub trait StreamIdTrait: Clone + std::fmt::Debug + std::hash::Hash + PartialEq + Eq {}