1 // Copyright 2017 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 <gtest/gtest.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <time.h>
9 
10 #include <memory>
11 #include <unordered_map>
12 
13 extern "C" {
14 #include "cras_iodev.h"    // stubbed
15 #include "cras_rstream.h"  // stubbed
16 #include "cras_shm.h"
17 #include "cras_types.h"
18 #include "dev_io.h"      // tested
19 #include "dev_stream.h"  // stubbed
20 #include "utlist.h"
21 
22 struct audio_thread_event_log* atlog;
23 }
24 
25 #include "dev_io_stubs.h"
26 #include "iodev_stub.h"
27 #include "metrics_stub.h"
28 #include "rstream_stub.h"
29 
30 static float dev_stream_capture_software_gain_scaler_val;
31 static float input_data_get_software_gain_scaler_val;
32 static unsigned int dev_stream_capture_avail_ret = 480;
33 struct set_dev_rate_data {
34   unsigned int dev_rate;
35   double dev_rate_ratio;
36   double main_rate_ratio;
37   int coarse_rate_adjust;
38 };
39 std::unordered_map<struct dev_stream*, set_dev_rate_data> set_dev_rate_map;
40 
41 namespace {
42 
43 class DevIoSuite : public testing::Test {
44  protected:
SetUp()45   virtual void SetUp() {
46     atlog = static_cast<audio_thread_event_log*>(calloc(1, sizeof(*atlog)));
47     iodev_stub_reset();
48     rstream_stub_reset();
49     fill_audio_format(&format, 48000);
50     set_dev_rate_map.clear();
51     stream = create_stream(1, 1, CRAS_STREAM_INPUT, cb_threshold, &format);
52   }
53 
TearDown()54   virtual void TearDown() { free(atlog); }
55 
56   size_t cb_threshold = 480;
57   cras_audio_format format;
58   StreamPtr stream;
59 };
60 
TEST_F(DevIoSuite,SendCapturedFails)61 TEST_F(DevIoSuite, SendCapturedFails) {
62   // rstream's next callback is now and there is enough data to fill.
63   struct timespec start;
64   clock_gettime(CLOCK_MONOTONIC_RAW, &start);
65   stream->rstream->next_cb_ts = start;
66   AddFakeDataToStream(stream.get(), 480);
67 
68   struct open_dev* dev_list = NULL;
69   DevicePtr dev = create_device(CRAS_STREAM_INPUT, cb_threshold, &format,
70                                 CRAS_NODE_TYPE_MIC);
71   DL_APPEND(dev_list, dev->odev.get());
72   add_stream_to_dev(dev->dev, stream);
73 
74   // Set failure response from frames_queued.
75   iodev_stub_frames_queued(dev->dev.get(), -3, start);
76 
77   EXPECT_EQ(-3, dev_io_send_captured_samples(dev_list));
78 }
79 
TEST_F(DevIoSuite,CaptureGain)80 TEST_F(DevIoSuite, CaptureGain) {
81   struct open_dev* dev_list = NULL;
82   struct open_dev* odev_list = NULL;
83   struct timespec ts;
84   DevicePtr dev = create_device(CRAS_STREAM_INPUT, cb_threshold, &format,
85                                 CRAS_NODE_TYPE_MIC);
86 
87   dev->dev->state = CRAS_IODEV_STATE_NORMAL_RUN;
88   iodev_stub_frames_queued(dev->dev.get(), 20, ts);
89   DL_APPEND(dev_list, dev->odev.get());
90   add_stream_to_dev(dev->dev, stream);
91 
92   /* The applied scaler gain should match what is reported by input_data. */
93   dev->dev->active_node->ui_gain_scaler = 1.0f;
94   input_data_get_software_gain_scaler_val = 1.0f;
95   dev_io_capture(&dev_list, &odev_list);
96   EXPECT_EQ(1.0f, dev_stream_capture_software_gain_scaler_val);
97 
98   input_data_get_software_gain_scaler_val = 0.99f;
99   dev_io_capture(&dev_list, &odev_list);
100   EXPECT_EQ(0.99f, dev_stream_capture_software_gain_scaler_val);
101 
102   dev->dev->active_node->ui_gain_scaler = 0.6f;
103   input_data_get_software_gain_scaler_val = 0.7f;
104   dev_io_capture(&dev_list, &odev_list);
105   EXPECT_FLOAT_EQ(0.42f, dev_stream_capture_software_gain_scaler_val);
106 }
107 
108 /*
109  * When input and output devices are on the internal sound card,
110  * and their device rates are the same, use the estimated rate
111  * on the output device as the estimated rate of input device.
112  */
TEST_F(DevIoSuite,CopyOutputEstimatedRate)113 TEST_F(DevIoSuite, CopyOutputEstimatedRate) {
114   struct open_dev* idev_list = NULL;
115   struct open_dev* odev_list = NULL;
116   struct timespec ts;
117   DevicePtr out_dev = create_device(CRAS_STREAM_OUTPUT, cb_threshold, &format,
118                                     CRAS_NODE_TYPE_INTERNAL_SPEAKER);
119   DevicePtr in_dev = create_device(CRAS_STREAM_INPUT, cb_threshold, &format,
120                                    CRAS_NODE_TYPE_MIC);
121 
122   in_dev->dev->state = CRAS_IODEV_STATE_NORMAL_RUN;
123   iodev_stub_frames_queued(in_dev->dev.get(), 20, ts);
124   DL_APPEND(idev_list, in_dev->odev.get());
125   add_stream_to_dev(in_dev->dev, stream);
126   DL_APPEND(odev_list, out_dev->odev.get());
127   iodev_stub_on_internal_card(out_dev->dev->active_node, 1);
128   iodev_stub_on_internal_card(in_dev->dev->active_node, 1);
129 
130   iodev_stub_est_rate_ratio(in_dev->dev.get(), 0.8f);
131   iodev_stub_est_rate_ratio(out_dev->dev.get(), 1.2f);
132 
133   dev_io_capture(&idev_list, &odev_list);
134 
135   EXPECT_FLOAT_EQ(1.2f, set_dev_rate_map[stream->dstream.get()].dev_rate_ratio);
136 }
137 
138 /*
139  * When input and output devices are not both on the internal sound card,
140  * estimated rates are independent.
141  */
TEST_F(DevIoSuite,InputOutputIndependentEstimatedRate)142 TEST_F(DevIoSuite, InputOutputIndependentEstimatedRate) {
143   struct open_dev* idev_list = NULL;
144   struct open_dev* odev_list = NULL;
145   struct timespec ts;
146   DevicePtr out_dev = create_device(CRAS_STREAM_OUTPUT, cb_threshold, &format,
147                                     CRAS_NODE_TYPE_INTERNAL_SPEAKER);
148   DevicePtr in_dev = create_device(CRAS_STREAM_INPUT, cb_threshold, &format,
149                                    CRAS_NODE_TYPE_USB);
150 
151   in_dev->dev->state = CRAS_IODEV_STATE_NORMAL_RUN;
152   iodev_stub_frames_queued(in_dev->dev.get(), 20, ts);
153   DL_APPEND(idev_list, in_dev->odev.get());
154   add_stream_to_dev(in_dev->dev, stream);
155   DL_APPEND(odev_list, out_dev->odev.get());
156   iodev_stub_on_internal_card(out_dev->dev->active_node, 1);
157   iodev_stub_on_internal_card(in_dev->dev->active_node, 0);
158 
159   iodev_stub_est_rate_ratio(in_dev->dev.get(), 0.8f);
160   iodev_stub_est_rate_ratio(out_dev->dev.get(), 1.2f);
161   iodev_stub_update_rate(in_dev->dev.get(), 1);
162 
163   dev_io_capture(&idev_list, &odev_list);
164 
165   EXPECT_FLOAT_EQ(0.8f, set_dev_rate_map[stream->dstream.get()].dev_rate_ratio);
166 }
167 
168 /*
169  * If any hw_level is larger than 1.5 * largest_cb_level and
170  * DROP_FRAMES_THRESHOLD_MS, reset all input devices.
171  */
TEST_F(DevIoSuite,SendCapturedNeedToResetDevices)172 TEST_F(DevIoSuite, SendCapturedNeedToResetDevices) {
173   struct timespec start;
174   struct timespec drop_time;
175   struct open_dev* dev_list = NULL;
176   bool rc;
177 
178   clock_gettime(CLOCK_MONOTONIC_RAW, &start);
179   AddFakeDataToStream(stream.get(), 0);
180 
181   DevicePtr dev1 =
182       create_device(CRAS_STREAM_INPUT, 1000, &format, CRAS_NODE_TYPE_MIC);
183   DevicePtr dev2 =
184       create_device(CRAS_STREAM_INPUT, 10000, &format, CRAS_NODE_TYPE_MIC);
185   DL_APPEND(dev_list, dev1->odev.get());
186   DL_APPEND(dev_list, dev2->odev.get());
187   add_stream_to_dev(dev1->dev, stream);
188   add_stream_to_dev(dev2->dev, stream);
189 
190   iodev_stub_frames_queued(dev1->dev.get(), 2880, start);
191   iodev_stub_frames_queued(dev2->dev.get(), 4800, start);
192   EXPECT_EQ(0, dev_io_send_captured_samples(dev_list));
193 
194   /*
195    * Should drop frames to one min_cb_level, which is MIN(2880, 4800) - 480 =
196    * 2400 (50ms).
197    */
198   rc = iodev_stub_get_drop_time(dev1->dev.get(), &drop_time);
199   EXPECT_EQ(true, rc);
200   EXPECT_EQ(0, drop_time.tv_sec);
201   EXPECT_EQ(50000000, drop_time.tv_nsec);
202 
203   rc = iodev_stub_get_drop_time(dev2->dev.get(), &drop_time);
204   EXPECT_EQ(true, rc);
205   EXPECT_EQ(0, drop_time.tv_sec);
206   EXPECT_EQ(50000000, drop_time.tv_nsec);
207 }
208 
209 /*
210  * If any hw_level is larger than 0.5 * buffer_size and
211  * DROP_FRAMES_THRESHOLD_MS, reset all input devices.
212  */
213 
TEST_F(DevIoSuite,SendCapturedNeedToResetDevices2)214 TEST_F(DevIoSuite, SendCapturedNeedToResetDevices2) {
215   struct timespec start;
216   struct timespec drop_time;
217   struct open_dev* dev_list = NULL;
218   bool rc;
219 
220   stream = create_stream(1, 1, CRAS_STREAM_INPUT, 2000, &format);
221 
222   clock_gettime(CLOCK_MONOTONIC_RAW, &start);
223   AddFakeDataToStream(stream.get(), 0);
224 
225   DevicePtr dev1 =
226       create_device(CRAS_STREAM_INPUT, 2048, &format, CRAS_NODE_TYPE_MIC);
227   DevicePtr dev2 =
228       create_device(CRAS_STREAM_INPUT, 10000, &format, CRAS_NODE_TYPE_MIC);
229   DL_APPEND(dev_list, dev1->odev.get());
230   DL_APPEND(dev_list, dev2->odev.get());
231   add_stream_to_dev(dev1->dev, stream);
232   add_stream_to_dev(dev2->dev, stream);
233 
234   iodev_stub_frames_queued(dev1->dev.get(), 2480, start);
235   iodev_stub_frames_queued(dev2->dev.get(), 2480, start);
236   EXPECT_EQ(0, dev_io_send_captured_samples(dev_list));
237 
238   /*
239    * Should drop frames to one min_cb_level, which is 2480 - 2000 = 480 (10ms).
240    */
241   rc = iodev_stub_get_drop_time(dev1->dev.get(), &drop_time);
242   EXPECT_EQ(true, rc);
243   EXPECT_EQ(0, drop_time.tv_sec);
244   EXPECT_EQ(10000000, drop_time.tv_nsec);
245 
246   rc = iodev_stub_get_drop_time(dev2->dev.get(), &drop_time);
247   EXPECT_EQ(true, rc);
248   EXPECT_EQ(0, drop_time.tv_sec);
249   EXPECT_EQ(10000000, drop_time.tv_nsec);
250 }
251 
252 /*
253  * If the hw_level is larger than 1.5 * largest_cb_level but less than
254  * DROP_FRAMES_THRESHOLD_MS, do nothing.
255  */
TEST_F(DevIoSuite,SendCapturedLevelLessThanThreshold)256 TEST_F(DevIoSuite, SendCapturedLevelLessThanThreshold) {
257   struct timespec start;
258   struct timespec drop_time;
259   struct open_dev* dev_list = NULL;
260   bool rc;
261 
262   clock_gettime(CLOCK_MONOTONIC_RAW, &start);
263   AddFakeDataToStream(stream.get(), 0);
264 
265   DevicePtr dev =
266       create_device(CRAS_STREAM_INPUT, 480, &format, CRAS_NODE_TYPE_MIC);
267   DL_APPEND(dev_list, dev->odev.get());
268   add_stream_to_dev(dev->dev, stream);
269 
270   iodev_stub_frames_queued(dev->dev.get(), 2048, start);
271   EXPECT_EQ(0, dev_io_send_captured_samples(dev_list));
272 
273   rc = iodev_stub_get_drop_time(dev->dev.get(), &drop_time);
274   EXPECT_EQ(false, rc);
275 }
276 
277 /*
278  * If all hw_level is less than 1.5 * largest_cb_level and 0.5 * buffer_size,
279  * do nothing.
280  */
TEST_F(DevIoSuite,SendCapturedNoNeedToResetDevices)281 TEST_F(DevIoSuite, SendCapturedNoNeedToResetDevices) {
282   struct timespec start;
283   struct timespec drop_time;
284   struct open_dev* dev_list = NULL;
285   bool rc;
286 
287   clock_gettime(CLOCK_MONOTONIC_RAW, &start);
288   AddFakeDataToStream(stream.get(), 0);
289 
290   DevicePtr dev1 =
291       create_device(CRAS_STREAM_INPUT, 1000, &format, CRAS_NODE_TYPE_MIC);
292   DevicePtr dev2 =
293       create_device(CRAS_STREAM_INPUT, 10000, &format, CRAS_NODE_TYPE_MIC);
294   DL_APPEND(dev_list, dev1->odev.get());
295   DL_APPEND(dev_list, dev2->odev.get());
296   add_stream_to_dev(dev1->dev, stream);
297   add_stream_to_dev(dev2->dev, stream);
298 
299   iodev_stub_frames_queued(dev1->dev.get(), 400, start);
300   iodev_stub_frames_queued(dev2->dev.get(), 400, start);
301   EXPECT_EQ(0, dev_io_send_captured_samples(dev_list));
302 
303   rc = iodev_stub_get_drop_time(dev1->dev.get(), &drop_time);
304   EXPECT_EQ(false, rc);
305 
306   rc = iodev_stub_get_drop_time(dev2->dev.get(), &drop_time);
307   EXPECT_EQ(false, rc);
308 }
309 
310 /*
311  * On loopback and hotword devices, if any hw_level is larger than
312  *  1.5 * largest_cb_level and DROP_FRAMES_THRESHOLD_MS, do nothing.
313  */
TEST_F(DevIoSuite,SendCapturedNoNeedToDrop)314 TEST_F(DevIoSuite, SendCapturedNoNeedToDrop) {
315   struct timespec start;
316   struct timespec drop_time;
317   struct open_dev* dev_list = NULL;
318   bool rc;
319 
320   clock_gettime(CLOCK_MONOTONIC_RAW, &start);
321   AddFakeDataToStream(stream.get(), 0);
322 
323   DevicePtr dev1 =
324       create_device(CRAS_STREAM_INPUT, 480, &format, CRAS_NODE_TYPE_HOTWORD);
325   DevicePtr dev2 = create_device(CRAS_STREAM_INPUT, 480, &format,
326                                  CRAS_NODE_TYPE_POST_MIX_PRE_DSP);
327   DevicePtr dev3 =
328       create_device(CRAS_STREAM_INPUT, 480, &format, CRAS_NODE_TYPE_POST_DSP);
329 
330   DL_APPEND(dev_list, dev1->odev.get());
331   DL_APPEND(dev_list, dev2->odev.get());
332   DL_APPEND(dev_list, dev3->odev.get());
333 
334   add_stream_to_dev(dev1->dev, stream);
335   add_stream_to_dev(dev2->dev, stream);
336   add_stream_to_dev(dev3->dev, stream);
337 
338   iodev_stub_frames_queued(dev1->dev.get(), 4800, start);
339   iodev_stub_frames_queued(dev2->dev.get(), 4800, start);
340   iodev_stub_frames_queued(dev2->dev.get(), 4800, start);
341 
342   EXPECT_EQ(0, dev_io_send_captured_samples(dev_list));
343 
344   rc = iodev_stub_get_drop_time(dev1->dev.get(), &drop_time);
345   EXPECT_EQ(false, rc);
346 
347   rc = iodev_stub_get_drop_time(dev2->dev.get(), &drop_time);
348   EXPECT_EQ(false, rc);
349 
350   rc = iodev_stub_get_drop_time(dev3->dev.get(), &drop_time);
351   EXPECT_EQ(false, rc);
352 }
353 
354 /* Stubs */
355 extern "C" {
356 
input_data_get_for_stream(struct input_data * data,struct cras_rstream * stream,struct buffer_share * offsets,struct cras_audio_area ** area,unsigned int * offset)357 int input_data_get_for_stream(struct input_data* data,
358                               struct cras_rstream* stream,
359                               struct buffer_share* offsets,
360                               struct cras_audio_area** area,
361                               unsigned int* offset) {
362   return 0;
363 }
364 
input_data_put_for_stream(struct input_data * data,struct cras_rstream * stream,struct buffer_share * offsets,unsigned int frames)365 int input_data_put_for_stream(struct input_data* data,
366                               struct cras_rstream* stream,
367                               struct buffer_share* offsets,
368                               unsigned int frames) {
369   return 0;
370 }
371 
input_data_get_software_gain_scaler(struct input_data * data,float idev_sw_gain_scaler,struct cras_rstream * stream)372 float input_data_get_software_gain_scaler(struct input_data* data,
373                                           float idev_sw_gain_scaler,
374                                           struct cras_rstream* stream) {
375   return input_data_get_software_gain_scaler_val;
376 }
377 
cras_audio_thread_event_drop_samples()378 int cras_audio_thread_event_drop_samples() {
379   return 0;
380 }
381 
cras_audio_thread_event_severe_underrun()382 int cras_audio_thread_event_severe_underrun() {
383   return 0;
384 }
385 
dev_stream_attached_devs(const struct dev_stream * dev_stream)386 int dev_stream_attached_devs(const struct dev_stream* dev_stream) {
387   return 0;
388 }
dev_stream_update_frames(const struct dev_stream * dev_stream)389 void dev_stream_update_frames(const struct dev_stream* dev_stream) {}
dev_stream_playback_frames(const struct dev_stream * dev_stream)390 int dev_stream_playback_frames(const struct dev_stream* dev_stream) {
391   return 0;
392 }
dev_stream_is_pending_reply(const struct dev_stream * dev_stream)393 int dev_stream_is_pending_reply(const struct dev_stream* dev_stream) {
394   return 0;
395 }
dev_stream_mix(struct dev_stream * dev_stream,const struct cras_audio_format * fmt,uint8_t * dst,unsigned int num_to_write)396 int dev_stream_mix(struct dev_stream* dev_stream,
397                    const struct cras_audio_format* fmt,
398                    uint8_t* dst,
399                    unsigned int num_to_write) {
400   return 0;
401 }
dev_stream_set_dev_rate(struct dev_stream * dev_stream,unsigned int dev_rate,double dev_rate_ratio,double main_rate_ratio,int coarse_rate_adjust)402 void dev_stream_set_dev_rate(struct dev_stream* dev_stream,
403                              unsigned int dev_rate,
404                              double dev_rate_ratio,
405                              double main_rate_ratio,
406                              int coarse_rate_adjust) {
407   set_dev_rate_data new_data;
408   new_data.dev_rate = dev_rate;
409   new_data.dev_rate_ratio = dev_rate_ratio;
410   new_data.main_rate_ratio = main_rate_ratio;
411   new_data.coarse_rate_adjust = coarse_rate_adjust;
412 
413   set_dev_rate_map[dev_stream] = new_data;
414 }
dev_stream_capture_update_rstream(struct dev_stream * dev_stream)415 int dev_stream_capture_update_rstream(struct dev_stream* dev_stream) {
416   return 0;
417 }
dev_stream_wake_time(struct dev_stream * dev_stream,unsigned int curr_level,struct timespec * level_tstamp,unsigned int cap_limit,int is_cap_limit_stream,struct timespec * wake_time_out)418 int dev_stream_wake_time(struct dev_stream* dev_stream,
419                          unsigned int curr_level,
420                          struct timespec* level_tstamp,
421                          unsigned int cap_limit,
422                          int is_cap_limit_stream,
423                          struct timespec* wake_time_out) {
424   return 0;
425 }
dev_stream_flush_old_audio_messages(struct dev_stream * dev_stream)426 int dev_stream_flush_old_audio_messages(struct dev_stream* dev_stream) {
427   return 0;
428 }
dev_stream_set_delay(const struct dev_stream * dev_stream,unsigned int delay_frames)429 void dev_stream_set_delay(const struct dev_stream* dev_stream,
430                           unsigned int delay_frames) {}
dev_stream_capture(struct dev_stream * dev_stream,const struct cras_audio_area * area,unsigned int area_offset,float software_gain_scaler)431 unsigned int dev_stream_capture(struct dev_stream* dev_stream,
432                                 const struct cras_audio_area* area,
433                                 unsigned int area_offset,
434                                 float software_gain_scaler) {
435   dev_stream_capture_software_gain_scaler_val = software_gain_scaler;
436   return 0;
437 }
dev_stream_update_next_wake_time(struct dev_stream * dev_stream)438 void dev_stream_update_next_wake_time(struct dev_stream* dev_stream) {}
dev_stream_request_playback_samples(struct dev_stream * dev_stream,const struct timespec * now)439 int dev_stream_request_playback_samples(struct dev_stream* dev_stream,
440                                         const struct timespec* now) {
441   return 0;
442 }
dev_stream_playback_update_rstream(struct dev_stream * dev_stream)443 int dev_stream_playback_update_rstream(struct dev_stream* dev_stream) {
444   return 0;
445 }
dev_stream_destroy(struct dev_stream * dev_stream)446 void dev_stream_destroy(struct dev_stream* dev_stream) {}
dev_stream_capture_avail(const struct dev_stream * dev_stream)447 unsigned int dev_stream_capture_avail(const struct dev_stream* dev_stream) {
448   return dev_stream_capture_avail_ret;
449 }
dev_stream_create(struct cras_rstream * stream,unsigned int dev_id,const struct cras_audio_format * dev_fmt,void * dev_ptr,struct timespec * cb_ts,const struct timespec * sleep_interval_ts)450 struct dev_stream* dev_stream_create(struct cras_rstream* stream,
451                                      unsigned int dev_id,
452                                      const struct cras_audio_format* dev_fmt,
453                                      void* dev_ptr,
454                                      struct timespec* cb_ts,
455                                      const struct timespec* sleep_interval_ts) {
456   return 0;
457 }
cras_device_monitor_error_close(unsigned int dev_idx)458 int cras_device_monitor_error_close(unsigned int dev_idx) {
459   return 0;
460 }
461 }  // extern "C"
462 
463 }  //  namespace
464 
main(int argc,char ** argv)465 int main(int argc, char** argv) {
466   ::testing::InitGoogleTest(&argc, argv);
467   return RUN_ALL_TESTS();
468 }
469