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