Skip to content

Commit

Permalink
fix(anni-playback): more fixes to device changes (#39)
Browse files Browse the repository at this point in the history
* fix(anni-playback): recreate `CpalOutputStream` on device change

* fix(anni-playback): recreate CpalOutputStream lazily

Recreating immediately after device tends to fail

* build: patch cpal

the patch enables cpal to respect device selection on windows
see: RustAudio/cpal#740

* fix(anni-playback): fix build on non-windows system

* chore(anni-playback): avoid unnecessary mut

* chore(anni-playback): reduce log level
  • Loading branch information
snylonue authored Jan 1, 2024
1 parent b034251 commit 6a439c3
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 45 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ once_cell = "1"
rusqlite = { git = "https://github.com/ProjectAnni/rusqlite", branch = "wasm32-unknown-unknown" }
# Remove this patch after https://github.com/mackwic/colored/pull/119 was merged
colored = { git = "https://github.com/ProjectAnni/colored", branch = "master" }
cpal = { git = "https://github.com/sidit77/cpal.git", branch = "master" }
2 changes: 2 additions & 0 deletions anni-playback/src/cpal_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ impl CpalOutputStream {
.default_output_device()
.context("Failed to get default output device.")?;

log::debug!("default device: {:?}", device.name());

let config;

#[cfg(target_os = "windows")]
Expand Down
60 changes: 15 additions & 45 deletions anni-playback/src/decoder/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,28 +68,28 @@ pub struct Decoder {
cpal_output_stream: CpalOutputStream,
cpal_output: Option<CpalOutput>,
playback: Option<Playback>,
preload_playback: Option<(Playback, CpalOutput)>,
preload_playback: Option<Playback>,
/// The `JoinHandle` for the thread that preloads a file.
preload_thread: Option<JoinHandle<anyhow::Result<(Playback, CpalOutput)>>>,
preload_thread: Option<JoinHandle<anyhow::Result<Playback>>>,
spec: SignalSpec,
}

impl Decoder {
/// Creates a new decoder.
pub fn new(controls: Controls, thread_killer: Receiver<bool>) -> Self {
// TODO: allow specifying sample rate by user
let spec = SignalSpec::new_with_layout(44100, Layout::Stereo);

Decoder {
thread_killer,
controls: controls.clone(),
state: DecoderState::Idle,
cpal_output_stream: CpalOutputStream::new(
// TODO: allow specifying sample rate by user
SignalSpec::new_with_layout(44100, Layout::Stereo),
controls,
)
.unwrap(),
cpal_output_stream: CpalOutputStream::new(spec, controls).unwrap(),
cpal_output: None,
playback: None,
preload_playback: None,
preload_thread: None,
spec,
}
}

Expand Down Expand Up @@ -190,28 +190,10 @@ impl Decoder {
// and pause playback. Once the user is ready, they can start
// playback themselves.
InternalPlayerEvent::DeviceChanged => {
log::debug!("device changed");
self.controls.pause();
self.cpal_output = None;
self.cpal_output_stream = CpalOutputStream::new(
SignalSpec::new_with_layout(44100, Layout::Stereo),
self.controls.clone(),
)?;

// The device change will also affect the preloaded playback.
if self.preload_playback.is_some() {
let (playback, cpal_output) = self.preload_playback.take().unwrap();
let buffer_signal = playback.buffer_signal.clone();

self.preload_playback.replace((
playback,
self.cpal_output_stream.create_output(
buffer_signal,
cpal_output.spec,
cpal_output.duration,
),
));
}
}
}
InternalPlayerEvent::Preload(source, buffer_signal) => {
self.preload_playback = None;
self.controls.set_is_file_preloaded(false);
Expand Down Expand Up @@ -247,6 +229,7 @@ impl Decoder {
let spec = *preload.spec();
let duration = preload.capacity() as u64;

self.cpal_output_stream = CpalOutputStream::new(self.spec, self.controls.clone())?;
self.cpal_output
.replace(self.cpal_output_stream.create_output(
playback.buffer_signal.clone(),
Expand Down Expand Up @@ -328,6 +311,7 @@ impl Decoder {
if self.cpal_output.is_none() {
let spec = *decoded.spec();
let duration = decoded.capacity() as u64;
self.cpal_output_stream = CpalOutputStream::new(self.spec, self.controls.clone())?;
self.cpal_output
.replace(self.cpal_output_stream.create_output(
playback.buffer_signal.clone(),
Expand Down Expand Up @@ -356,9 +340,8 @@ impl Decoder {
}

// If there is a preloaded file, then swap it with the current playback.
if let Some((playback, cpal_output)) = self.preload_playback.take() {
if let Some(playback) = self.preload_playback.take() {
self.playback = Some(playback);
self.cpal_output = Some(cpal_output);

self.controls.send_internal_event(InternalPlayerEvent::Play);
self.controls.preload_played();
Expand Down Expand Up @@ -433,11 +416,7 @@ impl Decoder {
&self,
source: Box<dyn MediaSource>,
buffer_signal: Arc<AtomicBool>,
) -> JoinHandle<anyhow::Result<(Playback, CpalOutput)>> {
let controls = self.controls.clone();
let config = self.cpal_output_stream.config.clone();
let ring_buffer_writer = self.cpal_output_stream.ring_buffer_writer.clone();

) -> JoinHandle<anyhow::Result<Playback>> {
thread::spawn(move || {
let mut playback = Self::open(source, buffer_signal.clone())?;
// Preload
Expand All @@ -451,16 +430,7 @@ impl Decoder {
buf_ref.convert(&mut buf);
playback.preload = Some(buf);

let cpal_output = CpalOutput::new(
buffer_signal,
spec,
duration,
config,
controls,
ring_buffer_writer,
);

Ok((playback, cpal_output))
Ok(playback)
})
}

Expand Down

0 comments on commit 6a439c3

Please sign in to comment.