use ringbuf to limit audio latency

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2023-03-29 16:59:50 +08:00
parent bdc11eb035
commit 80b5033fb7
3 changed files with 62 additions and 38 deletions

62
Cargo.lock generated
View File

@ -4814,6 +4814,15 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "ringbuf"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93ca10b9c9e53ac855a2d6953bce34cef6edbac32c4b13047a4d59d67299420a"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "rpassword"
version = "2.1.0"
@ -4972,6 +4981,7 @@ dependencies = [
"rdev",
"repng",
"reqwest",
"ringbuf",
"rpassword 7.2.0",
"rubato",
"runas",
@ -6773,12 +6783,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.42.1",
"windows_i686_gnu 0.42.1",
"windows_i686_msvc 0.42.1",
"windows_x86_64_gnu 0.42.1",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.42.1",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
@ -6792,24 +6802,24 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.42.1"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.42.1",
"windows_i686_gnu 0.42.1",
"windows_i686_msvc 0.42.1",
"windows_x86_64_gnu 0.42.1",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.42.1",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.1"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_msvc"
@ -6837,9 +6847,9 @@ checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.1"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_i686_gnu"
@ -6867,9 +6877,9 @@ checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
[[package]]
name = "windows_i686_gnu"
version = "0.42.1"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_msvc"
@ -6897,9 +6907,9 @@ checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
[[package]]
name = "windows_i686_msvc"
version = "0.42.1"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_x86_64_gnu"
@ -6927,15 +6937,15 @@ checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.1"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.1"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_msvc"
@ -6963,9 +6973,9 @@ checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.1"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "winit"

View File

@ -72,6 +72,7 @@ cidr-utils = "0.5.9"
[target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies]
cpal = "0.14"
ringbuf = "0.3"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
machine-uid = "0.2"

View File

@ -14,6 +14,8 @@ use cpal::{
Device, Host, StreamConfig,
};
use magnum_opus::{Channels::*, Decoder as AudioDecoder};
#[cfg(not(any(target_os = "android", target_os = "linux")))]
use ringbuf::{ring_buffer::RbBase, Rb};
use sha2::{Digest, Sha256};
use uuid::Uuid;
@ -701,7 +703,7 @@ pub struct AudioHandler {
#[cfg(target_os = "linux")]
simple: Option<psimple::Simple>,
#[cfg(not(any(target_os = "android", target_os = "linux")))]
audio_buffer: Arc<std::sync::Mutex<std::collections::vec_deque::VecDeque<f32>>>,
audio_buffer: AudioBuffer,
sample_rate: (u32, u32),
#[cfg(not(any(target_os = "android", target_os = "linux")))]
audio_stream: Option<Box<dyn StreamTrait>>,
@ -710,6 +712,18 @@ pub struct AudioHandler {
ready: Arc<std::sync::Mutex<bool>>,
}
#[cfg(not(any(target_os = "android", target_os = "linux")))]
struct AudioBuffer(pub Arc<std::sync::Mutex<ringbuf::HeapRb<f32>>>);
#[cfg(not(any(target_os = "android", target_os = "linux")))]
impl Default for AudioBuffer {
fn default() -> Self {
Self(Arc::new(std::sync::Mutex::new(
ringbuf::HeapRb::<f32>::new(48000 * 2), // 48000hz, 2 channel, 1 second
)))
}
}
impl AudioHandler {
/// Start the audio playback.
#[cfg(target_os = "linux")]
@ -816,11 +830,7 @@ impl AudioHandler {
{
let sample_rate0 = self.sample_rate.0;
let sample_rate = self.sample_rate.1;
let audio_buffer = self.audio_buffer.clone();
// avoiding memory overflow if audio_buffer consumer side has problem
if audio_buffer.lock().unwrap().len() as u32 > sample_rate * 120 {
*audio_buffer.lock().unwrap() = Default::default();
}
let audio_buffer = self.audio_buffer.0.clone();
if sample_rate != sample_rate0 {
let buffer = crate::resample_channels(
&buffer[0..n],
@ -828,12 +838,12 @@ impl AudioHandler {
sample_rate,
channels,
);
audio_buffer.lock().unwrap().extend(buffer);
audio_buffer.lock().unwrap().push_slice_overwrite(&buffer);
} else {
audio_buffer
.lock()
.unwrap()
.extend(buffer[0..n].iter().cloned());
.push_slice_overwrite(&buffer[0..n]);
}
}
#[cfg(target_os = "android")]
@ -861,7 +871,7 @@ impl AudioHandler {
// too many errors, will improve later
log::trace!("an error occurred on stream: {}", err);
};
let audio_buffer = self.audio_buffer.clone();
let audio_buffer = self.audio_buffer.0.clone();
let ready = self.ready.clone();
let stream = device.build_output_stream(
config,
@ -871,10 +881,13 @@ impl AudioHandler {
}
let mut lock = audio_buffer.lock().unwrap();
let mut n = data.len();
if lock.len() < n {
n = lock.len();
if lock.occupied_len() < n {
n = lock.occupied_len();
}
let mut input = lock.drain(0..n);
let mut elems = vec![0.0f32; n];
lock.pop_slice(&mut elems);
drop(lock);
let mut input = elems.into_iter();
for sample in data.iter_mut() {
*sample = match input.next() {
Some(x) => T::from(&x),