diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2006-11-14 14:00:15 +0000 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@nokia.com> | 2006-11-14 14:00:15 +0000 |
commit | a25501d26a40907f384d223d8f87f93e5ff89ff7 (patch) | |
tree | 5ca9481bbed1509600373bc2b638514b1528b698 | |
parent | b801c1b07d43ed42e7651238de3831b503a449f5 (diff) |
Support for fetching the RFCOMM channel through SDP
-rw-r--r-- | audio/headset.c | 181 |
1 files changed, 169 insertions, 12 deletions
diff --git a/audio/headset.c b/audio/headset.c index 307b9212..0ecc2e4e 100644 --- a/audio/headset.c +++ b/audio/headset.c @@ -66,7 +66,6 @@ struct hs_connection { }; static char *on_init_bda = NULL; -static int on_init_ch = 2; static int started = 0; @@ -76,6 +75,8 @@ static GMainLoop *main_loop = NULL; static struct hs_connection *connected_hs = NULL; +static int hs_connect(const char *address); + static int set_nonblocking(int fd, int *err) { long arg; @@ -411,7 +412,6 @@ static void register_reply(DBusPendingCall *call, void *data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusError derr; - int err; dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { @@ -427,11 +427,10 @@ static void register_reply(DBusPendingCall *call, void *data) if (!on_init_bda) return; - if (rfcomm_connect(NULL, NULL, BDADDR_ANY, on_init_bda, on_init_ch, &err) < 0) + if (hs_connect(on_init_bda) < 0) exit(1); } - int headset_dbus_init(char *bda) { DBusMessage *msg; @@ -474,6 +473,172 @@ int headset_dbus_init(char *bda) return 0; } +static void record_reply(DBusPendingCall *call, void *data) +{ + DBusMessage *reply; + DBusError derr; + uint8_t *array; + int array_len, record_len, ch = -1; + sdp_record_t *record = NULL; + sdp_list_t *protos; + char *address = data; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + error("GetRemoteServiceRecord failed: %s", derr.message); + dbus_error_free(&derr); + goto failed; + } + + dbus_message_get_args(reply, NULL, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &array, &array_len, + DBUS_TYPE_INVALID); + + if (!array) { + error("Unable to get handle array from reply"); + goto failed; + } + + record = sdp_extract_pdu(array, &record_len); + if (!record) { + error("Unable to extract service record from reply"); + goto failed; + } + + if (record_len != array_len) + debug("warning: array len (%d) != record len (%d)", + array_len, record_len); + + if (!sdp_get_access_protos(record, &protos)) { + ch = sdp_get_proto_port(protos, RFCOMM_UUID); + sdp_list_foreach(protos, (sdp_list_func_t)sdp_list_free, NULL); + sdp_list_free(protos, NULL); + } + + if (ch == -1) { + error("Unable to extract RFCOMM channel from service record"); + goto failed; + } + + if (rfcomm_connect(NULL, NULL, BDADDR_ANY, address, ch, NULL) < 0) { + error("Unable to connect to %s", address); + goto failed; + } + +failed: + if (record) + sdp_record_free(record); + dbus_message_unref(reply); + free(data); +} + +static void handles_reply(DBusPendingCall *call, void *data) +{ + DBusMessage *msg = NULL, *reply; + DBusPendingCall *pending; + DBusError derr; + char *address = data; + dbus_uint32_t *array = NULL; + dbus_uint32_t handle; + int array_len; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&derr); + if (dbus_set_error_from_message(&derr, reply)) { + error("GetRemoteServiceHandles failed: %s", derr.message); + dbus_error_free(&derr); + goto failed; + } + + dbus_message_get_args(reply, NULL, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &array, &array_len, + DBUS_TYPE_INVALID); + + if (!array) { + error("Unable to get handle array from reply"); + goto failed; + } + + if (array_len < 1) { + debug("No record handles found"); + goto failed; + } + + if (array_len > 1) + debug("Multiple records found. Using the first one."); + + msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0", + "org.bluez.Adapter", + "GetRemoteServiceRecord"); + if (!msg) { + error("Unable to allocate new method call"); + goto failed; + } + + handle = array[0]; + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &address, + DBUS_TYPE_UINT32, &handle, + DBUS_TYPE_INVALID); + + if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) { + error("Sending GetRemoteServiceRecord failed"); + goto failed; + } + + dbus_pending_call_set_notify(pending, record_reply, data, NULL); + dbus_message_unref(msg); + + dbus_message_unref(reply); + + return; + +failed: + if (msg) + dbus_message_unref(msg); + dbus_message_unref(reply); + free(data); +} + +static int hs_connect(const char *address) +{ + DBusMessage *msg; + DBusPendingCall *pending; + char *data; + const char *hs_svc = "hsp"; + + data = strdup(address); + if (!data) + return -ENOMEM; + + msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0", + "org.bluez.Adapter", + "GetRemoteServiceHandles"); + if (!msg) { + free(data); + return -ENOMEM; + } + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &address, + DBUS_TYPE_STRING, &hs_svc, + DBUS_TYPE_INVALID); + + + if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) { + error("Sending GetRemoteServiceHandles failed"); + free(data); + dbus_message_unref(msg); + return -1; + } + + dbus_pending_call_set_notify(pending, handles_reply, data, NULL); + dbus_message_unref(msg); + + return 0; +} int main(int argc, char *argv[]) { @@ -486,14 +651,6 @@ int main(int argc, char *argv[]) daemonize = 0; break; - case 'c': - on_init_ch = strtol(optarg, NULL, 0); - if (on_init_ch < 0 || on_init_ch > 255) { - error("Invalid channel"); - exit(1); - } - break; - default: printf("Usage: %s [-n] [-c channel] [bdaddr]\n", argv[0]); exit(1); |