diff --git a/gui/src/imp/desktop.rs b/gui/src/imp/desktop.rs index 9e4df94..e1ac2ca 100644 --- a/gui/src/imp/desktop.rs +++ b/gui/src/imp/desktop.rs @@ -1,13 +1,11 @@ use crate::app::Command; use color_eyre::eyre::{eyre, Error}; use cpal::traits::{DeviceTrait, HostTrait}; -use crossbeam_queue::ArrayQueue; use dioxus::hooks::{UnboundedReceiver, UnboundedSender}; use futures::io::{AsyncRead, AsyncWrite}; use mumble_protocol::control::{ClientControlCodec, ControlPacket}; use mumble_protocol::Serverbound; use mumble_web2_common::GuiConfig; -use std::collections::VecDeque; use std::net::ToSocketAddrs; use std::sync::Mutex; use std::{fmt, io, sync::Arc}; @@ -35,7 +33,7 @@ pub struct AudioSystem { input: cpal::Device, } -const BUF_LEN: usize = 480; // 20 ms +type Buffer = Arc>>>; impl AudioSystem { pub fn new() -> Result { @@ -58,19 +56,35 @@ impl AudioSystem { } pub fn create_player(&mut self) -> Result { - let queue = Arc::new(ArrayQueue::<[i16; BUF_LEN]>::new(10)); + let buffer = Arc::new(Mutex::new(dasp_ring_buffer::Bounded::from_raw_parts( + 0, + 0, + vec![ + 0; + 2400 // 50ms of buffer + ], + ))); let decoder = opus::Decoder::new(48_000, opus::Channels::Mono)?; let stream = { - let queue = queue.clone(); + let buffer = buffer.clone(); self.output.build_output_stream( &cpal::StreamConfig { channels: 1, sample_rate: cpal::SampleRate(48_000), - buffer_size: cpal::BufferSize::Fixed(BUF_LEN as u32), // 20ms playback delay + buffer_size: cpal::BufferSize::Fixed(480), // 10ms playback delay }, - move |out, info| match queue.pop() { - Some(buf) => out.copy_from_slice(&buf[..]), - None => out.fill(0), + move |frame, info| { + let mut buffer = buffer.lock().unwrap(); + for x in frame.iter_mut() { + match buffer.pop() { + Some(y) => { + *x = y; + } + None => { + *x = 0; + } + } + } }, move |err| error!("could not create output stream {err:?}"), None, @@ -79,9 +93,8 @@ impl AudioSystem { Ok(AudioPlayer { decoder, stream, - queue, + buffer, tmp: vec![0; 2400], - pos: 0, }) } } @@ -89,32 +102,31 @@ impl AudioSystem { pub struct AudioPlayer { decoder: opus::Decoder, stream: cpal::Stream, - queue: Arc>, + buffer: Buffer, tmp: Vec, - pos: usize, } impl AudioPlayer { pub fn play_opus(&mut self, payload: &[u8]) { - match self - .decoder - .decode(payload, &mut self.tmp[self.pos..], false) - { - Ok(l) => { - self.pos += l; - } - Err(e) => { - error!("opus decode error {e:?}"); + let len = loop { + match self.decoder.decode(payload, &mut self.tmp, false) { + Ok(l) => break l, + Err(e) => { + error!("opus decode error {e:?}"); + return; + } } }; - while self.pos >= BUF_LEN { - let mut chunk = [0; BUF_LEN]; - chunk.copy_from_slice(&self.tmp[..BUF_LEN]); - dbg!(&chunk); - let _ = self.queue.push(chunk); - let i = std::cell::Cell::new(0usize); - self.tmp.retain(|_| i.replace(i.get() + 1) >= BUF_LEN); - self.pos -= BUF_LEN; + + let mut buffer = self.buffer.lock().unwrap(); + let mut overrun = 0; + for x in &self.tmp[..len] { + if let Some(_) = buffer.push(*x) { + overrun += 1; + } + } + if overrun > 0 { + warn!("playback overrun by {overrun} samples"); } } }