Пример #1
0
static DBusHandlerResult bluez_change(DBusConnection *c,
                                      DBusMessage *msg, void *data)
{
    char *name, *before, *after;

    (void)c;
    (void)data;

    if (!dbus_message_get_args(msg, NULL,
                               DBUS_TYPE_STRING, &name,
                               DBUS_TYPE_STRING, &before,
                               DBUS_TYPE_STRING, &after,
                               DBUS_TYPE_INVALID) ||
        strcmp(name, BLUEZ_DBUS_NAME))
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    
    if (!after[0]) {                              /* bluez gone */
        OHM_INFO("BlueZ is down.");
        bt_delete_all_facts();
        dres_all();
    }
    else
        OHM_INFO("BlueZ is up.");

    return DBUS_HANDLER_RESULT_HANDLED;
}
Пример #2
0
gboolean bluetooth_deinit(OhmPlugin *plugin)
{
    (void) plugin;

    if (sys_conn) {
        watch_dbus_addr(BLUEZ_DBUS_NAME, FALSE, bluez_change, NULL);
        
        dbus_connection_unref(sys_conn);
        sys_conn = NULL;
    }

    if (bt_delete_all_facts())
        dres_all();

    return TRUE;
}
Пример #3
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;
}
Пример #4
0
static DBusHandlerResult info(DBusConnection *c, DBusMessage * msg, void *data)
{
    int              driver    = -1;
    int              connected = -1;
    int             *valueptr  = &driver;
    int              value     = -1;
    DBusMessageIter  msgit;
    DBusMessageIter  devit;
    char            *string;
    char            *end;
    char            *device;
    gboolean         is_info;

    (void) c;
    (void) data;

    /* This is an example of what we should get:

       string "connected"
       string "1"
       array [
          string "fmtx"
       ]

    */

    is_info = dbus_message_is_signal(msg, "com.nokia.policy", "info");
    if (!is_info)
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

    OHM_DEBUG(DBG_INFO, "received an info message");

    dbus_message_iter_init(msg, &msgit);

    for (;;) {
        if (dbus_message_iter_get_arg_type(&msgit) != DBUS_TYPE_STRING)
            goto done;

        dbus_message_iter_get_basic(&msgit, (void *)&string);

        if (!strcmp(string, "media"))
            goto not_our_signal;

        if (!strcmp(string, "driver")) {
            valueptr = &driver;

            if (!dbus_message_iter_next(&msgit))
                goto done;
        }
        else if (!strcmp(string, "connected")) {
            valueptr = &connected;

            if (!dbus_message_iter_next(&msgit))
                goto done;
        }
        else {
            value = strtol(string, &end, 10);

            if (*end == '\0' && (value == 0 || value == 1)) {
                *valueptr = value;
                break;
            }

            goto done;
        }
    }

    if (!dbus_message_iter_next(&msgit) ||
        dbus_message_iter_get_arg_type(&msgit) != DBUS_TYPE_ARRAY)
        goto done;

    dbus_message_iter_recurse(&msgit, &devit);

    do {
        if (dbus_message_iter_get_arg_type(&devit) != DBUS_TYPE_STRING)
            continue;

        dbus_message_iter_get_basic(&devit, (void *)&device);

        OHM_DEBUG(DBG_INFO, "device: '%s', driver: '%d', connected: '%d'",
                  device ? device : "NULL", driver, connected);
        if (!is_spurious_event(device, driver, connected))
            dres_accessory_request(device, driver, connected);

    } while (dbus_message_iter_next(&devit));

    dres_all();

 done:
 not_our_signal:
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
Пример #5
0
static void get_properties_update_fact_cb (DBusPendingCall *pending, void *user_data)
{
    DBusMessage *reply = NULL;
    DBusMessageIter iter, array_iter, dict_iter, variant_iter, uuid_iter;
    gchar **dbus_data = user_data;
    gchar *path = dbus_data[0];
    gchar *interface = dbus_data[1];
    gboolean is_hfp = FALSE, is_hsp = FALSE;
    OhmFact *bt_connected = NULL;

    g_free(dbus_data);

    if (pending == NULL) 
        goto error;

    reply = dbus_pending_call_steal_reply(pending);
    dbus_pending_call_unref(pending);
    pending = NULL;

    if (reply == NULL) {
        goto error;
    }

    if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
        goto error;
    }

    dbus_message_iter_init(reply, &iter);

    if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
        goto error;
    }

    dbus_message_iter_recurse(&iter, &array_iter);

    while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_DICT_ENTRY) {

        /* the arg type will be DBUS_TYPE_INVALID at the end of the
         * array */

        gchar *key = NULL;
        int type;

        /* process the dicts */
        dbus_message_iter_recurse(&array_iter, &dict_iter);

        /* key must be string */
        if (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_STRING) {
            goto error;
        }
        dbus_message_iter_get_basic(&dict_iter, &key);

        /* go on to the value */
        dbus_message_iter_next(&dict_iter);

        dbus_message_iter_recurse(&dict_iter, &variant_iter);
        type = dbus_message_iter_get_arg_type(&variant_iter);

        if (strcmp(key, "UUIDs") == 0) {

            if (type == DBUS_TYPE_ARRAY) {
                dbus_message_iter_recurse(&variant_iter, &uuid_iter);
                while (dbus_message_iter_get_arg_type(&uuid_iter) == DBUS_TYPE_STRING) {
                    gchar *uuid = NULL;

                    dbus_message_iter_get_basic(&uuid_iter, &uuid);

                    if (!uuid)
                        break;

                    else if (strcmp(uuid, HFP_UUID) == 0) {
                        is_hfp = TRUE;
                    }
                    else if (strcmp(uuid, HSP_UUID) == 0) {
                        is_hsp = TRUE;
                    }
                    dbus_message_iter_next(&uuid_iter);
                }
            }
            else {
                OHM_DEBUG(DBG_BT, "Error: type '%u'\n",
                        dbus_message_iter_get_arg_type(&dict_iter));
            }
        }
        dbus_message_iter_next(&array_iter);
    }

    /* get the BT fact */
    OHM_DEBUG(DBG_BT, "Device %s %s HFP support",
            path, is_hfp ? "has" : "has not");

    OHM_DEBUG(DBG_BT, "Device %s %s HSP support",
            path, is_hsp ? "has" : "has not");

    if ((bt_connected = bt_get_connected(path)) != NULL) {

        GValue *gval_state = ohm_fact_get(bt_connected, BT_TYPE_HSP);
        GValue *gval_prev_state = ohm_fact_get(bt_connected, "bthsp_prev_state");
        const gchar *state = NULL, *prev_state = NULL;
        gboolean run_dres;

        define_hfp_status(bt_connected, is_hfp);
        define_hsp_status(bt_connected, is_hsp);

        if (gval_state != NULL &&
                G_VALUE_TYPE(gval_state) == G_TYPE_STRING) {
            state = g_value_get_string(gval_state);
        }

        if (gval_prev_state != NULL &&
                G_VALUE_TYPE(gval_prev_state) == G_TYPE_STRING) {
            prev_state = g_value_get_string(gval_prev_state);
        }

        OHM_DEBUG(DBG_BT, "running state transition from %s to %s from HFP/HSP status cb",
                prev_state ? prev_state : "NULL", state ? state : "NULL");

        run_dres = bt_state_transition(BT_TYPE_HSP, path, 
                map_to_state(prev_state), map_to_state(state));

        dres_all();
    }

error:

    if (reply)
        dbus_message_unref (reply);

    g_free(path);
    g_free(interface);

    return;
}
Пример #6
0
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;
}