• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 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 <stdio.h>
7 #include <stdlib.h>
8 
9 extern "C" {
10 // For audio_thread_log.h use.
11 struct audio_thread_event_log* atlog;
12 int atlog_rw_shm_fd;
13 int atlog_ro_shm_fd;
14 #include "audio_thread_log.h"
15 #include "cras_audio_area.h"
16 #include "cras_iodev.h"
17 #include "cras_iodev_list.h"
18 #include "cras_loopback_iodev.h"
19 #include "cras_shm.h"
20 #include "cras_types.h"
21 #include "dev_stream.h"
22 #include "utlist.h"
23 }
24 
25 namespace {
26 
27 static const unsigned int kBufferFrames = 16384;
28 static const unsigned int kFrameBytes = 4;
29 static const unsigned int kBufferSize = kBufferFrames * kFrameBytes;
30 
31 static struct timespec time_now;
32 static cras_audio_area* mock_audio_area;
33 static loopback_hook_data_t loop_hook;
34 static struct cras_iodev* enabled_dev;
35 static unsigned int cras_iodev_list_add_input_called;
36 static unsigned int cras_iodev_list_rm_input_called;
37 static unsigned int cras_iodev_list_set_device_enabled_callback_called;
38 static device_enabled_callback_t device_enabled_callback_cb;
39 static device_disabled_callback_t device_disabled_callback_cb;
40 static void* device_enabled_callback_cb_data;
41 static int cras_iodev_list_register_loopback_called;
42 static int cras_iodev_list_unregister_loopback_called;
43 
44 static char* atlog_name;
45 
46 class LoopBackTestSuite : public testing::Test {
47  protected:
SetUp()48   virtual void SetUp() {
49     mock_audio_area = (cras_audio_area*)calloc(
50         1, sizeof(*mock_audio_area) + sizeof(cras_channel_area) * 2);
51     for (unsigned int i = 0; i < kBufferSize; i++) {
52       buf_[i] = rand();
53     }
54     fmt_.frame_rate = 48000;
55     fmt_.num_channels = 2;
56     fmt_.format = SND_PCM_FORMAT_S16_LE;
57 
58     loop_in_ = loopback_iodev_create(LOOPBACK_POST_MIX_PRE_DSP);
59     EXPECT_EQ(1, cras_iodev_list_add_input_called);
60     loop_in_->format = &fmt_;
61 
62     loop_hook = NULL;
63     cras_iodev_list_add_input_called = 0;
64     cras_iodev_list_rm_input_called = 0;
65     cras_iodev_list_set_device_enabled_callback_called = 0;
66     cras_iodev_list_register_loopback_called = 0;
67     cras_iodev_list_unregister_loopback_called = 0;
68 
69     ASSERT_FALSE(asprintf(&atlog_name, "/ATlog-%d", getpid()) < 0);
70     /* To avoid un-used variable warning. */
71     atlog_rw_shm_fd = atlog_ro_shm_fd = -1;
72     atlog = audio_thread_event_log_init(atlog_name);
73   }
74 
TearDown()75   virtual void TearDown() {
76     loopback_iodev_destroy(loop_in_);
77     EXPECT_EQ(1, cras_iodev_list_rm_input_called);
78     EXPECT_EQ(NULL, device_enabled_callback_cb);
79     EXPECT_EQ(NULL, device_disabled_callback_cb);
80     free(mock_audio_area);
81     audio_thread_event_log_deinit(atlog, atlog_name);
82     free(atlog_name);
83   }
84 
85   uint8_t buf_[kBufferSize];
86   struct cras_audio_format fmt_;
87   struct cras_iodev* loop_in_;
88 };
89 
TEST_F(LoopBackTestSuite,InstallLoopHook)90 TEST_F(LoopBackTestSuite, InstallLoopHook) {
91   struct cras_iodev iodev;
92   struct timespec tstamp;
93 
94   iodev.direction = CRAS_STREAM_OUTPUT;
95   iodev.format = &fmt_;
96   iodev.streams = NULL;
97   iodev.info.idx = 123;
98   enabled_dev = &iodev;
99 
100   // Open loopback devices.
101   EXPECT_EQ(0, loop_in_->configure_dev(loop_in_));
102   EXPECT_EQ(1, cras_iodev_list_set_device_enabled_callback_called);
103   EXPECT_EQ(1, cras_iodev_list_register_loopback_called);
104 
105   // Signal an output device is enabled.
106   device_enabled_callback_cb(&iodev, device_enabled_callback_cb_data);
107 
108   // Expect that a hook was added to the iodev
109   EXPECT_EQ(2, cras_iodev_list_register_loopback_called);
110   ASSERT_NE(reinterpret_cast<loopback_hook_data_t>(NULL), loop_hook);
111 
112   // Check zero frames queued.
113   EXPECT_EQ(0, loop_in_->frames_queued(loop_in_, &tstamp));
114 
115   device_disabled_callback_cb(&iodev, device_enabled_callback_cb_data);
116   EXPECT_EQ(1, cras_iodev_list_unregister_loopback_called);
117   EXPECT_EQ(3, cras_iodev_list_register_loopback_called);
118 
119   enabled_dev->info.idx = 456;
120   device_enabled_callback_cb(&iodev, device_enabled_callback_cb_data);
121   EXPECT_EQ(4, cras_iodev_list_register_loopback_called);
122 
123   // Close loopback devices.
124   EXPECT_EQ(0, loop_in_->close_dev(loop_in_));
125   EXPECT_EQ(2, cras_iodev_list_unregister_loopback_called);
126   EXPECT_EQ(2, cras_iodev_list_set_device_enabled_callback_called);
127 }
128 
TEST_F(LoopBackTestSuite,SelectDevFromAToB)129 TEST_F(LoopBackTestSuite, SelectDevFromAToB) {
130   struct cras_iodev iodev1, iodev2;
131 
132   iodev1.direction = CRAS_STREAM_OUTPUT;
133   iodev2.direction = CRAS_STREAM_OUTPUT;
134   enabled_dev = &iodev1;
135 
136   enabled_dev->info.idx = 111;
137   EXPECT_EQ(0, loop_in_->configure_dev(loop_in_));
138   EXPECT_EQ(1, cras_iodev_list_set_device_enabled_callback_called);
139   EXPECT_EQ(1, cras_iodev_list_register_loopback_called);
140 
141   /* Not the current sender being disabled, assert unregister not called. */
142   iodev2.info.idx = 222;
143   device_disabled_callback_cb(&iodev2, device_enabled_callback_cb_data);
144   EXPECT_EQ(0, cras_iodev_list_unregister_loopback_called);
145   EXPECT_EQ(1, cras_iodev_list_register_loopback_called);
146 
147   enabled_dev = &iodev2;
148   device_disabled_callback_cb(&iodev1, device_enabled_callback_cb_data);
149   EXPECT_EQ(1, cras_iodev_list_unregister_loopback_called);
150   EXPECT_EQ(2, cras_iodev_list_register_loopback_called);
151 
152   EXPECT_EQ(0, loop_in_->close_dev(loop_in_));
153 }
154 
155 // Test how loopback works if there isn't any output devices open.
TEST_F(LoopBackTestSuite,OpenIdleSystem)156 TEST_F(LoopBackTestSuite, OpenIdleSystem) {
157   cras_audio_area* area;
158   unsigned int nread = 1024;
159   struct timespec tstamp;
160   int rc;
161 
162   // No active output device.
163   enabled_dev = NULL;
164   time_now.tv_sec = 100;
165   time_now.tv_nsec = 0;
166 
167   EXPECT_EQ(0, loop_in_->configure_dev(loop_in_));
168   EXPECT_EQ(1, cras_iodev_list_set_device_enabled_callback_called);
169 
170   // Should be 480 samples after 480/frame rate seconds
171   time_now.tv_nsec += 480 * 1e9 / 48000;
172   EXPECT_EQ(480, loop_in_->frames_queued(loop_in_, &tstamp));
173 
174   // Verify frames from loopback record.
175   loop_in_->get_buffer(loop_in_, &area, &nread);
176   EXPECT_EQ(480, nread);
177   memset(buf_, 0, nread * kFrameBytes);
178   rc = memcmp(area->channels[0].buf, buf_, nread * kFrameBytes);
179   EXPECT_EQ(0, rc);
180   loop_in_->put_buffer(loop_in_, nread);
181 
182   // Check zero frames queued.
183   EXPECT_EQ(0, loop_in_->frames_queued(loop_in_, &tstamp));
184 
185   EXPECT_EQ(0, loop_in_->close_dev(loop_in_));
186 }
187 
TEST_F(LoopBackTestSuite,SimpleLoopback)188 TEST_F(LoopBackTestSuite, SimpleLoopback) {
189   cras_audio_area* area;
190   unsigned int nframes = 1024;
191   unsigned int nread = 1024;
192   int rc;
193   struct cras_iodev iodev;
194   struct dev_stream stream;
195   struct timespec tstamp;
196 
197   iodev.streams = &stream;
198   enabled_dev = &iodev;
199 
200   loop_in_->configure_dev(loop_in_);
201   ASSERT_NE(reinterpret_cast<void*>(NULL), loop_hook);
202 
203   // Loopback callback for the hook.
204   loop_hook(buf_, nframes, &fmt_, loop_in_);
205 
206   // Verify frames from loopback record.
207   loop_in_->get_buffer(loop_in_, &area, &nread);
208   EXPECT_EQ(nframes, nread);
209   rc = memcmp(area->channels[0].buf, buf_, nframes * kFrameBytes);
210   EXPECT_EQ(0, rc);
211   loop_in_->put_buffer(loop_in_, nread);
212 
213   // Check zero frames queued.
214   EXPECT_EQ(0, loop_in_->frames_queued(loop_in_, &tstamp));
215 
216   EXPECT_EQ(0, loop_in_->close_dev(loop_in_));
217 }
218 
219 // TODO(chinyue): Test closing last iodev while streaming loopback data.
220 
221 /* Stubs */
222 extern "C" {
223 
cras_audio_area_config_buf_pointers(struct cras_audio_area * area,const struct cras_audio_format * fmt,uint8_t * base_buffer)224 void cras_audio_area_config_buf_pointers(struct cras_audio_area* area,
225                                          const struct cras_audio_format* fmt,
226                                          uint8_t* base_buffer) {
227   mock_audio_area->channels[0].buf = base_buffer;
228 }
229 
cras_iodev_free_audio_area(struct cras_iodev * iodev)230 void cras_iodev_free_audio_area(struct cras_iodev* iodev) {}
231 
cras_iodev_free_format(struct cras_iodev * iodev)232 void cras_iodev_free_format(struct cras_iodev* iodev) {}
233 
cras_iodev_init_audio_area(struct cras_iodev * iodev,int num_channels)234 void cras_iodev_init_audio_area(struct cras_iodev* iodev, int num_channels) {
235   iodev->area = mock_audio_area;
236 }
237 
cras_iodev_add_node(struct cras_iodev * iodev,struct cras_ionode * node)238 void cras_iodev_add_node(struct cras_iodev* iodev, struct cras_ionode* node) {
239   DL_APPEND(iodev->nodes, node);
240 }
241 
cras_iodev_set_active_node(struct cras_iodev * iodev,struct cras_ionode * node)242 void cras_iodev_set_active_node(struct cras_iodev* iodev,
243                                 struct cras_ionode* node) {}
cras_iodev_list_register_loopback(enum CRAS_LOOPBACK_TYPE loopback_type,unsigned int output_dev_idx,loopback_hook_data_t hook_data,loopback_hook_control_t hook_start,unsigned int loopback_dev_idx)244 void cras_iodev_list_register_loopback(enum CRAS_LOOPBACK_TYPE loopback_type,
245                                        unsigned int output_dev_idx,
246                                        loopback_hook_data_t hook_data,
247                                        loopback_hook_control_t hook_start,
248                                        unsigned int loopback_dev_idx) {
249   cras_iodev_list_register_loopback_called++;
250   loop_hook = hook_data;
251 }
252 
cras_iodev_list_unregister_loopback(enum CRAS_LOOPBACK_TYPE loopback_type,unsigned int output_dev_idx,unsigned int loopback_dev_idx)253 void cras_iodev_list_unregister_loopback(enum CRAS_LOOPBACK_TYPE loopback_type,
254                                          unsigned int output_dev_idx,
255                                          unsigned int loopback_dev_idx) {
256   cras_iodev_list_unregister_loopback_called++;
257 }
258 
cras_iodev_list_add_input(struct cras_iodev * input)259 int cras_iodev_list_add_input(struct cras_iodev* input) {
260   cras_iodev_list_add_input_called++;
261   return 0;
262 }
263 
cras_iodev_list_rm_input(struct cras_iodev * input)264 int cras_iodev_list_rm_input(struct cras_iodev* input) {
265   cras_iodev_list_rm_input_called++;
266   return 0;
267 }
268 
cras_iodev_list_set_device_enabled_callback(device_enabled_callback_t enabled_cb,device_disabled_callback_t disabled_cb,void * cb_data)269 int cras_iodev_list_set_device_enabled_callback(
270     device_enabled_callback_t enabled_cb,
271     device_disabled_callback_t disabled_cb,
272     void* cb_data) {
273   cras_iodev_list_set_device_enabled_callback_called++;
274   device_enabled_callback_cb = enabled_cb;
275   device_disabled_callback_cb = disabled_cb;
276   device_enabled_callback_cb_data = cb_data;
277   return 0;
278 }
279 
clock_gettime(clockid_t clk_id,struct timespec * tp)280 int clock_gettime(clockid_t clk_id, struct timespec* tp) {
281   *tp = time_now;
282   return 0;
283 }
284 
cras_iodev_list_get_first_enabled_iodev(enum CRAS_STREAM_DIRECTION direction)285 struct cras_iodev* cras_iodev_list_get_first_enabled_iodev(
286     enum CRAS_STREAM_DIRECTION direction) {
287   return enabled_dev;
288 }
289 
290 }  // extern "C"
291 
292 }  //  namespace
293 
main(int argc,char ** argv)294 int main(int argc, char** argv) {
295   ::testing::InitGoogleTest(&argc, argv);
296   return RUN_ALL_TESTS();
297 }
298