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