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