mirror of
https://github.com/RustAudio/rodio
synced 2024-11-10 06:04:16 +00:00
Add OutputStreamHandle
This commit is contained in:
parent
7ad840793c
commit
d7c77aa52e
11 changed files with 75 additions and 52 deletions
|
@ -3,24 +3,24 @@ use std::thread;
|
|||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
let stream = rodio::OutputStream::try_default().unwrap();
|
||||
let (_stream, stream_handle) = rodio::OutputStream::try_default().unwrap();
|
||||
|
||||
let file = std::fs::File::open("examples/beep.wav").unwrap();
|
||||
let beep1 = stream.play_once(BufReader::new(file)).unwrap();
|
||||
let beep1 = stream_handle.play_once(BufReader::new(file)).unwrap();
|
||||
beep1.set_volume(0.2);
|
||||
println!("Started beep1");
|
||||
|
||||
thread::sleep(Duration::from_millis(1500));
|
||||
|
||||
let file = std::fs::File::open("examples/beep2.wav").unwrap();
|
||||
let beep2 = stream.play_once(BufReader::new(file)).unwrap();
|
||||
let beep2 = stream_handle.play_once(BufReader::new(file)).unwrap();
|
||||
beep2.set_volume(0.3);
|
||||
beep2.detach();
|
||||
println!("Started beep2");
|
||||
|
||||
thread::sleep(Duration::from_millis(1500));
|
||||
let file = std::fs::File::open("examples/beep3.ogg").unwrap();
|
||||
let beep3 = stream.play_once(file).unwrap();
|
||||
let beep3 = stream_handle.play_once(file).unwrap();
|
||||
beep3.set_volume(0.2);
|
||||
println!("Started beep3");
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::io::BufReader;
|
||||
|
||||
fn main() {
|
||||
let stream = rodio::OutputStream::try_default().unwrap();
|
||||
let sink = rodio::Sink::new(&stream);
|
||||
let (_stream, handle) = rodio::OutputStream::try_default().unwrap();
|
||||
let sink = rodio::Sink::try_new(&handle).unwrap();
|
||||
|
||||
let file = std::fs::File::open("examples/music.flac").unwrap();
|
||||
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap());
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::io::BufReader;
|
||||
|
||||
fn main() {
|
||||
let stream = rodio::OutputStream::try_default().unwrap();
|
||||
let sink = rodio::Sink::new(&stream);
|
||||
let (_stream, handle) = rodio::OutputStream::try_default().unwrap();
|
||||
let sink = rodio::Sink::try_new(&handle).unwrap();
|
||||
|
||||
let file = std::fs::File::open("examples/music.mp3").unwrap();
|
||||
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap());
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::io::BufReader;
|
||||
|
||||
fn main() {
|
||||
let stream = rodio::OutputStream::try_default().unwrap();
|
||||
let sink = rodio::Sink::new(&stream);
|
||||
let (_stream, handle) = rodio::OutputStream::try_default().unwrap();
|
||||
let sink = rodio::Sink::try_new(&handle).unwrap();
|
||||
|
||||
let file = std::fs::File::open("examples/music.ogg").unwrap();
|
||||
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap());
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::io::BufReader;
|
||||
|
||||
fn main() {
|
||||
let stream = rodio::OutputStream::try_default().unwrap();
|
||||
let sink = rodio::Sink::new(&stream);
|
||||
let (_stream, handle) = rodio::OutputStream::try_default().unwrap();
|
||||
let sink = rodio::Sink::try_new(&handle).unwrap();
|
||||
|
||||
let file = std::fs::File::open("examples/music.wav").unwrap();
|
||||
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap());
|
||||
|
|
|
@ -3,8 +3,8 @@ use std::io::BufReader;
|
|||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
let stream = rodio::OutputStream::try_default().unwrap();
|
||||
let sink = rodio::Sink::new(&stream);
|
||||
let (_stream, handle) = rodio::OutputStream::try_default().unwrap();
|
||||
let sink = rodio::Sink::try_new(&handle).unwrap();
|
||||
|
||||
let file = std::fs::File::open("examples/music.ogg").unwrap();
|
||||
let source = rodio::Decoder::new(BufReader::new(file)).unwrap();
|
||||
|
|
|
@ -3,13 +3,13 @@ use std::thread;
|
|||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
let stream = rodio::OutputStream::try_default().unwrap();
|
||||
let sink = rodio::SpatialSink::new(
|
||||
&stream,
|
||||
let (_stream, handle) = rodio::OutputStream::try_default().unwrap();
|
||||
let sink = rodio::SpatialSink::try_new(
|
||||
&handle,
|
||||
[-10.0, 0.0, 0.0],
|
||||
[1.0, 0.0, 0.0],
|
||||
[-1.0, 0.0, 0.0],
|
||||
);
|
||||
).unwrap();
|
||||
|
||||
let file = std::fs::File::open("examples/music.ogg").unwrap();
|
||||
let source = rodio::Decoder::new(BufReader::new(file)).unwrap();
|
||||
|
|
|
@ -20,11 +20,11 @@
|
|||
//! use std::io::BufReader;
|
||||
//! use rodio::Source;
|
||||
//!
|
||||
//! let stream = rodio::OutputStream::try_default().unwrap();
|
||||
//! let (stream, stream_handle) = rodio::OutputStream::try_default().unwrap();
|
||||
//!
|
||||
//! let file = File::open("sound.ogg").unwrap();
|
||||
//! let source = rodio::Decoder::new(BufReader::new(file)).unwrap();
|
||||
//! stream.play_raw(source.convert_samples());
|
||||
//! stream_handle.play_raw(source.convert_samples());
|
||||
//! ```
|
||||
//!
|
||||
//! ## Sink
|
||||
|
@ -38,8 +38,8 @@
|
|||
//! ```no_run
|
||||
//! use rodio::Sink;
|
||||
//!
|
||||
//! let stream = rodio::OutputStream::try_default().unwrap();
|
||||
//! let sink = rodio::Sink::new(&stream);
|
||||
//! let (stream, stream_handle) = rodio::OutputStream::try_default().unwrap();
|
||||
//! let sink = rodio::Sink::try_new(&stream_handle).unwrap();
|
||||
//!
|
||||
//! // Add a dummy source of the sake of the example.
|
||||
//! let source = rodio::source::SineWave::new(440);
|
||||
|
|
10
src/sink.rs
10
src/sink.rs
|
@ -1,4 +1,4 @@
|
|||
use crate::stream::OutputStream;
|
||||
use crate::stream::{OutputStreamHandle, PlayError};
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize};
|
||||
use std::sync::mpsc::Receiver;
|
||||
|
@ -32,12 +32,12 @@ struct Controls {
|
|||
}
|
||||
|
||||
impl Sink {
|
||||
/// Builds a new `Sink`, beginning playback on a Device.
|
||||
/// Builds a new `Sink`, beginning playback on a stream.
|
||||
#[inline]
|
||||
pub fn new(stream: &OutputStream) -> Sink {
|
||||
pub fn try_new(stream: &OutputStreamHandle) -> Result<Sink, PlayError> {
|
||||
let (sink, queue_rx) = Sink::new_idle();
|
||||
stream.play_raw(queue_rx);
|
||||
sink
|
||||
stream.play_raw(queue_rx)?;
|
||||
Ok(sink)
|
||||
}
|
||||
|
||||
/// Builds a new `Sink`.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::source::Spatial;
|
||||
use crate::stream::OutputStream;
|
||||
use crate::stream::{OutputStreamHandle, PlayError};
|
||||
use crate::Sample;
|
||||
use crate::Sink;
|
||||
use crate::Source;
|
||||
|
@ -21,21 +21,20 @@ struct SoundPositions {
|
|||
|
||||
impl SpatialSink {
|
||||
/// Builds a new `SpatialSink`.
|
||||
#[inline]
|
||||
pub fn new(
|
||||
stream: &OutputStream,
|
||||
pub fn try_new(
|
||||
stream: &OutputStreamHandle,
|
||||
emitter_position: [f32; 3],
|
||||
left_ear: [f32; 3],
|
||||
right_ear: [f32; 3],
|
||||
) -> SpatialSink {
|
||||
SpatialSink {
|
||||
sink: Sink::new(stream),
|
||||
) -> Result<SpatialSink, PlayError> {
|
||||
Ok(SpatialSink {
|
||||
sink: Sink::try_new(stream)?,
|
||||
positions: Arc::new(Mutex::new(SoundPositions {
|
||||
emitter_position,
|
||||
left_ear,
|
||||
right_ear,
|
||||
})),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the position of the sound emitter in 3 dimensional space.
|
||||
|
|
|
@ -6,55 +6,79 @@ use cpal::{
|
|||
traits::{DeviceTrait, HostTrait, StreamTrait},
|
||||
Sample,
|
||||
};
|
||||
use std::convert::TryFrom;
|
||||
use std::io::{Read, Seek};
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::{error, fmt};
|
||||
|
||||
/// Immovable `cpal::Stream` container.
|
||||
/// If this is dropped playback will end & attached `OutputStreamHandle`s will no longer work.
|
||||
pub struct OutputStream {
|
||||
mixer: Arc<DynamicMixerController<f32>>,
|
||||
_stream: cpal::Stream,
|
||||
}
|
||||
|
||||
impl TryFrom<&'_ cpal::Device> for OutputStream {
|
||||
type Error = StreamError;
|
||||
|
||||
fn try_from(device: &cpal::Device) -> Result<Self, Self::Error> {
|
||||
let (mixer, _stream) = device.new_output_stream();
|
||||
_stream.play()?;
|
||||
Ok(Self { mixer, _stream })
|
||||
}
|
||||
/// More flexible handle to a `OutputStream` that provides playback.
|
||||
#[derive(Clone)]
|
||||
pub struct OutputStreamHandle {
|
||||
mixer: Weak<DynamicMixerController<f32>>,
|
||||
}
|
||||
|
||||
impl OutputStream {
|
||||
pub fn try_default() -> Result<Self, StreamError> {
|
||||
pub fn try_from_device(
|
||||
device: &cpal::Device,
|
||||
) -> Result<(Self, OutputStreamHandle), StreamError> {
|
||||
let (mixer, _stream) = device.new_output_stream();
|
||||
_stream.play()?;
|
||||
let out = Self { mixer, _stream };
|
||||
let handle = OutputStreamHandle {
|
||||
mixer: Arc::downgrade(&out.mixer),
|
||||
};
|
||||
Ok((out, handle))
|
||||
}
|
||||
|
||||
pub fn try_default() -> Result<(Self, OutputStreamHandle), StreamError> {
|
||||
let device = cpal::default_host()
|
||||
.default_output_device()
|
||||
.ok_or(StreamError::NoDevice)?;
|
||||
Self::try_from(&device)
|
||||
Self::try_from_device(&device)
|
||||
}
|
||||
}
|
||||
|
||||
impl OutputStreamHandle {
|
||||
/// Plays a source with a device until it ends.
|
||||
pub fn play_raw<S>(&self, source: S)
|
||||
pub fn play_raw<S>(&self, source: S) -> Result<(), PlayError>
|
||||
where
|
||||
S: Source<Item = f32> + Send + 'static,
|
||||
{
|
||||
self.mixer.add(source);
|
||||
let mixer = self.mixer.upgrade().ok_or(PlayError::NoDevice)?;
|
||||
mixer.add(source);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Plays a sound once. Returns a `Sink` that can be used to control the sound.
|
||||
#[inline]
|
||||
pub fn play_once<R>(&self, input: R) -> Result<Sink, decoder::DecoderError>
|
||||
pub fn play_once<R>(&self, input: R) -> Result<Sink, PlayError>
|
||||
where
|
||||
R: Read + Seek + Send + 'static,
|
||||
{
|
||||
let input = decoder::Decoder::new(input)?;
|
||||
let sink = Sink::new(&self);
|
||||
let sink = Sink::try_new(self)?;
|
||||
sink.append(input);
|
||||
Ok(sink)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PlayError {
|
||||
DecoderError(decoder::DecoderError),
|
||||
NoDevice,
|
||||
}
|
||||
|
||||
impl From<decoder::DecoderError> for PlayError {
|
||||
fn from(err: decoder::DecoderError) -> Self {
|
||||
Self::DecoderError(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum StreamError {
|
||||
PlayStreamError(cpal::PlayStreamError),
|
||||
|
|
Loading…
Reference in a new issue