• 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 bool audio_format_valid;
22 static unsigned int cras_make_fd_nonblocking_called;
23 static unsigned int cras_observer_remove_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 mock_shm;
28 static struct cras_rstream mock_rstream;
29 
ResetStubData()30 void ResetStubData() {
31   audio_format_valid = true;
32   cras_make_fd_nonblocking_called = 0;
33   cras_observer_remove_called = 0;
34   stream_list_add_called = 0;
35   stream_list_add_return = 0;
36   stream_list_rm_called = 0;
37 }
38 
39 namespace {
40 
TEST(RClientSuite,CreateSendMessage)41 TEST(RClientSuite, CreateSendMessage) {
42   struct cras_rclient* rclient;
43   int rc;
44   struct cras_client_connected msg;
45   int pipe_fds[2];
46 
47   ResetStubData();
48 
49   rc = pipe(pipe_fds);
50   ASSERT_EQ(0, rc);
51 
52   rclient = cras_playback_rclient_create(pipe_fds[1], 800);
53   ASSERT_NE((void*)NULL, rclient);
54   EXPECT_EQ(800, rclient->id);
55 
56   rc = read(pipe_fds[0], &msg, sizeof(msg));
57   EXPECT_EQ(sizeof(msg), rc);
58   EXPECT_EQ(CRAS_CLIENT_CONNECTED, msg.header.id);
59 
60   rclient->ops->destroy(rclient);
61   EXPECT_EQ(1, cras_observer_remove_called);
62   close(pipe_fds[0]);
63   close(pipe_fds[1]);
64 }
65 
66 class CPRMessageSuite : public testing::Test {
67  protected:
SetUp()68   virtual void SetUp() {
69     int rc;
70     struct cras_client_connected msg;
71 
72     rc = pipe(pipe_fds_);
73     if (rc < 0)
74       return;
75 
76     rclient_ = cras_playback_rclient_create(pipe_fds_[1], 1);
77     rc = read(pipe_fds_[0], &msg, sizeof(msg));
78     if (rc < 0)
79       return;
80 
81     fmt = {
82         .format = SND_PCM_FORMAT_S16_LE,
83         .frame_rate = 48000,
84         .num_channels = 2,
85     };
86     cras_audio_format_set_default_channel_layout(&fmt);
87     ResetStubData();
88   }
89 
TearDown()90   virtual void TearDown() {
91     rclient_->ops->destroy(rclient_);
92     close(pipe_fds_[0]);
93     close(pipe_fds_[1]);
94   }
95 
96   struct cras_rclient* rclient_;
97   struct cras_audio_format fmt;
98   int pipe_fds_[2];
99   int fd_;
100 };
101 
TEST_F(CPRMessageSuite,StreamConnectMessage)102 TEST_F(CPRMessageSuite, StreamConnectMessage) {
103   struct cras_client_stream_connected out_msg;
104   int rc;
105 
106   struct cras_connect_message msg;
107   cras_stream_id_t stream_id = 0x10002;
108   cras_fill_connect_message(&msg, CRAS_STREAM_OUTPUT, stream_id,
109                             CRAS_STREAM_TYPE_DEFAULT, CRAS_CLIENT_TYPE_UNKNOWN,
110                             480, 240, /*flags=*/0, /*effects=*/0, fmt,
111                             NO_DEVICE);
112   ASSERT_EQ(stream_id, msg.stream_id);
113 
114   fd_ = 100;
115   rclient_->ops->handle_message_from_client(rclient_, &msg.header, &fd_, 1);
116   EXPECT_EQ(1, cras_make_fd_nonblocking_called);
117   EXPECT_EQ(1, stream_list_add_called);
118   EXPECT_EQ(0, stream_list_rm_called);
119 
120   rc = read(pipe_fds_[0], &out_msg, sizeof(out_msg));
121   EXPECT_EQ(sizeof(out_msg), rc);
122   EXPECT_EQ(stream_id, out_msg.stream_id);
123 }
124 
TEST_F(CPRMessageSuite,StreamConnectMessageInvalidDirection)125 TEST_F(CPRMessageSuite, StreamConnectMessageInvalidDirection) {
126   struct cras_client_stream_connected out_msg;
127   int rc;
128 
129   struct cras_connect_message msg;
130   cras_stream_id_t stream_id = 0x10002;
131 
132   for (int i = 0; i < CRAS_NUM_DIRECTIONS; i++) {
133     const auto dir = static_cast<CRAS_STREAM_DIRECTION>(i);
134     if (dir == CRAS_STREAM_OUTPUT)
135       continue;
136     cras_fill_connect_message(&msg, dir, stream_id, CRAS_STREAM_TYPE_DEFAULT,
137                               CRAS_CLIENT_TYPE_UNKNOWN, 480, 240, /*flags=*/0,
138                               /*effects=*/0, fmt, NO_DEVICE);
139     ASSERT_EQ(stream_id, msg.stream_id);
140 
141     fd_ = 100;
142     rc = rclient_->ops->handle_message_from_client(rclient_, &msg.header, &fd_,
143                                                    1);
144     EXPECT_EQ(0, rc);
145     EXPECT_EQ(0, cras_make_fd_nonblocking_called);
146     EXPECT_EQ(0, stream_list_add_called);
147     EXPECT_EQ(0, stream_list_rm_called);
148 
149     rc = read(pipe_fds_[0], &out_msg, sizeof(out_msg));
150     EXPECT_EQ(sizeof(out_msg), rc);
151     EXPECT_EQ(-EINVAL, out_msg.err);
152     EXPECT_EQ(stream_id, out_msg.stream_id);
153   }
154 }
155 
TEST_F(CPRMessageSuite,StreamConnectMessageInvalidClientId)156 TEST_F(CPRMessageSuite, StreamConnectMessageInvalidClientId) {
157   struct cras_client_stream_connected out_msg;
158   int rc;
159 
160   struct cras_connect_message msg;
161   cras_stream_id_t stream_id = 0x20002;  // stream_id with invalid client_id
162   cras_fill_connect_message(&msg, CRAS_STREAM_OUTPUT, stream_id,
163                             CRAS_STREAM_TYPE_DEFAULT, CRAS_CLIENT_TYPE_UNKNOWN,
164                             480, 240, /*flags=*/0, /*effects=*/0, fmt,
165                             NO_DEVICE);
166   ASSERT_EQ(stream_id, msg.stream_id);
167 
168   fd_ = 100;
169   rc =
170       rclient_->ops->handle_message_from_client(rclient_, &msg.header, &fd_, 1);
171   EXPECT_EQ(0, rc);
172   EXPECT_EQ(0, cras_make_fd_nonblocking_called);
173   EXPECT_EQ(0, stream_list_add_called);
174   EXPECT_EQ(0, stream_list_rm_called);
175 
176   rc = read(pipe_fds_[0], &out_msg, sizeof(out_msg));
177   EXPECT_EQ(sizeof(out_msg), rc);
178   EXPECT_EQ(-EINVAL, out_msg.err);
179   EXPECT_EQ(stream_id, out_msg.stream_id);
180 }
181 
TEST_F(CPRMessageSuite,StreamConnectMessageInvalidAudioFormat)182 TEST_F(CPRMessageSuite, StreamConnectMessageInvalidAudioFormat) {
183   struct cras_client_stream_connected out_msg;
184   int rc;
185 
186   struct cras_connect_message msg;
187   cras_stream_id_t stream_id = 0x10002;
188   cras_fill_connect_message(&msg, CRAS_STREAM_OUTPUT, stream_id,
189                             CRAS_STREAM_TYPE_DEFAULT, CRAS_CLIENT_TYPE_UNKNOWN,
190                             480, 240, /*flags=*/0, /*effects=*/0, fmt,
191                             NO_DEVICE);
192   ASSERT_EQ(stream_id, msg.stream_id);
193 
194   audio_format_valid = false;  // stubs out verification failure.
195 
196   fd_ = 100;
197   rc =
198       rclient_->ops->handle_message_from_client(rclient_, &msg.header, &fd_, 1);
199   EXPECT_EQ(0, rc);
200   EXPECT_EQ(0, cras_make_fd_nonblocking_called);
201   EXPECT_EQ(0, stream_list_add_called);
202   EXPECT_EQ(0, stream_list_rm_called);
203 
204   rc = read(pipe_fds_[0], &out_msg, sizeof(out_msg));
205   EXPECT_EQ(sizeof(out_msg), rc);
206   EXPECT_EQ(-EINVAL, out_msg.err);
207   EXPECT_EQ(stream_id, out_msg.stream_id);
208 }
209 
TEST_F(CPRMessageSuite,StreamDisconnectMessage)210 TEST_F(CPRMessageSuite, StreamDisconnectMessage) {
211   struct cras_disconnect_stream_message msg;
212   cras_stream_id_t stream_id = 0x10002;
213   cras_fill_disconnect_stream_message(&msg, stream_id);
214 
215   rclient_->ops->handle_message_from_client(rclient_, &msg.header, NULL, 0);
216   EXPECT_EQ(0, stream_list_add_called);
217   EXPECT_EQ(1, stream_list_rm_called);
218 }
219 
TEST_F(CPRMessageSuite,StreamDisconnectMessageInvalidClientId)220 TEST_F(CPRMessageSuite, StreamDisconnectMessageInvalidClientId) {
221   struct cras_disconnect_stream_message msg;
222   cras_stream_id_t stream_id = 0x20002;  // stream_id with invalid client_id
223   cras_fill_disconnect_stream_message(&msg, stream_id);
224 
225   rclient_->ops->handle_message_from_client(rclient_, &msg.header, NULL, 0);
226   EXPECT_EQ(0, stream_list_add_called);
227   EXPECT_EQ(0, stream_list_rm_called);
228 }
229 }  // namespace
230 
main(int argc,char ** argv)231 int main(int argc, char** argv) {
232   ::testing::InitGoogleTest(&argc, argv);
233   return RUN_ALL_TESTS();
234 }
235 
236 /* stubs */
237 extern "C" {
238 
cras_iodev_list_get_stream_list()239 struct stream_list* cras_iodev_list_get_stream_list() {
240   return NULL;
241 }
242 
cras_make_fd_nonblocking(int fd)243 int cras_make_fd_nonblocking(int fd) {
244   cras_make_fd_nonblocking_called++;
245   return 0;
246 }
247 
cras_observer_remove(struct cras_observer_client * client)248 void cras_observer_remove(struct cras_observer_client* client) {
249   cras_observer_remove_called++;
250 }
251 
cras_rstream_get_effects(const struct cras_rstream * stream)252 unsigned int cras_rstream_get_effects(const struct cras_rstream* stream) {
253   return 0;
254 }
255 
cras_send_with_fds(int sockfd,const void * buf,size_t len,int * fd,unsigned int num_fds)256 int cras_send_with_fds(int sockfd,
257                        const void* buf,
258                        size_t len,
259                        int* fd,
260                        unsigned int num_fds) {
261   return write(sockfd, buf, len);
262 }
263 
cras_sys_state_shm_fd()264 key_t cras_sys_state_shm_fd() {
265   return 1;
266 }
267 
cras_system_set_suspended(int suspended)268 void cras_system_set_suspended(int suspended) {}
269 
stream_list_rm_all_client_streams(struct stream_list * list,struct cras_rclient * rclient)270 int stream_list_rm_all_client_streams(struct stream_list* list,
271                                       struct cras_rclient* rclient) {
272   return 0;
273 }
274 
stream_list_rm(struct stream_list * list,cras_stream_id_t id)275 int stream_list_rm(struct stream_list* list, cras_stream_id_t id) {
276   stream_list_rm_called++;
277   return 0;
278 }
279 
stream_list_add(struct stream_list * list,struct cras_rstream_config * config,struct cras_rstream ** stream)280 int stream_list_add(struct stream_list* list,
281                     struct cras_rstream_config* config,
282                     struct cras_rstream** stream) {
283   int ret;
284 
285   *stream = &mock_rstream;
286 
287   stream_list_add_called++;
288   ret = stream_list_add_return;
289   if (ret)
290     stream_list_add_return = -EINVAL;
291 
292   mock_rstream.shm = &mock_shm;
293   mock_rstream.direction = config->direction;
294   mock_rstream.stream_id = config->stream_id;
295 
296   return ret;
297 }
298 
cras_audio_format_valid(const struct cras_audio_format * fmt)299 bool cras_audio_format_valid(const struct cras_audio_format* fmt) {
300   return audio_format_valid;
301 }
302 
detect_rtc_stream_pair(struct stream_list * list,struct cras_rstream * stream)303 void detect_rtc_stream_pair(struct stream_list* list,
304                             struct cras_rstream* stream) {
305   return;
306 }
307 
308 }  // extern "C"
309