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