aboutsummaryrefslogtreecommitdiffstats
path: root/binding/bluetooth-api.c
diff options
context:
space:
mode:
Diffstat (limited to 'binding/bluetooth-api.c')
-rw-r--r--binding/bluetooth-api.c232
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 */
};