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