• 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 
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