static gboolean bt_delete_all_facts() { OhmFactStore *fs = ohm_fact_store_get_fact_store(); GSList *list = ohm_fact_store_get_facts_by_name(fs, BT_DEVICE); gboolean resolve_all = FALSE; OHM_DEBUG(DBG_BT, "Bluez went away!"); while (list) { OhmFact *bt_connected = (OhmFact *) list->data; gboolean disconnect_a2dp = disconnect_device(bt_connected, BT_TYPE_A2DP); gboolean disconnect_hsp = disconnect_device(bt_connected, BT_TYPE_HSP); ohm_fact_store_remove(fs, bt_connected); g_object_unref(bt_connected); if (disconnect_a2dp || disconnect_hsp) resolve_all = TRUE; list = ohm_fact_store_get_facts_by_name(fs, BT_DEVICE); } return resolve_all; }
void fsif_init(OhmPlugin *plugin) { (void)plugin; fs = ohm_fact_store_get_fact_store(); updated_id = g_signal_connect(G_OBJECT(fs), "updated" , G_CALLBACK(updated_cb) , NULL); inserted_id = g_signal_connect(G_OBJECT(fs), "inserted", G_CALLBACK(inserted_cb), NULL); removed_id = g_signal_connect(G_OBJECT(fs), "removed" , G_CALLBACK(removed_cb) , NULL); }
static void profile_value_change(const char *profile, const char *key, const char *val, const char *type, void *dummy) { /* A value has changed in the currently active value */ OhmFactStore *fs = ohm_fact_store_get_fact_store(); OhmFact *fact = NULL; /* get the previous fact with the profile name */ GSList *list = ohm_fact_store_get_facts_by_name(fs, FACTSTORE_PROFILE); (void) profile; (void) type; (void) dummy; OHM_DEBUG(DBG_PROFILE, "profile value change: '%s', '%s'", key, val); if (g_slist_length(list) != 1) { OHM_DEBUG(DBG_PROFILE, "Error: there isn't a unique profile fact"); return; } fact = list->data; if (fact && key) { GValue *gval = NULL; gval = ohm_fact_get(fact, key); if (gval && G_VALUE_TYPE(gval) == G_TYPE_STRING && strcmp(val, g_value_get_string(gval)) == 0) { /* the value is already there, no need to trigger an update */ return; } gval = NULL; /* change the value */ if (val) gval = ohm_value_from_string(val); OHM_DEBUG(DBG_PROFILE, "changing key %s with new value '%s'", key, val); ohm_fact_set(fact, key, gval); } else { OHM_DEBUG(DBG_PROFILE, "Error, no facts or empty key"); } return; }
static int profile_load_state(void) { OhmFactStore *fs = ohm_fact_store_get_fact_store(); OhmFact *fact; GSList *l, *n; gchar key[128]; GValue *value; FILE *fp; int err; if ((fp = fopen(PROFILE_SAVE_PATH, "r")) == NULL) { if (errno != ENOENT) OHM_ERROR("profile: could not load saved state from %s (%d: %s)", PROFILE_SAVE_PATH, errno, strerror(errno)); return errno; } /* remove any old profile facts */ l = ohm_fact_store_get_facts_by_name(fs, FACTSTORE_PROFILE); while (l != NULL) { n = l->next; ohm_fact_store_remove(fs, l->data); l = n; } /* create new fact and populate it with saved fields */ if ((fact = ohm_fact_new(FACTSTORE_PROFILE)) == NULL) { OHM_ERROR("profile: failed to create fact %s", FACTSTORE_PROFILE); fclose(fp); return ENOMEM; } while ((err = load_field(fp, key, sizeof(key), &value)) == 0) ohm_fact_set(fact, key, value); fclose(fp); if (err != ENOENT) { g_object_unref(fact); OHM_ERROR("profile: failed to load saved state"); return err; } ohm_fact_store_insert(fs, fact); OHM_INFO("profile: saved state loaded"); return 0; }
static gboolean bt_any_to_disconnected(const gchar *type, const gchar *path, enum bt_state prev_state, enum bt_state new_state) { (void) new_state; OhmFactStore *fs = ohm_fact_store_get_fact_store(); OhmFact *bt_connected = bt_get_connected(path); GValue *gval = NULL; OHM_DEBUG(DBG_BT, "running dres with type %s and setting device off", type); if (!bt_connected) return FALSE; if (prev_state == BT_STATE_NONE || prev_state == BT_STATE_CONNECTING || prev_state == BT_STATE_DISCONNECTED || !disconnect_device(bt_connected, type)) { OHM_DEBUG(DBG_BT, "there was nothing to disconnect"); } /* see if the other profiles are also disconnected: if yes, * remove the fact */ if (strcmp(type, BT_TYPE_A2DP) == 0) { gval = ohm_fact_get(bt_connected, BT_TYPE_HSP); } else { gval = ohm_fact_get(bt_connected, BT_TYPE_A2DP); } if ((gval == NULL || G_VALUE_TYPE(gval) != G_TYPE_STRING || strcmp(g_value_get_string(gval), BT_STATE_DISCONNECTED_S) == 0)) { ohm_fact_store_remove(fs, bt_connected); g_object_unref(bt_connected); bt_connected = NULL; } /* this is now ran in disconnect_device */ /* dres_accessory_request(type, -1, 0); */ return TRUE; }
/* get the fact representing the connected device */ static OhmFact * bt_get_connected(const gchar *path) { OhmFactStore *fs = ohm_fact_store_get_fact_store(); OhmFact *ret = NULL; GSList *e, *list = ohm_fact_store_get_facts_by_name(fs, BT_DEVICE); for (e = list; e != NULL; e = g_slist_next(e)) { OhmFact *tmp = (OhmFact *) e->data; GValue *gval = ohm_fact_get(tmp, "bt_path"); if (gval && G_VALUE_TYPE(gval) == G_TYPE_STRING && strcmp(path, g_value_get_string(gval)) == 0) { ret = e->data; break; } } return ret; }
void action_init(OhmPlugin *plugin) { char *register_name = "signaling.register_enforcement_point"; char *unregister_name = "signaling.unregister_enforcement_point"; char *register_signature = (char *)register_ep_SIGNATURE; char *unregister_signature = (char *)unregister_ep_SIGNATURE; char *signals[] = {"dsp_actions", NULL}; (void)plugin; ENTER; ohm_module_find_method(register_name, ®ister_signature, (void *)®ister_ep); ohm_module_find_method(unregister_name, &unregister_signature, (void *)&unregister_ep); if (!register_ep || !unregister_ep) { OHM_ERROR("dspep: can't find mandatory signaling methods. " "DSP enforcement point disabled"); } else { if ((conn = register_ep("dspep", signals)) == NULL) { OHM_ERROR("dspep: failed to register to receive '%s' signals. " "DSP enforcement point disabled", signals[0]); } else { factstore = ohm_fact_store_get_fact_store(); decision_id = g_signal_connect(conn, "on-decision", G_CALLBACK(decision_signal_cb), NULL); keychange_id = g_signal_connect(conn, "on-key-change", G_CALLBACK(key_change_signal_cb), NULL); OHM_INFO("dspep: DSP enforcement point enabled"); } } LEAVE; }
void fsif_exit(OhmPlugin *plugin) { (void)plugin; fs = ohm_fact_store_get_fact_store(); if (g_signal_handler_is_connected(G_OBJECT(fs), updated_id)) { g_signal_handler_disconnect(G_OBJECT(fs), updated_id); updated_id = 0; } if (g_signal_handler_is_connected(G_OBJECT(fs), inserted_id)) { g_signal_handler_disconnect(G_OBJECT(fs), inserted_id); inserted_id = 0; } if (g_signal_handler_is_connected(G_OBJECT(fs), removed_id)) { g_signal_handler_disconnect(G_OBJECT(fs), removed_id); removed_id = 0; } }
DBusHandlerResult bt_device_removed(DBusConnection *c, DBusMessage * msg, void *data) { /* This is called apparently anytime a device does not tell that it * has been removed itself. We somehow need to ensure that this * device actually is a HSP or A2DP device. */ OhmFactStore *fs = ohm_fact_store_get_fact_store(); gchar *path = NULL; (void) data; (void) c; if (!msg) goto end; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { OhmFact *bt_connected = bt_get_connected(path); if (bt_connected) { gboolean disconnect_a2dp = disconnect_device(bt_connected, BT_TYPE_A2DP); gboolean disconnect_hsp = disconnect_device(bt_connected, BT_TYPE_HSP); ohm_fact_store_remove(fs, bt_connected); g_object_unref(bt_connected); if (disconnect_a2dp || disconnect_hsp) dres_all(); } /* else a bt device disconnected but there were no known bt headsets * connected, just disregard */ } end: return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
static void plugin_init(OhmPlugin *plugin) { (void)plugin; GObject *conn = NULL; gulong decision_cb; gulong keychange_cb; const char *port_str; char *e; unsigned short port; char *signals[] = { "video_actions", NULL }; OHM_DEBUG_INIT(video); OHM_INFO("Video EP: init ..."); do { if (!(port_str = ohm_plugin_get_param(plugin, "notification-port"))) port = VIDEOEP_NOTIFICATION_PORT; else { port = strtoul(port_str, &e, 10); if (*e != '\0') { OHM_ERROR("videoep: invalid notification port '%s'", port_str); port = VIDEOEP_NOTIFICATION_PORT; } } if (register_ep == NULL) { OHM_ERROR("videoep: 'signaling.register_enforcement_point()' " "not found"); break; } if ((conn = register_ep("videoep", signals)) == NULL) { OHM_ERROR("videoep: Failed to initialize VieoEP"); break; } if ((videoep = malloc(sizeof(*videoep))) == NULL) { OHM_ERROR("videoep: Can't allocate memory for 'videoep'"); break; } decision_cb = g_signal_connect(conn, "on-decision", G_CALLBACK(decision_signal_cb), (gpointer)videoep); keychange_cb = g_signal_connect(conn, "on-key-change", G_CALLBACK(key_change_signal_cb), (gpointer)videoep); memset(videoep, 0, sizeof(*videoep)); videoep->fs = ohm_fact_store_get_fact_store(); videoep->conn = conn; videoep->decision_cb = decision_cb; videoep->keychange_cb = keychange_cb; videoep->xr = xrt_init(":0"); videoep->notif = notify_init(port); xrt_connect_to_xserver(videoep->xr); return; /* everything went OK */ } while(0); /* Something failed */ if (conn != NULL) unregister_ep(videoep->conn); free(videoep); }
static int is_spurious_event(char *device, int driver, int connected) { /* * Filter out obviously spurious/duplicate events. Spurious events are * events that obviously do not represent any state change (eg. getting * a connected=0 event while already in disconnected state). */ GSList *list; OhmFact *fact; GValue *gval; int val, dmatch, cmatch, spurious = FALSE; OhmFactStore *store; store = ohm_fact_store_get_fact_store(); list = ohm_fact_store_get_facts_by_name(store, FACT_DEVICE_ACCESSIBLE); for ( ; list ; list = list->next) { fact = (OhmFact *)list->data; gval = ohm_fact_get(fact, "name"); if (!gval || G_VALUE_TYPE(gval) != G_TYPE_STRING) continue; if (strcmp(g_value_get_string(gval), device)) continue; if (driver != -1 && (gval = ohm_fact_get(fact, "driver")) != NULL) { switch (G_VALUE_TYPE(gval)) { case G_TYPE_INT: val = g_value_get_int(gval); break; case G_TYPE_UINT: val = g_value_get_uint(gval); break; case G_TYPE_LONG: val = g_value_get_long(gval); break; case G_TYPE_ULONG: val = g_value_get_ulong(gval); break; default: val = driver; /* ignored (ie. match) */ } dmatch = (val == driver); } else dmatch = TRUE; if (connected != -1 && (gval=ohm_fact_get(fact,"connected")) != NULL) { switch (G_VALUE_TYPE(gval)) { case G_TYPE_INT: val = g_value_get_int(gval); break; case G_TYPE_UINT: val = g_value_get_uint(gval); break; case G_TYPE_LONG: val = g_value_get_long(gval); break; case G_TYPE_ULONG: val = g_value_get_ulong(gval); break; default: val = connected; /* ignored (ie. match) */ } cmatch = (val == connected); } else cmatch = TRUE; spurious = dmatch && cmatch; /* no change is a spurious event */ break; } OHM_DEBUG(DBG_INFO, "%s, driver: %d, connected: %d is %sa spurious event", device, driver, connected, spurious ? "" : "not "); return spurious; }
static gboolean profile_create_fact(const char *profile, profileval_t *values) { OhmFactStore *fs = ohm_fact_store_get_fact_store(); GSList *list = NULL; OhmFact *fact = NULL; GValue *gval = NULL; if (!profile) return FALSE; /* get the previous fact with the profile name */ list = ohm_fact_store_get_facts_by_name(fs, FACTSTORE_PROFILE); if (g_slist_length(list) > 1) { OHM_DEBUG(DBG_PROFILE, "Error: multiple profile facts"); return FALSE; } if (g_slist_length(list) == 1) { fact = list->data; if (fact) { GSList *fields = NULL, *e = NULL; gboolean process = TRUE; /* remove existing fields */ do { fields = ohm_fact_get_fields(fact); gboolean found = FALSE; for (e = fields; e != NULL; e = g_slist_next(e)) { GQuark qk = (GQuark)GPOINTER_TO_INT(e->data); const gchar *field_name = g_quark_to_string(qk); ohm_fact_del(fact, field_name); found = TRUE; break; } if (!found) process = FALSE; } while (process); } } else { /* no previous fact */ OHM_DEBUG(DBG_PROFILE, "Creating a new profile fact"); fact = ohm_fact_new(FACTSTORE_PROFILE); /* put the fact in the factstore -- this way we have the same * update semantics (update called on each key) */ ohm_fact_store_insert(fs, fact); /* TODO: check return */ } /* fill the fact with the profile name and the values */ OHM_DEBUG(DBG_PROFILE, "setting key %s with value %s", PROFILE_NAME_KEY, profile); gval = ohm_value_from_string(profile); ohm_fact_set(fact, PROFILE_NAME_KEY, gval); if (values) { while (values->pv_key) { if (values->pv_val) { OHM_DEBUG(DBG_PROFILE, "setting key %s with value %s", values->pv_key, values->pv_val); gval = ohm_value_from_string(values->pv_val); ohm_fact_set(fact, values->pv_key, gval); } values++; } } OHM_DEBUG(DBG_PROFILE, "created fact: fs: %p, fact: %p", fs, fact); profile_save_state(fact); return TRUE; }
static gboolean bt_state_changed(const gchar *type, const gchar *path, const gchar *state) { OhmFactStore *fs = ohm_fact_store_get_fact_store(); gchar *prev_state = NULL; OhmFact *bt_connected = bt_get_connected(path); gboolean run_dres = FALSE; GValue *gval_state; gboolean bt_audio_connected = FALSE; //OHM_DEBUG(DBG_BT, "type: %s, state: %s", type, state); if (strcmp(type, BT_TYPE_AUDIO) == 0) { if (bt_connected) { gval_state = ohm_value_from_string(state); ohm_fact_set(bt_connected, type, gval_state); } if (strcmp(state, BT_STATE_CONNECTED_S) == 0) { /* Get a2dp and hsp status if AudioSink or Headset changed to * connected or playing before Audio state changed to connected. */ get_properties(path, BT_INTERFACE_A2DP, get_properties_cb); get_properties(path, BT_INTERFACE_HSP, get_properties_cb); } return TRUE; } if(bt_connected) { gval_state = ohm_fact_get(bt_connected, BT_TYPE_AUDIO); if (gval_state != NULL && G_VALUE_TYPE(gval_state) == G_TYPE_STRING) { bt_audio_connected = strcmp(g_value_get_string(gval_state), BT_STATE_CONNECTED_S) == 0 ? TRUE : FALSE; } } /* In pulseaudio module-bluetooth-device is loaded after BT Audio interface * gets connected. Need to wait until then to be able to route audio. */ if ((strcmp(state, BT_STATE_CONNECTED_S) == 0 || strcmp(state, BT_STATE_PLAYING_S) == 0) && !bt_audio_connected) { OHM_DEBUG(DBG_BT, "type: %s, state: %s transition not allowed.", type, state); return TRUE; } /* Type is either HSP or A2DP. HFP is distinguished from HSW by a * flag in the BT fact. */ if (!bt_connected) { GValue *gval = NULL; /* first time: create a new fact */ /* TODO: check that this doesn't leak memory! */ bt_connected = ohm_fact_new(BT_DEVICE); /* TODO: set the bthsp and bta2dp fields to "na" or "unknown" * values */ if (bt_connected == NULL) { OHM_DEBUG(DBG_BT, "could not create the BT fact!"); goto error; } else { /* add the object path to the bluetooth fact in order to * remember the device */ gval = ohm_value_from_string(path); ohm_fact_set(bt_connected, "bt_path", gval); ohm_fact_store_insert(fs, bt_connected); } } else { gval_state = ohm_fact_get(bt_connected, type); if (gval_state != NULL && G_VALUE_TYPE(gval_state) == G_TYPE_STRING) { /* copy the value so that we can overwrite the one in the * fact */ prev_state = g_strdup(g_value_get_string(gval_state)); } } OHM_DEBUG(DBG_BT, "type: %s, prev_state: %s, state: %s", type, prev_state ? prev_state : "NULL", state); gval_state = ohm_value_from_string(state); ohm_fact_set(bt_connected, type, gval_state); if (strcmp(type, BT_TYPE_HSP) == 0) { /* check if we already have the information about the accurate * mono profile status */ if (!hfp_status_defined(bt_connected) || !hsp_status_defined(bt_connected)) { /* We don't know the HFP or HSP status yet. Process the dres * only after we know the status. */ OHM_DEBUG(DBG_BT, "querying HFP/HSP state for device %s", path); if (prev_state) { GValue *gval_prev_state = ohm_value_from_string(prev_state); ohm_fact_set(bt_connected, "bthsp_prev_state", gval_prev_state); } if (get_properties(path, BT_INTERFACE_DEVICE, get_properties_update_fact_cb)) { /* continue processing in the callback */ goto end; } } } OHM_DEBUG(DBG_BT, "running state transition from %s to %s from BT status_changed cb", prev_state ? prev_state : "NULL", state ? state : "NULL"); if (prev_state && state && strcmp(prev_state, BT_STATE_CONNECTING_S) == 0 && strcmp(state, BT_STATE_PLAYING_S) == 0) { /* When state transition is not allowed state might change to playing. * In this case state change is from connecting to playing, and connected state * transition is not done. We need manually do it first */ run_dres = bt_state_transition(type, path, map_to_state(prev_state), map_to_state(BT_STATE_CONNECTED_S)); if (run_dres) dres_all(); } run_dres = bt_state_transition(type, path, map_to_state(prev_state), map_to_state(state)); if (run_dres) dres_all(); end: g_free(prev_state); return TRUE; error: return FALSE; }
/******************** * pl_fact_exists ********************/ static foreign_t pl_fact_exists(term_t pl_name, term_t pl_fields, term_t pl_list, control_t handle) { context_t *ctx; char *name, factname[64]; fid_t frame; term_t pl_values; OhmFact *f; switch (PL_foreign_control(handle)) { case PL_FIRST_CALL: if (!PL_is_list(pl_fields) || /*!PL_is_list(pl_list) ||*/ !PL_get_chars(pl_name, &name, CVT_ALL)) PL_fail; strncpy(factname, name, sizeof(factname)); factname[sizeof(factname)-1] = '\0'; if ((ctx = malloc(sizeof(*ctx))) == NULL) PL_fail; memset(ctx, 0, sizeof(*ctx)); if (get_field_names(ctx, pl_fields) != 0) { free(ctx); PL_fail; } ctx->store = ohm_fact_store_get_fact_store(); ctx->facts = ohm_fact_store_get_facts_by_name(ctx->store, factname); break; case PL_REDO: ctx = PL_foreign_context_address(handle); break; case PL_CUTTED: ctx = PL_foreign_context_address(handle); goto nomore; default: PL_fail; } /* XXX TODO: shouldn't we discard the frame here instead of closing them */ frame = PL_open_foreign_frame(); while (ctx->facts != NULL) { f = (OhmFact *)ctx->facts->data; ctx->facts = g_slist_next(ctx->facts); if (!fact_values(ctx, f, &pl_values) && PL_unify(pl_list, pl_values)) { PL_close_foreign_frame(frame); /* PL_discard_foreign_frame ??? */ PL_retry_address(ctx); } PL_rewind_foreign_frame(frame); } PL_close_foreign_frame(frame); /* PL_discard_foreign_frame ??? */ nomore: if (ctx->fields) free(ctx->fields); free(ctx); PL_fail; }