diff options
author | Vinicius Costa Gomes <vinicius.gomes@openbossa.org> | 2013-03-25 19:05:18 -0300 |
---|---|---|
committer | Denis Kenzior <denkenz@gmail.com> | 2013-03-26 23:23:39 -0500 |
commit | c3cd427ee8a3facc5e4fe4c53ba10cb8a1efb8b3 (patch) | |
tree | 3b346ab457a5419469b7dcb7d8baa9ba9e22a57a /src/handsfree-audio.c | |
parent | 93ac1669a069a1bcce1ed121ca60977db53abf4e (diff) | |
download | ofono-c3cd427ee8a3facc5e4fe4c53ba10cb8a1efb8b3.tar.bz2 |
handsfree-audio: Add support for initiating SCO connections
When calling the card's .Connect() method, we should be able to
establish a SCO connection.
Right now, we only have support for establishing the SCO connection
directly, this is what is expected from HFP 1.5 HF/AG devices.
Diffstat (limited to 'src/handsfree-audio.c')
-rw-r--r-- | src/handsfree-audio.c | 93 |
1 files changed, 92 insertions, 1 deletions
diff --git a/src/handsfree-audio.c b/src/handsfree-audio.c index c7fa2fbe..795a68bd 100644 --- a/src/handsfree-audio.c +++ b/src/handsfree-audio.c @@ -53,6 +53,7 @@ struct ofono_handsfree_card { char *remote; char *local; char *path; + DBusMessage *msg; const struct ofono_handsfree_card_driver *driver; void *driver_data; }; @@ -235,10 +236,100 @@ static DBusMessage *card_get_properties(DBusConnection *conn, return reply; } +static int card_connect_sco(struct ofono_handsfree_card *card) +{ + struct sockaddr_sco addr; + int sk, ret; + + sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET | O_NONBLOCK | SOCK_CLOEXEC, + BTPROTO_SCO); + if (sk < 0) + return -1; + + /* Bind to local address */ + memset(&addr, 0, sizeof(addr)); + addr.sco_family = AF_BLUETOOTH; + bt_str2ba(card->local, &addr.sco_bdaddr); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(sk); + return -1; + } + + /* Connect to remote device */ + memset(&addr, 0, sizeof(addr)); + addr.sco_family = AF_BLUETOOTH; + bt_str2ba(card->remote, &addr.sco_bdaddr); + + ret = connect(sk, (struct sockaddr *) &addr, sizeof(addr)); + if (ret < 0 && errno != EINPROGRESS) { + close(sk); + return -1; + } + + return sk; +} + +static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond, + gpointer user_data) + +{ + struct ofono_handsfree_card *card = user_data; + DBusMessage *reply; + int sk; + + if (agent == NULL) { + /* There's no agent, so there's no one to reply to */ + reply = NULL; + goto done; + } + + if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) { + reply = __ofono_error_failed(card->msg); + goto done; + } + + sk = g_io_channel_unix_get_fd(io); + + close(sk); + + reply = dbus_message_new_method_return(card->msg); + +done: + if (reply) + g_dbus_send_message(ofono_dbus_get_connection(), reply); + + dbus_message_unref(card->msg); + card->msg = NULL; + + return FALSE; +} + static DBusMessage *card_connect(DBusConnection *conn, DBusMessage *msg, void *data) { - return __ofono_error_not_implemented(msg); + struct ofono_handsfree_card *card = data; + GIOChannel *io; + int sk; + + if (agent == NULL) + return __ofono_error_not_available(msg); + + if (card->msg) + return __ofono_error_busy(msg); + + sk = card_connect_sco(card); + if (sk < 0) + return __ofono_error_failed(msg); + + io = g_io_channel_unix_new(sk); + g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + sco_connect_cb, card); + g_io_channel_unref(io); + + card->msg = dbus_message_ref(msg); + + return NULL; } static const GDBusMethodTable card_methods[] = { |