3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2014 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 #include "lib/bluetooth.h"
34 #include "btio/btio.h"
36 #include "src/shared/util.h"
43 GIOChannel *server_io;
51 bt_sco_confirm_func_t confirm_cb;
52 bt_sco_conn_func_t connect_cb;
53 bt_sco_disconn_func_t disconnect_cb;
56 /* We support only one sco for the moment */
57 static bool sco_in_use = false;
59 static void clear_remote_address(struct bt_sco *sco)
61 memset(&sco->remote_addr, 0, sizeof(bdaddr_t));
64 static gboolean disconnect_watch(GIOChannel *chan, GIOCondition cond,
67 struct bt_sco *sco = user_data;
69 g_io_channel_shutdown(sco->io, TRUE, NULL);
70 g_io_channel_unref(sco->io);
77 if (sco->disconnect_cb)
78 sco->disconnect_cb(&sco->remote_addr);
80 clear_remote_address(sco);
85 static void connect_sco_cb(GIOChannel *chan, GError *err, gpointer user_data)
87 struct bt_sco *sco = user_data;
91 /* Lets unref connecting io */
93 g_io_channel_unref(sco->io);
98 error("sco: Audio connect failed (%s)", err->message);
101 * Connect_sco_cb is called only when connect_cb is in place
102 * Therefore it is safe to call it
104 sco->connect_cb(SCO_STATUS_ERROR, &sco->remote_addr);
106 clear_remote_address(sco);
111 g_io_channel_set_close_on_unref(chan, TRUE);
113 sco->io = g_io_channel_ref(chan);
114 sco->watch = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
115 disconnect_watch, sco);
117 /* It is safe to call it here */
118 sco->connect_cb(SCO_STATUS_OK, &sco->remote_addr);
121 static void confirm_sco_cb(GIOChannel *chan, gpointer user_data)
126 struct bt_sco *sco = user_data;
127 uint16_t voice_settings;
131 bt_io_get(chan, &err,
132 BT_IO_OPT_DEST, address,
133 BT_IO_OPT_DEST_BDADDR, &bdaddr,
136 error("sco: audio confirm failed (%s)", err->message);
141 if (!sco->confirm_cb || !sco->connect_cb) {
142 error("sco: Connect and/or confirm callback not registered ");
146 /* Check if there is SCO */
148 error("sco: SCO is in progress");
152 if (!sco->confirm_cb(&bdaddr, &voice_settings)) {
153 error("sco: Audio connection from %s rejected", address);
157 bacpy(&sco->remote_addr, &bdaddr);
159 DBG("Incoming SCO connection from %s, voice settings 0x%x", address,
163 bt_io_set(chan, &err, BT_IO_OPT_VOICE, voice_settings,
166 error("sco: Could not set voice settings (%s)", err->message);
171 if (!bt_io_accept(chan, connect_sco_cb, sco, NULL, NULL)) {
172 error("sco: Failed to accept audio connection");
176 sco->io = g_io_channel_ref(chan);
181 g_io_channel_shutdown(chan, TRUE, NULL);
184 static bool sco_listen(struct bt_sco *sco)
191 sco->server_io = bt_io_listen(NULL, confirm_sco_cb, sco, NULL, &err,
192 BT_IO_OPT_SOURCE_BDADDR,
195 if (!sco->server_io) {
196 error("sco: Failed to listen on SCO: %s", err->message);
204 struct bt_sco *bt_sco_new(const bdaddr_t *local_bdaddr)
211 /* For now we support only one SCO connection per time */
215 sco = new0(struct bt_sco, 1);
219 bacpy(&sco->local_addr, local_bdaddr);
221 if (!sco_listen(sco)) {
228 return bt_sco_ref(sco);
231 struct bt_sco *bt_sco_ref(struct bt_sco *sco)
236 __sync_fetch_and_add(&sco->ref_count, 1);
241 static void sco_free(struct bt_sco *sco)
243 if (sco->server_io) {
244 g_io_channel_shutdown(sco->server_io, TRUE, NULL);
245 g_io_channel_unref(sco->server_io);
249 g_io_channel_shutdown(sco->io, TRUE, NULL);
250 g_io_channel_unref(sco->io);
257 void bt_sco_unref(struct bt_sco *sco)
264 if (__sync_sub_and_fetch(&sco->ref_count, 1))
270 bool bt_sco_connect(struct bt_sco *sco, const bdaddr_t *addr,
271 uint16_t voice_settings)
278 if (!sco || !sco->connect_cb || !addr) {
279 error("sco: Incorrect parameters or missing connect_cb");
283 /* Check if we have connection in progress */
285 error("sco: Connection already in progress");
289 io = bt_io_connect(connect_sco_cb, sco, NULL, &gerr,
290 BT_IO_OPT_SOURCE_BDADDR, &sco->local_addr,
291 BT_IO_OPT_DEST_BDADDR, addr,
292 BT_IO_OPT_VOICE, voice_settings,
296 error("sco: unable to connect audio: %s", gerr->message);
303 bacpy(&sco->remote_addr, addr);
308 void bt_sco_disconnect(struct bt_sco *sco)
314 g_io_channel_shutdown(sco->io, TRUE, NULL);
317 bool bt_sco_get_fd_and_mtu(struct bt_sco *sco, int *fd, uint16_t *mtu)
321 if (!sco->io || !fd || !mtu)
325 if (!bt_io_get(sco->io, &err, BT_IO_OPT_MTU, mtu, BT_IO_OPT_INVALID)) {
326 error("Unable to get MTU: %s\n", err->message);
331 *fd = g_io_channel_unix_get_fd(sco->io);
336 void bt_sco_set_confirm_cb(struct bt_sco *sco,
337 bt_sco_confirm_func_t func)
339 sco->confirm_cb = func;
342 void bt_sco_set_connect_cb(struct bt_sco *sco, bt_sco_conn_func_t func)
344 sco->connect_cb = func;
347 void bt_sco_set_disconnect_cb(struct bt_sco *sco,
348 bt_sco_disconn_func_t func)
350 sco->disconnect_cb = func;