audio(legacy): Use ring buffer instead of a hand-rolled one

Piotr Osiewicz created

Change summary

Cargo.lock                                           |  7 +++++++
Cargo.toml                                           |  1 +
crates/livekit_client/Cargo.toml                     |  1 +
crates/livekit_client/src/livekit_client/playback.rs | 14 +++++++-------
4 files changed, 16 insertions(+), 7 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -9935,6 +9935,7 @@ dependencies = [
  "objc",
  "parking_lot",
  "postage",
+ "ringbuffer",
  "rodio",
  "serde",
  "serde_json",
@@ -14491,6 +14492,12 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "ringbuffer"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57b0b88a509053cbfd535726dcaaceee631313cef981266119527a1d110f6d2b"
+
 [[package]]
 name = "rkyv"
 version = "0.7.45"

Cargo.toml 🔗

@@ -669,6 +669,7 @@ reqwest = { git = "https://github.com/zed-industries/reqwest.git", rev = "c15662
     "socks",
     "stream",
 ], package = "zed-reqwest", version = "0.12.15-zed" }
+ringbuffer = "0.16.0"
 rsa = "0.9.6"
 runtimelib = { version = "1.4.0", default-features = false, features = [
     "async-dispatcher-runtime", "aws-lc-rs"

crates/livekit_client/Cargo.toml 🔗

@@ -35,6 +35,7 @@ log.workspace = true
 nanoid.workspace = true
 parking_lot.workspace = true
 postage.workspace = true
+ringbuffer.workspace = true
 rodio.workspace = true
 serde.workspace = true
 serde_urlencoded.workspace = true

crates/livekit_client/src/livekit_client/playback.rs 🔗

@@ -22,6 +22,7 @@ use livekit::webrtc::{
 };
 use log::info;
 use parking_lot::Mutex;
+use ringbuffer::{ConstGenericRingBuffer, RingBuffer};
 use rodio::Source;
 use serde::{Deserialize, Serialize};
 use settings::Settings;
@@ -29,7 +30,7 @@ use std::cell::RefCell;
 use std::sync::Weak;
 use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
 use std::time::Duration;
-use std::{borrow::Cow, collections::VecDeque, sync::Arc};
+use std::{borrow::Cow, sync::Arc};
 use util::{ResultExt as _, maybe};
 
 mod source;
@@ -305,6 +306,7 @@ impl AudioStack {
                                         output_config.channels() as u32,
                                         output_config.sample_rate(),
                                     );
+                                    drop(mixer);
                                     buf = sampled.to_vec();
                                     apm.lock()
                                         .process_reverse_stream(
@@ -519,7 +521,7 @@ struct AudioMixerSource {
     ssrc: i32,
     sample_rate: u32,
     num_channels: u32,
-    buffer: Arc<Mutex<VecDeque<Vec<i16>>>>,
+    buffer: Arc<Mutex<ConstGenericRingBuffer<Vec<i16>, 10>>>,
 }
 
 impl AudioMixerSource {
@@ -529,11 +531,9 @@ impl AudioMixerSource {
             self.sample_rate * self.num_channels / 100
         );
 
+        let data = frame.data.into_owned();
         let mut buffer = self.buffer.lock();
-        buffer.push_back(frame.data.to_vec());
-        while buffer.len() > 10 {
-            buffer.pop_front();
-        }
+        buffer.enqueue(data);
     }
 }
 
@@ -548,7 +548,7 @@ impl libwebrtc::native::audio_mixer::AudioMixerSource for AudioMixerSource {
 
     fn get_audio_frame_with_info<'a>(&self, target_sample_rate: u32) -> Option<AudioFrame<'_>> {
         assert_eq!(self.sample_rate, target_sample_rate);
-        let buf = self.buffer.lock().pop_front()?;
+        let buf = self.buffer.lock().dequeue()?;
         Some(AudioFrame {
             data: Cow::Owned(buf),
             sample_rate: self.sample_rate,