1 #include <audio_utils/hal_smoothness.h>
2 #include <errno.h>
3 #include <float.h>
4 #include <gtest/gtest.h>
5 #include <limits.h>
6 
7 #include <memory>
8 
9 struct TestDeleter {
operator ()TestDeleter10   void operator()(hal_smoothness *p) { hal_smoothness_free(&p); }
11 };
12 
13 struct custom_private_data {
14   bool ran_callback;
15 
16   hal_smoothness_metrics metrics;
17 };
18 
custom_flush(hal_smoothness_metrics * metrics,void * private_data)19 void custom_flush(hal_smoothness_metrics *metrics, void *private_data) {
20   custom_private_data *data = (custom_private_data *)private_data;
21 
22   data->ran_callback = true;
23 
24   memcpy(&data->metrics, metrics, sizeof(hal_smoothness_metrics));
25 }
26 
27 class HalSmoothnessTest : public ::testing::Test {
28  protected:
CommonSmoothnessInit(unsigned int num_writes_to_log)29   void CommonSmoothnessInit(unsigned int num_writes_to_log) {
30     hal_smoothness *smoothness_init;
31     data = {};
32     data.ran_callback = false;
33     int result =
34         hal_smoothness_initialize(&smoothness_init, HAL_SMOOTHNESS_VERSION_1,
35                                   num_writes_to_log, custom_flush, &data);
36     ASSERT_EQ(result, 0);
37     smoothness = std::unique_ptr<hal_smoothness, TestDeleter>{smoothness_init};
38   }
39 
40   std::unique_ptr<hal_smoothness, TestDeleter> smoothness;
41   custom_private_data data;
42 };
43 
44 // Test that the callback runs after the total write count is equal to
45 // "num_writes_to_log".
TEST_F(HalSmoothnessTest,callback_should_run)46 TEST_F(HalSmoothnessTest, callback_should_run) {
47   ASSERT_NO_FATAL_FAILURE(
48       HalSmoothnessTest::CommonSmoothnessInit(/* num_writes_to_log= */ 1));
49   // Since "num_writes_to_log" is set to 1, after this write, the callback
50   // should run.
51   smoothness->increment_total_writes(smoothness.get(),
52                                      /* frames_written= */ 100,
53                                      /* timestamp */ 200);
54 
55   EXPECT_EQ(data.ran_callback, true);
56 }
57 
58 // Test that the callback should not run if the total write count is less than
59 // "num_writes_to_log".
TEST_F(HalSmoothnessTest,callback_should_not_run)60 TEST_F(HalSmoothnessTest, callback_should_not_run) {
61   ASSERT_NO_FATAL_FAILURE(
62       HalSmoothnessTest::CommonSmoothnessInit(/* num_writes_to_log= */ 2));
63 
64   // Since "num_writes_to_log" is set to 2, after this write, the callback
65   // should NOT run.
66   smoothness->increment_total_writes(smoothness.get(),
67                                      /* frames_written= */ 100,
68                                      /* timestamp */ 200);
69   EXPECT_EQ(data.ran_callback, false);
70 
71   smoothness->increment_total_writes(smoothness.get(),
72                                      /* frames_written= */ 100,
73                                      /* timestamp */ 200);
74   EXPECT_EQ(data.ran_callback, true);
75 }
76 
77 // Test that metric values in "struct hal_smoothness_metrics" that is passed
78 // into the callback are correct.
TEST_F(HalSmoothnessTest,verify_metrics)79 TEST_F(HalSmoothnessTest, verify_metrics) {
80   ASSERT_NO_FATAL_FAILURE(
81       HalSmoothnessTest::CommonSmoothnessInit(/* num_writes_to_log= */ 6));
82 
83   unsigned int timestamp = 200;
84 
85   // Simulate how these increment methods would be called during a real runtime.
86   smoothness->increment_total_writes(smoothness.get(),
87                                      /* frames_written= */ 1000, timestamp++);
88   smoothness->increment_total_writes(smoothness.get(),
89                                      /* frames_written= */ 1000, timestamp++);
90   smoothness->increment_underrun(smoothness.get(), /* frames_lost= */ 900);
91   smoothness->increment_total_writes(smoothness.get(),
92                                      /* frames_written= */ 100, timestamp++);
93   smoothness->increment_overrun(smoothness.get(), /* frames_lost */ 900);
94   smoothness->increment_total_writes(smoothness.get(),
95                                      /* frames_written= */ 100, timestamp++);
96   smoothness->increment_underrun(smoothness.get(), /* frames_lost */ 900);
97   smoothness->increment_total_writes(smoothness.get(),
98                                      /* frames_written= */ 100, timestamp++);
99   smoothness->increment_total_writes(smoothness.get(),
100                                      /* frames_written= */ 1000, timestamp);
101 
102   EXPECT_EQ(data.metrics.underrun_count, 2U);
103   EXPECT_EQ(data.metrics.overrun_count, 1U);
104   EXPECT_EQ(data.metrics.total_writes, 6U);
105   EXPECT_EQ(data.metrics.total_frames_written, 3300U);
106   EXPECT_EQ(data.metrics.total_frames_lost, 2700U);
107   EXPECT_EQ(data.metrics.timestamp, timestamp);
108 }
109 
110 // Test that metric values in "struct hal_smoothness_metrics" are reset after it
111 // has met "num_writes_to_log".
TEST_F(HalSmoothnessTest,verify_metrics_reset)112 TEST_F(HalSmoothnessTest, verify_metrics_reset) {
113   const unsigned int num_write_to_log = 6;
114   ASSERT_NO_FATAL_FAILURE(HalSmoothnessTest::CommonSmoothnessInit(
115       /* num_writes_to_log= */ num_write_to_log));
116 
117   int timestamp = 200;
118   // Simulate how these increment methods would be called during a real runtime.
119   smoothness->increment_total_writes(smoothness.get(),
120                                      /* frames_written= */ 1000,
121                                      /* timestamp */ timestamp++);
122   smoothness->increment_total_writes(smoothness.get(),
123                                      /* frames_written= */ 1000,
124                                      /* timestamp */ timestamp++);
125   smoothness->increment_underrun(smoothness.get(), /* frames_lost= */ 900);
126   smoothness->increment_total_writes(smoothness.get(),
127                                      /* frames_written= */ 100,
128                                      /* timestamp */ timestamp++);
129   smoothness->increment_overrun(smoothness.get(), /* frames_lost */ 900);
130   smoothness->increment_total_writes(smoothness.get(),
131                                      /* frames_written= */ 100,
132                                      /* timestamp */ timestamp++);
133   smoothness->increment_underrun(smoothness.get(), /* frames_lost */ 900);
134   smoothness->increment_total_writes(smoothness.get(),
135                                      /* frames_written= */ 100,
136                                      /* timestamp */ timestamp++);
137   smoothness->increment_total_writes(smoothness.get(),
138                                      /* frames_written= */ 1000,
139                                      /* timestamp */ timestamp++);
140 
141   const unsigned int frames_written_on_write = 1000;
142   // At this point, metrics values should be reset. We will write 6 more times
143   // to trigger the callback again.
144   for (unsigned int i = 0; i < num_write_to_log; i++) {
145     // last timestamp will be 211 because 206 + 5.
146     smoothness->increment_total_writes(smoothness.get(),
147                                        /* frames_written= */
148                                        frames_written_on_write,
149                                        /* timestamp */ timestamp + i);
150   }
151 
152   EXPECT_EQ(data.metrics.underrun_count, 0U);
153   EXPECT_EQ(data.metrics.overrun_count, 0U);
154   EXPECT_EQ(data.metrics.total_writes, 6U);
155   EXPECT_EQ(data.metrics.total_frames_written,
156             frames_written_on_write * num_write_to_log);
157   EXPECT_EQ(data.metrics.total_frames_lost, 0U);
158   EXPECT_EQ(data.metrics.timestamp, 211U);
159 }
160 
161 // Test that metric values in "struct hal_smoothness_metrics" that is passed
162 // into the callback are correct.
TEST_F(HalSmoothnessTest,smoothness_value_10ish)163 TEST_F(HalSmoothnessTest, smoothness_value_10ish) {
164   ASSERT_NO_FATAL_FAILURE(
165       HalSmoothnessTest::CommonSmoothnessInit(/* num_writes_to_log= */ 5));
166 
167   unsigned int timestamp = 200;
168   // Simulate how these increment methods would be called during a real runtime.
169   smoothness->increment_total_writes(smoothness.get(),
170                                      /* frames_written= */ 8000, timestamp++);
171   smoothness->increment_total_writes(smoothness.get(),
172                                      /* frames_written= */ 8000, timestamp++);
173   smoothness->increment_total_writes(smoothness.get(),
174                                      /* frames_written= */ 8000, timestamp++);
175   smoothness->increment_total_writes(smoothness.get(),
176                                      /* frames_written= */ 8000, timestamp++);
177   smoothness->increment_underrun(smoothness.get(), /* frames_lost */ 1);
178   smoothness->increment_total_writes(smoothness.get(),
179                                      /* frames_written= */ 7999, timestamp++);
180 
181   // -ln(1/40000)
182   EXPECT_FLOAT_EQ(data.metrics.smoothness_value, 10.596635);
183 }
184 
TEST_F(HalSmoothnessTest,smoothness_value_6ish)185 TEST_F(HalSmoothnessTest, smoothness_value_6ish) {
186   ASSERT_NO_FATAL_FAILURE(
187       HalSmoothnessTest::CommonSmoothnessInit(/* num_writes_to_log= */ 5));
188 
189   unsigned int timestamp = 200;
190   // Simulate how these increment methods would be called during a real runtime.
191   smoothness->increment_total_writes(smoothness.get(),
192                                      /* frames_written= */ 8000, timestamp++);
193   smoothness->increment_total_writes(smoothness.get(),
194                                      /* frames_written= */ 8000, timestamp++);
195   smoothness->increment_total_writes(smoothness.get(),
196                                      /* frames_written= */ 8000, timestamp++);
197   smoothness->increment_total_writes(smoothness.get(),
198                                      /* frames_written= */ 8000, timestamp++);
199   smoothness->increment_underrun(smoothness.get(), /* frames_lost */ 100);
200   smoothness->increment_total_writes(smoothness.get(),
201                                      /* frames_written= */ 7900, timestamp++);
202 
203   // -ln(1/400)
204   EXPECT_FLOAT_EQ(data.metrics.smoothness_value, 5.9914646);
205 }
206 
TEST_F(HalSmoothnessTest,log_zero_smoothness_value)207 TEST_F(HalSmoothnessTest, log_zero_smoothness_value) {
208   ASSERT_NO_FATAL_FAILURE(
209       HalSmoothnessTest::CommonSmoothnessInit(/* num_writes_to_log= */ 1));
210 
211   // Simulate how these increment methods would be called during a real runtime.
212   smoothness->increment_total_writes(smoothness.get(),
213                                      /* frames_written= */ 8000,
214                                      /* timestamp */ 200);
215 
216   // -ln(0). This should return DBL_MAX
217   EXPECT_FLOAT_EQ(data.metrics.smoothness_value, DBL_MAX);
218 }
219 
TEST(hal_smoothness,init_fail_with_zero_num_writes_to_log)220 TEST(hal_smoothness, init_fail_with_zero_num_writes_to_log) {
221   hal_smoothness *smoothness;
222   custom_private_data data;
223   int result = hal_smoothness_initialize(&smoothness, HAL_SMOOTHNESS_VERSION_1,
224                                          /* num_writes_to_log= */ 0,
225                                          custom_flush, &data);
226   EXPECT_EQ(result, -EINVAL);
227 }
228 
TEST(hal_smoothness,init_pass_with_null_private_data)229 TEST(hal_smoothness, init_pass_with_null_private_data) {
230   hal_smoothness *smoothness_init;
231   int result =
232       hal_smoothness_initialize(&smoothness_init, HAL_SMOOTHNESS_VERSION_1,
233                                 /* num_writes_to_log= */ 6, custom_flush, NULL);
234   ASSERT_EQ(result, 0);
235   auto smoothness =
236       std::unique_ptr<hal_smoothness, TestDeleter>{smoothness_init};
237 }
238 
TEST(hal_smoothness,hal_smoothness_free)239 TEST(hal_smoothness, hal_smoothness_free) {
240   hal_smoothness *smoothness;
241   custom_private_data data;
242   int result = hal_smoothness_initialize(&smoothness, HAL_SMOOTHNESS_VERSION_1,
243                                          /* num_writes_to_log= */ 6,
244                                          custom_flush, &data);
245   ASSERT_EQ(result, 0);
246 
247   hal_smoothness_free(&smoothness);
248   EXPECT_EQ(smoothness, nullptr);
249 }
250 
TEST(hal_smoothness,hal_smoothness_free_pass_in_null)251 TEST(hal_smoothness, hal_smoothness_free_pass_in_null) {
252   hal_smoothness *smoothness;
253 
254   hal_smoothness_free(&smoothness);
255   EXPECT_EQ(smoothness, nullptr);
256 }
257 
258 // Excluded testing overflow for values that only increment by 1 (ie.
259 // underrun_count, overrun_count, total_writes).
TEST_F(HalSmoothnessTest,underrun_overflow)260 TEST_F(HalSmoothnessTest, underrun_overflow) {
261   ASSERT_NO_FATAL_FAILURE(
262       HalSmoothnessTest::CommonSmoothnessInit(/* num_writes_to_log= */ 1));
263 
264   ASSERT_EQ(smoothness->increment_underrun(smoothness.get(),
265                                            /* frames_lost= */ UINT_MAX),
266             0);
267   ASSERT_EQ(
268       smoothness->increment_underrun(smoothness.get(), /* frames_lost= */ 1),
269       -EOVERFLOW);
270 }
271 
TEST_F(HalSmoothnessTest,overrun_overflow)272 TEST_F(HalSmoothnessTest, overrun_overflow) {
273   ASSERT_NO_FATAL_FAILURE(
274       HalSmoothnessTest::CommonSmoothnessInit(/* num_writes_to_log= */ 1));
275 
276   ASSERT_EQ(smoothness->increment_overrun(smoothness.get(),
277                                           /* frames_lost= */ UINT_MAX),
278             0);
279   ASSERT_EQ(
280       smoothness->increment_overrun(smoothness.get(), /* frames_lost= */ 1),
281       -EOVERFLOW);
282 }
283 
TEST_F(HalSmoothnessTest,overflow_total_writes)284 TEST_F(HalSmoothnessTest, overflow_total_writes) {
285   ASSERT_NO_FATAL_FAILURE(
286       HalSmoothnessTest::CommonSmoothnessInit(/* num_writes_to_log= */ 2));
287 
288   unsigned int timestamp = 200;
289   ASSERT_EQ(smoothness->increment_total_writes(smoothness.get(),
290                                                /* frames_written= */ UINT_MAX,
291                                                timestamp++),
292             0);
293   ASSERT_EQ(
294       smoothness->increment_total_writes(smoothness.get(),
295                                          /* frames_written= */ 1, timestamp++),
296       -EOVERFLOW);
297 }
298 
TEST_F(HalSmoothnessTest,flush)299 TEST_F(HalSmoothnessTest, flush) {
300   const unsigned int num_write_to_log = 5;
301   ASSERT_NO_FATAL_FAILURE(HalSmoothnessTest::CommonSmoothnessInit(
302       /* num_writes_to_log= */ num_write_to_log));
303 
304   unsigned int timestamp = 201;
305   smoothness->increment_total_writes(smoothness.get(),
306                                      /* frames_written= */ 1000, timestamp++);
307   smoothness->increment_underrun(smoothness.get(), /* frames_lost= */ 900);
308   smoothness->increment_total_writes(smoothness.get(),
309                                      /* frames_written= */ 100, timestamp++);
310   smoothness->increment_overrun(smoothness.get(), /* frames_lost */ 900);
311   smoothness->increment_total_writes(smoothness.get(),
312                                      /* frames_written= */ 100, timestamp);
313 
314   // Verify metrics have not been flushed yet
315   ASSERT_EQ(data.metrics.underrun_count, 0U);
316   ASSERT_EQ(data.metrics.overrun_count, 0U);
317   ASSERT_EQ(data.metrics.total_writes, 0U);
318   ASSERT_EQ(data.metrics.total_frames_written, 0U);
319   ASSERT_EQ(data.metrics.total_frames_lost, 0U);
320   ASSERT_EQ(data.metrics.timestamp, 0U);
321 
322   smoothness->flush(smoothness.get());
323 
324   // Verify metrics have been flushed.
325   EXPECT_EQ(data.metrics.underrun_count, 1U);
326   EXPECT_EQ(data.metrics.overrun_count, 1U);
327   EXPECT_EQ(data.metrics.total_writes, 3U);
328   EXPECT_EQ(data.metrics.total_frames_written, 1200U);
329   EXPECT_EQ(data.metrics.total_frames_lost, 1800U);
330   EXPECT_EQ(data.metrics.timestamp, timestamp++);
331 
332   const unsigned int frames_written_on_write = 1000;
333   // At this point, metrics values should be reset. We will write 5 more times
334   // to trigger the callback again.
335   for (unsigned int i = 0; i < num_write_to_log; i++) {
336     // last timestamp will be 208 because 204 + 4.
337     smoothness->increment_total_writes(smoothness.get(),
338                                        /* frames_written= */
339                                        frames_written_on_write,
340                                        /* timestamp */ timestamp + i);
341   }
342 
343   EXPECT_EQ(data.metrics.underrun_count, 0U);
344   EXPECT_EQ(data.metrics.overrun_count, 0U);
345   EXPECT_EQ(data.metrics.total_writes, 5U);
346   EXPECT_EQ(data.metrics.total_frames_written,
347             frames_written_on_write * num_write_to_log);
348   EXPECT_EQ(data.metrics.total_frames_lost, 0U);
349   EXPECT_EQ(data.metrics.timestamp, 208U);
350 }
351