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