#include <string.h>
#include <murphy/common/debug.h>
-#include <murphy/common/dbus.h>
+#include <murphy/common/dbus-libdbus.h>
+#include <murphy/common/hashtbl.h>
#include <murphy/common/list.h>
+#include <murphy/common/utils.h>
#include "dbusif.h"
#include "clients.h"
#define MAKE_DBUS_VERSION(major, minor, patch) \
(((major) << 16) | ((minor) << 8) | (patch))
-#if DBUS_VERSION < MAKE_DBUS_VERSION(1, 6, 8)
-/* For old versions, we define DBusBasicValue with the member we use... */
-typedef union {
- char *str;
- double dbl;
- dbus_bool_t bool_val;
-} DBusBasicValue;
-#endif
-
struct dbusif_s {
const char *bustype;
mrp_dbus_t *dbus;
mrp_list_hook_t modems;
};
-
-static modem_t *create_modem(context_t *, const char *, const char *,
- const char *);
-static void destroy_modem(modem_t *);
-static modem_t *reference_modem(modem_t *);
-static void unreference_modem(modem_t *);
-static modem_t *find_modem_by_path(context_t *, const char *);
-static void track_modems(context_t *, bool);
-static void query_all_modems(context_t *);
-static void query_modem(modem_t *);
-static void query_handsfree(modem_t *);
-
-static int modem_property_changed_cb(mrp_dbus_t *, DBusMessage *, void *);
-static int handsfree_property_changed_cb(mrp_dbus_t *, DBusMessage *, void *);
-static void modem_query_all_cb(mrp_dbus_t *, DBusMessage *, void *);
-static void modem_query_cb(mrp_dbus_t *, DBusMessage *, void *);
-static void handsfree_query_cb(mrp_dbus_t *, DBusMessage *, void *);
-
-static void set_modem_state(modem_t *, hfp_state_t);
-
-static void parse_modem_properties(context_t *,DBusMessageIter *,const char **,
- const char **, dbus_bool_t *);
-static void parse_handsfree_properties(modem_t *, DBusMessageIter *,
- hfp_state_t *);
-static void parse_property(DBusMessageIter *, const char **name,
- int *type, DBusBasicValue *);
-static void set_property(DBusMessageIter *, const char *, int, void *);
-
-
-int dbusif_create(context_t *ctx, mrp_mainloop_t *ml)
+static int mrp_dbus_is_basic_type(mrp_dbus_type_t t)
{
- dbusif_t *dbusif;
-
- if (!(dbusif = mrp_allocz(sizeof(dbusif_t))))
- return -1;
-
- dbusif->bustype = mrp_strdup("system");
- dbusif->dbus = mrp_dbus_get(ml, dbusif->bustype, NULL);
-
- if (!dbusif->dbus) {
- mrp_log_error("bluetooth voice recognition plugin: "
- "failed to obtain DBus");
- mrp_free(dbusif);
- return -1;
- }
-
- mrp_list_init(&dbusif->modems);
-
- ctx->dbusif = dbusif;
-
- return 0;
+ return t != MRP_DBUS_TYPE_ARRAY && t != MRP_DBUS_TYPE_VARIANT &&
+ t != MRP_DBUS_TYPE_STRUCT && t != MRP_DBUS_TYPE_DICT_ENTRY &&
+ t != MRP_DBUS_TYPE_INVALID;
}
-void dbusif_destroy(context_t *ctx)
+static const char * mrp_dbus_type_to_string(mrp_dbus_type_t t)
{
- dbusif_t *dbusif;
+ static char type_str[2] = "";
- if (ctx && (dbusif = ctx->dbusif)) {
- ctx->dbusif = NULL;
+ type_str[0] = t;
- mrp_dbus_unref(dbusif->dbus);
-
- mrp_free((void *)dbusif->bustype);
- mrp_free((void *)dbusif);
- }
+ return type_str;
}
-int dbusif_start(context_t *ctx)
+static modem_t *reference_modem(modem_t *modem)
{
- track_modems(ctx, TRUE);
- query_all_modems(ctx);
- return 0;
+ if (modem && modem->refcnt >= 0)
+ modem->refcnt++;
+
+ return modem->refcnt < 0 ? NULL : modem;
}
-void dbusif_stop(context_t *ctx)
+static void unreference_modem(modem_t *modem)
{
- dbusif_t *dbusif;
- modem_t *modem;
- mrp_list_hook_t *entry, *n;
+ device_t *dev = NULL;
- track_modems(ctx, FALSE);
+ if (modem) {
+ if (modem->refcnt > 1)
+ modem->refcnt--;
+ else {
+ mrp_log_info("remove bluetooth modem '%s' @ %s (paths %s)",
+ modem->name, modem->addr, modem->path);
- if (ctx && (dbusif = ctx->dbusif)) {
- mrp_list_foreach(&dbusif->modems, entry, n) {
- modem = mrp_list_entry(entry, modem_t, link);
- destroy_modem(modem);
+ if ((dev = modem->device)) {
+ modem->device = NULL;
+ clients_remove_device(dev);
+ }
+
+ mrp_list_delete(&modem->link);
+
+ mrp_free((void *)modem->path);
+ mrp_free((void *)modem->name);
+ mrp_free((void *)modem->addr);
+
+ mrp_free((void *)modem);
}
}
}
-int dbusif_set_voice_recognition(modem_t *modem, hfp_state_t state)
+static modem_t *find_modem_by_path(context_t *ctx, const char *path)
{
- context_t *ctx;
- dbusif_t *dbusif;
- DBusMessage *msg;
- DBusMessageIter mit;
- dbus_bool_t value;
+ modem_t *modem = NULL;
+ dbusif_t *dbusif = NULL;
+ mrp_list_hook_t *entry, *n;
- if (!modem || !modem->path || !(ctx = modem->ctx) ||
- !(dbusif = ctx->dbusif))
- return -1;
+ if (!ctx || !path || !(dbusif = ctx->dbusif))
+ return NULL;
- switch (state) {
- case VOICE_RECOGNITION_ON: value = TRUE; break;
- case VOICE_RECOGNITION_OFF: value = FALSE; break;
- default: /* invalid */ return -1;
+ mrp_list_foreach(&dbusif->modems, entry, n) {
+ modem = mrp_list_entry(entry, modem_t, link);
+ if (!strcmp(path, modem->path))
+ return modem;
}
- msg = dbus_message_new_method_call("org.ofono",
- modem->path,
- "org.ofono.Handsfree",
- "SetProperty");
- if (!msg)
- return -1;
-
- dbus_message_iter_init_append(msg, &mit);
- set_property(&mit, "VoiceRecognition", DBUS_TYPE_BOOLEAN, &value);
-
- mrp_dbus_send_msg(dbusif->dbus, msg);
-
- dbus_message_unref(msg);
-
- return 0;
+ return NULL;
}
-
static modem_t *create_modem(context_t *ctx,
const char *path,
const char *name,
const char *addr)
{
- dbusif_t *dbusif;
- modem_t *modem;
+ modem_t *modem = NULL;
+ dbusif_t *dbusif = NULL;
if (!ctx || !path || !addr || !(dbusif = ctx->dbusif))
return NULL;
}
}
-static modem_t *reference_modem(modem_t *modem)
-{
- if (modem && modem->refcnt >= 0)
- modem->refcnt++;
-
- return modem->refcnt < 0 ? NULL : modem;
-}
+typedef struct {
+ mrp_dbus_type_t type;
+ void *value;
+ size_t n_values; /* for arrays */
+} property_info_t;
-static void unreference_modem(modem_t *modem)
+static property_info_t * property_info_new(mrp_dbus_type_t type)
{
- device_t *dev;
-
- if (modem) {
- if (modem->refcnt > 1)
- modem->refcnt--;
- else {
- mrp_log_info("remove bluetooth modem '%s' @ %s (paths %s)",
- modem->name, modem->addr, modem->path);
+ property_info_t *p = NULL;
- if ((dev = modem->device)) {
- modem->device = NULL;
- clients_remove_device(dev);
- }
+ if ((p = mrp_allocz(sizeof(*p)))) {
+ p->type = type;
+ p->value = 0;
+ p->n_values = 0;
+ }
- mrp_list_delete(&modem->link);
-
- mrp_free((void *)modem->path);
- mrp_free((void *)modem->name);
- mrp_free((void *)modem->addr);
-
- mrp_free((void *)modem);
- }
- }
+ return p;
}
-
-static modem_t *find_modem_by_path(context_t *ctx, const char *path)
+static void property_hash_free(void *key, void *object)
{
- dbusif_t *dbusif;
- modem_t *modem;
- mrp_list_hook_t *entry, *n;
+ property_info_t *p = object;
- if (!ctx || !path || !(dbusif = ctx->dbusif))
- return NULL;
-
- mrp_list_foreach(&dbusif->modems, entry, n) {
- modem = mrp_list_entry(entry, modem_t, link);
- if (!strcmp(path, modem->path))
- return modem;
- }
+ MRP_UNUSED(key);
- return NULL;
+ if (p)
+ mrp_free(p);
}
-static void track_modems(context_t *ctx, bool track)
+static int parse_property_value_basic(mrp_dbus_msg_t *msg,
+ const char *name,
+ mrp_dbus_type_t type,
+ void *value_out)
{
- static const char *modem_interface = "org.ofono.Modem";
- static const char *handsfree_interface = "org.ofono.Handsfree";
- static const char *member = "PropertyChanged";
+ const char *n = NULL;
- dbusif_t *dbusif;
+ if (!name || !value_out || !mrp_dbus_is_basic_type(type))
+ return FALSE;
- if (ctx && (dbusif = ctx->dbusif)) {
- if (track) {
- mrp_dbus_add_signal_handler(dbusif->dbus, NULL, NULL,
- modem_interface, member,
- modem_property_changed_cb, ctx);
- mrp_dbus_add_signal_handler(dbusif->dbus, NULL, NULL,
- handsfree_interface, member,
- handsfree_property_changed_cb, ctx);
- mrp_dbus_install_filter(dbusif->dbus, NULL, NULL,
- modem_interface, member, NULL);
- mrp_dbus_install_filter(dbusif->dbus, NULL, NULL,
- handsfree_interface, member, NULL);
- }
- else {
- mrp_dbus_del_signal_handler(dbusif->dbus, NULL, NULL,
- modem_interface, member,
- modem_property_changed_cb, ctx);
- mrp_dbus_del_signal_handler(dbusif->dbus, NULL, NULL,
- handsfree_interface, member,
- handsfree_property_changed_cb, ctx);
- mrp_dbus_remove_filter(dbusif->dbus, NULL, NULL,
- modem_interface, member, NULL);
- mrp_dbus_remove_filter(dbusif->dbus, NULL, NULL,
- handsfree_interface, member, NULL);
- }
- }
-}
+ if (mrp_dbus_msg_arg_type(msg, NULL) != MRP_DBUS_TYPE_STRING)
+ return FALSE;
+ mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_STRING, &n);
-static void query_all_modems(context_t *ctx)
-{
- dbusif_t *dbusif;
- DBusMessage *msg;
+ if (strcmp(n, name))
+ return FALSE;
- if (!ctx || !(dbusif = ctx->dbusif))
- return;
+ if (mrp_dbus_msg_arg_type(msg, NULL) != MRP_DBUS_TYPE_VARIANT)
+ return FALSE;
- msg = dbus_message_new_method_call("org.ofono", "/", "org.ofono.Manager",
- "GetModems");
- if (msg) {
- mrp_dbus_send(dbusif->dbus, "org.ofono", "/", "org.ofono.Manager",
- "GetModems", 1000, modem_query_all_cb, ctx, msg);
- }
-}
+ mrp_dbus_msg_enter_container(msg, MRP_DBUS_TYPE_VARIANT,
+ mrp_dbus_type_to_string(type));
-static void query_modem(modem_t *modem)
-{
- context_t *ctx;
- dbusif_t *dbusif;
- DBusMessage *msg;
- const char *path;
- modem_t *ref;
+ mrp_dbus_msg_read_basic(msg, type, value_out);
- if (!modem || !(ctx = modem->ctx) || !(path = modem->path) ||
- !(dbusif = ctx->dbusif))
- return;
+ mrp_dbus_msg_exit_container(msg); /* v */
- msg = dbus_message_new_method_call("org.ofono", path, "org.ofono.Modem",
- "GetProperties");
- if (msg) {
- if ((ref = reference_modem(modem))) {
- mrp_dbus_send(dbusif->dbus, "org.ofono", path, "org.ofono.Modem",
- "GetProperties", 1000, modem_query_cb, ref, msg);
- }
- }
+ return TRUE;
}
-static void query_handsfree(modem_t *modem)
+static void parse_propertites(mrp_dbus_msg_t *msg,
+ mrp_htbl_t *prop_tbl,
+ size_t size)
{
- context_t *ctx;
- dbusif_t *dbusif;
- DBusMessage *msg;
- const char *path;
- modem_t *ref;
+ size_t n_found = 0;
- if (!modem || !(ctx = modem->ctx) || !(path = modem->path) ||
- !(dbusif = ctx->dbusif))
+ if (mrp_dbus_msg_arg_type(msg, NULL) != MRP_DBUS_TYPE_ARRAY)
return;
- msg = dbus_message_new_method_call("org.ofono",path,"org.ofono.Handsfree",
- "GetProperties");
- if (msg) {
- if ((ref = reference_modem(modem))) {
- mrp_dbus_send(dbusif->dbus, "org.ofono",path,"org.ofono.Handsfree",
- "GetProperties", 1000, handsfree_query_cb, ref, msg);
- }
- }
-}
-
-static int modem_property_changed_cb(mrp_dbus_t *dbus,
- DBusMessage *msg,
- void *user_data)
-{
- context_t *ctx = (context_t *)user_data;
- dbusif_t *dbusif;
- DBusMessageIter mit;
- const char *path;
- modem_t *modem;
- const char *prop;
- int type;
- DBusBasicValue value;
+ if (!mrp_dbus_msg_enter_container(msg, MRP_DBUS_TYPE_ARRAY, "{sv}"))
+ return;
- MRP_UNUSED(dbus);
+ while (mrp_dbus_msg_enter_container(msg, MRP_DBUS_TYPE_DICT_ENTRY, NULL)) {
+ const char *prop = NULL;
+ property_info_t *p_info = NULL;
- if (ctx && (dbusif = ctx->dbusif) && dbus_message_iter_init(msg, &mit)) {
- path = dbus_message_get_path(msg);
+ mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_STRING, &prop);
- parse_property(&mit, &prop, &type, &value);
+ p_info = (property_info_t *)mrp_htbl_lookup(prop_tbl, (void*)prop);
+ if (p_info) {
+ mrp_dbus_msg_enter_container(msg, MRP_DBUS_TYPE_VARIANT, NULL);
- if (path && prop) {
- if (!strcmp(prop, "Online")) {
- modem = find_modem_by_path(ctx, path);
+ /* NOTE: Currently we handle only string arrays, should modify
+ * based on need
+ */
+ if (p_info->type == MRP_DBUS_TYPE_ARRAY)
+ mrp_dbus_msg_read_array(msg, MRP_DBUS_TYPE_STRING,
+ &p_info->value, &p_info->n_values);
+ else if (mrp_dbus_is_basic_type(p_info->type))
+ mrp_dbus_msg_read_basic(msg, p_info->type, &p_info->value);
- if (value.bool_val) {
- if (path && !modem) {
- if ((modem = create_modem(ctx, path, "", ""))) {
- query_modem(modem);
- query_handsfree(modem);
- }
- }
- }
- else {
- if (modem)
- destroy_modem(modem);
- }
- }
+ mrp_dbus_msg_exit_container(msg); /* v */
+ n_found++;
}
- }
- return FALSE;
-}
+ mrp_dbus_msg_exit_container(msg); /* "{sv}" */
-static int handsfree_property_changed_cb(mrp_dbus_t *dbus,
- DBusMessage *msg,
- void *user_data)
-{
- context_t *ctx = (context_t *)user_data;
- dbusif_t *dbusif;
- DBusMessageIter mit;
- const char *path;
- modem_t *modem;
- const char *prop;
- int type;
- DBusBasicValue value;
- hfp_state_t state;
-
- MRP_UNUSED(dbus);
-
- if (ctx && (dbusif = ctx->dbusif) && dbus_message_iter_init(msg, &mit)) {
- path = dbus_message_get_path(msg);
-
- parse_property(&mit, &prop, &type, &value);
-
- if (path && prop) {
- if (!strcmp(prop, "VoiceRecognition")) {
- if ((modem = find_modem_by_path(ctx, path))) {
- if (value.bool_val)
- state = VOICE_RECOGNITION_ON;
- else
- state = VOICE_RECOGNITION_OFF;
-
- set_modem_state(modem, state);
- }
- }
- }
+ /* check if found all requested properties */
+ if (n_found == size)
+ break;
}
- return FALSE;
+ mrp_dbus_msg_exit_container(msg); /* a{sv} */
}
-static void modem_query_all_cb(mrp_dbus_t *dbus,
- DBusMessage *msg,
- void *user_data)
+static void parse_modem_properties(mrp_dbus_msg_t *msg,
+ const char **btaddr,
+ const char **btname,
+ uint32_t *online)
{
- context_t *ctx = (context_t *)user_data;
- dbusif_t *dbusif;
- device_t *dev;
- const char *path;
- const char *addr;
- const char *name;
- dbus_bool_t online;
- modem_t *modem;
- DBusMessageIter mit, ait, sit;
-
- MRP_UNUSED(dbus);
-
- if (ctx && (dbusif = ctx->dbusif) && dbus_message_iter_init(msg, &mit)) {
- if (dbus_message_iter_get_arg_type(&mit) != DBUS_TYPE_ARRAY)
- return;
-
- dbus_message_iter_recurse(&mit, &ait);
+ bool has_handsfree_interface = FALSE;
- while (dbus_message_iter_get_arg_type(&ait) == DBUS_TYPE_STRUCT) {
- dbus_message_iter_recurse(&ait, &sit);
+ if (!msg || !btaddr || !btname || !online)
+ return;
- if (dbus_message_iter_get_arg_type(&sit) == DBUS_TYPE_OBJECT_PATH){
- dbus_message_iter_get_basic(&sit, &path);
- dbus_message_iter_next(&sit);
- parse_modem_properties(ctx, &sit, &addr, &name, &online);
+ const char **interfaces = NULL;
+ mrp_htbl_config_t conf = {
+ .nbucket = 0,
+ .nentry = 4,
+ .comp = mrp_string_comp,
+ .hash = mrp_string_hash,
+ .free = property_hash_free
+ };
+ property_info_t *info = NULL;
+ mrp_htbl_t *prop_tbl = mrp_htbl_create(&conf);
+
+ info = property_info_new(MRP_DBUS_TYPE_STRING);
+ mrp_htbl_insert(prop_tbl, "Name", info);
+ info = property_info_new(MRP_DBUS_TYPE_STRING);
+ mrp_htbl_insert(prop_tbl, "Serial", info);
+ info = property_info_new(MRP_DBUS_TYPE_BOOLEAN);
+ mrp_htbl_insert(prop_tbl, "Online", info);
+ info = property_info_new(MRP_DBUS_TYPE_ARRAY);
+ mrp_htbl_insert(prop_tbl, "Interfaces", info);
+
+ parse_propertites(msg, prop_tbl, 4);
+
+ info = (property_info_t *)mrp_htbl_lookup(prop_tbl, (void*)"Name");
+ *btname = (const char *)info->value;
+ info = (property_info_t *)mrp_htbl_lookup(prop_tbl, (void*)"Serial");
+ *btaddr = (const char *)info->value;
+ info = (property_info_t *)mrp_htbl_lookup(prop_tbl, (void*)"Online");
+ *online = *(uint32_t *)info->value;
+ info = (property_info_t *)mrp_htbl_lookup(prop_tbl, (void*)"Interfaces");
+ interfaces = (const char **)info->value;
+ if (interfaces) {
+ size_t i;
+
+ for (i = 0; i < info->n_values; i++) {
+ if (!strcmp(interfaces[i], "org.ofono.Handsfree")) {
+ has_handsfree_interface = TRUE;
+ break;
+ }
+ }
+ }
- if (path && online) {
- if ((dev = clients_add_device(ctx, addr)) &&
- (modem = create_modem(ctx, path, name, addr)))
- {
- modem->device = dev;
- dev->modem = modem;
+ mrp_htbl_destroy(prop_tbl, TRUE);
- mrp_log_info("created bluetooth modem '%s' @ %s "
- "(path %s)", modem->name, modem->addr,
- modem->path);
- query_handsfree(modem);
- }
- }
- }
-
- dbus_message_iter_next(&ait);
- }
+ if (!has_handsfree_interface) {
+ // *btname = "<unknown>";
+ // *btaddr = "<unknown>";
+ *online = FALSE;
}
}
static void modem_query_cb(mrp_dbus_t *dbus,
- DBusMessage *msg,
+ mrp_dbus_msg_t *msg,
void *user_data)
{
modem_t *modem = (modem_t *)user_data;
- device_t *dev;
- context_t *ctx;
- const char *addr;
- const char *name;
- dbus_bool_t online;
- DBusMessageIter mit;
+ context_t *ctx = NULL;
MRP_UNUSED(dbus);
if (modem && (ctx = modem->ctx)) {
+ if (mrp_dbus_msg_type(msg) != MRP_DBUS_MESSAGE_TYPE_ERROR) {
+ const char *addr = NULL;
+ const char *name = NULL;
+ uint32_t online;
+ device_t *dev = NULL;
- if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR) {
- if (dbus_message_iter_init(msg, &mit)) {
- parse_modem_properties(ctx, &mit, &addr, &name, &online);
+ parse_modem_properties(msg, &addr, &name, &online);
- if (!online || !name || !(dev = clients_add_device(ctx, addr)))
- destroy_modem(modem);
- else {
- mrp_free((void *)modem->addr);
- mrp_free((void *)modem->name);
+ if (!online || !name || !(dev = clients_add_device(ctx, addr)))
+ destroy_modem(modem);
+ else {
+ mrp_free((void *)modem->addr);
+ mrp_free((void *)modem->name);
- modem->addr = mrp_strdup(addr);
- modem->name = mrp_strdup(name);
- modem->device = dev;
+ modem->addr = mrp_strdup(addr);
+ modem->name = mrp_strdup(name);
+ modem->device = dev;
- dev->modem = modem;
+ dev->modem = modem;
- mrp_log_info("created bluetooth modem '%s' @ %s (path %s)",
- modem->name, modem->addr, modem->path);
- }
+ mrp_log_info("created bluetooth modem '%s' @ %s (path %s)",
+ modem->name, modem->addr, modem->path);
}
}
}
}
-static void handsfree_query_cb(mrp_dbus_t *dbus,
- DBusMessage *msg,
- void *user_data)
+static void query_modem(modem_t *modem)
{
- modem_t *modem = (modem_t *)user_data;
- context_t *ctx;
- hfp_state_t state;
- DBusMessageIter mit;
+ context_t *ctx = NULL;
+ dbusif_t *dbusif = NULL;
+ modem_t *ref = NULL;
- MRP_UNUSED(dbus);
+ if (!modem || !modem->path || !(ctx = modem->ctx) ||
+ !(dbusif = ctx->dbusif))
+ return;
- if (modem && (ctx = modem->ctx)) {
+ if ((ref = reference_modem(modem))) {
+ mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(dbusif->dbus,
+ "org.ofono",
+ modem->path,
+ "org.ofono.Modem",
+ "GetProperties");
+ mrp_dbus_send(dbusif->dbus, "org.ofono", modem->path, "org.ofono.Modem",
+ "GetProperties", 1000, modem_query_cb, ref, msg);
+ mrp_dbus_msg_unref(msg);
+ }
+}
+
+static void parse_handsfree_properties(modem_t *modem,
+ mrp_dbus_msg_t *msg,
+ hfp_state_t *state)
+{
+ mrp_htbl_config_t conf = {
+ .nbucket = 0,
+ .nentry = 1,
+ .comp = mrp_string_comp,
+ .hash = mrp_string_hash,
+ .free = property_hash_free
+ };
+ property_info_t *info = NULL;
+ mrp_htbl_t *prop_tbl = NULL;
+
+ if (!modem || !msg || !state)
+ return;
- if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR) {
+ *state = VOICE_RECOGNITION_UNKNOWN;
- if (dbus_message_iter_init(msg, &mit)) {
- parse_handsfree_properties(modem, &mit, &state);
- set_modem_state(modem, state);
- }
+ prop_tbl = mrp_htbl_create(&conf);
+ info = property_info_new(MRP_DBUS_TYPE_BOOLEAN);
+ mrp_htbl_insert(prop_tbl, "VoiceRecognition", info);
- unreference_modem(modem);
- }
- }
+ parse_propertites(msg, prop_tbl, 1);
+
+ *state = (uint32_t)(ptrdiff_t)((property_info_t *)mrp_htbl_lookup(
+ prop_tbl, (void*)"VoiceRecognition"))->value ?
+ VOICE_RECOGNITION_ON : VOICE_RECOGNITION_OFF;
+
+ mrp_htbl_destroy(prop_tbl, TRUE);
}
static void set_modem_state(modem_t *modem, hfp_state_t state)
if (state == modem->state)
return;
+ modem->state = state;
+
+ if (!(device = modem->device))
+ return;
+
switch (state) {
case VOICE_RECOGNITION_ON:
mrp_log_info("bluetooth modem: setting voicerecognition on "
"for modem %s", modem->addr);
- modem->state = VOICE_RECOGNITION_ON;
- if ((device = modem->device) && (card = device->card)) {
+ if ((card = device->card)) {
pulseif_set_card_profile(card, "hfgw");
}
break;
case VOICE_RECOGNITION_OFF:
mrp_log_info("bluetooth modem: setting voicerecognition off "
"for modem %s", modem->addr);
- modem->state = VOICE_RECOGNITION_OFF;
- if ((device = modem->device)) {
- clients_stop_recognising_voice(device);
- }
+ clients_stop_recognising_voice(device);
break;
default:
}
}
-static void parse_modem_properties(context_t *ctx,
- DBusMessageIter *sit,
- const char **btaddr,
- const char **btname,
- dbus_bool_t *online)
+static void handsfree_query_cb(mrp_dbus_t *dbus,
+ mrp_dbus_msg_t *msg,
+ void *user_data)
{
- const char *prop;
- int type;
- DBusBasicValue value;
- DBusMessageIter ait, dit, vit, iit;
- dbus_bool_t has_handsfree_interface = FALSE;
+ modem_t *modem = (modem_t *)user_data;
+ hfp_state_t state = VOICE_RECOGNITION_UNKNOWN;
- if (!ctx || !sit || !btaddr || !btname || !online)
- return;
+ MRP_UNUSED(dbus);
- *btname = "<unknown>";
- *btaddr = "<unknown>";
- *online = FALSE;
+ if (!modem) return;
- if (dbus_message_iter_get_arg_type(sit) != DBUS_TYPE_ARRAY)
- return;
+ if (mrp_dbus_msg_type(msg) != MRP_DBUS_MESSAGE_TYPE_ERROR) {
+ parse_handsfree_properties(modem, msg, &state);
+ set_modem_state(modem, state);
+ }
- dbus_message_iter_recurse(sit, &ait);
-
- while (dbus_message_iter_get_arg_type(&ait) == DBUS_TYPE_DICT_ENTRY) {
+ unreference_modem(modem);
+}
- dbus_message_iter_recurse(&ait, &dit);
+static void query_handsfree(modem_t *modem)
+{
+ context_t *ctx = NULL;;
+ dbusif_t *dbusif = NULL;
+ modem_t *ref = NULL;
- dbus_message_iter_get_basic(&dit, &prop);
- dbus_message_iter_next(&dit);
+ if (!modem || !modem->path || !(ctx = modem->ctx) ||
+ !(dbusif = ctx->dbusif))
+ return;
- dbus_message_iter_recurse(&dit, &vit);
- type = dbus_message_iter_get_arg_type(&vit);
+ if ((ref = reference_modem(modem))) {
+ mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(dbusif->dbus,
+ "org.ofono",
+ modem->path,
+ "org.ofono.Handsfree",
+ "GetProperties");
+ mrp_dbus_send(dbusif->dbus, "org.ofono", modem->path,
+ "org.ofono.Handsfree", "GetProperties", 1000,
+ handsfree_query_cb, ref, msg);
+ mrp_dbus_msg_unref(msg);
+ }
+}
- if (type != DBUS_TYPE_ARRAY) {
- memset(&value, 0, sizeof(value));
- dbus_message_iter_get_basic(&vit, &value);
+static int modem_property_changed_cb(mrp_dbus_t *dbus,
+ mrp_dbus_msg_t *msg,
+ void *user_data)
+{
+ context_t *ctx = (context_t *)user_data;
+ const char *path = NULL;
+ uint32_t is_online = FALSE;
- if (!strcmp(prop, "Online"))
- *online = value.bool_val;
- else if(!strcmp(prop, "Name"))
- *btname = value.str;
- else if (!strcmp(prop, "Serial"))
- *btaddr = value.str;
- }
- else {
- if (!strcmp(prop, "Interfaces")) {
- dbus_message_iter_recurse(&vit, &iit);
+ MRP_UNUSED(dbus);
- while (dbus_message_iter_get_arg_type(&iit)==DBUS_TYPE_STRING){
- dbus_message_iter_get_basic(&iit, &value);
+ if (!ctx || !ctx->dbusif ||
+ !(path = mrp_dbus_msg_path(msg)))
+ return FALSE;
- if (!strcmp(value.str, "org.ofono.Handsfree")) {
- has_handsfree_interface = TRUE;
- break;
- }
+ if (parse_property_value_basic(msg, "Online", MRP_DBUS_TYPE_BOOLEAN,
+ &is_online)) {
+ modem_t *modem = find_modem_by_path(ctx, path);
- dbus_message_iter_next(&iit);
+ if (is_online) {
+ if (!modem) {
+ if ((modem = create_modem(ctx, path, "", ""))) {
+ query_modem(modem);
+ query_handsfree(modem);
}
}
+ } else if (modem) {
+ destroy_modem(modem);
}
-
- dbus_message_iter_next(&ait);
}
- if (!has_handsfree_interface) {
- *btname = "<unknown>";
- *btaddr = "<unknown>";
- *online = FALSE;
+ return FALSE;
+}
+
+
+static int handsfree_property_changed_cb(mrp_dbus_t *dbus,
+ mrp_dbus_msg_t *msg,
+ void *user_data)
+{
+ context_t *ctx = (context_t *)user_data;
+ const char *path = mrp_dbus_msg_path(msg);
+ modem_t *modem = NULL;
+ uint32_t state = FALSE;
+
+ MRP_UNUSED(dbus);
+
+ if (!ctx || !ctx->dbusif || !path)
+ return FALSE;
+
+ if (!(modem = find_modem_by_path(ctx, path)))
+ return FALSE;
+
+ if (parse_property_value_basic(msg, "VoiceRecognition",
+ MRP_DBUS_TYPE_BOOLEAN, &state)) {
+ set_modem_state(modem,
+ state ? VOICE_RECOGNITION_ON : VOICE_RECOGNITION_OFF);
}
+
+ return FALSE;
}
-static void parse_handsfree_properties(modem_t *modem,
- DBusMessageIter *sit,
- hfp_state_t *state)
+static void modem_query_all_cb(mrp_dbus_t *dbus,
+ mrp_dbus_msg_t *msg,
+ void *user_data)
{
- const char *prop;
- int type;
- DBusBasicValue value;
- DBusMessageIter ait, dit, vit;
+ context_t *ctx = (context_t *)user_data;
+ modem_t *modem;
- if (!modem || !sit || !state)
- return;
+ MRP_UNUSED(dbus);
- *state = VOICE_RECOGNITION_UNKNOWN;
+ if (!ctx || !ctx->dbusif)
+ return;
- if (dbus_message_iter_get_arg_type(sit) != DBUS_TYPE_ARRAY)
+ if (mrp_dbus_msg_arg_type(msg, NULL) != MRP_DBUS_TYPE_ARRAY)
return;
- dbus_message_iter_recurse(sit, &ait);
+ mrp_dbus_msg_enter_container(msg, MRP_DBUS_TYPE_ARRAY, "(oa{sv})");
- while (dbus_message_iter_get_arg_type(&ait) == DBUS_TYPE_DICT_ENTRY) {
+ while (mrp_dbus_msg_enter_container(msg, MRP_DBUS_TYPE_STRUCT, NULL)) {
+ device_t *dev;
+ const char *path = NULL;
+ const char *addr;
+ const char *name;
+ uint32_t online;
- dbus_message_iter_recurse(&ait, &dit);
+ mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_OBJECT_PATH, &path);
- dbus_message_iter_get_basic(&dit, &prop);
- dbus_message_iter_next(&dit);
+ parse_modem_properties(msg, &addr, &name, &online);
- dbus_message_iter_recurse(&dit, &vit);
- type = dbus_message_iter_get_arg_type(&vit);
+ mrp_log_info("Modem details: %s %s %s %d", path, addr, name, online);
- if (type != DBUS_TYPE_ARRAY) {
- memset(&value, 0, sizeof(value));
- dbus_message_iter_get_basic(&vit, &value);
+ if (path && online) {
+ if ((dev = clients_add_device(ctx, addr)) &&
+ (modem = create_modem(ctx, path, name, addr)))
+ {
+ modem->device = dev;
+ dev->modem = modem;
- if (!strcmp(prop, "VoiceRecognition")) {
- if (value.bool_val)
- *state = VOICE_RECOGNITION_ON;
- else
- *state = VOICE_RECOGNITION_OFF;
+ mrp_log_info("created bluetooth modem '%s' @ %s "
+ "(path %s)", modem->name, modem->addr,
+ modem->path);
+ query_handsfree(modem);
}
}
- dbus_message_iter_next(&ait);
+ mrp_dbus_msg_exit_container(msg); /* (oa{sv}) */
}
+
+ mrp_dbus_msg_exit_container(msg); /* a(oa{sv}) */
}
-static void parse_property(DBusMessageIter *it,
- const char **name,
- int *type,
- DBusBasicValue *value)
+static void track_modems(context_t *ctx, bool track)
{
- DBusMessageIter vit;
+ static const char *modem_interface = "org.ofono.Modem";
+ static const char *handsfree_interface = "org.ofono.Handsfree";
+ static const char *member = "PropertyChanged";
+ dbusif_t *dbusif = NULL;
+
+ if (!ctx || !(dbusif = ctx->dbusif))
+ return;
+
+ if (track) {
+ mrp_dbus_add_signal_handler(dbusif->dbus, NULL, NULL,
+ modem_interface, member,
+ modem_property_changed_cb, ctx);
+ mrp_dbus_add_signal_handler(dbusif->dbus, NULL, NULL,
+ handsfree_interface, member,
+ handsfree_property_changed_cb, ctx);
+ mrp_dbus_install_filter(dbusif->dbus, NULL, NULL,
+ modem_interface, member, NULL);
+ mrp_dbus_install_filter(dbusif->dbus, NULL, NULL,
+ handsfree_interface, member, NULL);
+ }
+ else {
+ mrp_dbus_del_signal_handler(dbusif->dbus, NULL, NULL,
+ modem_interface, member,
+ modem_property_changed_cb, ctx);
+ mrp_dbus_del_signal_handler(dbusif->dbus, NULL, NULL,
+ handsfree_interface, member,
+ handsfree_property_changed_cb, ctx);
+ mrp_dbus_remove_filter(dbusif->dbus, NULL, NULL,
+ modem_interface, member, NULL);
+ mrp_dbus_remove_filter(dbusif->dbus, NULL, NULL,
+ handsfree_interface, member, NULL);
+ }
+}
- if (it && name && type && value) {
- if (dbus_message_iter_get_arg_type(it) != DBUS_TYPE_STRING)
- goto failed;
+static void query_all_modems(context_t *ctx)
+{
+ uint32_t query_id;
+ dbusif_t *dbusif = NULL;
- dbus_message_iter_get_basic(it, name);
+ if (!ctx || !(dbusif = ctx->dbusif))
+ return;
- if (!dbus_message_iter_next(it))
- goto failed;
+ query_id = mrp_dbus_call(dbusif->dbus,
+ "org.ofono", "/", "org.ofono.Manager",
+ "GetModems", 1000, modem_query_all_cb, ctx,
+ MRP_DBUS_TYPE_INVALID);
+ if (query_id == 0) {
+ /* query modems failed */
+ }
+}
- if (dbus_message_iter_get_arg_type(it) != DBUS_TYPE_VARIANT)
- goto failed;
+static void set_property(mrp_dbus_msg_t *msg,
+ const char *name,
+ mrp_dbus_type_t type,
+ void *value)
+{
+ mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_DICT_ENTRY, NULL);
- dbus_message_iter_recurse(it, &vit);
+ mrp_dbus_msg_append_basic(msg, DBUS_TYPE_STRING, (void*)name);
- if ((*type = dbus_message_iter_get_arg_type(&vit)) == DBUS_TYPE_ARRAY)
- goto failed;
+ mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_VARIANT, NULL);
+ mrp_dbus_msg_append_basic(msg, (char)type, value);
+ mrp_dbus_msg_close_container(msg); /* variant */
- dbus_message_iter_get_basic(&vit, value);
+ mrp_dbus_msg_close_container(msg); /* dictionary */
+}
- return;
+int dbusif_create(context_t *ctx, mrp_mainloop_t *ml)
+{
+ dbusif_t *dbusif;
+
+ if (!(dbusif = mrp_allocz(sizeof(dbusif_t))))
+ return -1;
+
+ dbusif->bustype = mrp_strdup("system");
+ dbusif->dbus = mrp_dbus_get(ml, dbusif->bustype, NULL);
+
+ if (!dbusif->dbus) {
+ mrp_log_error("bluetooth voice recognition plugin: "
+ "failed to obtain DBus");
+ mrp_free(dbusif);
+ return -1;
}
- failed:
- *name = "<unknown>";
- *type = 0;
- memset(value, 0, sizeof(*value));
+ mrp_list_init(&dbusif->modems);
+
+ ctx->dbusif = dbusif;
+
+ return 0;
}
-static void set_property(DBusMessageIter *it,
- const char *name,
- int type,
- void *value)
+void dbusif_destroy(context_t *ctx)
{
- char type_str[2] = { type, 0 };
- DBusMessageIter vit;
+ dbusif_t *dbusif;
+
+ if (ctx && (dbusif = ctx->dbusif)) {
+ ctx->dbusif = NULL;
- dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &name);
+ mrp_dbus_unref(dbusif->dbus);
- dbus_message_iter_open_container(it, DBUS_TYPE_VARIANT, type_str, &vit);
- dbus_message_iter_append_basic(&vit, type, value);
- dbus_message_iter_close_container(it, &vit);
+ mrp_free((void *)dbusif->bustype);
+ mrp_free((void *)dbusif);
+ }
+}
+
+int dbusif_start(context_t *ctx)
+{
+ track_modems(ctx, TRUE);
+ query_all_modems(ctx);
+ return 0;
+}
+
+void dbusif_stop(context_t *ctx)
+{
+ dbusif_t *dbusif;
+ modem_t *modem;
+ mrp_list_hook_t *entry, *n;
+
+ track_modems(ctx, FALSE);
+
+ if (ctx && (dbusif = ctx->dbusif)) {
+ mrp_list_foreach(&dbusif->modems, entry, n) {
+ modem = mrp_list_entry(entry, modem_t, link);
+ destroy_modem(modem);
+ }
+ }
}
+int dbusif_set_voice_recognition(modem_t *modem, hfp_state_t state)
+{
+ context_t *ctx = NULL;
+ dbusif_t *dbusif = NULL;;
+ mrp_dbus_msg_t *msg = NULL;
+ uint32_t value;
+
+ if (!modem || !modem->path || !(ctx = modem->ctx) ||
+ !(dbusif = ctx->dbusif))
+ return -1;
+
+ switch (state) {
+ case VOICE_RECOGNITION_ON: value = TRUE; break;
+ case VOICE_RECOGNITION_OFF: value = FALSE; break;
+ default: /* invalid */ return -1;
+ }
+
+ msg = mrp_dbus_msg_method_call(dbusif->dbus, "org.ofono",
+ modem->path,
+ "org.ofono.Handsfree",
+ "SetProperty");
+
+ if (!msg)
+ return -1;
+
+ set_property(msg, "VoiceRecognition", MRP_DBUS_TYPE_BOOLEAN, &value);
+
+ mrp_dbus_send_msg(dbusif->dbus, msg);
+
+ mrp_dbus_msg_unref(msg);
+
+ return 0;
+}
+
+
/*
* Local Variables:
* c-basic-offset: 4