summaryrefslogtreecommitdiff
path: root/cras/src/server/rust/src/rate_estimator.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cras/src/server/rust/src/rate_estimator.rs')
-rw-r--r--cras/src/server/rust/src/rate_estimator.rs188
1 files changed, 0 insertions, 188 deletions
diff --git a/cras/src/server/rust/src/rate_estimator.rs b/cras/src/server/rust/src/rate_estimator.rs
deleted file mode 100644
index 585f346b..00000000
--- a/cras/src/server/rust/src/rate_estimator.rs
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright 2019 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-pub mod rate_estimator_bindings;
-
-use std::error;
-use std::fmt;
-use std::time::Duration;
-
-#[derive(Debug)]
-pub enum Error {
- InvalidSmoothFactor(f64),
-}
-
-impl error::Error for Error {}
-
-impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- use Error::*;
- match self {
- InvalidSmoothFactor(sf) => write!(f, "Smooth factor {} is not between 0.0 and 1.0", sf),
- }
- }
-}
-
-type Result<T> = std::result::Result<T, Error>;
-
-const MAX_RATE_SKEW: f64 = 100.0;
-
-/// Hold information to calculate linear least square from
-/// several (x, y) samples.
-#[derive(Debug, Default)]
-struct LeastSquares {
- sum_x: f64,
- sum_y: f64,
- sum_xy: f64,
- sum_x2: f64,
- num_samples: u32,
-}
-
-impl LeastSquares {
- fn new() -> Self {
- Self::default()
- }
-
- fn add_sample(&mut self, x: f64, y: f64) {
- self.sum_x += x;
- self.sum_y += y;
- self.sum_xy += x * y;
- self.sum_x2 += x * x;
- self.num_samples += 1;
- }
-
- fn best_fit_slope(&self) -> f64 {
- let num = self.num_samples as f64 * self.sum_xy - self.sum_x * self.sum_y;
- let den = self.num_samples as f64 * self.sum_x2 - self.sum_x * self.sum_x;
- num / den
- }
-}
-
-/// An estimator holding the required information to determine the actual frame
-/// rate of an audio device.
-///
-/// # Members
-/// * `last_level` - Buffer level of the audio device at last check time.
-/// * `level_diff` - Number of frames written to or read from audio device
-/// since the last check time. Rate estimator will use this
-/// change plus the difference of buffer level to derive the
-/// number of frames audio device has actually processed.
-/// * `window_start` - The start time of the current window.
-/// * `window_size` - The size of the window.
-/// * `window_frames` - The number of frames accumulated in current window.
-/// * `lsq` - The helper used to estimate sample rate.
-/// * `smooth_factor` - A scaling factor used to average the previous and new
-/// rate estimates to ensure that estimates do not change
-/// too quickly.
-/// * `estimated_rate` - The estimated rate at which samples are consumed.
-pub struct RateEstimator {
- last_level: i32,
- level_diff: i32,
- window_start: Option<Duration>,
- window_size: Duration,
- window_frames: u32,
- lsq: LeastSquares,
- smooth_factor: f64,
- estimated_rate: f64,
-}
-
-impl RateEstimator {
- /// Creates a rate estimator.
- ///
- /// # Arguments
- /// * `rate` - The initial value to estimate rate from.
- /// * `window_size` - The window size of the rate estimator.
- /// * `smooth_factor` - The coefficient used to calculate moving average
- /// from old estimated rate values. Must be between
- /// 0.0 and 1.0
- ///
- /// # Errors
- /// * If `smooth_factor` is not between 0.0 and 1.0
- pub fn try_new(rate: u32, window_size: Duration, smooth_factor: f64) -> Result<Self> {
- if smooth_factor < 0.0 || smooth_factor > 1.0 {
- return Err(Error::InvalidSmoothFactor(smooth_factor));
- }
-
- Ok(RateEstimator {
- last_level: 0,
- level_diff: 0,
- window_start: None,
- window_size,
- window_frames: 0,
- lsq: LeastSquares::new(),
- smooth_factor,
- estimated_rate: rate as f64,
- })
- }
-
- /// Resets the estimated rate
- ///
- /// Reset the estimated rate to `rate`, and erase all collected data.
- pub fn reset_rate(&mut self, rate: u32) {
- self.last_level = 0;
- self.level_diff = 0;
- self.window_start = None;
- self.window_frames = 0;
- self.lsq = LeastSquares::new();
- self.estimated_rate = rate as f64;
- }
-
- /// Adds additional frames transmitted to/from audio device.
- ///
- /// # Arguments
- /// * `frames` - The number of frames written to the device. For input,
- /// this should be negative to indicate how many samples
- /// were read.
- pub fn add_frames(&mut self, frames: i32) {
- self.level_diff += frames;
- }
-
- /// Gets the estimated rate.
- pub fn get_estimated_rate(&self) -> f64 {
- self.estimated_rate
- }
-
- /// Check the timestamp and buffer level difference since last check time,
- /// and use them as a new sample to update the estimated rate.
- ///
- /// # Arguments
- /// * `level` - The current buffer level of audio device.
- /// * `now` - The time at which this function is called.
- ///
- /// # Returns
- /// True if the estimated rate is updated and window is reset,
- /// otherwise false.
- pub fn update_estimated_rate(&mut self, level: i32, now: Duration) -> bool {
- let start = match self.window_start {
- None => {
- self.window_start = Some(now);
- return false;
- }
- Some(t) => t,
- };
-
- let delta = match now.checked_sub(start) {
- Some(d) => d,
- None => return false,
- };
- self.window_frames += (self.last_level - level + self.level_diff).abs() as u32;
- self.level_diff = 0;
- self.last_level = level;
-
- let secs = (delta.as_secs() as f64) + delta.subsec_nanos() as f64 / 1_000_000_000.0;
- self.lsq.add_sample(secs, self.window_frames as f64);
- if delta > self.window_size && self.lsq.num_samples > 1 {
- let rate = self.lsq.best_fit_slope();
- if (self.estimated_rate - rate).abs() < MAX_RATE_SKEW {
- self.estimated_rate =
- rate * (1.0 - self.smooth_factor) + self.estimated_rate * self.smooth_factor;
- }
- self.lsq = LeastSquares::new();
- self.window_start = Some(now);
- self.window_frames = 0;
- return true;
- }
- false
- }
-}