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 <stdint.h>
7 #include <syslog.h>
8 #include <sys/socket.h>
9 #include <unistd.h>
10
11 #include "cras_a2dp_endpoint.h"
12 #include "cras_bt_adapter.h"
13 #include "cras_bt_constants.h"
14 #include "cras_bt_log.h"
15 #include "cras_bt_profile.h"
16 #include "cras_hfp_ag_profile.h"
17 #include "cras_hfp_info.h"
18 #include "cras_hfp_iodev.h"
19 #include "cras_hfp_alsa_iodev.h"
20 #include "cras_server_metrics.h"
21 #include "cras_system_state.h"
22 #include "cras_iodev_list.h"
23 #include "utlist.h"
24
25 #define HFP_AG_PROFILE_NAME "Hands-Free Voice gateway"
26 #define HFP_AG_PROFILE_PATH "/org/chromium/Cras/Bluetooth/HFPAG"
27 #define HFP_VERSION_1_5 0x0105
28 #define HSP_AG_PROFILE_NAME "Headset Voice gateway"
29 #define HSP_AG_PROFILE_PATH "/org/chromium/Cras/Bluetooth/HSPAG"
30 #define HSP_VERSION_1_2 0x0102
31 #define HSP_VERSION_1_2_STR "0x0102"
32
33 #define HSP_AG_RECORD \
34 "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" \
35 "<record>" \
36 " <attribute id=\"0x0001\">" \
37 " <sequence>" \
38 " <uuid value=\"" HSP_AG_UUID "\" />" \
39 " <uuid value=\"" GENERIC_AUDIO_UUID "\" />" \
40 " </sequence>" \
41 " </attribute>" \
42 " <attribute id=\"0x0004\">" \
43 " <sequence>" \
44 " <sequence>" \
45 " <uuid value=\"0x0100\" />" \
46 " </sequence>" \
47 " <sequence>" \
48 " <uuid value=\"0x0003\" />" \
49 " <uint8 value=\"0x0c\" />" \
50 " </sequence>" \
51 " </sequence>" \
52 " </attribute>" \
53 " <attribute id=\"0x0005\">" \
54 " <sequence>" \
55 " <uuid value=\"0x1002\" />" \
56 " </sequence>" \
57 " </attribute>" \
58 " <attribute id=\"0x0009\">" \
59 " <sequence>" \
60 " <sequence>" \
61 " <uuid value=\"" HSP_HS_UUID "\" />" \
62 " <uint16 value=\"" HSP_VERSION_1_2_STR "\" />" \
63 " </sequence>" \
64 " </sequence>" \
65 " </attribute>" \
66 " <attribute id=\"0x0100\">" \
67 " <text value=\"" HSP_AG_PROFILE_NAME "\" />" \
68 " </attribute>" \
69 " <attribute id=\"0x0301\" >" \
70 " <uint8 value=\"0x01\" />" \
71 " </attribute>" \
72 "</record>"
73
74 /* Object representing the audio gateway role for HFP/HSP.
75 * Members:
76 * idev - The input iodev for HFP/HSP.
77 * odev - The output iodev for HFP/HSP.
78 * info - The hfp_info object for SCO audio.
79 * slc_handle - The service level connection.
80 * device - The bt device associated with this audio gateway.
81 * a2dp_delay_retries - The number of retries left to delay starting
82 * the hfp/hsp audio gateway to wait for a2dp connection.
83 * conn - The dbus connection used to send message to bluetoothd.
84 * profile - The profile enum of this audio gateway.
85 */
86 struct audio_gateway {
87 struct cras_iodev *idev;
88 struct cras_iodev *odev;
89 struct hfp_info *info;
90 struct hfp_slc_handle *slc_handle;
91 struct cras_bt_device *device;
92 int a2dp_delay_retries;
93 DBusConnection *conn;
94 enum cras_bt_device_profile profile;
95 struct audio_gateway *prev, *next;
96 };
97
98 static struct audio_gateway *connected_ags;
99
need_go_sco_pcm(struct cras_bt_device * device)100 static int need_go_sco_pcm(struct cras_bt_device *device)
101 {
102 return cras_iodev_list_get_sco_pcm_iodev(CRAS_STREAM_INPUT) ||
103 cras_iodev_list_get_sco_pcm_iodev(CRAS_STREAM_OUTPUT);
104 }
105
destroy_audio_gateway(struct audio_gateway * ag)106 static void destroy_audio_gateway(struct audio_gateway *ag)
107 {
108 DL_DELETE(connected_ags, ag);
109
110 if (need_go_sco_pcm(ag->device)) {
111 if (ag->idev)
112 hfp_alsa_iodev_destroy(ag->idev);
113 if (ag->odev)
114 hfp_alsa_iodev_destroy(ag->odev);
115 } else {
116 if (ag->idev)
117 hfp_iodev_destroy(ag->idev);
118 if (ag->odev)
119 hfp_iodev_destroy(ag->odev);
120 }
121
122 if (ag->info) {
123 if (hfp_info_running(ag->info))
124 hfp_info_stop(ag->info);
125 hfp_info_destroy(ag->info);
126 }
127 if (ag->slc_handle)
128 hfp_slc_destroy(ag->slc_handle);
129
130 free(ag);
131 }
132
133 /* Checks if there already a audio gateway connected for device. */
has_audio_gateway(struct cras_bt_device * device)134 static int has_audio_gateway(struct cras_bt_device *device)
135 {
136 struct audio_gateway *ag;
137 DL_FOREACH (connected_ags, ag) {
138 if (ag->device == device)
139 return 1;
140 }
141 return 0;
142 }
143
cras_hfp_ag_release(struct cras_bt_profile * profile)144 static void cras_hfp_ag_release(struct cras_bt_profile *profile)
145 {
146 struct audio_gateway *ag;
147
148 DL_FOREACH (connected_ags, ag)
149 destroy_audio_gateway(ag);
150 }
151
152 /* Callback triggered when SLC is initialized. */
cras_hfp_ag_slc_initialized(struct hfp_slc_handle * handle)153 static int cras_hfp_ag_slc_initialized(struct hfp_slc_handle *handle)
154 {
155 struct audio_gateway *ag;
156
157 DL_SEARCH_SCALAR(connected_ags, ag, slc_handle, handle);
158 if (!ag)
159 return -EINVAL;
160
161 /* Log if the hands-free device supports WBS or not. Assuming the
162 * codec negotiation feature means the WBS capability on headset.
163 */
164 cras_server_metrics_hfp_wideband_support(
165 hfp_slc_get_hf_codec_negotiation_supported(handle));
166
167 /* Defer the starting of audio gateway to bt_device. */
168 return cras_bt_device_audio_gateway_initialized(ag->device);
169 }
170
cras_hfp_ag_slc_disconnected(struct hfp_slc_handle * handle)171 static int cras_hfp_ag_slc_disconnected(struct hfp_slc_handle *handle)
172 {
173 struct audio_gateway *ag;
174
175 DL_SEARCH_SCALAR(connected_ags, ag, slc_handle, handle);
176 if (!ag)
177 return -EINVAL;
178
179 destroy_audio_gateway(ag);
180 cras_bt_device_notify_profile_dropped(
181 ag->device, CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
182 return 0;
183 }
184
check_for_conflict_ag(struct cras_bt_device * new_connected)185 static int check_for_conflict_ag(struct cras_bt_device *new_connected)
186 {
187 struct audio_gateway *ag;
188
189 /* Check if there's already an A2DP/HFP device. */
190 DL_FOREACH (connected_ags, ag) {
191 if (cras_bt_device_has_a2dp(ag->device))
192 return -1;
193 }
194
195 /* Check if there's already an A2DP-only device. */
196 if (cras_a2dp_connected_device() &&
197 cras_bt_device_supports_profile(new_connected,
198 CRAS_BT_DEVICE_PROFILE_A2DP_SINK))
199 return -1;
200
201 return 0;
202 }
203
cras_hfp_ag_remove_conflict(struct cras_bt_device * device)204 int cras_hfp_ag_remove_conflict(struct cras_bt_device *device)
205 {
206 struct audio_gateway *ag;
207
208 DL_FOREACH (connected_ags, ag) {
209 if (ag->device == device)
210 continue;
211 cras_bt_device_notify_profile_dropped(
212 ag->device, CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
213 destroy_audio_gateway(ag);
214 }
215 return 0;
216 }
217
cras_hfp_ag_new_connection(DBusConnection * conn,struct cras_bt_profile * profile,struct cras_bt_device * device,int rfcomm_fd)218 static int cras_hfp_ag_new_connection(DBusConnection *conn,
219 struct cras_bt_profile *profile,
220 struct cras_bt_device *device,
221 int rfcomm_fd)
222 {
223 struct cras_bt_adapter *adapter;
224 struct audio_gateway *ag;
225 int ag_features;
226
227 BTLOG(btlog, BT_HFP_NEW_CONNECTION, 0, 0);
228
229 if (has_audio_gateway(device)) {
230 syslog(LOG_ERR,
231 "Audio gateway exists when %s connects for profile %s",
232 cras_bt_device_name(device), profile->name);
233 close(rfcomm_fd);
234 return 0;
235 }
236
237 if (check_for_conflict_ag(device))
238 return -1;
239
240 ag = (struct audio_gateway *)calloc(1, sizeof(*ag));
241 ag->device = device;
242 ag->conn = conn;
243 ag->profile = cras_bt_device_profile_from_uuid(profile->uuid);
244
245 adapter = cras_bt_device_adapter(device);
246 /*
247 * If the WBS enabled flag is set and adapter reports wbs capability
248 * then add codec negotiation feature.
249 * TODO(hychao): AND the two conditions to let bluetooth daemon
250 * control whether to turn on WBS feature.
251 */
252 ag_features = profile->features;
253 if (cras_system_get_bt_wbs_enabled() &&
254 cras_bt_adapter_wbs_supported(adapter))
255 ag_features |= AG_CODEC_NEGOTIATION;
256
257 ag->slc_handle = hfp_slc_create(rfcomm_fd, 0, ag_features, device,
258 cras_hfp_ag_slc_initialized,
259 cras_hfp_ag_slc_disconnected);
260 DL_APPEND(connected_ags, ag);
261 return 0;
262 }
263
cras_hfp_ag_request_disconnection(struct cras_bt_profile * profile,struct cras_bt_device * device)264 static void cras_hfp_ag_request_disconnection(struct cras_bt_profile *profile,
265 struct cras_bt_device *device)
266 {
267 struct audio_gateway *ag;
268
269 BTLOG(btlog, BT_HFP_REQUEST_DISCONNECT, 0, 0);
270
271 DL_FOREACH (connected_ags, ag) {
272 if (ag->slc_handle && ag->device == device) {
273 destroy_audio_gateway(ag);
274 cras_bt_device_notify_profile_dropped(
275 ag->device,
276 CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
277 }
278 }
279 }
280
cras_hfp_ag_cancel(struct cras_bt_profile * profile)281 static void cras_hfp_ag_cancel(struct cras_bt_profile *profile)
282 {
283 }
284
285 static struct cras_bt_profile cras_hfp_ag_profile = {
286 .name = HFP_AG_PROFILE_NAME,
287 .object_path = HFP_AG_PROFILE_PATH,
288 .uuid = HFP_AG_UUID,
289 .version = HFP_VERSION_1_5,
290 .role = NULL,
291 .features = CRAS_AG_SUPPORTED_FEATURES & 0x1F,
292 .record = NULL,
293 .release = cras_hfp_ag_release,
294 .new_connection = cras_hfp_ag_new_connection,
295 .request_disconnection = cras_hfp_ag_request_disconnection,
296 .cancel = cras_hfp_ag_cancel
297 };
298
cras_hfp_ag_profile_create(DBusConnection * conn)299 int cras_hfp_ag_profile_create(DBusConnection *conn)
300 {
301 return cras_bt_add_profile(conn, &cras_hfp_ag_profile);
302 }
303
cras_hsp_ag_new_connection(DBusConnection * conn,struct cras_bt_profile * profile,struct cras_bt_device * device,int rfcomm_fd)304 static int cras_hsp_ag_new_connection(DBusConnection *conn,
305 struct cras_bt_profile *profile,
306 struct cras_bt_device *device,
307 int rfcomm_fd)
308 {
309 struct audio_gateway *ag;
310
311 BTLOG(btlog, BT_HSP_NEW_CONNECTION, 0, 0);
312
313 if (has_audio_gateway(device)) {
314 syslog(LOG_ERR,
315 "Audio gateway exists when %s connects for profile %s",
316 cras_bt_device_name(device), profile->name);
317 close(rfcomm_fd);
318 return 0;
319 }
320
321 if (check_for_conflict_ag(device))
322 return -1;
323
324 ag = (struct audio_gateway *)calloc(1, sizeof(*ag));
325 ag->device = device;
326 ag->conn = conn;
327 ag->profile = cras_bt_device_profile_from_uuid(profile->uuid);
328 ag->slc_handle = hfp_slc_create(rfcomm_fd, 1, profile->features, device,
329 NULL, cras_hfp_ag_slc_disconnected);
330 DL_APPEND(connected_ags, ag);
331 cras_hfp_ag_slc_initialized(ag->slc_handle);
332 return 0;
333 }
334
cras_hsp_ag_request_disconnection(struct cras_bt_profile * profile,struct cras_bt_device * device)335 static void cras_hsp_ag_request_disconnection(struct cras_bt_profile *profile,
336 struct cras_bt_device *device)
337 {
338 struct audio_gateway *ag;
339
340 BTLOG(btlog, BT_HSP_REQUEST_DISCONNECT, 0, 0);
341
342 DL_FOREACH (connected_ags, ag) {
343 if (ag->slc_handle && ag->device == device) {
344 destroy_audio_gateway(ag);
345 cras_bt_device_notify_profile_dropped(
346 ag->device, CRAS_BT_DEVICE_PROFILE_HSP_HEADSET);
347 }
348 }
349 }
350
351 static struct cras_bt_profile cras_hsp_ag_profile = {
352 .name = HSP_AG_PROFILE_NAME,
353 .object_path = HSP_AG_PROFILE_PATH,
354 .uuid = HSP_AG_UUID,
355 .version = HSP_VERSION_1_2,
356 .role = NULL,
357 .record = HSP_AG_RECORD,
358 .release = cras_hfp_ag_release,
359 .new_connection = cras_hsp_ag_new_connection,
360 .request_disconnection = cras_hsp_ag_request_disconnection,
361 .cancel = cras_hfp_ag_cancel
362 };
363
cras_hfp_ag_start(struct cras_bt_device * device)364 int cras_hfp_ag_start(struct cras_bt_device *device)
365 {
366 struct audio_gateway *ag;
367
368 BTLOG(btlog, BT_AUDIO_GATEWAY_START, 0, 0);
369
370 DL_SEARCH_SCALAR(connected_ags, ag, device, device);
371 if (ag == NULL)
372 return -EEXIST;
373
374 /*
375 * There is chance that bluetooth stack notifies us about remote
376 * device's capability incrementally in multiple events. That could
377 * cause hfp_ag_start be called more than once. Check if the input
378 * HFP iodev is already created so we don't re-create HFP resources.
379 */
380 if (ag->idev)
381 return 0;
382
383 if (need_go_sco_pcm(device)) {
384 struct cras_iodev *in_aio, *out_aio;
385
386 in_aio = cras_iodev_list_get_sco_pcm_iodev(CRAS_STREAM_INPUT);
387 out_aio = cras_iodev_list_get_sco_pcm_iodev(CRAS_STREAM_OUTPUT);
388
389 ag->idev = hfp_alsa_iodev_create(in_aio, ag->device,
390 ag->slc_handle, ag->profile);
391 ag->odev = hfp_alsa_iodev_create(out_aio, ag->device,
392 ag->slc_handle, ag->profile);
393 } else {
394 ag->info = hfp_info_create(
395 hfp_slc_get_selected_codec(ag->slc_handle));
396 ag->idev =
397 hfp_iodev_create(CRAS_STREAM_INPUT, ag->device,
398 ag->slc_handle, ag->profile, ag->info);
399 ag->odev =
400 hfp_iodev_create(CRAS_STREAM_OUTPUT, ag->device,
401 ag->slc_handle, ag->profile, ag->info);
402 }
403
404 if (!ag->idev && !ag->odev) {
405 destroy_audio_gateway(ag);
406 return -ENOMEM;
407 }
408
409 return 0;
410 }
411
cras_hfp_ag_suspend_connected_device(struct cras_bt_device * device)412 void cras_hfp_ag_suspend_connected_device(struct cras_bt_device *device)
413 {
414 struct audio_gateway *ag;
415
416 DL_SEARCH_SCALAR(connected_ags, ag, device, device);
417 if (ag)
418 destroy_audio_gateway(ag);
419 }
420
cras_hfp_ag_get_active_handle()421 struct hfp_slc_handle *cras_hfp_ag_get_active_handle()
422 {
423 /* Returns the first handle for HFP qualification. In future we
424 * might want this to return the HFP device user is selected. */
425 return connected_ags ? connected_ags->slc_handle : NULL;
426 }
427
cras_hfp_ag_get_slc(struct cras_bt_device * device)428 struct hfp_slc_handle *cras_hfp_ag_get_slc(struct cras_bt_device *device)
429 {
430 struct audio_gateway *ag;
431 DL_FOREACH (connected_ags, ag) {
432 if (ag->device == device)
433 return ag->slc_handle;
434 }
435 return NULL;
436 }
437
cras_hsp_ag_profile_create(DBusConnection * conn)438 int cras_hsp_ag_profile_create(DBusConnection *conn)
439 {
440 return cras_bt_add_profile(conn, &cras_hsp_ag_profile);
441 }
442