Home | History | Annotate | Download | only in server
      1 /* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  */
      5 #include "math.h"
      6 
      7 #include "cras_util.h"
      8 #include "rate_estimator.h"
      9 
     10 /* The max rate skew that considered reasonable */
     11 #define MAX_RATE_SKEW 100
     12 
     13 static void least_square_reset(struct least_square *lsq)
     14 {
     15 	memset(lsq, 0, sizeof(*lsq));
     16 }
     17 
     18 void least_square_add_sample(struct least_square *lsq, double x, double y)
     19 {
     20 	lsq->sum_x += x;
     21 	lsq->sum_y += y;
     22 	lsq->sum_xy += x * y;
     23 	lsq->sum_x2 += x * x;
     24 	lsq->num_samples++;
     25 }
     26 
     27 double least_square_best_fit_slope(struct least_square *lsq)
     28 {
     29 	double num, denom;
     30 	num = lsq->num_samples * lsq->sum_xy - lsq->sum_x * lsq->sum_y;
     31 	denom = lsq->num_samples * lsq->sum_x2 - lsq->sum_x * lsq->sum_x;
     32 	return num / denom;
     33 }
     34 
     35 void rate_estimator_destroy(struct rate_estimator *re)
     36 {
     37 	if (re)
     38 		free(re);
     39 }
     40 
     41 struct rate_estimator *rate_estimator_create(unsigned int rate,
     42 					     const struct timespec *window_size,
     43 					     double smooth_factor)
     44 {
     45 	struct rate_estimator *re;
     46 
     47 	re = (struct rate_estimator *)calloc(1, sizeof(*re));
     48 	if (re == NULL)
     49 		return NULL;
     50 
     51 	re->window_size = *window_size;
     52 	re->estimated_rate = rate;
     53 	re->smooth_factor = smooth_factor;
     54 
     55 	return re;
     56 }
     57 
     58 void rate_estimator_add_frames(struct rate_estimator *re, int fr)
     59 {
     60 	re->level_diff += fr;
     61 }
     62 
     63 double rate_estimator_get_rate(struct rate_estimator *re)
     64 {
     65 	return re->estimated_rate;
     66 }
     67 
     68 void rate_estimator_reset_rate(struct rate_estimator *re, unsigned int rate)
     69 {
     70 	re->estimated_rate = rate;
     71 	least_square_reset(&re->lsq);
     72 	re->window_start_ts.tv_sec = 0;
     73 	re->window_start_ts.tv_nsec = 0;
     74 	re->window_frames = 0;
     75 	re->level_diff = 0;
     76 	re->last_level = 0;
     77 }
     78 
     79 int rate_estimator_check(struct rate_estimator *re, int level,
     80 			 struct timespec *now)
     81 {
     82 	struct timespec td;
     83 
     84 	/* TODO(hychao) - is this the right thing to do if level is 0? */
     85 	if ((re->window_start_ts.tv_sec == 0) || (level == 0)) {
     86 		re->window_start_ts = *now;
     87 		re->window_frames = 0;
     88 		re->level_diff = 0;
     89 		re->last_level = level;
     90 		return 0;
     91 	}
     92 
     93 	subtract_timespecs(now, &re->window_start_ts, &td);
     94 	re->window_frames += abs(re->last_level - level + re->level_diff);
     95 	re->level_diff = 0;
     96 	re->last_level = level;
     97 
     98 	least_square_add_sample(&re->lsq,
     99 				td.tv_sec + (double)td.tv_nsec / 1000000000L,
    100 				re->window_frames);
    101 	if (timespec_after(&td, &re->window_size) &&
    102 	    re->lsq.num_samples > 1) {
    103 		double rate = least_square_best_fit_slope(&re->lsq);
    104 		if (fabs(re->estimated_rate - rate) < MAX_RATE_SKEW)
    105 			re->estimated_rate = rate * (1 - re->smooth_factor) +
    106 					re->smooth_factor * re->estimated_rate;
    107 		least_square_reset(&re->lsq);
    108 		re->window_start_ts = *now;
    109 		re->window_frames = 0;
    110 		return 1;
    111 	}
    112 	return 0;
    113 }
    114