Home | History | Annotate | Download | only in server
      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