• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2006-2010  Nokia Corporation
6  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
7  *  Copyright (C) 2008-2009  Leonid Movshovich <event.riga@gmail.org>
8  *  Copyright (C) 2010  ProFUSION embedded systems
9  *
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24  *
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 
37 #include <glib.h>
38 #include <dbus/dbus.h>
39 #include <gdbus.h>
40 
41 #include <bluetooth/bluetooth.h>
42 #include <bluetooth/hci.h>
43 #include <bluetooth/hci_lib.h>
44 #include <bluetooth/sco.h>
45 #include <bluetooth/sdp.h>
46 #include <bluetooth/sdp_lib.h>
47 
48 #include "glib-helper.h"
49 #include "device.h"
50 #include "gateway.h"
51 #include "log.h"
52 #include "error.h"
53 #include "btio.h"
54 #include "dbus-common.h"
55 
56 #ifndef DBUS_TYPE_UNIX_FD
57 #define DBUS_TYPE_UNIX_FD -1
58 #endif
59 
60 struct hf_agent {
61 	char *name;	/* Bus id */
62 	char *path;	/* D-Bus path */
63 	guint watch;	/* Disconnect watch */
64 };
65 
66 struct gateway {
67 	gateway_state_t state;
68 	GIOChannel *rfcomm;
69 	GIOChannel *sco;
70 	gateway_stream_cb_t sco_start_cb;
71 	void *sco_start_cb_data;
72 	struct hf_agent *agent;
73 	DBusMessage *msg;
74 };
75 
76 int gateway_close(struct audio_device *device);
77 
state2str(gateway_state_t state)78 static const char *state2str(gateway_state_t state)
79 {
80 	switch (state) {
81 	case GATEWAY_STATE_DISCONNECTED:
82 		return "disconnected";
83 	case GATEWAY_STATE_CONNECTING:
84 		return "connecting";
85 	case GATEWAY_STATE_CONNECTED:
86 		return "connected";
87 	case GATEWAY_STATE_PLAYING:
88 		return "playing";
89 	default:
90 		return "";
91 	}
92 }
93 
agent_free(struct hf_agent * agent)94 static void agent_free(struct hf_agent *agent)
95 {
96 	if (!agent)
97 		return;
98 
99 	g_free(agent->name);
100 	g_free(agent->path);
101 	g_free(agent);
102 }
103 
change_state(struct audio_device * dev,gateway_state_t new_state)104 static void change_state(struct audio_device *dev, gateway_state_t new_state)
105 {
106 	struct gateway *gw = dev->gateway;
107 	const char *val;
108 
109 	if (gw->state == new_state)
110 		return;
111 
112 	val = state2str(new_state);
113 	gw->state = new_state;
114 
115 	emit_property_changed(dev->conn, dev->path,
116 			AUDIO_GATEWAY_INTERFACE, "State",
117 			DBUS_TYPE_STRING, &val);
118 }
119 
agent_disconnect(struct audio_device * dev,struct hf_agent * agent)120 static void agent_disconnect(struct audio_device *dev, struct hf_agent *agent)
121 {
122 	DBusMessage *msg;
123 
124 	msg = dbus_message_new_method_call(agent->name, agent->path,
125 			"org.bluez.HandsfreeAgent", "Release");
126 
127 	g_dbus_send_message(dev->conn, msg);
128 }
129 
agent_sendfd(struct hf_agent * agent,int fd,DBusPendingCallNotifyFunction notify,void * data)130 static gboolean agent_sendfd(struct hf_agent *agent, int fd,
131 		DBusPendingCallNotifyFunction notify, void *data)
132 {
133 	struct audio_device *dev = data;
134 	DBusMessage *msg;
135 	DBusPendingCall *call;
136 
137 	msg = dbus_message_new_method_call(agent->name, agent->path,
138 			"org.bluez.HandsfreeAgent", "NewConnection");
139 
140 	dbus_message_append_args(msg, DBUS_TYPE_UNIX_FD, &fd,
141 					DBUS_TYPE_INVALID);
142 
143 	if (dbus_connection_send_with_reply(dev->conn, msg, &call, -1) == FALSE)
144 		return FALSE;
145 
146 	dbus_pending_call_set_notify(call, notify, dev, NULL);
147 	dbus_pending_call_unref(call);
148 
149 	return TRUE;
150 }
151 
sco_io_cb(GIOChannel * chan,GIOCondition cond,struct audio_device * dev)152 static gboolean sco_io_cb(GIOChannel *chan, GIOCondition cond,
153 			struct audio_device *dev)
154 {
155 	struct gateway *gw = dev->gateway;
156 
157 	if (cond & G_IO_NVAL)
158 		return FALSE;
159 
160 	if (cond & (G_IO_ERR | G_IO_HUP)) {
161 		DBG("sco connection is released");
162 		g_io_channel_shutdown(gw->sco, TRUE, NULL);
163 		g_io_channel_unref(gw->sco);
164 		gw->sco = NULL;
165 		change_state(dev, GATEWAY_STATE_CONNECTED);
166 		return FALSE;
167 	}
168 
169 	return TRUE;
170 }
171 
sco_connect_cb(GIOChannel * chan,GError * err,gpointer user_data)172 static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
173 {
174 	struct audio_device *dev = (struct audio_device *) user_data;
175 	struct gateway *gw = dev->gateway;
176 
177 	DBG("at the begin of sco_connect_cb() in gateway.c");
178 
179 	gw->sco = g_io_channel_ref(chan);
180 
181 	if (gw->sco_start_cb)
182 		gw->sco_start_cb(dev, err, gw->sco_start_cb_data);
183 
184 	if (err) {
185 		error("sco_connect_cb(): %s", err->message);
186 		gateway_close(dev);
187 		return;
188 	}
189 
190 	g_io_add_watch(gw->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
191 				(GIOFunc) sco_io_cb, dev);
192 }
193 
newconnection_reply(DBusPendingCall * call,void * data)194 static void newconnection_reply(DBusPendingCall *call, void *data)
195 {
196 	struct audio_device *dev = data;
197 	DBusMessage *reply = dbus_pending_call_steal_reply(call);
198 	DBusError derr;
199 
200 	if (!dev->gateway->rfcomm) {
201 		DBG("RFCOMM disconnected from server before agent reply");
202 		goto done;
203 	}
204 
205 	dbus_error_init(&derr);
206 	if (!dbus_set_error_from_message(&derr, reply)) {
207 		DBG("Agent reply: file descriptor passed successfully");
208 		change_state(dev, GATEWAY_STATE_CONNECTED);
209 		goto done;
210 	}
211 
212 	DBG("Agent reply: %s", derr.message);
213 
214 	dbus_error_free(&derr);
215 	gateway_close(dev);
216 
217 done:
218 	dbus_message_unref(reply);
219 }
220 
rfcomm_connect_cb(GIOChannel * chan,GError * err,gpointer user_data)221 static void rfcomm_connect_cb(GIOChannel *chan, GError *err,
222 				gpointer user_data)
223 {
224 	struct audio_device *dev = user_data;
225 	struct gateway *gw = dev->gateway;
226 	DBusMessage *reply;
227 	int sk, ret;
228 
229 	if (err) {
230 		error("connect(): %s", err->message);
231 		if (gw->sco_start_cb)
232 			gw->sco_start_cb(dev, err, gw->sco_start_cb_data);
233 		goto fail;
234 	}
235 
236 	if (!gw->agent) {
237 		error("Handsfree Agent not registered");
238 		goto fail;
239 	}
240 
241 	sk = g_io_channel_unix_get_fd(chan);
242 
243 	gw->rfcomm = g_io_channel_ref(chan);
244 
245 	ret = agent_sendfd(gw->agent, sk, newconnection_reply, dev);
246 
247 	if (!gw->msg)
248 		return;
249 
250 	if (ret)
251 		reply = dbus_message_new_method_return(gw->msg);
252 	else
253 		reply = g_dbus_create_error(gw->msg, ERROR_INTERFACE ".Failed",
254 					"Can not pass file descriptor");
255 
256 	g_dbus_send_message(dev->conn, reply);
257 
258 	return;
259 
260 fail:
261 	if (gw->msg)
262 		error_common_reply(dev->conn, gw->msg,
263 						ERROR_INTERFACE ".Failed",
264 						"Connection attempt failed");
265 
266 	change_state(dev, GATEWAY_STATE_DISCONNECTED);
267 }
268 
get_record_cb(sdp_list_t * recs,int err,gpointer user_data)269 static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
270 {
271 	struct audio_device *dev = user_data;
272 	struct gateway *gw = dev->gateway;
273 	int ch;
274 	sdp_list_t *protos, *classes;
275 	uuid_t uuid;
276 	GIOChannel *io;
277 	GError *gerr = NULL;
278 
279 	if (err < 0) {
280 		error("Unable to get service record: %s (%d)", strerror(-err),
281 					-err);
282 		goto fail;
283 	}
284 
285 	if (!recs || !recs->data) {
286 		error("No records found");
287 		err = -EIO;
288 		goto fail;
289 	}
290 
291 	if (sdp_get_service_classes(recs->data, &classes) < 0) {
292 		error("Unable to get service classes from record");
293 		err = -EINVAL;
294 		goto fail;
295 	}
296 
297 	if (sdp_get_access_protos(recs->data, &protos) < 0) {
298 		error("Unable to get access protocols from record");
299 		err = -ENODATA;
300 		goto fail;
301 	}
302 
303 	memcpy(&uuid, classes->data, sizeof(uuid));
304 	sdp_list_free(classes, free);
305 
306 	if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16 ||
307 			uuid.value.uuid16 != HANDSFREE_AGW_SVCLASS_ID) {
308 		sdp_list_free(protos, NULL);
309 		error("Invalid service record or not HFP");
310 		err = -EIO;
311 		goto fail;
312 	}
313 
314 	ch = sdp_get_proto_port(protos, RFCOMM_UUID);
315 	sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
316 	sdp_list_free(protos, NULL);
317 	if (ch <= 0) {
318 		error("Unable to extract RFCOMM channel from service record");
319 		err = -EIO;
320 		goto fail;
321 	}
322 
323 	io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, dev, NULL, &gerr,
324 				BT_IO_OPT_SOURCE_BDADDR, &dev->src,
325 				BT_IO_OPT_DEST_BDADDR, &dev->dst,
326 				BT_IO_OPT_CHANNEL, ch,
327 				BT_IO_OPT_INVALID);
328 	if (!io) {
329 		error("Unable to connect: %s", gerr->message);
330 		gateway_close(dev);
331 		goto fail;
332 	}
333 
334 	g_io_channel_unref(io);
335 
336 	change_state(dev, GATEWAY_STATE_CONNECTING);
337 	return;
338 
339 fail:
340 	if (gw->msg)
341 		error_common_reply(dev->conn, gw->msg,
342 					ERROR_INTERFACE ".NotSupported",
343 					"Not supported");
344 
345 	change_state(dev, GATEWAY_STATE_DISCONNECTED);
346 
347 	if (!gerr)
348 		g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED,
349 				"connect: %s (%d)", strerror(-err), -err);
350 
351 	if (gw->sco_start_cb)
352 		gw->sco_start_cb(dev, gerr, gw->sco_start_cb_data);
353 
354 	g_error_free(gerr);
355 }
356 
get_records(struct audio_device * device)357 static int get_records(struct audio_device *device)
358 {
359 	uuid_t uuid;
360 
361 	sdp_uuid16_create(&uuid, HANDSFREE_AGW_SVCLASS_ID);
362 	return bt_search_service(&device->src, &device->dst, &uuid,
363 				get_record_cb, device, NULL);
364 }
365 
ag_connect(DBusConnection * conn,DBusMessage * msg,void * data)366 static DBusMessage *ag_connect(DBusConnection *conn, DBusMessage *msg,
367 				void *data)
368 {
369 	struct audio_device *au_dev = (struct audio_device *) data;
370 	struct gateway *gw = au_dev->gateway;
371 
372 	if (!gw->agent)
373 		return g_dbus_create_error(msg, ERROR_INTERFACE
374 				".Failed", "Agent not assigned");
375 
376 	if (get_records(au_dev) < 0)
377 		return g_dbus_create_error(msg, ERROR_INTERFACE
378 					".ConnectAttemptFailed",
379 					"Connect Attempt Failed");
380 
381 	gw->msg = dbus_message_ref(msg);
382 
383 	return NULL;
384 }
385 
gateway_close(struct audio_device * device)386 int gateway_close(struct audio_device *device)
387 {
388 	struct gateway *gw = device->gateway;
389 	int sock;
390 
391 	if (gw->rfcomm) {
392 		sock = g_io_channel_unix_get_fd(gw->rfcomm);
393 		shutdown(sock, SHUT_RDWR);
394 
395 		g_io_channel_shutdown(gw->rfcomm, TRUE, NULL);
396 		g_io_channel_unref(gw->rfcomm);
397 		gw->rfcomm = NULL;
398 	}
399 
400 	if (gw->sco) {
401 		g_io_channel_shutdown(gw->sco, TRUE, NULL);
402 		g_io_channel_unref(gw->sco);
403 		gw->sco = NULL;
404 		gw->sco_start_cb = NULL;
405 		gw->sco_start_cb_data = NULL;
406 	}
407 
408 	change_state(device, GATEWAY_STATE_DISCONNECTED);
409 
410 	return 0;
411 }
412 
ag_disconnect(DBusConnection * conn,DBusMessage * msg,void * data)413 static DBusMessage *ag_disconnect(DBusConnection *conn, DBusMessage *msg,
414 					void *data)
415 {
416 	struct audio_device *device = data;
417 	struct gateway *gw = device->gateway;
418 	DBusMessage *reply = NULL;
419 	char gw_addr[18];
420 
421 	if (!device->conn)
422 		return NULL;
423 
424 	reply = dbus_message_new_method_return(msg);
425 	if (!reply)
426 		return NULL;
427 
428 	if (!gw->rfcomm)
429 		return g_dbus_create_error(msg, ERROR_INTERFACE
430 						".NotConnected",
431 						"Device not Connected");
432 
433 	gateway_close(device);
434 	ba2str(&device->dst, gw_addr);
435 	DBG("Disconnected from %s, %s", gw_addr, device->path);
436 
437 	return reply;
438 }
439 
agent_exited(DBusConnection * conn,void * data)440 static void agent_exited(DBusConnection *conn, void *data)
441 {
442 	struct gateway *gateway = data;
443 	struct hf_agent *agent = gateway->agent;
444 
445 	DBG("Agent %s exited", agent->name);
446 
447 	agent_free(agent);
448 	gateway->agent = NULL;
449 }
450 
ag_get_properties(DBusConnection * conn,DBusMessage * msg,void * data)451 static DBusMessage *ag_get_properties(DBusConnection *conn, DBusMessage *msg,
452 					void *data)
453 {
454 	struct audio_device *device = data;
455 	struct gateway *gw = device->gateway;
456 	DBusMessage *reply;
457 	DBusMessageIter iter;
458 	DBusMessageIter dict;
459 	const char *value;
460 
461 
462 	reply = dbus_message_new_method_return(msg);
463 	if (!reply)
464 		return NULL;
465 
466 	dbus_message_iter_init_append(reply, &iter);
467 
468 	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
469 			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
470 			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
471 			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
472 
473 	value = state2str(gw->state);
474 	dict_append_entry(&dict, "State",
475 			DBUS_TYPE_STRING, &value);
476 
477 	dbus_message_iter_close_container(&iter, &dict);
478 
479 	return reply;
480 }
481 
register_agent(DBusConnection * conn,DBusMessage * msg,void * data)482 static DBusMessage *register_agent(DBusConnection *conn,
483 					DBusMessage *msg, void *data)
484 {
485 	struct audio_device *device = data;
486 	struct gateway *gw = device->gateway;
487 	struct hf_agent *agent;
488 	const char *path, *name;
489 
490 	if (gw->agent)
491 		return g_dbus_create_error(msg,
492 					ERROR_INTERFACE ".AlreadyExists",
493 					"Agent already exists");
494 
495 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
496 						DBUS_TYPE_INVALID))
497 		return g_dbus_create_error(msg,
498 					ERROR_INTERFACE ".InvalidArguments",
499 					"Invalid argument");
500 
501 	name = dbus_message_get_sender(msg);
502 	agent = g_new0(struct hf_agent, 1);
503 
504 	agent->name = g_strdup(name);
505 	agent->path = g_strdup(path);
506 
507 	agent->watch = g_dbus_add_disconnect_watch(conn, name,
508 						agent_exited, gw, NULL);
509 
510 	gw->agent = agent;
511 
512 	return dbus_message_new_method_return(msg);
513 }
514 
unregister_agent(DBusConnection * conn,DBusMessage * msg,void * data)515 static DBusMessage *unregister_agent(DBusConnection *conn,
516 				DBusMessage *msg, void *data)
517 {
518 	struct audio_device *device = data;
519 	struct gateway *gw = device->gateway;
520 	const char *path;
521 
522 	if (!gw->agent)
523 		goto done;
524 
525 	if (strcmp(gw->agent->name, dbus_message_get_sender(msg)) != 0)
526 		return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
527 							"Permission denied");
528 
529 	if (!dbus_message_get_args(msg, NULL,
530 				DBUS_TYPE_OBJECT_PATH, &path,
531 				DBUS_TYPE_INVALID))
532 		return g_dbus_create_error(msg,
533 				ERROR_INTERFACE ".InvalidArguments",
534 				"Invalid argument");
535 
536 	if (strcmp(gw->agent->path, path) != 0)
537 		return g_dbus_create_error(msg,
538 				ERROR_INTERFACE ".Failed",
539 				"Unknown object path");
540 
541 	g_dbus_remove_watch(device->conn, gw->agent->watch);
542 
543 	agent_free(gw->agent);
544 	gw->agent = NULL;
545 
546 done:
547 	return dbus_message_new_method_return(msg);
548 }
549 
550 static GDBusMethodTable gateway_methods[] = {
551 	{ "Connect", "", "", ag_connect, G_DBUS_METHOD_FLAG_ASYNC },
552 	{ "Disconnect", "", "", ag_disconnect, G_DBUS_METHOD_FLAG_ASYNC },
553 	{ "GetProperties", "", "a{sv}", ag_get_properties },
554 	{ "RegisterAgent", "o", "", register_agent },
555 	{ "UnregisterAgent", "o", "", unregister_agent },
556 	{ NULL, NULL, NULL, NULL }
557 };
558 
559 static GDBusSignalTable gateway_signals[] = {
560 	{ "PropertyChanged", "sv" },
561 	{ NULL, NULL }
562 };
563 
path_unregister(void * data)564 static void path_unregister(void *data)
565 {
566 	struct audio_device *dev = data;
567 
568 	DBG("Unregistered interface %s on path %s",
569 		AUDIO_GATEWAY_INTERFACE, dev->path);
570 
571 	gateway_close(dev);
572 
573 	g_free(dev->gateway);
574 	dev->gateway = NULL;
575 }
576 
gateway_unregister(struct audio_device * dev)577 void gateway_unregister(struct audio_device *dev)
578 {
579 	if (dev->gateway->agent)
580 		agent_disconnect(dev, dev->gateway->agent);
581 
582 	g_dbus_unregister_interface(dev->conn, dev->path,
583 						AUDIO_GATEWAY_INTERFACE);
584 }
585 
gateway_init(struct audio_device * dev)586 struct gateway *gateway_init(struct audio_device *dev)
587 {
588 	if (DBUS_TYPE_UNIX_FD < 0)
589 		return NULL;
590 
591 	if (!g_dbus_register_interface(dev->conn, dev->path,
592 					AUDIO_GATEWAY_INTERFACE,
593 					gateway_methods, gateway_signals,
594 					NULL, dev, path_unregister))
595 		return NULL;
596 
597 	return g_new0(struct gateway, 1);
598 
599 }
600 
gateway_is_connected(struct audio_device * dev)601 gboolean gateway_is_connected(struct audio_device *dev)
602 {
603 	return (dev && dev->gateway &&
604 			dev->gateway->state == GATEWAY_STATE_CONNECTED);
605 }
606 
gateway_connect_rfcomm(struct audio_device * dev,GIOChannel * io)607 int gateway_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
608 {
609 	if (!io)
610 		return -EINVAL;
611 
612 	dev->gateway->rfcomm = g_io_channel_ref(io);
613 
614 	return 0;
615 }
616 
gateway_connect_sco(struct audio_device * dev,GIOChannel * io)617 int gateway_connect_sco(struct audio_device *dev, GIOChannel *io)
618 {
619 	struct gateway *gw = dev->gateway;
620 
621 	if (gw->sco)
622 		return -EISCONN;
623 
624 	gw->sco = g_io_channel_ref(io);
625 
626 	g_io_add_watch(gw->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
627 						(GIOFunc) sco_io_cb, dev);
628 
629 	change_state(dev, GATEWAY_STATE_PLAYING);
630 
631 	return 0;
632 }
633 
gateway_start_service(struct audio_device * dev)634 void gateway_start_service(struct audio_device *dev)
635 {
636 	struct gateway *gw = dev->gateway;
637 	GError *err = NULL;
638 
639 	if (gw->rfcomm == NULL)
640 		return;
641 
642 	if (!bt_io_accept(gw->rfcomm, rfcomm_connect_cb, dev, NULL, &err)) {
643 		error("bt_io_accept: %s", err->message);
644 		g_error_free(err);
645 	}
646 }
647 
648 /* These are functions to be called from unix.c for audio system
649  * ifaces (alsa, gstreamer, etc.) */
gateway_request_stream(struct audio_device * dev,gateway_stream_cb_t cb,void * user_data)650 gboolean gateway_request_stream(struct audio_device *dev,
651 				gateway_stream_cb_t cb, void *user_data)
652 {
653 	struct gateway *gw = dev->gateway;
654 	GError *err = NULL;
655 	GIOChannel *io;
656 
657 	if (!gw->rfcomm) {
658 		gw->sco_start_cb = cb;
659 		gw->sco_start_cb_data = user_data;
660 		get_records(dev);
661 	} else if (!gw->sco) {
662 		gw->sco_start_cb = cb;
663 		gw->sco_start_cb_data = user_data;
664 		io = bt_io_connect(BT_IO_SCO, sco_connect_cb, dev, NULL, &err,
665 				BT_IO_OPT_SOURCE_BDADDR, &dev->src,
666 				BT_IO_OPT_DEST_BDADDR, &dev->dst,
667 				BT_IO_OPT_INVALID);
668 		if (!io) {
669 			error("%s", err->message);
670 			g_error_free(err);
671 			return FALSE;
672 		}
673 	} else if (cb)
674 		cb(dev, err, user_data);
675 
676 	return TRUE;
677 }
678 
gateway_config_stream(struct audio_device * dev,gateway_stream_cb_t sco_cb,void * user_data)679 int gateway_config_stream(struct audio_device *dev, gateway_stream_cb_t sco_cb,
680 				void *user_data)
681 {
682 	struct gateway *gw = dev->gateway;
683 
684 	if (!gw->rfcomm) {
685 		gw->sco_start_cb = sco_cb;
686 		gw->sco_start_cb_data = user_data;
687 		return get_records(dev);
688 	}
689 
690 	if (sco_cb)
691 		sco_cb(dev, NULL, user_data);
692 
693 	return 0;
694 }
695 
gateway_cancel_stream(struct audio_device * dev,unsigned int id)696 gboolean gateway_cancel_stream(struct audio_device *dev, unsigned int id)
697 {
698 	gateway_close(dev);
699 	return TRUE;
700 }
701 
gateway_get_sco_fd(struct audio_device * dev)702 int gateway_get_sco_fd(struct audio_device *dev)
703 {
704 	struct gateway *gw = dev->gateway;
705 
706 	if (!gw || !gw->sco)
707 		return -1;
708 
709 	return g_io_channel_unix_get_fd(gw->sco);
710 }
711 
gateway_suspend_stream(struct audio_device * dev)712 void gateway_suspend_stream(struct audio_device *dev)
713 {
714 	struct gateway *gw = dev->gateway;
715 
716 	if (!gw || !gw->sco)
717 		return;
718 
719 	g_io_channel_shutdown(gw->sco, TRUE, NULL);
720 	g_io_channel_unref(gw->sco);
721 	gw->sco = NULL;
722 	gw->sco_start_cb = NULL;
723 	gw->sco_start_cb_data = NULL;
724 }
725