Home | History | Annotate | Download | only in audio
      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 (at) holtmann.org>
      7  *  Copyright (C) 2008-2009  Leonid Movshovich <event.riga (at) 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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    601 gboolean gateway_is_connected(struct audio_device *dev)
    602 {
    603 	return (dev && dev->gateway &&
    604 			dev->gateway->state == GATEWAY_STATE_CONNECTED);
    605 }
    606 
    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 
    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 
    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.) */
    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 
    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 
    696 gboolean gateway_cancel_stream(struct audio_device *dev, unsigned int id)
    697 {
    698 	gateway_close(dev);
    699 	return TRUE;
    700 }
    701 
    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 
    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