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 
least_square_reset(struct least_square * lsq)13 static void least_square_reset(struct least_square *lsq)
14 {
15 	memset(lsq, 0, sizeof(*lsq));
16 }
17 
least_square_add_sample(struct least_square * lsq,double x,double y)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 
least_square_best_fit_slope(struct least_square * lsq)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 
rate_estimator_destroy(struct rate_estimator * re)35 void rate_estimator_destroy(struct rate_estimator *re)
36 {
37 	if (re)
38 		free(re);
39 }
40 
rate_estimator_create(unsigned int rate,const struct timespec * window_size,double smooth_factor)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 
rate_estimator_add_frames(struct rate_estimator * re,int fr)58 void rate_estimator_add_frames(struct rate_estimator *re, int fr)
59 {
60 	re->level_diff += fr;
61 }
62 
rate_estimator_get_rate(struct rate_estimator * re)63 double rate_estimator_get_rate(struct rate_estimator *re)
64 {
65 	return re->estimated_rate;
66 }
67 
rate_estimator_reset_rate(struct rate_estimator * re,unsigned int rate)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 
rate_estimator_check(struct rate_estimator * re,int level,struct timespec * now)79 int rate_estimator_check(struct rate_estimator *re, int level,
80 			 struct timespec *now)
81 {
82 	struct timespec td;
83 
84 	if (re->window_start_ts.tv_sec == 0) {
85 		re->window_start_ts = *now;
86 		return 0;
87 	}
88 
89 	subtract_timespecs(now, &re->window_start_ts, &td);
90 	re->window_frames += abs(re->last_level - level + re->level_diff);
91 	re->level_diff = 0;
92 	re->last_level = level;
93 
94 	least_square_add_sample(&re->lsq,
95 				td.tv_sec + (double)td.tv_nsec / 1000000000L,
96 				re->window_frames);
97 	if (timespec_after(&td, &re->window_size) &&
98 	    re->lsq.num_samples > 1) {
99 		double rate = least_square_best_fit_slope(&re->lsq);
100 		if (fabs(re->estimated_rate - rate) < MAX_RATE_SKEW)
101 			re->estimated_rate = rate * (1 - re->smooth_factor) +
102 					re->smooth_factor * re->estimated_rate;
103 		least_square_reset(&re->lsq);
104 		re->window_start_ts = *now;
105 		re->window_frames = 0;
106 		return 1;
107 	}
108 	return 0;
109 }
110