• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 <unistd.h>
8 
9 extern "C" {
10 #include "audio_thread.h"
11 #include "cras_bt_log.h"
12 #include "cras_messages.h"
13 #include "cras_rclient.h"
14 #include "cras_rstream.h"
15 #include "cras_system_state.h"
16 
17 // Access to data structures and static functions.
18 #include "cras_playback_rclient.c"
19 #include "cras_rclient_util.c"
20 }
21 static unsigned int cras_make_fd_nonblocking_called;
22 static unsigned int cras_observer_remove_called;
23 static unsigned int cras_server_metrics_stream_config_called;
24 static int stream_list_add_called;
25 static int stream_list_add_return;
26 static unsigned int stream_list_rm_called;
27 static struct cras_audio_shm dummy_shm;
28 static struct cras_rstream dummy_rstream;
29 static unsigned int cras_rstream_config_init_with_message_called;
30 
ResetStubData()31 void ResetStubData() {
32   cras_make_fd_nonblocking_called = 0;
33   cras_observer_remove_called = 0;
34   cras_server_metrics_stream_config_called = 0;
35   stream_list_add_called = 0;
36   stream_list_add_return = 0;
37   stream_list_rm_called = 0;
38   cras_rstream_config_init_with_message_called = 0;
39 }
40 
41 namespace {
42 
TEST(RClientSuite,CreateSendMessage)43 TEST(RClientSuite, CreateSendMessage) {
44   struct cras_rclient* rclient;
45   int rc;
46   struct cras_client_connected msg;
47   int pipe_fds[2];
48 
49   ResetStubData();
50 
51   rc = pipe(pipe_fds);
52   ASSERT_EQ(0, rc);
53 
54   rclient = cras_playback_rclient_create(pipe_fds[1], 800);
55   ASSERT_NE((void*)NULL, rclient);
56   EXPECT_EQ(800, rclient->id);
57 
58   rc = read(pipe_fds[0], &msg, sizeof(msg));
59   EXPECT_EQ(sizeof(msg), rc);
60   EXPECT_EQ(CRAS_CLIENT_CONNECTED, msg.header.id);
61 
62   rclient->ops->destroy(rclient);
63   EXPECT_EQ(1, cras_observer_remove_called);
64   close(pipe_fds[0]);
65   close(pipe_fds[1]);
66 }
67 
68 class CPRMessageSuite : public testing::Test {
69  protected:
SetUp()70   virtual void SetUp() {
71     int rc;
72     struct cras_client_connected msg;
73 
74     rc = pipe(pipe_fds_);
75     if (rc < 0)
76       return;
77 
78     rclient_ = cras_playback_rclient_create(pipe_fds_[1], 1);
79     rc = read(pipe_fds_[0], &msg, sizeof(msg));
80     if (rc < 0)
81       return;
82 
83     fmt = {
84         .format = SND_PCM_FORMAT_S16_LE,
85         .frame_rate = 48000,
86         .num_channels = 2,
87     };
88     cras_audio_format_set_default_channel_layout(&fmt);
89     ResetStubData();
90   }
91 
TearDown()92   virtual void TearDown() {
93     rclient_->ops->destroy(rclient_);
94     close(pipe_fds_[0]);
95     close(pipe_fds_[1]);
96   }
97 
98   struct cras_rclient* rclient_;
99   struct cras_audio_format fmt;
100   int pipe_fds_[2];
101   int fd_;
102 };
103 
TEST_F(CPRMessageSuite,StreamConnectMessage)104 TEST_F(CPRMessageSuite, StreamConnectMessage) {
105   struct cras_client_stream_connected out_msg;
106   int rc;
107 
108   struct cras_connect_message msg;
109   cras_stream_id_t stream_id = 0x10002;
110   cras_fill_connect_message(&msg, CRAS_STREAM_OUTPUT, stream_id,
111                             CRAS_STREAM_TYPE_DEFAULT, CRAS_CLIENT_TYPE_UNKNOWN,
112                             480, 240, /*flags=*/0, /*effects=*/0, fmt,
113                             NO_DEVICE, /*client_shm_size=*/0);
114   ASSERT_EQ(stream_id, msg.stream_id);
115 
116   fd_ = 100;
117   rclient_->ops->handle_message_from_client(rclient_, &msg.header, &fd_, 1);
118   EXPECT_EQ(1, cras_make_fd_nonblocking_called);
119   EXPECT_EQ(1, cras_rstream_config_init_with_message_called);
120   EXPECT_EQ(1, stream_list_add_called);
121   EXPECT_EQ(0, stream_list_rm_called);
122 
123   rc = read(pipe_fds_[0], &out_msg, sizeof(out_msg));
124   EXPECT_EQ(sizeof(out_msg), rc);
125   EXPECT_EQ(stream_id, out_msg.stream_id);
126 }
127 
TEST_F(CPRMessageSuite,StreamConnectMessageInvalidDirection)128 TEST_F(CPRMessageSuite, StreamConnectMessageInvalidDirection) {
129   struct cras_client_stream_connected out_msg;
130   int rc;
131 
132   struct cras_connect_message msg;
133   cras_stream_id_t stream_id = 0x10002;
134 
135   for (int i = 0; i < CRAS_NUM_DIRECTIONS; i++) {
136     const auto dir = static_cast<CRAS_STREAM_DIRECTION>(i);
137     if (dir == CRAS_STREAM_OUTPUT)
138       continue;
139     cras_fill_connect_message(&msg, dir, stream_id, CRAS_STREAM_TYPE_DEFAULT,
140                               CRAS_CLIENT_TYPE_UNKNOWN, 480, 240, /*flags=*/0,
141                               /*effects=*/0, fmt, NO_DEVICE,
142                               /*client_shm_size=*/0);
143     ASSERT_EQ(stream_id, msg.stream_id);
144 
145     fd_ = 100;
146     rc = rclient_->ops->handle_message_from_client(rclient_, &msg.header, &fd_,
147                                                    1);
148     EXPECT_EQ(-EINVAL, rc);
149     EXPECT_EQ(0, cras_make_fd_nonblocking_called);
150     EXPECT_EQ(0, cras_rstream_config_init_with_message_called);
151     EXPECT_EQ(0, stream_list_add_called);
152     EXPECT_EQ(0, stream_list_rm_called);
153 
154     rc = read(pipe_fds_[0], &out_msg, sizeof(out_msg));
155     EXPECT_EQ(sizeof(out_msg), rc);
156     EXPECT_EQ(-EINVAL, out_msg.err);
157     EXPECT_EQ(stream_id, out_msg.stream_id);
158   }
159 }
160 
TEST_F(CPRMessageSuite,StreamConnectMessageInvalidClientId)161 TEST_F(CPRMessageSuite, StreamConnectMessageInvalidClientId) {
162   struct cras_client_stream_connected out_msg;
163   int rc;
164 
165   struct cras_connect_message msg;
166   cras_stream_id_t stream_id = 0x20002;  // stream_id with invalid client_id
167   cras_fill_connect_message(&msg, CRAS_STREAM_OUTPUT, stream_id,
168                             CRAS_STREAM_TYPE_DEFAULT, CRAS_CLIENT_TYPE_UNKNOWN,
169                             480, 240, /*flags=*/0, /*effects=*/0, fmt,
170                             NO_DEVICE, /*client_shm_size=*/0);
171   ASSERT_EQ(stream_id, msg.stream_id);
172 
173   fd_ = 100;
174   rc =
175       rclient_->ops->handle_message_from_client(rclient_, &msg.header, &fd_, 1);
176   EXPECT_EQ(-EINVAL, rc);
177   EXPECT_EQ(0, cras_make_fd_nonblocking_called);
178   EXPECT_EQ(0, cras_rstream_config_init_with_message_called);
179   EXPECT_EQ(0, stream_list_add_called);
180   EXPECT_EQ(0, stream_list_rm_called);
181 
182   rc = read(pipe_fds_[0], &out_msg, sizeof(out_msg));
183   EXPECT_EQ(sizeof(out_msg), rc);
184   EXPECT_EQ(-EINVAL, out_msg.err);
185   EXPECT_EQ(stream_id, out_msg.stream_id);
186 }
187 
188 /*
189  * TODO(yuhsaun): Remove this test when there are no client uses the old
190  * craslib. (CRAS_PROTO_VER = 3)
191  */
TEST_F(CPRMessageSuite,StreamConnectMessageOldProtocal)192 TEST_F(CPRMessageSuite, StreamConnectMessageOldProtocal) {
193   struct cras_client_stream_connected out_msg;
194   int rc;
195 
196   struct cras_connect_message_old msg;
197   cras_stream_id_t stream_id = 0x10002;
198 
199   msg.proto_version = 3;
200   msg.direction = CRAS_STREAM_OUTPUT;
201   msg.stream_id = stream_id;
202   msg.stream_type = CRAS_STREAM_TYPE_DEFAULT;
203   msg.buffer_frames = 480;
204   msg.cb_threshold = 240;
205   msg.flags = 0;
206   msg.effects = 0;
207   pack_cras_audio_format(&msg.format, &fmt);
208   msg.dev_idx = NO_DEVICE;
209   msg.header.id = CRAS_SERVER_CONNECT_STREAM;
210   msg.header.length = sizeof(struct cras_connect_message_old);
211 
212   fd_ = 100;
213   rc =
214       rclient_->ops->handle_message_from_client(rclient_, &msg.header, &fd_, 1);
215   EXPECT_EQ(1, cras_make_fd_nonblocking_called);
216   EXPECT_EQ(1, cras_rstream_config_init_with_message_called);
217   EXPECT_EQ(1, stream_list_add_called);
218   EXPECT_EQ(0, stream_list_rm_called);
219 
220   rc = read(pipe_fds_[0], &out_msg, sizeof(out_msg));
221   EXPECT_EQ(sizeof(out_msg), rc);
222   EXPECT_EQ(stream_id, out_msg.stream_id);
223 }
224 
TEST_F(CPRMessageSuite,StreamDisconnectMessage)225 TEST_F(CPRMessageSuite, StreamDisconnectMessage) {
226   struct cras_disconnect_stream_message msg;
227   cras_stream_id_t stream_id = 0x10002;
228   cras_fill_disconnect_stream_message(&msg, stream_id);
229 
230   rclient_->ops->handle_message_from_client(rclient_, &msg.header, NULL, 0);
231   EXPECT_EQ(0, stream_list_add_called);
232   EXPECT_EQ(1, stream_list_rm_called);
233 }
234 
TEST_F(CPRMessageSuite,StreamDisconnectMessageInvalidClientId)235 TEST_F(CPRMessageSuite, StreamDisconnectMessageInvalidClientId) {
236   struct cras_disconnect_stream_message msg;
237   cras_stream_id_t stream_id = 0x20002;  // stream_id with invalid client_id
238   cras_fill_disconnect_stream_message(&msg, stream_id);
239 
240   rclient_->ops->handle_message_from_client(rclient_, &msg.header, NULL, 0);
241   EXPECT_EQ(0, stream_list_add_called);
242   EXPECT_EQ(0, stream_list_rm_called);
243 }
244 }  // namespace
245 
main(int argc,char ** argv)246 int main(int argc, char** argv) {
247   ::testing::InitGoogleTest(&argc, argv);
248   return RUN_ALL_TESTS();
249 }
250 
251 /* stubs */
252 extern "C" {
253 
cras_iodev_list_get_stream_list()254 struct stream_list* cras_iodev_list_get_stream_list() {
255   return NULL;
256 }
257 
cras_make_fd_nonblocking(int fd)258 int cras_make_fd_nonblocking(int fd) {
259   cras_make_fd_nonblocking_called++;
260   return 0;
261 }
262 
cras_observer_remove(struct cras_observer_client * client)263 void cras_observer_remove(struct cras_observer_client* client) {
264   cras_observer_remove_called++;
265 }
266 
cras_rstream_get_effects(const struct cras_rstream * stream)267 unsigned int cras_rstream_get_effects(const struct cras_rstream* stream) {
268   return 0;
269 }
270 
cras_server_metrics_stream_config(struct cras_rstream_config * config)271 int cras_server_metrics_stream_config(struct cras_rstream_config* config) {
272   cras_server_metrics_stream_config_called++;
273   return 0;
274 }
275 
cras_send_with_fds(int sockfd,const void * buf,size_t len,int * fd,unsigned int num_fds)276 int cras_send_with_fds(int sockfd,
277                        const void* buf,
278                        size_t len,
279                        int* fd,
280                        unsigned int num_fds) {
281   return write(sockfd, buf, len);
282 }
283 
cras_sys_state_shm_fd()284 key_t cras_sys_state_shm_fd() {
285   return 1;
286 }
287 
cras_system_set_suspended(int suspended)288 void cras_system_set_suspended(int suspended) {}
289 
stream_list_rm_all_client_streams(struct stream_list * list,struct cras_rclient * rclient)290 int stream_list_rm_all_client_streams(struct stream_list* list,
291                                       struct cras_rclient* rclient) {
292   return 0;
293 }
294 
stream_list_rm(struct stream_list * list,cras_stream_id_t id)295 int stream_list_rm(struct stream_list* list, cras_stream_id_t id) {
296   stream_list_rm_called++;
297   return 0;
298 }
299 
stream_list_add(struct stream_list * list,struct cras_rstream_config * config,struct cras_rstream ** stream)300 int stream_list_add(struct stream_list* list,
301                     struct cras_rstream_config* config,
302                     struct cras_rstream** stream) {
303   int ret;
304 
305   *stream = &dummy_rstream;
306 
307   stream_list_add_called++;
308   ret = stream_list_add_return;
309   if (ret)
310     stream_list_add_return = -EINVAL;
311 
312   dummy_rstream.shm = &dummy_shm;
313   dummy_rstream.direction = config->direction;
314   dummy_rstream.stream_id = config->stream_id;
315 
316   return ret;
317 }
318 
cras_rstream_config_init_with_message(struct cras_rclient * client,const struct cras_connect_message * msg,int * aud_fd,int * client_shm_fd,const struct cras_audio_format * remote_fmt,struct cras_rstream_config * stream_config)319 void cras_rstream_config_init_with_message(
320     struct cras_rclient* client,
321     const struct cras_connect_message* msg,
322     int* aud_fd,
323     int* client_shm_fd,
324     const struct cras_audio_format* remote_fmt,
325     struct cras_rstream_config* stream_config) {
326   cras_rstream_config_init_with_message_called++;
327 }
328 
cras_rstream_config_cleanup(struct cras_rstream_config * stream_config)329 void cras_rstream_config_cleanup(struct cras_rstream_config* stream_config) {}
330 
331 }  // extern "C"
332