Remove device mixer map, rename stream wrapper to OutputStream

This commit is contained in:
Alex Butler 2020-02-03 23:06:23 +00:00
parent c93adb2582
commit b5071c947d
No known key found for this signature in database
GPG key ID: E1355A2F8E415521
12 changed files with 84 additions and 85 deletions

View file

@ -3,22 +3,22 @@ use std::thread;
use std::time::Duration; use std::time::Duration;
fn main() { fn main() {
let device = rodio::RodioDevice::default_output().unwrap(); let stream = rodio::OutputStream::try_default().unwrap();
let file = std::fs::File::open("examples/beep.wav").unwrap(); let file = std::fs::File::open("examples/beep.wav").unwrap();
let beep1 = device.play_once(BufReader::new(file)).unwrap(); let beep1 = stream.play_once(BufReader::new(file)).unwrap();
beep1.set_volume(0.2); beep1.set_volume(0.2);
println!("Started beep1"); println!("Started beep1");
thread::sleep(Duration::from_millis(1500)); thread::sleep(Duration::from_millis(1500));
let file = std::fs::File::open("examples/beep2.wav").unwrap(); let file = std::fs::File::open("examples/beep2.wav").unwrap();
device.play_once(BufReader::new(file)).unwrap().detach(); stream.play_once(BufReader::new(file)).unwrap().detach();
println!("Started beep2"); println!("Started beep2");
thread::sleep(Duration::from_millis(1500)); thread::sleep(Duration::from_millis(1500));
let file = std::fs::File::open("examples/beep3.ogg").unwrap(); let file = std::fs::File::open("examples/beep3.ogg").unwrap();
let beep3 = device.play_once(file).unwrap(); let beep3 = stream.play_once(file).unwrap();
println!("Started beep3"); println!("Started beep3");
thread::sleep(Duration::from_millis(1500)); thread::sleep(Duration::from_millis(1500));

View file

@ -1,8 +1,8 @@
use std::io::BufReader; use std::io::BufReader;
fn main() { fn main() {
let device = rodio::RodioDevice::default_output().unwrap(); let stream = rodio::OutputStream::try_default().unwrap();
let sink = rodio::Sink::new(&device); let sink = rodio::Sink::new(&stream);
let file = std::fs::File::open("examples/music.flac").unwrap(); let file = std::fs::File::open("examples/music.flac").unwrap();
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap()); sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap());

View file

@ -1,8 +1,8 @@
use std::io::BufReader; use std::io::BufReader;
fn main() { fn main() {
let device = rodio::RodioDevice::default_output().unwrap(); let stream = rodio::OutputStream::try_default().unwrap();
let sink = rodio::Sink::new(&device); let sink = rodio::Sink::new(&stream);
let file = std::fs::File::open("examples/music.mp3").unwrap(); let file = std::fs::File::open("examples/music.mp3").unwrap();
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap()); sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap());

View file

@ -1,8 +1,8 @@
use std::io::BufReader; use std::io::BufReader;
fn main() { fn main() {
let device = rodio::RodioDevice::default_output().unwrap(); let stream = rodio::OutputStream::try_default().unwrap();
let sink = rodio::Sink::new(&device); let sink = rodio::Sink::new(&stream);
let file = std::fs::File::open("examples/music.ogg").unwrap(); let file = std::fs::File::open("examples/music.ogg").unwrap();
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap()); sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap());

View file

@ -1,8 +1,8 @@
use std::io::BufReader; use std::io::BufReader;
fn main() { fn main() {
let device = rodio::RodioDevice::default_output().unwrap(); let stream = rodio::OutputStream::try_default().unwrap();
let sink = rodio::Sink::new(&device); let sink = rodio::Sink::new(&stream);
let file = std::fs::File::open("examples/music.wav").unwrap(); let file = std::fs::File::open("examples/music.wav").unwrap();
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap()); sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap());

View file

@ -1,12 +1,10 @@
use rodio;
use rodio::Source; use rodio::Source;
use std::io::BufReader; use std::io::BufReader;
use std::time::Duration; use std::time::Duration;
fn main() { fn main() {
let device = rodio::RodioDevice::default_output().unwrap(); let stream = rodio::OutputStream::try_default().unwrap();
let sink = rodio::Sink::new(&device); let sink = rodio::Sink::new(&stream);
let file = std::fs::File::open("examples/music.ogg").unwrap(); let file = std::fs::File::open("examples/music.ogg").unwrap();
let source = rodio::Decoder::new(BufReader::new(file)).unwrap(); let source = rodio::Decoder::new(BufReader::new(file)).unwrap();

View file

@ -1,13 +1,11 @@
use rodio;
use std::io::BufReader; use std::io::BufReader;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
fn main() { fn main() {
let device = rodio::RodioDevice::default_output().unwrap(); let stream = rodio::OutputStream::try_default().unwrap();
let sink = rodio::SpatialSink::new( let sink = rodio::SpatialSink::new(
&device, &stream,
[-10.0, 0.0, 0.0], [-10.0, 0.0, 0.0],
[1.0, 0.0, 0.0], [1.0, 0.0, 0.0],
[-1.0, 0.0, 0.0], [-1.0, 0.0, 0.0],

View file

@ -1,30 +0,0 @@
use crate::device::CpalDeviceExt;
use crate::dynamic_mixer::DynamicMixerController;
use crate::source::Source;
use cpal::traits::{DeviceTrait, StreamTrait};
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Default)]
pub(crate) struct DeviceMixer {
// TODO: don't use the device name as it's slow
/// Device name -> (mixer, stream)
mixers: HashMap<String, (Arc<DynamicMixerController<f32>>, cpal::Stream)>,
}
impl DeviceMixer {
pub(crate) fn play<S>(&mut self, device: &cpal::Device, source: S)
where
S: Source<Item = f32> + Send + 'static,
{
let device_name = device.name().expect("No device name");
let (ref mut mixer, _) = self.mixers.entry(device_name).or_insert_with(|| {
let (mixer, stream) = device.new_output_stream();
stream.play().expect("play");
(mixer, stream)
});
mixer.add(source);
}
}

View file

@ -20,11 +20,11 @@
//! use std::io::BufReader; //! use std::io::BufReader;
//! use rodio::Source; //! use rodio::Source;
//! //!
//! let device = rodio::RodioDevice::default_output().unwrap(); //! let stream = rodio::OutputStream::try_default().unwrap();
//! //!
//! let file = File::open("sound.ogg").unwrap(); //! let file = File::open("sound.ogg").unwrap();
//! let source = rodio::Decoder::new(BufReader::new(file)).unwrap(); //! let source = rodio::Decoder::new(BufReader::new(file)).unwrap();
//! device.play_raw(source.convert_samples()); //! stream.play_raw(source.convert_samples());
//! ``` //! ```
//! //!
//! ## Sink //! ## Sink
@ -38,8 +38,8 @@
//! ```no_run //! ```no_run
//! use rodio::Sink; //! use rodio::Sink;
//! //!
//! let device = rodio::RodioDevice::default_output().unwrap(); //! let stream = rodio::OutputStream::try_default().unwrap();
//! let sink = Sink::new(&device); //! let sink = rodio::Sink::new(&stream);
//! //!
//! // Add a dummy source of the sake of the example. //! // Add a dummy source of the sake of the example.
//! let source = rodio::source::SineWave::new(440); //! let source = rodio::source::SineWave::new(440);
@ -86,16 +86,8 @@ pub use cpal::{
traits::DeviceTrait, Device, Devices, DevicesError, Format, InputDevices, OutputDevices, traits::DeviceTrait, Device, Devices, DevicesError, Format, InputDevices, OutputDevices,
}; };
pub use crate::conversions::Sample;
pub use crate::decoder::Decoder;
pub use crate::device::RodioDevice;
pub use crate::sink::Sink;
pub use crate::source::Source;
pub use crate::spatial_sink::SpatialSink;
mod conversions; mod conversions;
mod device; mod stream;
mod device_mixer;
mod sink; mod sink;
mod spatial_sink; mod spatial_sink;
@ -105,3 +97,10 @@ pub mod dynamic_mixer;
pub mod queue; pub mod queue;
pub mod source; pub mod source;
pub mod static_buffer; pub mod static_buffer;
pub use crate::conversions::Sample;
pub use crate::decoder::Decoder;
pub use crate::stream::{OutputStream, StreamError};
pub use crate::sink::Sink;
pub use crate::source::Source;
pub use crate::spatial_sink::SpatialSink;

View file

@ -1,4 +1,4 @@
use crate::device::RodioDevice; use crate::stream::OutputStream;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::sync::atomic::{AtomicBool, AtomicUsize};
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
@ -34,9 +34,9 @@ struct Controls {
impl Sink { impl Sink {
/// Builds a new `Sink`, beginning playback on a Device. /// Builds a new `Sink`, beginning playback on a Device.
#[inline] #[inline]
pub fn new(device: &RodioDevice) -> Sink { pub fn new(stream: &OutputStream) -> Sink {
let (sink, queue_rx) = Sink::new_idle(); let (sink, queue_rx) = Sink::new_idle();
device.play_raw(queue_rx); stream.play_raw(queue_rx);
sink sink
} }

View file

@ -1,4 +1,4 @@
use crate::device::RodioDevice; use crate::stream::OutputStream;
use crate::source::Spatial; use crate::source::Spatial;
use crate::Sample; use crate::Sample;
use crate::Sink; use crate::Sink;
@ -23,13 +23,13 @@ impl SpatialSink {
/// Builds a new `SpatialSink`. /// Builds a new `SpatialSink`.
#[inline] #[inline]
pub fn new( pub fn new(
device: &RodioDevice, stream: &OutputStream,
emitter_position: [f32; 3], emitter_position: [f32; 3],
left_ear: [f32; 3], left_ear: [f32; 3],
right_ear: [f32; 3], right_ear: [f32; 3],
) -> SpatialSink { ) -> SpatialSink {
SpatialSink { SpatialSink {
sink: Sink::new(device), sink: Sink::new(stream),
positions: Arc::new(Mutex::new(SoundPositions { positions: Arc::new(Mutex::new(SoundPositions {
emitter_position, emitter_position,
left_ear, left_ear,

View file

@ -1,33 +1,37 @@
use crate::decoder; use crate::decoder;
use crate::device_mixer::DeviceMixer;
use crate::dynamic_mixer::{self, DynamicMixerController}; use crate::dynamic_mixer::{self, DynamicMixerController};
use crate::sink::Sink; use crate::sink::Sink;
use crate::source::Source; use crate::source::Source;
use cpal::{ use cpal::{
traits::{DeviceTrait, HostTrait}, traits::{DeviceTrait, HostTrait, StreamTrait},
Sample, Sample,
}; };
use std::cell::RefCell; use std::convert::TryFrom;
use std::io::{Read, Seek}; use std::io::{Read, Seek};
use std::sync::Arc; use std::sync::Arc;
use std::{error, fmt};
pub struct RodioDevice { pub struct OutputStream {
mixer: RefCell<DeviceMixer>, mixer: Arc<DynamicMixerController<f32>>,
inner: cpal::Device, _stream: cpal::Stream,
} }
impl From<cpal::Device> for RodioDevice { impl TryFrom<&'_ cpal::Device> for OutputStream {
fn from(device: cpal::Device) -> Self { type Error = StreamError;
Self {
inner: device, fn try_from(device: &cpal::Device) -> Result<Self, Self::Error> {
mixer: <_>::default(), let (mixer, _stream) = device.new_output_stream();
} _stream.play()?;
Ok(Self { mixer, _stream })
} }
} }
impl RodioDevice { impl OutputStream {
pub fn default_output() -> Option<Self> { pub fn try_default() -> Result<Self, StreamError> {
Some(cpal::default_host().default_output_device()?.into()) let device = cpal::default_host()
.default_output_device()
.ok_or(StreamError::NoDevice)?;
Self::try_from(&device)
} }
/// Plays a source with a device until it ends. /// Plays a source with a device until it ends.
@ -35,7 +39,7 @@ impl RodioDevice {
where where
S: Source<Item = f32> + Send + 'static, S: Source<Item = f32> + Send + 'static,
{ {
self.mixer.borrow_mut().play(&self.inner, source) self.mixer.add(source);
} }
/// Plays a sound once. Returns a `Sink` that can be used to control the sound. /// Plays a sound once. Returns a `Sink` that can be used to control the sound.
@ -51,6 +55,36 @@ impl RodioDevice {
} }
} }
#[derive(Debug)]
pub enum StreamError {
PlayStreamError(cpal::PlayStreamError),
NoDevice,
}
impl From<cpal::PlayStreamError> for StreamError {
fn from(err: cpal::PlayStreamError) -> Self {
Self::PlayStreamError(err)
}
}
impl fmt::Display for StreamError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::PlayStreamError(e) => e.fmt(f),
Self::NoDevice => write!(f, "NoDevice"),
}
}
}
impl error::Error for StreamError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
Self::PlayStreamError(e) => Some(e),
Self::NoDevice => None,
}
}
}
/// Extensions to `cpal::Device` /// Extensions to `cpal::Device`
pub(crate) trait CpalDeviceExt { pub(crate) trait CpalDeviceExt {
fn new_output_stream_with_format( fn new_output_stream_with_format(