1 /* Copyright (c) 2013 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
6 #include <gtest/gtest.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <sys/socket.h>
10
11 extern "C" {
12 #include "cras_bt_log.h"
13 #include "cras_hfp_slc.h"
14 #include "cras_telephony.h"
15 }
16
17 static struct hfp_slc_handle* handle;
18 static struct cras_telephony_handle fake_telephony;
19 static int cras_bt_device_update_hardware_volume_called;
20 static int slc_initialized_cb_called;
21 static int slc_disconnected_cb_called;
22 static int cras_system_add_select_fd_called;
23 static void (*slc_cb)(void* data);
24 static void* slc_cb_data;
25 static int fake_errno;
26 static struct cras_bt_device* device =
27 reinterpret_cast<struct cras_bt_device*>(2);
28 static void (*cras_tm_timer_cb)(struct cras_timer* t, void* data);
29 static void* cras_tm_timer_cb_data;
30
31 int slc_initialized_cb(struct hfp_slc_handle* handle);
32 int slc_disconnected_cb(struct hfp_slc_handle* handle);
33
ResetStubData()34 void ResetStubData() {
35 slc_initialized_cb_called = 0;
36 cras_system_add_select_fd_called = 0;
37 cras_bt_device_update_hardware_volume_called = 0;
38 slc_cb = NULL;
39 slc_cb_data = NULL;
40 }
41
42 namespace {
43
TEST(HfpSlc,CreateSlcHandle)44 TEST(HfpSlc, CreateSlcHandle) {
45 ResetStubData();
46
47 handle = hfp_slc_create(0, 0, AG_ENHANCED_CALL_STATUS, device,
48 slc_initialized_cb, slc_disconnected_cb);
49 ASSERT_EQ(1, cras_system_add_select_fd_called);
50 ASSERT_EQ(handle, slc_cb_data);
51
52 hfp_slc_destroy(handle);
53 }
54
TEST(HfpSlc,InitializeSlc)55 TEST(HfpSlc, InitializeSlc) {
56 int err;
57 int sock[2];
58 char buf[256];
59 char* chp;
60 ResetStubData();
61
62 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
63 handle = hfp_slc_create(sock[0], 0, AG_ENHANCED_CALL_STATUS, device,
64 slc_initialized_cb, slc_disconnected_cb);
65
66 err = write(sock[1], "AT+CIND=?\r", 10);
67 ASSERT_EQ(10, err);
68 slc_cb(slc_cb_data);
69 err = read(sock[1], buf, 256);
70
71 /* Assert "\r\n+CIND: ... \r\n" response is received */
72 chp = strstr(buf, "\r\n");
73 ASSERT_NE((void*)NULL, (void*)chp);
74 ASSERT_EQ(0, strncmp("\r\n+CIND:", chp, 8));
75 chp += 2;
76 chp = strstr(chp, "\r\n");
77 ASSERT_NE((void*)NULL, (void*)chp);
78
79 /* Assert "\r\nOK\r\n" response is received */
80 chp += 2;
81 chp = strstr(chp, "\r\n");
82 ASSERT_NE((void*)NULL, (void*)chp);
83 ASSERT_EQ(0, strncmp("\r\nOK", chp, 4));
84
85 err = write(sock[1], "AT+CMER=3,0,0,1\r", 16);
86 ASSERT_EQ(16, err);
87 slc_cb(slc_cb_data);
88
89 ASSERT_EQ(1, slc_initialized_cb_called);
90
91 /* Assert "\r\nOK\r\n" response is received */
92 err = read(sock[1], buf, 256);
93
94 chp = strstr(buf, "\r\n");
95 ASSERT_NE((void*)NULL, (void*)chp);
96 ASSERT_EQ(0, strncmp("\r\nOK", chp, 4));
97
98 err = write(sock[1], "AT+VGS=13\r", 10);
99 ASSERT_EQ(err, 10);
100 slc_cb(slc_cb_data);
101
102 err = read(sock[1], buf, 256);
103
104 chp = strstr(buf, "\r\n");
105 ASSERT_NE((void*)NULL, (void*)chp);
106 ASSERT_EQ(0, strncmp("\r\nOK", chp, 4));
107
108 ASSERT_EQ(1, cras_bt_device_update_hardware_volume_called);
109
110 hfp_slc_destroy(handle);
111 }
112
TEST(HfpSlc,DisconnectSlc)113 TEST(HfpSlc, DisconnectSlc) {
114 int sock[2];
115 ResetStubData();
116
117 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
118 handle = hfp_slc_create(sock[0], 0, AG_ENHANCED_CALL_STATUS, device,
119 slc_initialized_cb, slc_disconnected_cb);
120 /* Close socket right away to make read() get negative err code, and
121 * fake the errno to ECONNRESET. */
122 close(sock[0]);
123 close(sock[1]);
124 fake_errno = 104;
125 slc_cb(slc_cb_data);
126
127 ASSERT_EQ(1, slc_disconnected_cb_called);
128
129 hfp_slc_destroy(handle);
130 }
131
TEST(HfpSlc,CodecNegotiation)132 TEST(HfpSlc, CodecNegotiation) {
133 int codec;
134 int err;
135 int sock[2];
136 char buf[256];
137 char* pos;
138 ResetStubData();
139
140 btlog = cras_bt_event_log_init();
141
142 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
143 handle = hfp_slc_create(sock[0], 0, AG_CODEC_NEGOTIATION, device,
144 slc_initialized_cb, slc_disconnected_cb);
145
146 codec = hfp_slc_get_selected_codec(handle);
147 EXPECT_EQ(HFP_CODEC_ID_CVSD, codec);
148
149 /* Fake that HF supports codec negotiation. */
150 err = write(sock[1], "AT+BRSF=128\r", 12);
151 ASSERT_EQ(err, 12);
152 slc_cb(slc_cb_data);
153 err = read(sock[1], buf, 256);
154
155 /* Fake that HF supports mSBC codec. */
156 err = write(sock[1], "AT+BAC=1,2\r", 11);
157 ASSERT_EQ(err, 11);
158 slc_cb(slc_cb_data);
159 err = read(sock[1], buf, 256);
160
161 /* Fake event reporting command to indicate SLC established. */
162 err = write(sock[1], "AT+CMER=3,0,0,1\r", 16);
163 ASSERT_EQ(err, 16);
164 slc_cb(slc_cb_data);
165
166 /* Assert that AG side prefers mSBC codec. */
167 codec = hfp_slc_get_selected_codec(handle);
168 EXPECT_EQ(HFP_CODEC_ID_MSBC, codec);
169
170 /* Assert CRAS initiates codec selection to mSBC. */
171 memset(buf, 0, 256);
172 err = read(sock[1], buf, 256);
173 pos = strstr(buf, "\r\n+BCS:2\r\n");
174 ASSERT_NE((void*)NULL, pos);
175
176 err = write(sock[1], "AT+VGS=9\r", 9);
177 ASSERT_EQ(err, 9);
178 slc_cb(slc_cb_data);
179
180 /* Assert CRAS initiates codec selection to mSBC. */
181 memset(buf, 0, 256);
182 err = read(sock[1], buf, 256);
183 pos = strstr(buf, "\r\n+BCS:2\r\n");
184 ASSERT_NE((void*)NULL, pos);
185
186 /* Fake that receiving codec selection from HF. */
187 err = write(sock[1], "AT+BCS=2\r", 9);
188 ASSERT_EQ(err, 9);
189 slc_cb(slc_cb_data);
190
191 memset(buf, 0, 256);
192 err = read(sock[1], buf, 256);
193 pos = strstr(buf, "\r\n+BCS:2\r\n");
194 ASSERT_EQ((void*)NULL, pos);
195
196 hfp_slc_destroy(handle);
197 cras_bt_event_log_deinit(btlog);
198 }
199
TEST(HfpSlc,CodecNegotiationTimeout)200 TEST(HfpSlc, CodecNegotiationTimeout) {
201 int codec;
202 int err;
203 int sock[2];
204 char buf[256];
205 char* pos;
206 ResetStubData();
207
208 btlog = cras_bt_event_log_init();
209
210 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
211 handle = hfp_slc_create(sock[0], 0, AG_CODEC_NEGOTIATION, device,
212 slc_initialized_cb, slc_disconnected_cb);
213
214 codec = hfp_slc_get_selected_codec(handle);
215 EXPECT_EQ(HFP_CODEC_ID_CVSD, codec);
216
217 /* Fake that HF supports codec negotiation. */
218 err = write(sock[1], "AT+BRSF=128\r", 12);
219 ASSERT_EQ(err, 12);
220 slc_cb(slc_cb_data);
221 err = read(sock[1], buf, 256);
222
223 /* Fake that HF supports mSBC codec. */
224 err = write(sock[1], "AT+BAC=1,2\r", 11);
225 ASSERT_EQ(err, 11);
226 slc_cb(slc_cb_data);
227 err = read(sock[1], buf, 256);
228
229 /* Fake event reporting command to indicate SLC established. */
230 err = write(sock[1], "AT+CMER=3,0,0,1\r", 16);
231 ASSERT_EQ(err, 16);
232 slc_cb(slc_cb_data);
233
234 ASSERT_NE((void*)NULL, cras_tm_timer_cb);
235
236 /* Assert that AG side prefers mSBC codec. */
237 codec = hfp_slc_get_selected_codec(handle);
238 EXPECT_EQ(HFP_CODEC_ID_MSBC, codec);
239
240 /* Assert CRAS initiates codec selection to mSBC. */
241 memset(buf, 0, 256);
242 err = read(sock[1], buf, 256);
243 pos = strstr(buf, "\r\n+BCS:2\r\n");
244 ASSERT_NE((void*)NULL, pos);
245
246 /* Assume codec negotiation failed. so timeout is reached. */
247 cras_tm_timer_cb(NULL, cras_tm_timer_cb_data);
248
249 codec = hfp_slc_get_selected_codec(handle);
250 EXPECT_EQ(HFP_CODEC_ID_CVSD, codec);
251
252 /* Expects CRAS fallback and selects to CVSD codec. */
253 memset(buf, 0, 256);
254 err = read(sock[1], buf, 256);
255 pos = strstr(buf, "\r\n+BCS:1\r\n");
256 ASSERT_NE((void*)NULL, pos);
257
258 hfp_slc_destroy(handle);
259 cras_bt_event_log_deinit(btlog);
260 }
261
262 } // namespace
263
slc_initialized_cb(struct hfp_slc_handle * handle)264 int slc_initialized_cb(struct hfp_slc_handle* handle) {
265 slc_initialized_cb_called++;
266 return 0;
267 }
268
slc_disconnected_cb(struct hfp_slc_handle * handle)269 int slc_disconnected_cb(struct hfp_slc_handle* handle) {
270 slc_disconnected_cb_called++;
271 return 0;
272 }
273
274 extern "C" {
275
276 struct cras_bt_event_log* btlog;
277
cras_system_add_select_fd(int fd,void (* callback)(void * data),void * callback_data)278 int cras_system_add_select_fd(int fd,
279 void (*callback)(void* data),
280 void* callback_data) {
281 cras_system_add_select_fd_called++;
282 slc_cb = callback;
283 slc_cb_data = callback_data;
284 return 0;
285 }
286
cras_system_rm_select_fd(int fd)287 void cras_system_rm_select_fd(int fd) {}
288
cras_bt_device_update_hardware_volume(struct cras_bt_device * device,int volume)289 void cras_bt_device_update_hardware_volume(struct cras_bt_device* device,
290 int volume) {
291 cras_bt_device_update_hardware_volume_called++;
292 }
293
294 /* To return fake errno */
__errno_location()295 int* __errno_location() {
296 return &fake_errno;
297 }
298
cras_system_state_get_tm()299 struct cras_tm* cras_system_state_get_tm() {
300 return NULL;
301 }
302
cras_tm_create_timer(struct cras_tm * tm,unsigned int ms,void (* cb)(struct cras_timer * t,void * data),void * cb_data)303 struct cras_timer* cras_tm_create_timer(struct cras_tm* tm,
304 unsigned int ms,
305 void (*cb)(struct cras_timer* t,
306 void* data),
307 void* cb_data) {
308 cras_tm_timer_cb = cb;
309 cras_tm_timer_cb_data = cb_data;
310 return reinterpret_cast<struct cras_timer*>(0x404);
311 }
312
cras_tm_cancel_timer(struct cras_tm * tm,struct cras_timer * t)313 void cras_tm_cancel_timer(struct cras_tm* tm, struct cras_timer* t) {}
314 }
315
316 // For telephony
cras_telephony_get()317 struct cras_telephony_handle* cras_telephony_get() {
318 return &fake_telephony;
319 }
320
cras_telephony_store_dial_number(int len,const char * num)321 void cras_telephony_store_dial_number(int len, const char* num) {}
322
cras_telephony_event_answer_call()323 int cras_telephony_event_answer_call() {
324 return 0;
325 }
326
cras_telephony_event_terminate_call()327 int cras_telephony_event_terminate_call() {
328 return 0;
329 }
330
main(int argc,char ** argv)331 int main(int argc, char** argv) {
332 ::testing::InitGoogleTest(&argc, argv);
333 return RUN_ALL_TESTS();
334 }
335