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_profile.h" 15 #include "cras_hfp_ag_profile.h" 16 #include "cras_hfp_info.h" 17 #include "cras_hfp_iodev.h" 18 #include "cras_hfp_slc.h" 19 #include "cras_system_state.h" 20 #include "utlist.h" 21 22 #define STR(s) #s 23 #define VSTR(id) STR(id) 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 32 #define HSP_AG_RECORD \ 33 "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" \ 34 "<record>" \ 35 " <attribute id=\"0x0001\">" \ 36 " <sequence>" \ 37 " <uuid value=\"" HSP_AG_UUID "\" />" \ 38 " <uuid value=\"" GENERIC_AUDIO_UUID "\" />" \ 39 " </sequence>" \ 40 " </attribute>" \ 41 " <attribute id=\"0x0004\">" \ 42 " <sequence>" \ 43 " <sequence>" \ 44 " <uuid value=\"0x0100\" />" \ 45 " </sequence>" \ 46 " <sequence>" \ 47 " <uuid value=\"0x0003\" />" \ 48 " <uint8 value=\"0x0c\" />" \ 49 " </sequence>" \ 50 " </sequence>" \ 51 " </attribute>" \ 52 " <attribute id=\"0x0005\">" \ 53 " <sequence>" \ 54 " <uuid value=\"0x1002\" />" \ 55 " </sequence>" \ 56 " </attribute>" \ 57 " <attribute id=\"0x0009\">" \ 58 " <sequence>" \ 59 " <sequence>" \ 60 " <uuid value=\"" HSP_HS_UUID "\" />" \ 61 " <uint16 value=\"" VSTR(HSP_VERSION_1_2) "\" />" \ 62 " </sequence>" \ 63 " </sequence>" \ 64 " </attribute>" \ 65 " <attribute id=\"0x0100\">" \ 66 " <text value=\"" HSP_AG_PROFILE_NAME "\" />" \ 67 " </attribute>" \ 68 " <attribute id=\"0x0301\" >" \ 69 " <uint8 value=\"0x01\" />" \ 70 " </attribute>" \ 71 "</record>" 72 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 100 static void destroy_audio_gateway(struct audio_gateway *ag) 101 { 102 DL_DELETE(connected_ags, ag); 103 104 if (ag->idev) 105 hfp_iodev_destroy(ag->idev); 106 if (ag->odev) 107 hfp_iodev_destroy(ag->odev); 108 if (ag->info) { 109 if (hfp_info_running(ag->info)) 110 hfp_info_stop(ag->info); 111 hfp_info_destroy(ag->info); 112 } 113 if (ag->slc_handle) 114 hfp_slc_destroy(ag->slc_handle); 115 116 /* If the bt device is not using a2dp, do a deeper clean up 117 * to force disconnect it. */ 118 if (!cras_bt_device_has_a2dp(ag->device)) 119 cras_bt_device_disconnect(ag->conn, ag->device); 120 121 free(ag); 122 } 123 124 /* Checks if there already a audio gateway connected for device. */ 125 static int has_audio_gateway(struct cras_bt_device *device) 126 { 127 struct audio_gateway *ag; 128 DL_FOREACH(connected_ags, ag) { 129 if (ag->device == device) 130 return 1; 131 } 132 return 0; 133 } 134 135 static void cras_hfp_ag_release(struct cras_bt_profile *profile) 136 { 137 cras_hfp_ag_suspend(); 138 } 139 140 /* Callback triggered when SLC is initialized. */ 141 static int cras_hfp_ag_slc_initialized(struct hfp_slc_handle *handle) 142 { 143 struct audio_gateway *ag; 144 145 DL_SEARCH_SCALAR(connected_ags, ag, slc_handle, handle); 146 if (!ag) 147 return -EINVAL; 148 149 /* Defer the starting of audio gateway to bt_device. */ 150 return cras_bt_device_audio_gateway_initialized(ag->device); 151 } 152 153 static int cras_hfp_ag_slc_disconnected(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 destroy_audio_gateway(ag); 162 return 0; 163 } 164 165 static int check_for_conflict_ag(struct cras_bt_device *new_connected) 166 { 167 struct audio_gateway *ag; 168 169 /* Check if there's already an A2DP/HFP device. */ 170 DL_FOREACH(connected_ags, ag) { 171 if (cras_bt_device_has_a2dp(ag->device)) 172 return -1; 173 } 174 175 /* Check if there's already an A2DP-only device. */ 176 if (cras_a2dp_connected_device() && 177 cras_bt_device_supports_profile( 178 new_connected, CRAS_BT_DEVICE_PROFILE_A2DP_SINK)) 179 return -1; 180 181 return 0; 182 } 183 184 static void possibly_remove_conflict_dev(void *data) 185 { 186 struct cras_bt_device *device = (struct cras_bt_device *)data; 187 struct audio_gateway *ag, *new_ag = NULL; 188 struct cras_bt_device *a2dp_device; 189 190 /* Check if the device is still connected. */ 191 DL_FOREACH(connected_ags, ag) { 192 if (ag->device == device) 193 new_ag = ag; 194 } 195 if (!new_ag) 196 return; 197 198 /* Kick out any previously connected hfp iodev. */ 199 DL_FOREACH(connected_ags, ag) { 200 if (ag == new_ag) 201 continue; 202 destroy_audio_gateway(ag); 203 } 204 205 /* Kick out any previously connected a2dp iodev. */ 206 a2dp_device = cras_a2dp_connected_device(); 207 if (a2dp_device && a2dp_device != device) { 208 cras_a2dp_suspend_connected_device(a2dp_device); 209 cras_bt_device_disconnect(new_ag->conn, a2dp_device); 210 } 211 } 212 213 static int cras_hfp_ag_new_connection(DBusConnection *conn, 214 struct cras_bt_profile *profile, 215 struct cras_bt_device *device, 216 int rfcomm_fd) 217 { 218 struct audio_gateway *ag; 219 220 if (has_audio_gateway(device)) { 221 syslog(LOG_ERR, "Audio gateway exists when %s connects for profile %s", 222 cras_bt_device_name(device), profile->name); 223 close(rfcomm_fd); 224 return 0; 225 } 226 227 if (check_for_conflict_ag(device)) 228 return -1; 229 230 cras_bt_device_set_append_iodev_cb(device, possibly_remove_conflict_dev); 231 ag = (struct audio_gateway *)calloc(1, sizeof(*ag)); 232 ag->device = device; 233 ag->conn = conn; 234 ag->profile = cras_bt_device_profile_from_uuid(profile->uuid); 235 ag->slc_handle = hfp_slc_create(rfcomm_fd, 236 0, 237 device, 238 cras_hfp_ag_slc_initialized, 239 cras_hfp_ag_slc_disconnected); 240 DL_APPEND(connected_ags, ag); 241 return 0; 242 } 243 244 static void cras_hfp_ag_request_disconnection(struct cras_bt_profile *profile, 245 struct cras_bt_device *device) 246 { 247 struct audio_gateway *ag; 248 DL_FOREACH(connected_ags, ag) { 249 if (ag->slc_handle && ag->device == device) 250 destroy_audio_gateway(ag); 251 } 252 } 253 254 static void cras_hfp_ag_cancel(struct cras_bt_profile *profile) 255 { 256 } 257 258 static struct cras_bt_profile cras_hfp_ag_profile = { 259 .name = HFP_AG_PROFILE_NAME, 260 .object_path = HFP_AG_PROFILE_PATH, 261 .uuid = HFP_AG_UUID, 262 .version = HFP_VERSION_1_5, 263 .role = NULL, 264 .features = HFP_SUPPORTED_FEATURE & 0x1F, 265 .record = NULL, 266 .release = cras_hfp_ag_release, 267 .new_connection = cras_hfp_ag_new_connection, 268 .request_disconnection = cras_hfp_ag_request_disconnection, 269 .cancel = cras_hfp_ag_cancel 270 }; 271 272 int cras_hfp_ag_profile_create(DBusConnection *conn) 273 { 274 return cras_bt_add_profile(conn, &cras_hfp_ag_profile); 275 } 276 277 static int cras_hsp_ag_new_connection(DBusConnection *conn, 278 struct cras_bt_profile *profile, 279 struct cras_bt_device *device, 280 int rfcomm_fd) 281 { 282 struct audio_gateway *ag; 283 284 if (has_audio_gateway(device)) { 285 syslog(LOG_ERR, "Audio gateway exists when %s connects for profile %s", 286 cras_bt_device_name(device), profile->name); 287 close(rfcomm_fd); 288 return 0; 289 } 290 291 if (check_for_conflict_ag(device)) 292 return -1; 293 294 cras_bt_device_set_append_iodev_cb(device, possibly_remove_conflict_dev); 295 ag = (struct audio_gateway *)calloc(1, sizeof(*ag)); 296 ag->device = device; 297 ag->conn = conn; 298 ag->profile = cras_bt_device_profile_from_uuid(profile->uuid); 299 ag->slc_handle = hfp_slc_create(rfcomm_fd, 1, device, NULL, 300 cras_hfp_ag_slc_disconnected); 301 DL_APPEND(connected_ags, ag); 302 cras_hfp_ag_slc_initialized(ag->slc_handle); 303 return 0; 304 } 305 306 static struct cras_bt_profile cras_hsp_ag_profile = { 307 .name = HSP_AG_PROFILE_NAME, 308 .object_path = HSP_AG_PROFILE_PATH, 309 .uuid = HSP_AG_UUID, 310 .version = HSP_VERSION_1_2, 311 .role = NULL, 312 .record = HSP_AG_RECORD, 313 .release = cras_hfp_ag_release, 314 .new_connection = cras_hsp_ag_new_connection, 315 .request_disconnection = cras_hfp_ag_request_disconnection, 316 .cancel = cras_hfp_ag_cancel 317 }; 318 319 int cras_hfp_ag_start(struct cras_bt_device *device) 320 { 321 struct audio_gateway *ag; 322 323 DL_SEARCH_SCALAR(connected_ags, ag, device, device); 324 if (ag == NULL) 325 return -EEXIST; 326 327 ag->info = hfp_info_create(); 328 ag->idev = hfp_iodev_create(CRAS_STREAM_INPUT, ag->device, 329 ag->slc_handle, 330 ag->profile, ag->info); 331 ag->odev = hfp_iodev_create(CRAS_STREAM_OUTPUT, ag->device, 332 ag->slc_handle, 333 ag->profile, ag->info); 334 335 if (!ag->idev && !ag->odev) { 336 destroy_audio_gateway(ag); 337 return -ENOMEM; 338 } 339 340 return 0; 341 } 342 343 void cras_hfp_ag_suspend() 344 { 345 struct audio_gateway *ag; 346 DL_FOREACH(connected_ags, ag) 347 destroy_audio_gateway(ag); 348 } 349 350 void cras_hfp_ag_suspend_connected_device(struct cras_bt_device *device) 351 { 352 struct audio_gateway *ag; 353 354 DL_SEARCH_SCALAR(connected_ags, ag, device, device); 355 if (ag) 356 destroy_audio_gateway(ag); 357 } 358 359 struct hfp_slc_handle *cras_hfp_ag_get_active_handle() 360 { 361 /* Returns the first handle for HFP qualification. In future we 362 * might want this to return the HFP device user is selected. */ 363 return connected_ags ? connected_ags->slc_handle : NULL; 364 } 365 366 struct hfp_slc_handle *cras_hfp_ag_get_slc(struct cras_bt_device *device) 367 { 368 struct audio_gateway *ag; 369 DL_FOREACH(connected_ags, ag) { 370 if (ag->device == device) 371 return ag->slc_handle; 372 } 373 return NULL; 374 } 375 376 int cras_hsp_ag_profile_create(DBusConnection *conn) 377 { 378 return cras_bt_add_profile(conn, &cras_hsp_ag_profile); 379 } 380