• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2006-2007  Nokia Corporation
6  *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
7  *  Copyright (C) 2008-2009  Leonid Movshovich <event.riga@gmail.org>
8  *
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23  *
24  */
25 
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29 
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 
36 #include <glib.h>
37 #include <dbus/dbus.h>
38 #include <gdbus.h>
39 
40 #include <bluetooth/bluetooth.h>
41 #include <bluetooth/hci.h>
42 #include <bluetooth/hci_lib.h>
43 #include <bluetooth/sco.h>
44 #include <bluetooth/sdp.h>
45 #include <bluetooth/sdp_lib.h>
46 
47 #include "glib-helper.h"
48 #include "device.h"
49 #include "gateway.h"
50 #include "logging.h"
51 #include "error.h"
52 #include "btio.h"
53 #include "dbus-common.h"
54 
55 #define RFCOMM_BUF_SIZE 256
56 /* not-more-then-16 defined by GSM + 1 for NULL + padding */
57 #define AG_INDICATOR_DESCR_SIZE 20
58 #define AG_CALLER_NUM_SIZE 64	/* size of number + type */
59 
60 /* commands */
61 #define AG_FEATURES "AT+BRSF=26\r"     /* = 0x7F = All features supported */
62 #define AG_INDICATORS_SUPP "AT+CIND=?\r"
63 #define AG_INDICATORS_VAL "AT+CIND?\r"
64 #define AG_INDICATORS_ENABLE "AT+CMER=3,0,0,1\r"
65 #define AG_HOLD_MPTY_SUPP "AT+CHLD=?\r"
66 #define AG_CALLER_IDENT_ENABLE "AT+CLIP=1\r"
67 #define AG_CARRIER_FORMAT "AT+COPS=3,0\r"
68 #define AG_EXTENDED_RESULT_CODE "AT+CMEE=1\r"
69 
70 #define AG_FEATURE_3WAY 0x1
71 #define AG_FEATURE_EXTENDED_RES_CODE 0x100
72 /* Hold and multipary AG features.
73  * Comments below are copied from hands-free spec for reference */
74 /* Releases all held calls or sets User Determined User Busy (UDUB)
75  * for a waiting call */
76 #define AG_CHLD_0 0x01
77 /* Releases all active calls (if any exist) and accepts the other
78  * (held or waiting) call */
79 #define AG_CHLD_1 0x02
80 /* Releases specified active call only <x> */
81 #define AG_CHLD_1x 0x04
82 /* Places all active calls (if any exist) on hold and accepts the other
83  * (held or waiting) call */
84 #define AG_CHLD_2 0x08
85 /* Request private consultation mode with specified call <x> (Place all
86  * calls on hold EXCEPT the call <x>) */
87 #define AG_CHLD_2x 0x10
88 /* Adds a held call to the conversation */
89 #define AG_CHLD_3 0x20
90 /* Connects the two calls and disconnects the subscriber from both calls
91  * (Explicit Call Transfer). Support for this value and its associated
92  * functionality is optional for the HF. */
93 #define AG_CHLD_4 0x40
94 
95 #define OK_RESPONSE "\r\nOK\r\n"
96 #define ERROR_RESPONSE "\r\nERROR\r\n"
97 
98 struct indicator {
99 	gchar descr[AG_INDICATOR_DESCR_SIZE];
100 	gint value;
101 };
102 
103 struct gateway {
104 	gateway_state_t state;
105 	GIOChannel *rfcomm;
106 	guint rfcomm_watch_id;
107 	GIOChannel *sco;
108 	gateway_stream_cb_t sco_start_cb;
109 	void *sco_start_cb_data;
110 	DBusMessage *connect_message;
111 	guint ag_features;
112 	guint hold_multiparty_features;
113 	GSList *indies;
114 	gboolean is_dialing;
115 	gboolean call_active;
116 
117 	int sp_gain;
118 	int mic_gain;
119 };
120 
121 static gboolean rfcomm_ag_data_cb(GIOChannel *chan, GIOCondition cond,
122 					struct audio_device *device);
123 
124 int gateway_close(struct audio_device *device);
125 
rfcomm_start_watch(struct audio_device * dev)126 static void rfcomm_start_watch(struct audio_device *dev)
127 {
128 	struct gateway *gw = dev->gateway;
129 
130 	gw->rfcomm_watch_id = g_io_add_watch(gw->rfcomm,
131 			G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
132 			(GIOFunc) rfcomm_ag_data_cb, dev);
133 }
134 
rfcomm_stop_watch(struct audio_device * dev)135 static void rfcomm_stop_watch(struct audio_device *dev)
136 {
137 	struct gateway *gw = dev->gateway;
138 
139 	g_source_remove(gw->rfcomm_watch_id);
140 }
141 
io_channel_write_all(GIOChannel * io,gchar * data,gsize count)142 static gboolean io_channel_write_all(GIOChannel *io, gchar *data,
143 					gsize count)
144 {
145 	gsize written = 0;
146 	GIOStatus status;
147 
148 	while (count > 0) {
149 		status = g_io_channel_write_chars(io, data, count, &written,
150 						NULL);
151 		if (status != G_IO_STATUS_NORMAL)
152 			return FALSE;
153 
154 		data += written;
155 		count -= written;
156 	}
157 	return TRUE;
158 }
159 
160 /* it's worth to mention that data and response could be the same pointers */
rfcomm_send_and_read(struct gateway * gw,gchar * data,gchar * response,gsize count)161 static gboolean rfcomm_send_and_read(struct gateway *gw, gchar *data,
162                                     gchar *response, gsize count)
163 {
164 	GIOChannel *rfcomm = gw->rfcomm;
165 	gsize read = 0;
166 	gboolean got_ok = FALSE;
167 	gboolean got_error = FALSE;
168 	gchar *resp_buf = response;
169 	gsize toread = RFCOMM_BUF_SIZE - 1;
170 	GIOStatus status;
171 
172 	if (!io_channel_write_all(rfcomm, data, count))
173 		return FALSE;
174 
175 	while (!(got_ok || got_error)) {
176 		status = g_io_channel_read_chars(rfcomm, resp_buf, toread,
177 						&read, NULL);
178 		if (status == G_IO_STATUS_NORMAL)
179 			resp_buf[read] = '\0';
180 		else {
181 			debug("rfcomm_send_and_read(): %m");
182 			return FALSE;
183 		}
184 		got_ok = NULL != strstr(resp_buf, OK_RESPONSE);
185 		got_error = NULL != strstr(resp_buf, ERROR_RESPONSE);
186 		resp_buf += read;
187 		toread -= read;
188 	}
189 	return TRUE;
190 }
191 
192 /* get <descr> from the names: (<descr>, (<values>)), (<descr>, (<values>))
193  * ... */
parse_indicator_names(gchar * names,GSList * indies)194 static GSList *parse_indicator_names(gchar *names, GSList *indies)
195 {
196 	gchar *current = names - 1;
197 	GSList *result = indies;
198 	gchar *next;
199 	struct indicator *ind;
200 
201 	while (current != NULL) {
202 		current += 2;
203 		next = strstr(current, ",(");
204 		ind = g_slice_new(struct indicator);
205 		strncpy(ind->descr, current, 20);
206 		ind->descr[(intptr_t) next - (intptr_t) current] = '\0';
207 		result = g_slist_append(result, (gpointer) ind);
208 		current = strstr(next + 1, ",(");
209 	}
210 	return result;
211 }
212 
213 /* get values from <val0>,<val1>,... */
parse_indicator_values(gchar * values,GSList * indies)214 static GSList *parse_indicator_values(gchar *values, GSList *indies)
215 {
216 	gint val;
217 	gchar *current = values - 1;
218 	GSList *runner = indies;
219 	struct indicator *ind;
220 
221 	while (current != NULL) {
222 		current += 1;
223 		sscanf(current, "%d", &val);
224 		current = strchr(current, ',');
225 		ind = g_slist_nth_data(runner, 0);
226 		ind->value = val;
227 		runner = g_slist_next(runner);
228 	}
229 	return indies;
230 }
231 
232 /* get values from <val0>,<val1>,... */
get_hold_mpty_features(gchar * features)233 static guint get_hold_mpty_features(gchar *features)
234 {
235 	guint result = 0;
236 
237 	if (strstr(features, "0"))
238 		result |= AG_CHLD_0;
239 
240 	if (strstr(features, "1"))
241 		result |= AG_CHLD_1;
242 
243 	if (strstr(features, "1x"))
244 		result |= AG_CHLD_1x;
245 
246 	if (strstr(features, "2"))
247 		result |= AG_CHLD_2;
248 
249 	if (strstr(features, "2x"))
250 		result |= AG_CHLD_2x;
251 
252 	if (strstr(features, "3"))
253 		result |= AG_CHLD_3;
254 
255 	if (strstr(features, "4"))
256 		result |= AG_CHLD_4;
257 
258 	return result;
259 }
260 
establish_service_level_conn(struct gateway * gw)261 static gboolean establish_service_level_conn(struct gateway *gw)
262 {
263 	gchar buf[RFCOMM_BUF_SIZE];
264 	gboolean res;
265 
266 	debug("at the begin of establish_service_level_conn()");
267 	res = rfcomm_send_and_read(gw, AG_FEATURES, buf,
268 				sizeof(AG_FEATURES) - 1);
269 	if (!res || sscanf(buf, "\r\n+BRSF:%d", &gw->ag_features) != 1)
270 		return FALSE;
271 
272 	debug("features are 0x%X", gw->ag_features);
273 	res = rfcomm_send_and_read(gw, AG_INDICATORS_SUPP, buf,
274 				sizeof(AG_INDICATORS_SUPP) - 1);
275 	if (!res || !strstr(buf, "+CIND:"))
276 		return FALSE;
277 
278 	gw->indies = parse_indicator_names(strchr(buf, '('), NULL);
279 
280 	res = rfcomm_send_and_read(gw, AG_INDICATORS_VAL, buf,
281 		sizeof(AG_INDICATORS_VAL) - 1);
282 	if (!res || !strstr(buf, "+CIND:"))
283 		return FALSE;
284 
285 	gw->indies = parse_indicator_values(strchr(buf, ':') + 1, gw->indies);
286 
287 	res = rfcomm_send_and_read(gw, AG_INDICATORS_ENABLE, buf,
288 				sizeof(AG_INDICATORS_ENABLE) - 1);
289 	if (!res || !strstr(buf, "OK"))
290 		return FALSE;
291 
292 	if ((gw->ag_features & AG_FEATURE_3WAY) != 0) {
293 		res = rfcomm_send_and_read(gw, AG_HOLD_MPTY_SUPP, buf,
294 				sizeof(AG_HOLD_MPTY_SUPP) - 1);
295 		if (!res || !strstr(buf, "+CHLD:")) {
296 			g_slice_free1(RFCOMM_BUF_SIZE, buf);
297 			return FALSE;
298 		}
299 		gw->hold_multiparty_features = get_hold_mpty_features(
300 							strchr(buf, '('));
301 
302 	} else
303 		gw->hold_multiparty_features = 0;
304 
305 	debug("Service layer connection successfully established!");
306 	rfcomm_send_and_read(gw, AG_CALLER_IDENT_ENABLE, buf,
307 			sizeof(AG_CALLER_IDENT_ENABLE) - 1);
308 	rfcomm_send_and_read(gw, AG_CARRIER_FORMAT, buf,
309 			sizeof(AG_CARRIER_FORMAT) - 1);
310 	if ((gw->ag_features & AG_FEATURE_EXTENDED_RES_CODE) != 0)
311 		rfcomm_send_and_read(gw, AG_EXTENDED_RESULT_CODE, buf,
312 			sizeof(AG_EXTENDED_RESULT_CODE) - 1);
313 
314 	return TRUE;
315 }
316 
process_ind_change(struct audio_device * dev,guint index,gint value)317 static void process_ind_change(struct audio_device *dev, guint index,
318 							gint value)
319 {
320 	struct gateway *gw = dev->gateway;
321 	struct indicator *ind = g_slist_nth_data(gw->indies, index - 1);
322 	gchar *name = ind->descr;
323 
324 	ind->value = value;
325 
326 	debug("at the begin of process_ind_change, name is %s", name);
327 	if (!strcmp(name, "\"call\"")) {
328 		if (value > 0) {
329 			g_dbus_emit_signal(dev->conn, dev->path,
330 					AUDIO_GATEWAY_INTERFACE,
331 					"CallStarted", DBUS_TYPE_INVALID);
332 			gw->is_dialing = FALSE;
333 			gw->call_active = TRUE;
334 		} else {
335 			g_dbus_emit_signal(dev->conn, dev->path,
336 					AUDIO_GATEWAY_INTERFACE,
337 					"CallEnded", DBUS_TYPE_INVALID);
338 			gw->call_active = FALSE;
339 		}
340 
341 	} else if (!strcmp(name, "\"callsetup\"")) {
342 		if (value == 0 && gw->is_dialing) {
343 			g_dbus_emit_signal(dev->conn, dev->path,
344 					AUDIO_GATEWAY_INTERFACE,
345 					"CallTerminated",
346 					DBUS_TYPE_INVALID);
347 			gw->is_dialing = FALSE;
348 		} else if (!gw->is_dialing && value > 0)
349 			gw->is_dialing = TRUE;
350 
351 	} else if (!strcmp(name, "\"callheld\"")) {
352 		/* FIXME: The following code is based on assumptions only.
353 		 * Has to be tested for interoperability
354 		 * I assume that callheld=2 would be sent when dial from HF
355 		 * failed in case of 3-way call
356 		 * Unfortunately this path is not covered by the HF spec so
357 		 * the code has to be tested for interop
358 		*/
359 		/* '2' means: all calls held, no active calls */
360 		if (value == 2) {
361 			if (gw->is_dialing) {
362 				g_dbus_emit_signal(dev->conn, dev->path,
363 					AUDIO_GATEWAY_INTERFACE,
364 					"CallTerminated",
365 					DBUS_TYPE_INVALID);
366 				gw->is_dialing = FALSE;
367 			}
368 		}
369 	} else if (!strcmp(name, "\"service\""))
370 		emit_property_changed(dev->conn, dev->path,
371 				AUDIO_GATEWAY_INTERFACE, "RegistrationStatus",
372 				DBUS_TYPE_UINT16, &value);
373 	else if (!strcmp(name, "\"signal\""))
374 		emit_property_changed(dev->conn, dev->path,
375 				AUDIO_GATEWAY_INTERFACE, "SignalStrength",
376 				DBUS_TYPE_UINT16, &value);
377 	else if (!strcmp(name, "\"roam\""))
378 		emit_property_changed(dev->conn, dev->path,
379 				AUDIO_GATEWAY_INTERFACE, "RoamingStatus",
380 				DBUS_TYPE_UINT16, &value);
381 	else if (!strcmp(name, "\"battchg\""))
382 		emit_property_changed(dev->conn, dev->path,
383 				AUDIO_GATEWAY_INTERFACE, "BatteryCharge",
384 				DBUS_TYPE_UINT16, &value);
385 }
386 
process_ring(struct audio_device * device,GIOChannel * chan,gchar * buf)387 static void process_ring(struct audio_device *device, GIOChannel *chan,
388 			gchar *buf)
389 {
390 	gchar number[AG_CALLER_NUM_SIZE];
391 	gchar *cli;
392 	gchar *sep;
393 	gsize read;
394 	GIOStatus status;
395 
396 	rfcomm_stop_watch(device);
397 	status = g_io_channel_read_chars(chan, buf, RFCOMM_BUF_SIZE - 1, &read, NULL);
398 	if (status != G_IO_STATUS_NORMAL)
399 		return;
400 
401 	debug("at the begin of process_ring");
402 	if (strlen(buf) > AG_CALLER_NUM_SIZE + 10)
403 		error("process_ring(): buf is too long '%s'", buf);
404 	else if ((cli = strstr(buf, "\r\n+CLIP"))) {
405 		if (sscanf(cli, "\r\n+CLIP: \"%s", number) == 1) {
406 			sep = strchr(number, '"');
407 			sep[0] = '\0';
408 
409 			/* FIXME:signal will be emitted on each RING+CLIP.
410 			 * That's bad */
411 			cli = number;
412 			g_dbus_emit_signal(device->conn, device->path,
413 					AUDIO_GATEWAY_INTERFACE, "Ring",
414 					DBUS_TYPE_STRING, &cli,
415 					DBUS_TYPE_INVALID);
416 			device->gateway->is_dialing = TRUE;
417 		} else
418 			error("process_ring(): '%s' in place of +CLIP after RING", buf);
419 
420 	}
421 
422 	rfcomm_start_watch(device);
423 }
424 
rfcomm_ag_data_cb(GIOChannel * chan,GIOCondition cond,struct audio_device * device)425 static gboolean rfcomm_ag_data_cb(GIOChannel *chan, GIOCondition cond,
426 					struct audio_device *device)
427 {
428 	gchar buf[RFCOMM_BUF_SIZE];
429 	struct gateway *gw;
430 	gsize read;
431 	/* some space for value */
432 	gchar indicator[AG_INDICATOR_DESCR_SIZE + 4];
433 	gint value;
434 	guint index;
435 	gchar *sep;
436 
437 	debug("at the begin of rfcomm_ag_data_cb()");
438 	if (cond & G_IO_NVAL)
439 		return FALSE;
440 
441 	gw = device->gateway;
442 
443 	if (cond & (G_IO_ERR | G_IO_HUP)) {
444 		debug("connection with remote BT is closed");
445 		gateway_close(device);
446 		return FALSE;
447 	}
448 
449 	if (g_io_channel_read_chars(chan, buf, sizeof(buf) - 1, &read, NULL)
450 			!= G_IO_STATUS_NORMAL)
451 		return TRUE;
452 	buf[read] = '\0';
453 
454 	if (strlen(buf) > AG_INDICATOR_DESCR_SIZE + 14)
455 		error("rfcomm_ag_data_cb(): buf is too long '%s'", buf);
456 	else if (sscanf(buf, "\r\n+CIEV:%s\r\n", indicator) == 1) {
457 		sep = strchr(indicator, ',');
458 		sep[0] = '\0';
459 		sep += 1;
460 		index = atoi(indicator);
461 		value = atoi(sep);
462 		process_ind_change(device, index, value);
463 	} else if (strstr(buf, "RING"))
464 		process_ring(device, chan, buf);
465 	else if (sscanf(buf, "\r\n+BVRA:%d\r\n", &value) == 1) {
466 		if (value == 0)
467 			g_dbus_emit_signal(device->conn, device->path,
468 					AUDIO_GATEWAY_INTERFACE,
469 					"VoiceRecognitionActive",
470 					DBUS_TYPE_INVALID);
471 		else
472 			g_dbus_emit_signal(device->conn, device->path,
473 					AUDIO_GATEWAY_INTERFACE,
474 					"VoiceRecognitionInactive",
475 					DBUS_TYPE_INVALID);
476 	} else if (sscanf(buf, "\r\n+VGS:%d\r\n", &value) == 1) {
477 		gw->sp_gain = value;
478 		emit_property_changed(device->conn, device->path,
479 				AUDIO_GATEWAY_INTERFACE, "SpeakerGain",
480 				DBUS_TYPE_UINT16, &value);
481 	} else if (sscanf(buf, "\r\n+VGM:%d\r\n", &value) == 1) {
482 		gw->mic_gain = value;
483 		emit_property_changed(device->conn, device->path,
484 				AUDIO_GATEWAY_INTERFACE, "MicrophoneGain",
485 				DBUS_TYPE_UINT16, &value);
486 	} else
487 		error("rfcomm_ag_data_cb(): read wrong data '%s'", buf);
488 
489 	return TRUE;
490 }
491 
sco_io_cb(GIOChannel * chan,GIOCondition cond,struct audio_device * dev)492 static gboolean sco_io_cb(GIOChannel *chan, GIOCondition cond,
493 			struct audio_device *dev)
494 {
495 	struct gateway *gw = dev->gateway;
496 
497 	if (cond & G_IO_NVAL)
498 		return FALSE;
499 
500 	if (cond & (G_IO_ERR | G_IO_HUP)) {
501 		debug("sco connection is released");
502 		g_io_channel_shutdown(gw->sco, TRUE, NULL);
503 		g_io_channel_unref(gw->sco);
504 		gw->sco = NULL;
505 		return FALSE;
506 	}
507 
508 	return TRUE;
509 }
510 
sco_connect_cb(GIOChannel * chan,GError * err,gpointer user_data)511 static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
512 {
513 	struct audio_device *dev = (struct audio_device *) user_data;
514 	struct gateway *gw = dev->gateway;
515 
516 	debug("at the begin of sco_connect_cb() in gateway.c");
517 
518 	if (err) {
519 		error("sco_connect_cb(): %s", err->message);
520 		/* not sure, but from other point of view,
521 		 * what is the reason to have headset which
522 		 * cannot play audio? */
523 		if (gw->sco_start_cb)
524 			gw->sco_start_cb(NULL, gw->sco_start_cb_data);
525 		gateway_close(dev);
526 		return;
527 	}
528 
529 	gw->sco = g_io_channel_ref(chan);
530 	if (gw->sco_start_cb)
531 		gw->sco_start_cb(dev, gw->sco_start_cb_data);
532 
533 	/* why is this here? */
534 	fcntl(g_io_channel_unix_get_fd(chan), F_SETFL, 0);
535 	g_io_add_watch(gw->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
536 				(GIOFunc) sco_io_cb, dev);
537 }
538 
rfcomm_connect_cb(GIOChannel * chan,GError * err,gpointer user_data)539 static void rfcomm_connect_cb(GIOChannel *chan, GError *err,
540 				gpointer user_data)
541 {
542 	struct audio_device *dev = user_data;
543 	struct gateway *gw = dev->gateway;
544 	DBusMessage *conn_mes = gw->connect_message;
545 	gchar gw_addr[18];
546 	GIOFlags flags;
547 
548 	if (err) {
549 		error("connect(): %s", err->message);
550 		if (gw->sco_start_cb)
551 			gw->sco_start_cb(NULL, gw->sco_start_cb_data);
552 		return;
553 	}
554 
555 	ba2str(&dev->dst, gw_addr);
556 	/* Blocking mode should be default, but just in case: */
557 	flags = g_io_channel_get_flags(chan);
558 	flags &= ~G_IO_FLAG_NONBLOCK;
559 	flags &= G_IO_FLAG_MASK;
560 	g_io_channel_set_flags(chan, flags, NULL);
561 	g_io_channel_set_encoding(chan, NULL, NULL);
562 	g_io_channel_set_buffered(chan, FALSE);
563 	if (!gw->rfcomm)
564 		gw->rfcomm = g_io_channel_ref(chan);
565 
566 	if (establish_service_level_conn(dev->gateway)) {
567 		gboolean value = TRUE;
568 
569 		debug("%s: Connected to %s", dev->path, gw_addr);
570 		rfcomm_start_watch(dev);
571 		if (conn_mes) {
572 			DBusMessage *reply =
573 				dbus_message_new_method_return(conn_mes);
574 			dbus_connection_send(dev->conn, reply, NULL);
575 			dbus_message_unref(reply);
576 			dbus_message_unref(conn_mes);
577 			gw->connect_message = NULL;
578 		}
579 
580 		gw->state = GATEWAY_STATE_CONNECTED;
581 		emit_property_changed(dev->conn, dev->path,
582 				AUDIO_GATEWAY_INTERFACE,
583 				"Connected", DBUS_TYPE_BOOLEAN,	&value);
584 		return;
585 	} else
586 		error("%s: Failed to establish service layer connection to %s",
587 			dev->path, gw_addr);
588 
589 	if (NULL != gw->sco_start_cb)
590 		gw->sco_start_cb(NULL, gw->sco_start_cb_data);
591 
592 	gateway_close(dev);
593 }
594 
get_record_cb(sdp_list_t * recs,int perr,gpointer user_data)595 static void get_record_cb(sdp_list_t *recs, int perr, gpointer user_data)
596 {
597 	struct audio_device *dev = user_data;
598 	DBusMessage *msg = dev->gateway->connect_message;
599 	int ch = -1;
600 	sdp_list_t *protos, *classes;
601 	uuid_t uuid;
602 	gateway_stream_cb_t sco_cb;
603 	GIOChannel *io;
604 	GError *err = NULL;
605 
606 	if (perr < 0) {
607 		error("Unable to get service record: %s (%d)", strerror(-perr),
608 					-perr);
609 		goto fail;
610 	}
611 
612 	if (!recs || !recs->data) {
613 		error("No records found");
614 		goto fail;
615 	}
616 
617 	if (sdp_get_service_classes(recs->data, &classes) < 0) {
618 		error("Unable to get service classes from record");
619 		goto fail;
620 	}
621 
622 	if (sdp_get_access_protos(recs->data, &protos) < 0) {
623 		error("Unable to get access protocols from record");
624 		goto fail;
625 	}
626 
627 	memcpy(&uuid, classes->data, sizeof(uuid));
628 	sdp_list_free(classes, free);
629 
630 	if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16 ||
631 			uuid.value.uuid16 != HANDSFREE_AGW_SVCLASS_ID) {
632 		sdp_list_free(protos, NULL);
633 		error("Invalid service record or not HFP");
634 		goto fail;
635 	}
636 
637 	ch = sdp_get_proto_port(protos, RFCOMM_UUID);
638 	sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
639 	sdp_list_free(protos, NULL);
640 	if (ch <= 0) {
641 		error("Unable to extract RFCOMM channel from service record");
642 		goto fail;
643 	}
644 
645 	io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, dev, NULL, &err,
646 				BT_IO_OPT_SOURCE_BDADDR, &dev->src,
647 				BT_IO_OPT_DEST_BDADDR, &dev->dst,
648 				BT_IO_OPT_CHANNEL, ch,
649 				BT_IO_OPT_INVALID);
650 	if (!io) {
651 		error("Unable to connect: %s", err->message);
652 		if (msg) {
653 			error_common_reply(dev->conn, msg, ERROR_INTERFACE
654 						".ConnectionAttemptFailed",
655 						err->message);
656 			msg = NULL;
657 		}
658 		g_error_free(err);
659 		gateway_close(dev);
660 	}
661 
662 	g_io_channel_unref(io);
663 	return;
664 
665 fail:
666 	if (msg)
667 		error_common_reply(dev->conn, msg, ERROR_INTERFACE
668 					".NotSupported", "Not supported");
669 
670 	dev->gateway->connect_message = NULL;
671 
672 	sco_cb = dev->gateway->sco_start_cb;
673 	if (sco_cb)
674 		sco_cb(NULL, dev->gateway->sco_start_cb_data);
675 }
676 
get_records(struct audio_device * device)677 static int get_records(struct audio_device *device)
678 {
679 	uuid_t uuid;
680 
681 	sdp_uuid16_create(&uuid, HANDSFREE_AGW_SVCLASS_ID);
682 	return bt_search_service(&device->src, &device->dst, &uuid,
683 				get_record_cb, device, NULL);
684 }
685 
ag_connect(DBusConnection * conn,DBusMessage * msg,void * data)686 static DBusMessage *ag_connect(DBusConnection *conn, DBusMessage *msg,
687 				void *data)
688 {
689 	struct audio_device *au_dev = (struct audio_device *) data;
690 	struct gateway *gw = au_dev->gateway;
691 
692 	debug("at the begin of ag_connect()");
693 	if (gw->rfcomm)
694 		return g_dbus_create_error(msg, ERROR_INTERFACE
695 					".AlreadyConnected",
696 					"Already Connected");
697 
698 	gw->connect_message = dbus_message_ref(msg);
699 	if (get_records(au_dev) < 0) {
700 		dbus_message_unref(gw->connect_message);
701 		return g_dbus_create_error(msg, ERROR_INTERFACE
702 					".ConnectAttemptFailed",
703 					"Connect Attempt Failed");
704 	}
705 	debug("at the end of ag_connect()");
706 	return NULL;
707 }
708 
ag_disconnect(DBusConnection * conn,DBusMessage * msg,void * data)709 static DBusMessage *ag_disconnect(DBusConnection *conn, DBusMessage *msg,
710 					void *data)
711 {
712 	struct audio_device *device = data;
713 	struct gateway *gw = device->gateway;
714 	DBusMessage *reply = NULL;
715 	char gw_addr[18];
716 
717 	reply = dbus_message_new_method_return(msg);
718 	if (!reply)
719 		return NULL;
720 
721 	if (!gw->rfcomm)
722 		return g_dbus_create_error(msg, ERROR_INTERFACE
723 						".NotConnected",
724 						"Device not Connected");
725 
726 	gateway_close(device);
727 	ba2str(&device->dst, gw_addr);
728 	debug("Disconnected from %s, %s", gw_addr, device->path);
729 
730 	return reply;
731 }
732 
process_ag_reponse(DBusMessage * msg,gchar * response)733 static DBusMessage *process_ag_reponse(DBusMessage *msg, gchar *response)
734 {
735 	DBusMessage *reply;
736 
737 
738 	debug("in process_ag_reponse, response is %s", response);
739 	if (strstr(response, OK_RESPONSE))
740 		reply = dbus_message_new_method_return(msg);
741 	else {
742 		/* FIXME: some code should be here to processes errors
743 		 *  in better fasion */
744 		debug("AG responded with '%s' to %s method call", response,
745 				dbus_message_get_member(msg));
746 		reply = dbus_message_new_error(msg, ERROR_INTERFACE
747 					".OperationFailed",
748 					"Operation failed.See log for details");
749 	}
750 	return reply;
751 }
752 
process_simple(DBusMessage * msg,struct audio_device * dev,gchar * data)753 static DBusMessage *process_simple(DBusMessage *msg, struct audio_device *dev,
754 					gchar *data)
755 {
756 	struct gateway *gw = dev->gateway;
757 	gchar buf[RFCOMM_BUF_SIZE];
758 
759 	rfcomm_stop_watch(dev);
760 	rfcomm_send_and_read(gw, data, buf, strlen(data));
761 	rfcomm_start_watch(dev);
762 	return process_ag_reponse(msg, buf);
763 }
764 
765 #define AG_ANSWER "ATA\r"
766 
ag_answer(DBusConnection * conn,DBusMessage * msg,void * data)767 static DBusMessage *ag_answer(DBusConnection *conn, DBusMessage *msg,
768 				void *data)
769 {
770 	struct audio_device *dev = data;
771 	struct gateway *gw = dev->gateway;
772 
773 	if (!gw->rfcomm)
774 		return g_dbus_create_error(msg, ERROR_INTERFACE
775 					".NotConnected",
776 					"Not Connected");
777 
778 	if (gw->call_active)
779 		return g_dbus_create_error(msg, ERROR_INTERFACE
780 					".CallAlreadyAnswered",
781 					"Call AlreadyAnswered");
782 
783 	return process_simple(msg, dev, AG_ANSWER);
784 }
785 
786 #define AG_HANGUP "AT+CHUP\r"
787 
ag_terminate_call(DBusConnection * conn,DBusMessage * msg,void * data)788 static DBusMessage *ag_terminate_call(DBusConnection *conn, DBusMessage *msg,
789 				void *data)
790 {
791 	struct audio_device *dev = data;
792 	struct gateway *gw = dev->gateway;
793 
794 	if (!gw->rfcomm)
795 		return g_dbus_create_error(msg, ERROR_INTERFACE
796 					".NotConnected",
797 					"Not Connected");
798 
799 	return process_simple(msg, dev, AG_HANGUP);
800 }
801 
802 /* according to GSM spec */
803 #define ALLOWED_NUMBER_SYMBOLS "1234567890*#ABCD"
804 #define AG_PLACE_CALL "ATD%s;\r"
805 /* dialing from memory is not supported as headset spec doesn't define a way
806  * to retreive phone memory entries.
807  */
ag_call(DBusConnection * conn,DBusMessage * msg,void * data)808 static DBusMessage *ag_call(DBusConnection *conn, DBusMessage *msg,
809 				void *data)
810 {
811 	struct audio_device *device = data;
812 	struct gateway *gw = device->gateway;
813 	gchar buf[RFCOMM_BUF_SIZE];
814 	gchar *number;
815 	gint atd_len;
816 	DBusMessage *result;
817 
818 	debug("at the begin of ag_call()");
819 	if (!gw->rfcomm)
820 		return g_dbus_create_error(msg, ERROR_INTERFACE
821 					".NotConnected",
822 					"Not Connected");
823 
824 	dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
825 				DBUS_TYPE_INVALID);
826 	if (strlen(number) != strspn(number, ALLOWED_NUMBER_SYMBOLS))
827 		return dbus_message_new_error(msg,
828 			ERROR_INTERFACE ".BadNumber",
829 			"Number contains characters which are not allowed");
830 
831 	atd_len = sprintf(buf, AG_PLACE_CALL, number);
832 	rfcomm_stop_watch(device);
833 	rfcomm_send_and_read(gw, buf, buf, atd_len);
834 	rfcomm_start_watch(device);
835 
836 	result = process_ag_reponse(msg, buf);
837 	return result;
838 }
839 
840 #define AG_GET_CARRIER "AT+COPS?\r"
841 
ag_get_operator(DBusConnection * conn,DBusMessage * msg,void * data)842 static DBusMessage *ag_get_operator(DBusConnection *conn, DBusMessage *msg,
843 					void *data)
844 {
845 	struct audio_device *dev = (struct audio_device *) data;
846 	struct gateway *gw = dev->gateway;
847 	gchar buf[RFCOMM_BUF_SIZE];
848 	GIOChannel *rfcomm = gw->rfcomm;
849 	gsize read;
850 	gchar *result, *sep;
851 	DBusMessage *reply;
852 	GIOStatus status;
853 
854 	if (!gw->rfcomm)
855 		return g_dbus_create_error(msg, ERROR_INTERFACE
856 					".NotConnected",
857 					"Not Connected");
858 
859 	rfcomm_stop_watch(dev);
860 	io_channel_write_all(rfcomm, AG_GET_CARRIER, strlen(AG_GET_CARRIER));
861 
862 	status = g_io_channel_read_chars(rfcomm, buf, RFCOMM_BUF_SIZE - 1,
863 						&read, NULL);
864 	rfcomm_start_watch(dev);
865 	if (G_IO_STATUS_NORMAL == status) {
866 		buf[read] = '\0';
867 		if (strstr(buf, "+COPS")) {
868 			if (!strrchr(buf, ','))
869 				result = "0";
870 			else {
871 				result = strchr(buf, '\"') + 1;
872 				sep = strchr(result, '\"');
873 				sep[0] = '\0';
874 			}
875 
876 			reply = dbus_message_new_method_return(msg);
877 			dbus_message_append_args(reply, DBUS_TYPE_STRING,
878 						&result, DBUS_TYPE_INVALID);
879 		} else {
880 			info("ag_get_operator(): '+COPS' expected but"
881 				" '%s' received", buf);
882 			reply = dbus_message_new_error(msg, ERROR_INTERFACE
883 						".Failed",
884 						"Unexpected response from AG");
885 		}
886 	} else {
887 		error("ag_get_operator(): %m");
888 		reply = dbus_message_new_error(msg, ERROR_INTERFACE
889 					".ConnectionFailed",
890 					"Failed to receive response from AG");
891 	}
892 
893 	return reply;
894 }
895 
896 #define AG_SEND_DTMF "AT+VTS=%c\r"
ag_send_dtmf(DBusConnection * conn,DBusMessage * msg,void * data)897 static DBusMessage *ag_send_dtmf(DBusConnection *conn, DBusMessage *msg,
898 				void *data)
899 {
900 	struct audio_device *device = data;
901 	struct gateway *gw = device->gateway;
902 	gchar buf[RFCOMM_BUF_SIZE];
903 	gchar *number;
904 	gint com_len;
905 	gboolean got_ok = TRUE;
906 	gint num_len;
907 	gint i = 0;
908 
909 	if (!gw->rfcomm)
910 		return g_dbus_create_error(msg, ERROR_INTERFACE
911 					".NotConnected",
912 					"Not Connected");
913 
914 	dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
915 				DBUS_TYPE_INVALID);
916 	if (strlen(number) != strspn(number, ALLOWED_NUMBER_SYMBOLS))
917 		return dbus_message_new_error(msg,
918 			ERROR_INTERFACE ".BadNumber",
919 			"Number contains characters which are not allowed");
920 
921 	num_len = strlen(number);
922 	rfcomm_stop_watch(device);
923 	while (i < num_len && got_ok) {
924 		com_len = sprintf(buf, AG_SEND_DTMF, number[i]);
925 		rfcomm_send_and_read(gw, buf, buf, com_len);
926 		got_ok = NULL != strstr(buf, OK_RESPONSE);
927 		i += 1;
928 	}
929 	rfcomm_start_watch(device);
930 	return process_ag_reponse(msg, buf);
931 }
932 
933 #define AG_GET_SUBSCRIBER_NUMS "AT+CNUM\r"
934 #define CNUM_LEN 5             /* length of "+CNUM" string */
935 #define MAX_NUMBER_CNT 16
ag_get_subscriber_num(DBusConnection * conn,DBusMessage * msg,void * data)936 static DBusMessage *ag_get_subscriber_num(DBusConnection *conn,
937 					DBusMessage *msg, void *data)
938 {
939 	struct audio_device *device = data;
940 	struct gateway *gw = device->gateway;
941 	gchar buf[RFCOMM_BUF_SIZE];
942 	gchar *number, *end;
943 	DBusMessage *reply = dbus_message_new_method_return(msg);
944 
945 	if (!gw->rfcomm)
946 		return g_dbus_create_error(msg, ERROR_INTERFACE
947 					".NotConnected",
948 					"Not Connected");
949 
950 	rfcomm_stop_watch(device);
951 	rfcomm_send_and_read(gw, AG_GET_SUBSCRIBER_NUMS, buf,
952 			strlen(AG_GET_SUBSCRIBER_NUMS));
953 	rfcomm_start_watch(device);
954 
955 	if (strlen(buf) > AG_CALLER_NUM_SIZE + 21)
956 		error("ag_get_subscriber_num(): buf is too long '%s'", buf);
957 	else if (strstr(buf, "+CNUM")) {
958 		number = strchr(buf, ',');
959 		number++;
960 		end = strchr(number, ',');
961 		if (end) {
962 			*end = '\0';
963 			dbus_message_append_args(reply, DBUS_TYPE_STRING,
964 						&number, DBUS_TYPE_INVALID);
965 		}
966 	} else
967 		error("ag_get_subscriber_num(): read wrong data '%s'", buf);
968 
969 	return reply;
970 }
971 
ag_get_properties(DBusConnection * conn,DBusMessage * msg,void * data)972 static DBusMessage *ag_get_properties(DBusConnection *conn, DBusMessage *msg,
973 					void *data)
974 {
975 	struct audio_device *device = data;
976 	struct gateway *gw = device->gateway;
977 	DBusMessage *reply;
978 	DBusMessageIter iter;
979 	DBusMessageIter dict;
980 	gboolean value;
981 	guint index = 0;
982 	struct indicator *ind;
983 
984 	reply = dbus_message_new_method_return(msg);
985 	if (!reply)
986 		return NULL;
987 
988 	dbus_message_iter_init_append(reply, &iter);
989 
990 	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
991 			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
992 			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
993 			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
994 
995 	/* Connected */
996 	value = gateway_is_connected(device);
997 	dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);
998 
999 	if (!value)
1000 		goto done;
1001 
1002 	while ((ind = g_slist_nth_data(gw->indies, index))) {
1003 		if(!strcmp(ind->descr, "\"service\""))
1004 			dict_append_entry(&dict, "RegistrationStatus",
1005 					DBUS_TYPE_UINT16, &ind->value);
1006 		else if (!strcmp(ind->descr, "\"signal\""))
1007 			dict_append_entry(&dict, "SignalStrength",
1008 					DBUS_TYPE_UINT16, &ind->value);
1009 		else if (!strcmp(ind->descr, "\"roam\""))
1010 			dict_append_entry(&dict, "RoamingStatus",
1011 					DBUS_TYPE_UINT16, &ind->value);
1012 		else if (!strcmp(ind->descr, "\"battchg\""))
1013 			dict_append_entry(&dict, "BatteryCharge",
1014 					DBUS_TYPE_UINT16, &ind->value);
1015 		index++;
1016 	}
1017 
1018 	/* SpeakerGain */
1019 	dict_append_entry(&dict, "SpeakerGain", DBUS_TYPE_UINT16,
1020 				&device->gateway->sp_gain);
1021 
1022 	/* MicrophoneGain */
1023 	dict_append_entry(&dict, "MicrophoneGain", DBUS_TYPE_UINT16,
1024 				&device->gateway->mic_gain);
1025 done:
1026 	dbus_message_iter_close_container(&iter, &dict);
1027 	return reply;
1028 }
1029 
1030 static GDBusMethodTable gateway_methods[] = {
1031 	{ "Connect", "", "", ag_connect, G_DBUS_METHOD_FLAG_ASYNC },
1032 	{ "Disconnect", "", "", ag_disconnect },
1033 	{ "AnswerCall", "", "", ag_answer },
1034 	{ "TerminateCall", "", "", ag_terminate_call },
1035 	{ "Call", "s", "", ag_call },
1036 	{ "GetOperatorName", "", "s", ag_get_operator },
1037 	{ "SendDTMF", "s", "", ag_send_dtmf },
1038 	{ "GetSubscriberNumber", "", "s", ag_get_subscriber_num },
1039 	{ "GetProperties", "", "a{sv}", ag_get_properties },
1040 	{ NULL, NULL, NULL, NULL }
1041 };
1042 
1043 static GDBusSignalTable gateway_signals[] = {
1044 	{ "Ring", "s" },
1045 	{ "CallTerminated", "" },
1046 	{ "CallStarted", "" },
1047 	{ "CallEnded", "" },
1048 	{ "PropertyChanged", "sv" },
1049 	{ NULL, NULL }
1050 };
1051 
gateway_init(struct audio_device * dev)1052 struct gateway *gateway_init(struct audio_device *dev)
1053 {
1054 	struct gateway *gw;
1055 
1056 	if (!g_dbus_register_interface(dev->conn, dev->path,
1057 					AUDIO_GATEWAY_INTERFACE,
1058 					gateway_methods, gateway_signals,
1059 					NULL, dev, NULL))
1060 		return NULL;
1061 
1062 	debug("in gateway_init, dev is %p", dev);
1063 	gw = g_new0(struct gateway, 1);
1064 	gw->indies = NULL;
1065 	gw->is_dialing = FALSE;
1066 	gw->call_active = FALSE;
1067 	gw->state = GATEWAY_STATE_DISCONNECTED;
1068 	return gw;
1069 
1070 }
1071 
gateway_is_connected(struct audio_device * dev)1072 gboolean gateway_is_connected(struct audio_device *dev)
1073 {
1074 	return (dev && dev->gateway &&
1075 			dev->gateway->state == GATEWAY_STATE_CONNECTED);
1076 }
1077 
gateway_connect_rfcomm(struct audio_device * dev,GIOChannel * io)1078 int gateway_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
1079 {
1080 	if (!io)
1081 		return -EINVAL;
1082 
1083 	g_io_channel_ref(io);
1084 	dev->gateway->rfcomm = io;
1085 
1086 	return 0;
1087 }
1088 
gateway_connect_sco(struct audio_device * dev,GIOChannel * io)1089 int gateway_connect_sco(struct audio_device *dev, GIOChannel *io)
1090 {
1091 	struct gateway *gw = dev->gateway;
1092 
1093 	if (gw->sco)
1094 		return -EISCONN;
1095 
1096 	gw->sco = g_io_channel_ref(io);
1097 
1098 	g_io_add_watch(gw->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
1099                                 (GIOFunc) sco_io_cb, dev);
1100 	return 0;
1101 }
1102 
gateway_start_service(struct audio_device * device)1103 void gateway_start_service(struct audio_device *device)
1104 {
1105 	rfcomm_connect_cb(device->gateway->rfcomm, NULL, device);
1106 }
1107 
indicator_slice_free(gpointer mem)1108 static void indicator_slice_free(gpointer mem)
1109 {
1110 	g_slice_free(struct indicator, mem);
1111 }
1112 
gateway_close(struct audio_device * device)1113 int gateway_close(struct audio_device *device)
1114 {
1115 	struct gateway *gw = device->gateway;
1116 	GIOChannel *rfcomm = gw->rfcomm;
1117 	GIOChannel *sco = gw->sco;
1118 	gboolean value = FALSE;
1119 
1120 	g_slist_foreach(gw->indies, (GFunc) indicator_slice_free, NULL);
1121 	g_slist_free(gw->indies);
1122 	if (rfcomm) {
1123 		g_io_channel_shutdown(rfcomm, TRUE, NULL);
1124 		g_io_channel_unref(rfcomm);
1125 		gw->rfcomm = NULL;
1126 	}
1127 
1128 	if (sco) {
1129 		g_io_channel_shutdown(sco, TRUE, NULL);
1130 		g_io_channel_unref(sco);
1131 		gw->sco = NULL;
1132 		gw->sco_start_cb = NULL;
1133 		gw->sco_start_cb_data = NULL;
1134 	}
1135 
1136 	gw->state = GATEWAY_STATE_DISCONNECTED;
1137 
1138 	emit_property_changed(device->conn, device->path,
1139 				AUDIO_GATEWAY_INTERFACE,
1140 				"Connected", DBUS_TYPE_BOOLEAN, &value);
1141 	return 0;
1142 }
1143 
1144 /* These are functions to be called from unix.c for audio system
1145  * ifaces (alsa, gstreamer, etc.) */
gateway_request_stream(struct audio_device * dev,gateway_stream_cb_t cb,void * user_data)1146 gboolean gateway_request_stream(struct audio_device *dev,
1147 				gateway_stream_cb_t cb, void *user_data)
1148 {
1149 	struct gateway *gw = dev->gateway;
1150 	GError *err = NULL;
1151 	GIOChannel *io;
1152 
1153 	if (!gw->rfcomm) {
1154 		gw->sco_start_cb = cb;
1155 		gw->sco_start_cb_data = user_data;
1156 		get_records(dev);
1157 	} else if (!gw->sco) {
1158 		gw->sco_start_cb = cb;
1159 		gw->sco_start_cb_data = user_data;
1160 		io = bt_io_connect(BT_IO_SCO, sco_connect_cb, dev, NULL, &err,
1161 				BT_IO_OPT_SOURCE_BDADDR, &dev->src,
1162 				BT_IO_OPT_DEST_BDADDR, &dev->dst,
1163 				BT_IO_OPT_INVALID);
1164 		if (!io) {
1165 			error("%s", err->message);
1166 			g_error_free(err);
1167 			return FALSE;
1168 		}
1169 	} else {
1170 		if (cb)
1171 			cb(dev, user_data);
1172 	}
1173 
1174 	return TRUE;
1175 }
1176 
gateway_config_stream(struct audio_device * dev,gateway_stream_cb_t sco_cb,void * user_data)1177 int gateway_config_stream(struct audio_device *dev, gateway_stream_cb_t sco_cb,
1178 				void *user_data)
1179 {
1180 	struct gateway *gw = dev->gateway;
1181 
1182 	if (!gw->rfcomm) {
1183 		gw->sco_start_cb = sco_cb;
1184 		gw->sco_start_cb_data = user_data;
1185 		return get_records(dev);
1186 	}
1187 
1188 	if (sco_cb)
1189 		sco_cb(dev, user_data);
1190 
1191 	return 0;
1192 }
1193 
gateway_cancel_stream(struct audio_device * dev,unsigned int id)1194 gboolean gateway_cancel_stream(struct audio_device *dev, unsigned int id)
1195 {
1196 	gateway_close(dev);
1197 	return TRUE;
1198 }
1199 
gateway_get_sco_fd(struct audio_device * dev)1200 int gateway_get_sco_fd(struct audio_device *dev)
1201 {
1202 	struct gateway *gw = dev->gateway;
1203 
1204 	if (!gw || !gw->sco)
1205 		return -1;
1206 
1207 	return g_io_channel_unix_get_fd(gw->sco);
1208 }
1209 
gateway_suspend_stream(struct audio_device * dev)1210 void gateway_suspend_stream(struct audio_device *dev)
1211 {
1212 	struct gateway *gw = dev->gateway;
1213 
1214 	if (!gw || !gw->sco)
1215 		return;
1216 
1217 	g_io_channel_shutdown(gw->sco, TRUE, NULL);
1218 	g_io_channel_unref(gw->sco);
1219 	gw->sco = NULL;
1220 	gw->sco_start_cb = NULL;
1221 	gw->sco_start_cb_data = NULL;
1222 }
1223 
1224