mirror of
https://github.com/RustAudio/rodio
synced 2025-03-04 06:57:16 +00:00
Remove device mixer map, rename stream wrapper to OutputStream
This commit is contained in:
parent
c93adb2582
commit
b5071c947d
12 changed files with 84 additions and 85 deletions
|
@ -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));
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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],
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
25
src/lib.rs
25
src/lib.rs
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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(
|
Loading…
Add table
Reference in a new issue