diff options
Diffstat (limited to 'binding/bluetooth-api.c')
-rw-r--r-- | binding/bluetooth-api.c | 232 |
1 files changed, 186 insertions, 46 deletions
diff --git a/binding/bluetooth-api.c b/binding/bluetooth-api.c index 48bc460..5022ba9 100644 --- a/binding/bluetooth-api.c +++ b/binding/bluetooth-api.c @@ -231,11 +231,13 @@ void call_work_destroy_unlocked(struct call_work *cw) /* agent struct data */ g_free(cw->agent_data.device_path); - + cw->agent_data.device_path = NULL; g_free(cw->access_type); g_free(cw->type_arg); g_free(cw->method); g_free(cw->bluez_method); + g_free(cw->agent_data.fixed_pincode); + cw->agent_data.fixed_pincode = NULL; } void call_work_destroy(struct call_work *cw) @@ -300,7 +302,7 @@ static void bluez_devices_signal_callback( jresp = json_object_new_object(); - json_process_path(jresp, path); + json_process_path(jresp, path); jobj = json_object_new_object(); @@ -519,6 +521,47 @@ static void bluez_devices_signal_callback( json_object_put(jresp); } +static int bluetooth_select_init_adapter(struct init_data *id) +{ + struct bluetooth_state *ns =id->ns; + GError *error = NULL; + json_object *jresp, *jobj = NULL; + int ret, i; + size_t count; + + jresp = object_properties(ns, &error); + if (error) { + AFB_INFO("object_properties for adapters error: %s", + error->message); + g_clear_error(&error); + ret = -EIO; + } else { + json_object_object_get_ex(jresp, "adapters", &jobj); + count = json_object_array_length(jobj); + ret = (int)count; + + for (i = 1; (ret-i) >= 0; i++) { + json_object *idx = json_object_array_get_idx(jobj, count-i); + json_object *name = NULL; + const char *adapter; + json_object_object_get_ex(idx, "name", &name); + adapter = json_object_get_string(name); + if (!g_strcmp0(adapter, id->default_adapter)) { + id->ns->adapter = id->default_adapter; + break; + } + if (!(count-i)) { + /* fallback to 1st available adapter */ + id->ns->adapter = g_strdup(adapter); + AFB_WARNING("default adapter %s not found, fell back to: %s", + id->default_adapter, adapter); + } + } + json_object_put(jresp); + } + return ret; +} + static struct bluetooth_state *bluetooth_init(GMainLoop *loop) { struct bluetooth_state *ns; @@ -608,6 +651,10 @@ static gpointer bluetooth_func(gpointer ptr) struct bluetooth_state *ns; GMainLoop *loop; int rc = 0; + unsigned int delay; + unsigned int attempt; + + g_atomic_rc_box_acquire(id); loop = g_main_loop_new(NULL, FALSE); if (!loop) { @@ -615,7 +662,7 @@ static gpointer bluetooth_func(gpointer ptr) goto err_no_loop; } - /* real bluetooth init */ + // Do BlueZ D-Bus related init ns = bluetooth_init(loop); if (!ns) { AFB_ERROR("bluetooth_init() failed"); @@ -629,17 +676,41 @@ static gpointer bluetooth_func(gpointer ptr) goto err_no_agent; } - /* note that we wait for agent registration to signal done */ - afb_api_set_userdata(id->api, ns); - g_main_loop_run(loop); + + // Let main process know initialization is done + signal_init_done(id, 0); + + // Wait for an adapter to appear + rc = 0; + delay = 1; + attempt = 1; + while(rc <= 0) { + rc = bluetooth_select_init_adapter(id); + if (rc != 0) + break; + + // Back off querying rate after the first 60 seconds + if (attempt++ == 60) + delay = 10; + + sleep(delay); + } + + if (rc > 0) { + g_main_loop_run(loop); + } else { + AFB_ERROR("bluetooth_select_init_adapter() failed"); + } g_main_loop_unref(ns->loop); - bluetooth_unregister_agent(ns); + if (ns->agent_path) + bluetooth_unregister_agent(ns); bluetooth_cleanup(ns); afb_api_set_userdata(id->api, NULL); + g_atomic_rc_box_release(id); return NULL; @@ -651,18 +722,24 @@ err_no_ns: err_no_loop: signal_init_done(id, -1); + g_atomic_rc_box_release(id); return NULL; } static int init(afb_api_t api) { - struct init_data init_data, *id = &init_data; + struct init_data *id = NULL; json_object *args = NULL; gint64 end_time; int ret; + gboolean init_done; + + id = g_atomic_rc_box_new0(struct init_data); + if (!id) + return -ENOMEM; + g_atomic_rc_box_acquire(id); - memset(id, 0, sizeof(*id)); id->init_done = FALSE; id->rc = 0; id->api = api; @@ -681,13 +758,21 @@ static int init(afb_api_t api) return ret; } + id->default_adapter = get_default_adapter(id->api); + if (!id->default_adapter) { + id->default_adapter = g_strdup(BLUEZ_DEFAULT_ADAPTER); + ret = set_default_adapter(api, BLUEZ_DEFAULT_ADAPTER); + if (ret) + AFB_WARNING("Request to save default adapter to persistent storage failed "); + } + args = json_object_new_object(); json_object_object_add(args , "technology", json_object_new_string("bluetooth")); afb_api_call_sync(api, "network-manager", "enable_technology", args, NULL, NULL, NULL); global_thread = g_thread_new("agl-service-bluetooth", - bluetooth_func, - id); + bluetooth_func, + id); AFB_INFO("bluetooth-binding waiting for init done"); @@ -698,26 +783,31 @@ static int init(afb_api_t api) if (!g_cond_wait_until(&id->cond, &id->mutex, end_time)) break; } + ret = id->rc; + init_done = id->init_done; g_mutex_unlock(&id->mutex); + g_atomic_rc_box_release(id); - if (!id->init_done) { + if (!init_done) { AFB_ERROR("bluetooth-binding init timeout"); return -1; } - if (id->rc) - AFB_ERROR("bluetooth-binding init thread returned %d", - id->rc); + if (ret) + AFB_ERROR("bluetooth-binding init thread returned %d", ret); else AFB_INFO("bluetooth-binding operational"); - id->ns->default_adapter = get_default_adapter(id->api); - - return id->rc; + return ret; } static void mediaplayer1_send_event(struct bluetooth_state *ns) { + if (!ns->mediaplayer_path) { + AFB_ERROR("NULL mediaplayer_path"); + return; + } + gchar *player = g_strdup(ns->mediaplayer_path); json_object *jresp = mediaplayer_properties(ns, NULL, player); @@ -738,11 +828,16 @@ static void bluetooth_subscribe_unsubscribe(afb_req_t request, gboolean unsub) { struct bluetooth_state *ns = bluetooth_get_userdata(request); - json_object *jresp = json_object_new_object(); + json_object *jresp; const char *value; afb_event_t event; int rc; + if (!ns) { + afb_req_fail(request, "failed", "Cannot process request"); + return; + } + /* if value exists means to set offline mode */ value = afb_req_value(request, "value"); if (!value) { @@ -773,6 +868,7 @@ static void bluetooth_subscribe_unsubscribe(afb_req_t request, return; } + jresp = json_object_new_object(); afb_req_success_f(request, jresp, "Bluetooth %s to event \"%s\"", !unsub ? "subscribed" : "unsubscribed", value); @@ -794,9 +890,20 @@ static void bluetooth_list(afb_req_t request) GError *error = NULL; json_object *jresp; + if (!ns) { + afb_req_fail(request, "failed", "Cannot process request"); + return; + } + jresp = object_properties(ns, &error); + if (error) { + AFB_INFO("object_properties error: %s", + error->message); + g_clear_error(&error); + afb_req_fail(request, "failed", "BlueZ managed objects error"); + } else + afb_req_success(request, jresp, "BlueZ managed objects"); - afb_req_success(request, jresp, "Bluetooth - managed objects"); } static void bluetooth_state(afb_req_t request) @@ -806,7 +913,12 @@ static void bluetooth_state(afb_req_t request) json_object *jresp; const char *adapter = afb_req_value(request, "adapter"); - adapter = BLUEZ_ROOT_PATH(adapter ? adapter : ns->default_adapter); + if (!ns || (!adapter && !ns->adapter)) { + afb_req_fail(request, "failed", "No adapter"); + return; + } + + adapter = BLUEZ_ROOT_PATH(adapter ? adapter : ns->adapter); jresp = adapter_properties(ns, &error, adapter); if (!jresp) { @@ -825,7 +937,12 @@ static void bluetooth_adapter(afb_req_t request) const char *adapter = afb_req_value(request, "adapter"); const char *scan, *discoverable, *powered, *filter, *transport; - adapter = BLUEZ_ROOT_PATH(adapter ? adapter : ns->default_adapter); + if (!ns || (!adapter && !ns->adapter)) { + afb_req_fail(request, "failed", "No adapter"); + return; + } + + adapter = BLUEZ_ROOT_PATH(adapter ? adapter : ns->adapter); scan = afb_req_value(request, "discovery"); if (scan) { @@ -891,7 +1008,7 @@ static void bluetooth_adapter(afb_req_t request) uuid = json_array_to_strv(jobj); g_variant_builder_add(&builder, "{sv}", "UUIDs", - g_variant_new_strv((const gchar * const *) uuid, -1)); + g_variant_new_strv((const gchar * const *) uuid, -1)); g_strfreev(uuid); } @@ -923,22 +1040,30 @@ static void bluetooth_adapter(afb_req_t request) static void bluetooth_default_adapter(afb_req_t request) { - struct bluetooth_state *ns = bluetooth_get_userdata(request); const char *adapter = afb_req_value(request, "adapter"); json_object *jresp = json_object_new_object(); + afb_api_t api = afb_req_get_api(request); + const char *adapter_default = get_default_adapter(api); + int rc; - call_work_lock(ns); if (adapter) { - set_default_adapter(afb_req_get_api(request), adapter); - - if (ns->default_adapter) - g_free(ns->default_adapter); - ns->default_adapter = g_strdup(adapter); + if (adapter_default && g_strcmp0(adapter_default, adapter)) { + rc = set_default_adapter(api, adapter); + if (rc) { + AFB_DEBUG("Request to save default adapter to persistent storage failed "); + afb_req_fail(request, "failed", "Update default adapter failed"); + json_object_put(jresp); + return; + } + } + json_object_object_add(jresp, "adapter", json_object_new_string(adapter)); + } else if (adapter_default) { + json_object_object_add(jresp, "adapter", json_object_new_string(adapter_default)); + } else { + afb_req_fail(request, "failed", "No default adapter"); + json_object_put(jresp); + return; } - - json_object_object_add(jresp, "adapter", json_object_new_string(ns->default_adapter)); - call_work_unlock(ns); - afb_req_success(request, jresp, "Bluetooth - default adapter"); } @@ -1111,6 +1236,8 @@ static void bluetooth_pair_device(afb_req_t request) cw->request = request; afb_req_addref(request); + cw->agent_data.fixed_pincode = get_pincode(afb_req_get_api(request)); + cw->cpw = bluez_call_async(ns, BLUEZ_AT_DEVICE, device, "Pair", NULL, &error, pair_service_callback, cw); @@ -1171,10 +1298,10 @@ static void bluetooth_confirm_pairing(afb_req_t request) const char *value = afb_req_value(request, "pincode"); if (value) - pin = (int)strtol(value, NULL, 10); + pin = (int)strtol(value, NULL, 10); if (!value || !pin) { - afb_req_fail_f(request, "failed", "No pincode parameter"); + afb_req_fail(request, "failed", "No pincode parameter"); return; } @@ -1259,9 +1386,10 @@ static void bluetooth_avrcp_controls(afb_req_t request) { struct bluetooth_state *ns = bluetooth_get_userdata(request); const char *action = afb_req_value(request, "action"); - gchar *device, *player; + gchar *device, *player = NULL; GVariant *reply; GError *error = NULL; + json_object *jval = NULL; if (!action) { afb_req_fail(request, "failed", "No action given"); @@ -1271,7 +1399,11 @@ static void bluetooth_avrcp_controls(afb_req_t request) device = return_bluez_path(request); if (device) { /* TODO: handle multiple players per device */ - player = g_strconcat(device, "/", BLUEZ_DEFAULT_PLAYER, NULL); + jval = bluez_get_property(ns, BLUEZ_AT_MEDIACONTROL, device, FALSE, "Player", NULL); + if (jval) + player = (gchar *)json_object_get_string(jval); + if (!player) + player = g_strconcat(device, "/", BLUEZ_DEFAULT_PLAYER, NULL); g_free(device); } else { player = g_strdup(ns->mediaplayer_path); @@ -1303,13 +1435,22 @@ out_success: afb_req_success(request, NULL, "Bluetooth - AVRCP controls"); } -static void bluetooth_version(afb_req_t request) +static void bluetooth_pincode(afb_req_t request) { - json_object *jresp = json_object_new_object(); + char *error = NULL; + const char *pincode; + int rc; - json_object_object_add(jresp, "version", json_object_new_string("2.0")); + pincode = afb_req_value(request, "pincode"); + rc = set_pincode(afb_req_get_api(request), pincode, &error); + + if (rc) { + afb_req_fail(request, "failed", error); + return; + } - afb_req_success(request, jresp, "Bluetooth - Binding version"); + afb_req_success(request, NULL, "Bluetooth - pincode"); + return; } static const afb_verb_t bluetooth_verbs[] = { @@ -1374,11 +1515,10 @@ static const afb_verb_t bluetooth_verbs[] = { .callback = bluetooth_avrcp_controls, .info = "AVRCP controls" }, { - .verb = "version", + .verb = "set_pincode", .session = AFB_SESSION_NONE, - .callback = bluetooth_version, - .info = "Binding API version", - }, + .callback = bluetooth_pincode, + .info = "Set pincode for outgoing pairing"}, { } /* marker for end of the array */ }; |