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