1 // Copyright (c) 2012 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 <fcntl.h>
6 #include <gtest/gtest.h>
7 #include <stdio.h>
8 #include <sys/mman.h>
9 #include <sys/socket.h>
10 #include <sys/types.h>
11
12 extern "C" {
13 #include "cras_audio_area.h"
14 #include "cras_messages.h"
15 #include "cras_rstream.h"
16 #include "cras_shm.h"
17 }
18
19 #include "metrics_stub.h"
20
21 namespace {
22
23 class RstreamTestSuite : public testing::Test {
24 protected:
SetUp()25 virtual void SetUp() {
26 int rc;
27 int sock[2] = {-1, -1};
28
29 fmt_.format = SND_PCM_FORMAT_S16_LE;
30 fmt_.frame_rate = 48000;
31 fmt_.num_channels = 2;
32
33 config_.stream_id = 555;
34 config_.stream_type = CRAS_STREAM_TYPE_DEFAULT;
35 config_.client_type = CRAS_CLIENT_TYPE_UNKNOWN;
36 config_.direction = CRAS_STREAM_OUTPUT;
37 config_.dev_idx = NO_DEVICE;
38 config_.flags = 0;
39 config_.format = &fmt_;
40 config_.buffer_frames = 4096;
41 config_.cb_threshold = 2048;
42 config_.client_shm_size = 0;
43 config_.client_shm_fd = -1;
44
45 // Create a socket pair because it will be used in rstream.
46 rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
47 ASSERT_EQ(0, rc);
48 config_.audio_fd = sock[1];
49 client_fd_ = sock[0];
50
51 config_.client = NULL;
52 }
53
TearDown()54 virtual void TearDown() {
55 close(config_.audio_fd);
56 close(client_fd_);
57 }
58
format_equal(cras_audio_format * fmt1,cras_audio_format * fmt2)59 static bool format_equal(cras_audio_format* fmt1, cras_audio_format* fmt2) {
60 return fmt1->format == fmt2->format &&
61 fmt1->frame_rate == fmt2->frame_rate &&
62 fmt1->num_channels == fmt2->num_channels;
63 }
64
stub_client_reply(enum CRAS_AUDIO_MESSAGE_ID id,int frames,int err)65 void stub_client_reply(enum CRAS_AUDIO_MESSAGE_ID id, int frames, int err) {
66 int rc;
67 struct audio_message aud_msg;
68 // Create a message.
69 aud_msg.id = id;
70 aud_msg.frames = frames;
71 aud_msg.error = err;
72
73 // Use socket fd to stub message from client.
74 rc = write(client_fd_, &aud_msg, sizeof(aud_msg));
75 EXPECT_EQ(sizeof(aud_msg), rc);
76 return;
77 }
78
79 struct cras_audio_format fmt_;
80 struct cras_rstream_config config_;
81 int client_fd_;
82 };
83
TEST_F(RstreamTestSuite,InvalidDirection)84 TEST_F(RstreamTestSuite, InvalidDirection) {
85 struct cras_rstream* s;
86 int rc;
87
88 config_.direction = (enum CRAS_STREAM_DIRECTION)66;
89 rc = cras_rstream_create(&config_, &s);
90 EXPECT_NE(0, rc);
91 }
92
TEST_F(RstreamTestSuite,InvalidStreamType)93 TEST_F(RstreamTestSuite, InvalidStreamType) {
94 struct cras_rstream* s;
95 int rc;
96
97 config_.stream_type = (enum CRAS_STREAM_TYPE)7;
98 rc = cras_rstream_create(&config_, &s);
99 EXPECT_NE(0, rc);
100 }
101
TEST_F(RstreamTestSuite,InvalidBufferSize)102 TEST_F(RstreamTestSuite, InvalidBufferSize) {
103 struct cras_rstream* s;
104 int rc;
105
106 config_.buffer_frames = 3;
107 rc = cras_rstream_create(&config_, &s);
108 EXPECT_NE(0, rc);
109 }
110
TEST_F(RstreamTestSuite,InvalidCallbackThreshold)111 TEST_F(RstreamTestSuite, InvalidCallbackThreshold) {
112 struct cras_rstream* s;
113 int rc;
114
115 config_.cb_threshold = 3;
116 rc = cras_rstream_create(&config_, &s);
117 EXPECT_NE(0, rc);
118 }
119
TEST_F(RstreamTestSuite,InvalidStreamPointer)120 TEST_F(RstreamTestSuite, InvalidStreamPointer) {
121 int rc;
122
123 rc = cras_rstream_create(&config_, NULL);
124 EXPECT_NE(0, rc);
125 }
126
TEST_F(RstreamTestSuite,CreateOutput)127 TEST_F(RstreamTestSuite, CreateOutput) {
128 struct cras_rstream* s;
129 struct cras_audio_format fmt_ret;
130 struct cras_audio_shm* shm_ret;
131 struct cras_audio_shm shm_mapped;
132 int rc, header_fd = -1, samples_fd = -1;
133 size_t shm_size;
134
135 rc = cras_rstream_create(&config_, &s);
136 EXPECT_EQ(0, rc);
137 EXPECT_NE((void*)NULL, s);
138 EXPECT_EQ(4096, cras_rstream_get_buffer_frames(s));
139 EXPECT_EQ(2048, cras_rstream_get_cb_threshold(s));
140 EXPECT_EQ(CRAS_STREAM_TYPE_DEFAULT, cras_rstream_get_type(s));
141 EXPECT_EQ(CRAS_STREAM_OUTPUT, cras_rstream_get_direction(s));
142 EXPECT_NE((void*)NULL, cras_rstream_shm(s));
143 rc = cras_rstream_get_format(s, &fmt_ret);
144 EXPECT_EQ(0, rc);
145 EXPECT_TRUE(format_equal(&fmt_ret, &fmt_));
146
147 // Check if shm is really set up.
148 shm_ret = cras_rstream_shm(s);
149 ASSERT_NE((void*)NULL, shm_ret);
150 cras_rstream_get_shm_fds(s, &header_fd, &samples_fd);
151 shm_size = cras_shm_samples_size(shm_ret);
152 EXPECT_EQ(shm_size, 32768);
153 shm_mapped.header = (struct cras_audio_shm_header*)mmap(
154 NULL, cras_shm_header_size(), PROT_READ | PROT_WRITE, MAP_SHARED,
155 header_fd, 0);
156 EXPECT_NE((void*)NULL, shm_mapped.header);
157 cras_shm_copy_shared_config(&shm_mapped);
158 EXPECT_EQ(cras_shm_used_size(&shm_mapped), cras_shm_used_size(shm_ret));
159 munmap(shm_mapped.header, cras_shm_header_size());
160
161 cras_rstream_destroy(s);
162 }
163
TEST_F(RstreamTestSuite,CreateInput)164 TEST_F(RstreamTestSuite, CreateInput) {
165 struct cras_rstream* s;
166 struct cras_audio_format fmt_ret;
167 struct cras_audio_shm* shm_ret;
168 struct cras_audio_shm shm_mapped;
169 int rc, header_fd = -1, samples_fd = -1;
170 size_t shm_size;
171
172 config_.direction = CRAS_STREAM_INPUT;
173 rc = cras_rstream_create(&config_, &s);
174 EXPECT_EQ(0, rc);
175 EXPECT_NE((void*)NULL, s);
176 EXPECT_EQ(4096, cras_rstream_get_buffer_frames(s));
177 EXPECT_EQ(2048, cras_rstream_get_cb_threshold(s));
178 EXPECT_EQ(CRAS_STREAM_TYPE_DEFAULT, cras_rstream_get_type(s));
179 EXPECT_EQ(CRAS_STREAM_INPUT, cras_rstream_get_direction(s));
180 EXPECT_NE((void*)NULL, cras_rstream_shm(s));
181 rc = cras_rstream_get_format(s, &fmt_ret);
182 EXPECT_EQ(0, rc);
183 EXPECT_TRUE(format_equal(&fmt_ret, &fmt_));
184
185 // Check if shm is really set up.
186 shm_ret = cras_rstream_shm(s);
187 ASSERT_NE((void*)NULL, shm_ret);
188 cras_rstream_get_shm_fds(s, &header_fd, &samples_fd);
189 shm_size = cras_shm_samples_size(shm_ret);
190 EXPECT_EQ(shm_size, 32768);
191 shm_mapped.header = (struct cras_audio_shm_header*)mmap(
192 NULL, cras_shm_header_size(), PROT_READ | PROT_WRITE, MAP_SHARED,
193 header_fd, 0);
194 EXPECT_NE((void*)NULL, shm_mapped.header);
195 cras_shm_copy_shared_config(&shm_mapped);
196 EXPECT_EQ(cras_shm_used_size(&shm_mapped), cras_shm_used_size(shm_ret));
197 munmap(shm_mapped.header, cras_shm_header_size());
198
199 cras_rstream_destroy(s);
200 }
201
TEST_F(RstreamTestSuite,VerifyStreamTypes)202 TEST_F(RstreamTestSuite, VerifyStreamTypes) {
203 struct cras_rstream* s;
204 int rc;
205
206 config_.stream_type = CRAS_STREAM_TYPE_DEFAULT;
207 rc = cras_rstream_create(&config_, &s);
208 EXPECT_EQ(0, rc);
209 EXPECT_EQ(CRAS_STREAM_TYPE_DEFAULT, cras_rstream_get_type(s));
210 EXPECT_NE(CRAS_STREAM_TYPE_MULTIMEDIA, cras_rstream_get_type(s));
211 cras_rstream_destroy(s);
212
213 config_.stream_type = CRAS_STREAM_TYPE_VOICE_COMMUNICATION;
214 rc = cras_rstream_create(&config_, &s);
215 EXPECT_EQ(0, rc);
216 EXPECT_EQ(CRAS_STREAM_TYPE_VOICE_COMMUNICATION, cras_rstream_get_type(s));
217 cras_rstream_destroy(s);
218
219 config_.direction = CRAS_STREAM_INPUT;
220 config_.stream_type = CRAS_STREAM_TYPE_SPEECH_RECOGNITION;
221 rc = cras_rstream_create(&config_, &s);
222 EXPECT_EQ(0, rc);
223 EXPECT_EQ(CRAS_STREAM_TYPE_SPEECH_RECOGNITION, cras_rstream_get_type(s));
224 cras_rstream_destroy(s);
225
226 config_.stream_type = CRAS_STREAM_TYPE_PRO_AUDIO;
227 rc = cras_rstream_create(&config_, &s);
228 EXPECT_EQ(0, rc);
229 EXPECT_EQ(CRAS_STREAM_TYPE_PRO_AUDIO, cras_rstream_get_type(s));
230 cras_rstream_destroy(s);
231 }
232
TEST_F(RstreamTestSuite,OutputStreamIsPendingReply)233 TEST_F(RstreamTestSuite, OutputStreamIsPendingReply) {
234 struct cras_rstream* s;
235 int rc;
236 struct timespec ts;
237
238 rc = cras_rstream_create(&config_, &s);
239 EXPECT_EQ(0, rc);
240
241 // Not pending reply.
242 rc = cras_rstream_is_pending_reply(s);
243 EXPECT_EQ(0, rc);
244
245 // Request some data from client.
246 rc = cras_rstream_request_audio(s, &ts);
247 EXPECT_GT(rc, 0);
248
249 // Pending reply.
250 rc = cras_rstream_is_pending_reply(s);
251 EXPECT_EQ(1, rc);
252
253 cras_rstream_destroy(s);
254 }
255
TEST_F(RstreamTestSuite,OutputStreamFlushMessages)256 TEST_F(RstreamTestSuite, OutputStreamFlushMessages) {
257 struct cras_rstream* s;
258 int rc;
259 struct timespec ts;
260
261 rc = cras_rstream_create(&config_, &s);
262 EXPECT_EQ(0, rc);
263
264 // Not pending reply.
265 rc = cras_rstream_is_pending_reply(s);
266 EXPECT_EQ(0, rc);
267
268 // Request some data from client.
269 rc = cras_rstream_request_audio(s, &ts);
270 EXPECT_GT(rc, 0);
271
272 // Pending reply.
273 rc = cras_rstream_is_pending_reply(s);
274 EXPECT_EQ(1, rc);
275
276 // Client replies that data is ready.
277 stub_client_reply(AUDIO_MESSAGE_DATA_READY, 10, 0);
278
279 // Read messages.
280 cras_rstream_flush_old_audio_messages(s);
281
282 // NOT Pending reply.
283 rc = cras_rstream_is_pending_reply(s);
284 EXPECT_EQ(0, rc);
285
286 cras_rstream_destroy(s);
287 }
288
TEST_F(RstreamTestSuite,InputStreamIsPendingReply)289 TEST_F(RstreamTestSuite, InputStreamIsPendingReply) {
290 struct cras_rstream* s;
291 int rc;
292
293 config_.direction = CRAS_STREAM_INPUT;
294
295 rc = cras_rstream_create(&config_, &s);
296 EXPECT_EQ(0, rc);
297
298 // Not pending reply.
299 rc = cras_rstream_is_pending_reply(s);
300 EXPECT_EQ(0, rc);
301
302 // Some data is ready. Sends it to client.
303 rc = cras_rstream_audio_ready(s, 10);
304 EXPECT_GT(rc, 0);
305
306 // Pending reply.
307 rc = cras_rstream_is_pending_reply(s);
308 EXPECT_EQ(1, rc);
309
310 cras_rstream_destroy(s);
311 }
312
TEST_F(RstreamTestSuite,InputStreamFlushMessages)313 TEST_F(RstreamTestSuite, InputStreamFlushMessages) {
314 struct cras_rstream* s;
315 int rc;
316
317 config_.direction = CRAS_STREAM_INPUT;
318
319 rc = cras_rstream_create(&config_, &s);
320 EXPECT_EQ(0, rc);
321
322 // Not pending reply.
323 rc = cras_rstream_is_pending_reply(s);
324 EXPECT_EQ(0, rc);
325
326 // Some data is ready. Sends it to client.
327 rc = cras_rstream_audio_ready(s, 10);
328 EXPECT_GT(rc, 0);
329
330 // Pending reply.
331 rc = cras_rstream_is_pending_reply(s);
332 EXPECT_EQ(1, rc);
333
334 // Client replies that data is captured.
335 stub_client_reply(AUDIO_MESSAGE_DATA_CAPTURED, 10, 0);
336
337 // Read messages.
338 cras_rstream_flush_old_audio_messages(s);
339
340 // NOT Pending reply.
341 rc = cras_rstream_is_pending_reply(s);
342 EXPECT_EQ(0, rc);
343
344 cras_rstream_destroy(s);
345 }
346
347 } // namespace
348
main(int argc,char ** argv)349 int main(int argc, char** argv) {
350 ::testing::InitGoogleTest(&argc, argv);
351 return RUN_ALL_TESTS();
352 }
353
354 /* stubs */
355 extern "C" {
356
cras_audio_area_create(int num_channels)357 struct cras_audio_area* cras_audio_area_create(int num_channels) {
358 return NULL;
359 }
360
cras_audio_area_destroy(struct cras_audio_area * area)361 void cras_audio_area_destroy(struct cras_audio_area* area) {}
362
cras_audio_area_config_channels(struct cras_audio_area * area,const struct cras_audio_format * fmt)363 void cras_audio_area_config_channels(struct cras_audio_area* area,
364 const struct cras_audio_format* fmt) {}
365
buffer_share_create(unsigned int buf_sz)366 struct buffer_share* buffer_share_create(unsigned int buf_sz) {
367 return NULL;
368 }
369
buffer_share_destroy(struct buffer_share * mix)370 void buffer_share_destroy(struct buffer_share* mix) {}
371
buffer_share_offset_update(struct buffer_share * mix,unsigned int id,unsigned int frames)372 int buffer_share_offset_update(struct buffer_share* mix,
373 unsigned int id,
374 unsigned int frames) {
375 return 0;
376 }
377
buffer_share_get_new_write_point(struct buffer_share * mix)378 unsigned int buffer_share_get_new_write_point(struct buffer_share* mix) {
379 return 0;
380 }
381
buffer_share_add_id(struct buffer_share * mix,unsigned int id,void * data)382 int buffer_share_add_id(struct buffer_share* mix, unsigned int id, void* data) {
383 return 0;
384 }
385
buffer_share_rm_id(struct buffer_share * mix,unsigned int id)386 int buffer_share_rm_id(struct buffer_share* mix, unsigned int id) {
387 return 0;
388 }
389
buffer_share_id_offset(const struct buffer_share * mix,unsigned int id)390 unsigned int buffer_share_id_offset(const struct buffer_share* mix,
391 unsigned int id) {
392 return 0;
393 }
ewma_power_init(struct ewma_power * ewma,unsigned int rate)394 void ewma_power_init(struct ewma_power* ewma, unsigned int rate) {}
395
ewma_power_calculate(struct ewma_power * ewma,const int16_t * buf,unsigned int channels,unsigned int size)396 void ewma_power_calculate(struct ewma_power* ewma,
397 const int16_t* buf,
398 unsigned int channels,
399 unsigned int size) {}
400
cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction,enum CRAS_CLIENT_TYPE client_type)401 void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction,
402 enum CRAS_CLIENT_TYPE client_type) {}
403
cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction,enum CRAS_CLIENT_TYPE client_type)404 void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction,
405 enum CRAS_CLIENT_TYPE client_type) {}
406
cras_server_metrics_stream_create(const struct cras_rstream_config * config)407 int cras_server_metrics_stream_create(
408 const struct cras_rstream_config* config) {
409 return 0;
410 }
411
cras_server_metrics_stream_destroy(const struct cras_rstream * stream)412 int cras_server_metrics_stream_destroy(const struct cras_rstream* stream) {
413 return 0;
414 }
415
416 #ifdef HAVE_WEBRTC_APM
417 #define FAKE_CRAS_APM_PTR reinterpret_cast<struct cras_apm*>(0x99)
cras_apm_list_create(void * stream_ptr,uint64_t effects)418 struct cras_apm_list* cras_apm_list_create(void* stream_ptr, uint64_t effects) {
419 return NULL;
420 }
cras_apm_list_get_active_apm(void * stream_ptr,void * dev_ptr)421 struct cras_apm* cras_apm_list_get_active_apm(void* stream_ptr, void* dev_ptr) {
422 return FAKE_CRAS_APM_PTR;
423 }
cras_apm_list_destroy(struct cras_apm_list * list)424 int cras_apm_list_destroy(struct cras_apm_list* list) {
425 return 0;
426 }
cras_apm_list_get_effects(struct cras_apm_list * list)427 uint64_t cras_apm_list_get_effects(struct cras_apm_list* list) {
428 return APM_ECHO_CANCELLATION;
429 }
cras_apm_list_get(struct cras_apm_list * list,void * dev_ptr)430 struct cras_apm* cras_apm_list_get(struct cras_apm_list* list, void* dev_ptr) {
431 return NULL;
432 }
cras_apm_list_get_format(struct cras_apm * apm)433 struct cras_audio_format* cras_apm_list_get_format(struct cras_apm* apm) {
434 return NULL;
435 }
436 #endif
437 }
438