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