コード例 #1
0
ファイル: session.c プロジェクト: plundstr/ngfd
static gboolean
session_new_bus (const char *address)
{
    DBusError error;

    dbus_error_init (&error);

    if (session_bus != NULL) {
        N_DEBUG (LOG_CAT "received session bus address '%s'", address);
        dbus_connection_unref (session_bus);
        session_bus = NULL;
    }
    else
        N_DEBUG (LOG_CAT "received new session bus address '%s'", address);

    if ((session_bus = dbus_connection_open (address, &error)) == NULL ||
        !dbus_bus_register (session_bus, &error))
    {
        if (dbus_error_is_set(&error)) {
            N_WARNING (LOG_CAT "failed to connect to session bus %s (%s)",
                address, error.message);

            dbus_error_free (&error);
        }
        else
            N_WARNING (LOG_CAT "failed to connect to session bus %s", address);

        return FALSE;
    }

    session_reconnect ();

    return TRUE;
}
コード例 #2
0
ファイル: plugin.c プロジェクト: plundstr/ngfd
static void
setup_system_sound_levels (NValue *value)
{
    gchar **split = NULL;
    gchar **iter  = NULL;
    guint   i     = 0;

    if (!value) {
        N_WARNING (LOG_CAT "no system-sound-levels key defined "
                           "in profile.ini!");
        return;
    }

    if (n_value_type (value) != N_VALUE_TYPE_STRING) {
        N_WARNING (LOG_CAT "invalid value type for system sound levels!");
        return;
    }

    split = g_strsplit (n_value_get_string (value), ";", -1);
    for (iter = split; *iter; ++iter)
        ++num_system_sound_levels;

    system_sound_levels = (int*) g_malloc0 (sizeof (int) * num_system_sound_levels);
    for (iter = split, i = 0; *iter; ++iter, ++i) {
        system_sound_levels[i] = atoi (*iter);
        system_sound_levels[i] = CLAMP_VALUE (system_sound_levels[i], 0, 100);
    }

    g_strfreev (split);
}
コード例 #3
0
ファイル: plugin.c プロジェクト: kjokinie/ngfd
static int
mce_sink_initialize (NSinkInterface *iface)
{
    (void) iface;
    DBusError       error;

    dbus_error_init (&error);
    bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
    if (bus == NULL) {
        N_WARNING ("%s >> failed to get system bus: %s", __FUNCTION__, error.message);
        dbus_error_free (&error);
        return FALSE;
    }

    char *rule = "type='signal',interface='" MCE_SIGNAL_IF "'";
    dbus_bus_add_match(bus, rule, &error);
    if (dbus_error_is_set(&error)) {
        N_WARNING ("%s >> failed to add D-BUS match rule, cause: %s", __FUNCTION__, error.message);
        dbus_error_free (&error);
        return FALSE;
    }

    dbus_connection_add_filter(bus, mce_signal_filter, NULL, NULL);

    return TRUE;
}
コード例 #4
0
ファイル: volume-controller.c プロジェクト: kjokinie/ngfd
static gboolean
connect_peer_to_peer()
{
    DBusError   error;

    dbus_error_init (&error);
    volume_bus = dbus_connection_open (volume_pulse_address, &error);

    if (dbus_error_is_set (&error)) {
        N_WARNING (LOG_CAT "failed to open connection to pulseaudio: %s",
            error.message);
        dbus_error_free (&error);
        return FALSE;
    }

    dbus_connection_setup_with_g_main (volume_bus, NULL);

    if (!dbus_connection_add_filter (volume_bus, filter_cb, NULL, NULL)) {
        N_WARNING (LOG_CAT "failed to add filter");
        return FALSE;
    }

    process_queued_ops();

    return TRUE;
}
コード例 #5
0
ファイル: core.c プロジェクト: plundstr/ngfd
static NProplist*
n_core_load_params (NCore *core, const char *plugin_name)
{
    g_assert (core != NULL);
    g_assert (plugin_name != NULL);

    NProplist  *proplist  = NULL;
    GKeyFile   *keyfile   = NULL;
    gchar      *filename  = NULL;
    gchar      *full_path = NULL;
    gchar     **keys      = NULL;
    gchar     **iter      = NULL;
    GError     *error     = NULL;
    gchar      *value     = NULL;

    filename  = g_strdup_printf ("%s.ini", plugin_name);
    full_path = g_build_filename (core->conf_path, PLUGIN_CONF_PATH, filename, NULL);
    keyfile   = g_key_file_new ();

    if (!g_key_file_load_from_file (keyfile, full_path, G_KEY_FILE_NONE, &error)) {
        if (error->code & G_KEY_FILE_ERROR_NOT_FOUND) {
            N_WARNING (LOG_CAT "problem with configuration file '%s': %s",
                filename, error->message);
        }

        goto done;
    }

    keys = g_key_file_get_keys (keyfile, plugin_name, NULL, NULL);
    if (!keys) {
        N_WARNING (LOG_CAT "no group '%s' within configuration file '%s'",
            plugin_name, filename);
        goto done;
    }

    proplist = n_proplist_new ();
    for (iter = keys; *iter; ++iter) {
        if ((value = g_key_file_get_string (keyfile, plugin_name, *iter, NULL)) == NULL)
            continue;

        N_DEBUG (LOG_CAT "+ plugin parameter: %s = %s", *iter, value);
        n_proplist_set_string (proplist, *iter, value);
        g_free (value);
    }

    g_strfreev (keys);

done:
    if (error)
        g_error_free (error);

    if (keyfile)
        g_key_file_free (keyfile);

    g_free          (full_path);
    g_free          (filename);

    return proplist;
}
コード例 #6
0
ファイル: plugin.c プロジェクト: kjokinie/ngfd
/* Read and create proplist from a custom file */
static NProplist* ffm_read_props(const char *file_name)
{
	NProplist  *proplist  = NULL;
	GKeyFile   *keyfile   = NULL;
	gchar     **keys      = NULL;
	gchar     **iter      = NULL;
	GError     *error     = NULL;
	gchar      *value     = NULL;

	if (!file_name) {
		N_DEBUG (LOG_CAT "NULL file_name parameter, cannot read props");
		return NULL;
	}
	keyfile   = g_key_file_new ();

	N_DEBUG (LOG_CAT "Loading properties from file \"%s\"", file_name);

	if (!g_key_file_load_from_file (keyfile, file_name, G_KEY_FILE_NONE,
								&error)) {
		N_WARNING (LOG_CAT "problem with configuration file"
				" '%s': %s", file_name, error->message);
		goto done;
	}

	keys = g_key_file_get_keys (keyfile, FFM_PLUGIN_NAME, NULL, NULL);
	if (!keys) {
		N_WARNING (LOG_CAT "no group '%s' within configuration file "
				"'%s'", FFM_PLUGIN_NAME, file_name);
		goto done;
	}

	proplist = n_proplist_new ();

	for (iter = keys; *iter; ++iter) {
		if ((value = g_key_file_get_string (keyfile,
					FFM_PLUGIN_NAME, *iter, NULL)) == NULL)
			continue;

		N_DEBUG (LOG_CAT "+ plugin parameter: %s = %s", *iter, value);
		n_proplist_set_string (proplist, *iter, value);
		g_free (value);
	}
	g_strfreev (keys);

done:
	if (error)
		g_error_free (error);

	if (keyfile)
		g_key_file_free (keyfile);

	return proplist;
}
コード例 #7
0
ファイル: session.c プロジェクト: plundstr/ngfd
static gchar*
load_session_bus_address (const char *filename)
{
    FILE   *fp         = NULL;
    size_t  file_size  = 0;
    size_t  bytes_read = 0;
    char   *buf        = NULL;
    gchar  *address    = NULL;

    if (!filename)
        return NULL;

    if ((fp = fopen (filename, "r")) == NULL) {
        N_DEBUG (LOG_CAT "no address file %s", filename);
        return NULL;
    }

    fseek (fp, 0L, SEEK_END);
    file_size = ftell (fp);
    fseek (fp, 0L, SEEK_SET);

    if (file_size > 0) {
        if ((buf = (char*) g_try_malloc0 (sizeof (char) * file_size)) == NULL) {
            N_WARNING (LOG_CAT "failed to allocate memory to read session bus "
                               "address file.");
            fclose (fp);
            return NULL;
        }

        bytes_read = fread (buf, sizeof (char), file_size, fp);
        if (bytes_read != file_size) {
            N_WARNING (LOG_CAT "failed to read the session bus address file.");
            g_free (buf);
            fclose (fp);
            return NULL;
        }

        if ((address = parse_address (buf)) != NULL) {
            N_DEBUG (LOG_CAT "parsed DBus session bus address: %s", address);
        }
        else {
            N_WARNING (LOG_CAT "failed to parse DBus session bus address.");
        }

        g_free (buf);
    }

    fclose (fp);

    return address;
}
コード例 #8
0
ファイル: plugin.c プロジェクト: kjokinie/ngfd
static DBusHandlerResult
mce_signal_filter (DBusConnection *connection, DBusMessage *msg, void *user_data)
{
    (void) connection;
    (void) user_data;

    if (dbus_message_is_signal(msg, MCE_SIGNAL_IF, MCE_LED_PATTERN_DEACTIVATED_SIG)) {
        DBusError error;
        dbus_error_init(&error);

        gchar *pattern = NULL;

        if (!dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &pattern, DBUS_TYPE_INVALID)) {
            N_WARNING ("%s >> failed to read MCE signal arguments, cause: %s", __FUNCTION__, error.message);
            dbus_error_free(&error);
        } else {
            GList *event;
            N_DEBUG ("%s >> mce finished playing %s", __FUNCTION__, pattern);
            for (event = active_events; event != NULL; event = g_list_next(event)) {
                MceData *data = (MceData *) event->data;
                if (g_strcmp0(pattern, data->pattern) == 0) {
                    n_sink_interface_complete(data->iface, data->request);
                    N_DEBUG ("%s >> led pattern %s complete", __FUNCTION__, data->pattern);
                    active_events = g_list_remove_all(active_events, data);
                    break;
                }
            }
        }
    }

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
コード例 #9
0
ファイル: core.c プロジェクト: plundstr/ngfd
static void
n_core_parse_events_from_file (NCore *core, const char *filename)
{
    g_assert (core != NULL);
    g_assert (filename != NULL);

    GKeyFile  *keyfile    = NULL;
    GError    *error      = NULL;
    gchar    **group_list = NULL;
    gchar    **group      = NULL;
    NEvent    *event      = NULL;

    keyfile = g_key_file_new ();
    if (!g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, &error)) {
        N_WARNING (LOG_CAT "failed to load event file: %s", error->message);
        g_error_free    (error);
        g_key_file_free (keyfile);
        return;
    }

    /* each unique group is considered as an event, even if split within
       separate files. */

    N_DEBUG (LOG_CAT "processing event file '%s'", filename);

    group_list = g_key_file_get_groups (keyfile, NULL);
    for (group = group_list; *group; ++group) {
        event = n_event_new_from_group (core, keyfile, *group);
        if (event)
            n_core_add_event (core, event);
    }

    g_strfreev      (group_list);
    g_key_file_free (keyfile);
}
コード例 #10
0
ファイル: core.c プロジェクト: plundstr/ngfd
static void
n_core_parse_keytypes (NCore *core, GKeyFile *keyfile)
{
    g_assert (core != NULL);
    g_assert (keyfile != NULL);

    gchar **conf_keys = NULL;
    gchar **key       = NULL;
    gchar  *value     = NULL;
    int     key_type  = 0;

    /* load all the event configuration key entries. */

    conf_keys = g_key_file_get_keys (keyfile, "keytypes", NULL, NULL);
    if (!conf_keys)
        return;

    for (key = conf_keys; *key; ++key) {
        value = g_key_file_get_string (keyfile, "keytypes", *key, NULL);
        if (!value) {
            N_WARNING (LOG_CAT "no datatype defined for key '%s'", *key);
            continue;
        }

        if (strncmp (value, "INTEGER", 7) == 0)
            key_type = N_VALUE_TYPE_INT;
        else if (strncmp (value, "STRING", 6) == 0)
            key_type = N_VALUE_TYPE_STRING;
        else if (strncmp (value, "BOOLEAN", 7) == 0)
            key_type = N_VALUE_TYPE_BOOL;

        if (!key_type) {
            N_WARNING (LOG_CAT "unrecognized datatype '%s' for key '%s'",
                value, *key);
            g_free (value);
            continue;
        }

        N_DEBUG (LOG_CAT "new key type '%s' = %s", *key, value);
        g_hash_table_replace (core->key_types, g_strdup (*key), (gpointer) key_type);
        g_free (value);
    }

    g_strfreev (conf_keys);
}
コード例 #11
0
ファイル: volume-controller.c プロジェクト: kjokinie/ngfd
static gboolean
add_entry (const char *role, guint volume)
{
    DBusMessage     *msg     = NULL;
    DBusMessage     *reply   = NULL;
    const char      *empty   = "";
    gboolean         success = FALSE;
    dbus_bool_t      muted   = FALSE;
    dbus_bool_t      apply   = TRUE;
    dbus_uint32_t    vol     = 0;
    DBusMessageIter  iter;
    DBusError        error;

    if (!volume_bus || !role)
        return FALSE;

    /* convert the volume from 0-100 to PA_VOLUME_NORM range */
    vol = TO_PA_VOL(volume);

    dbus_error_init (&error);
    msg = dbus_message_new_method_call (0, STREAM_RESTORE_PATH,
        STREAM_RESTORE_IF, ADD_ENTRY_METHOD);

    if (msg == NULL)
        goto done;

    dbus_message_iter_init_append  (msg, &iter);
    dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &role);
    dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &empty);
    append_volume                  (&iter, vol);
    dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &muted);
    dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &apply);

    reply = dbus_connection_send_with_reply_and_block (volume_bus,
        msg, -1, &error);

    if (!reply) {
        if (dbus_error_is_set (&error)) {
            N_WARNING (LOG_CAT "failed to update volume role '%s': %s",
                role, error.message);
        }

        goto done;
    }

    N_DEBUG (LOG_CAT "volume for role '%s' set to %d", role, vol);
    success = TRUE;

done:
    dbus_error_free (&error);

    if (reply) dbus_message_unref (reply);
    if (msg)   dbus_message_unref (msg);

    return success;
}
コード例 #12
0
ファイル: volume-controller.c プロジェクト: kjokinie/ngfd
static void
get_address_reply_cb(DBusPendingCall *pending, void *data)
{
    DBusMessageIter iter;
    DBusMessageIter sub;
    int current_type;
    char *address = NULL;
    DBusMessage *msg = NULL;

    (void) data;

    msg = dbus_pending_call_steal_reply(pending);
    if (!msg) {
        N_WARNING(LOG_CAT "Could not get reply from pending call.");
        goto retry;
    }

    dbus_message_iter_init(msg, &iter);

    // Reply string is inside DBUS_TYPE_VARIANT
    while ((current_type = dbus_message_iter_get_arg_type(&iter)) != DBUS_TYPE_INVALID) {

        if (current_type == DBUS_TYPE_VARIANT) {
            dbus_message_iter_recurse(&iter, &sub);

            while ((current_type = dbus_message_iter_get_arg_type(&sub)) != DBUS_TYPE_INVALID) {
                if (current_type == DBUS_TYPE_STRING)
                    dbus_message_iter_get_basic(&sub, &address);
                dbus_message_iter_next(&sub);
            }
        }

        dbus_message_iter_next(&iter);
    }

    if (address) {
        N_DEBUG (LOG_CAT "Got PulseAudio DBus address: %s", address);
        volume_pulse_address = g_strdup(address);

        // Unref sesssion bus connection, it is not needed anymore.
        // Real communication is done with peer-to-peer connection.
        dbus_connection_unref(volume_session_bus);
        volume_session_bus = NULL;
    }

    // Always retry connection, if address was determined, it is used
    // to get peer-to-peer connection, if address wasn't determined,
    // we'll need to reconnect and retry anyway.
retry:
    if (msg)
        dbus_message_unref(msg);
    if (pending)
        dbus_pending_call_unref(pending);

    retry_connect();
}
コード例 #13
0
ファイル: plugin.c プロジェクト: kjokinie/ngfd
static gboolean
call_dbus_method (DBusConnection *bus, DBusMessage *msg)
{
    if (!dbus_connection_send (bus, msg, 0)) {
        N_WARNING ("Failed to send DBus message %s to interface %s", dbus_message_get_member (msg), dbus_message_get_interface (msg));
        return FALSE;
    }

    return TRUE;
}
コード例 #14
0
ファイル: volume-controller.c プロジェクト: kjokinie/ngfd
static gchar*
get_object_path (const char *stream_name)
{
    DBusMessage     *msg     = NULL;
    DBusMessage     *reply   = NULL;
    const gchar     *obj_path= NULL;
    gchar           *ret     = NULL;
    DBusError        error;

    g_assert (volume_bus);
    g_assert (stream_name);

    dbus_error_init (&error);
    msg = dbus_message_new_method_call (NULL,
                                        STREAM_RESTORE_PATH,
                                        STREAM_RESTORE_IF,
                                        "GetEntryByName");

    if (msg == NULL)
        goto done;

    dbus_message_append_args (msg, DBUS_TYPE_STRING, &stream_name, DBUS_TYPE_INVALID);

    reply = dbus_connection_send_with_reply_and_block (volume_bus,
                                                       msg, -1, &error);

    if (!reply) {
        if (dbus_error_is_set (&error)) {
            N_DEBUG (LOG_CAT "couldn't get object path for %s: %s",
                     stream_name, error.message);
        }

        goto done;
    }

    if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_OBJECT_PATH, &obj_path, DBUS_TYPE_INVALID)) {
        N_WARNING (LOG_CAT "failed to get object path");
        goto done;
    }

    ret = g_strdup (obj_path);

done:
    dbus_error_free (&error);

    if (reply) dbus_message_unref (reply);
    if (msg)   dbus_message_unref (msg);

    return ret;
}
コード例 #15
0
ファイル: core.c プロジェクト: plundstr/ngfd
static int
n_core_parse_configuration (NCore *core)
{
    g_assert (core != NULL);
    g_assert (core->conf_path != NULL);

    GKeyFile  *keyfile    = NULL;
    GError    *error      = NULL;
    gchar     *filename   = NULL;
    gchar    **plugins    = NULL;

    filename = g_build_filename (core->conf_path, DEFAULT_CONF_FILENAME, NULL);
    keyfile  = g_key_file_new ();

    if (!g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, &error)) {
        N_WARNING (LOG_CAT "failed to load configuration file file: %s", error->message);
        g_error_free    (error);
        g_key_file_free (keyfile);
        g_free          (filename);
        return FALSE;
    }

    N_DEBUG (LOG_CAT "parsing configuration file '%s'", filename);

    /* parse the required plugins. */
    if ((plugins = g_key_file_get_string_list (keyfile, "general", "plugins", NULL, NULL)) != NULL) {
        parse_plugins (plugins, &core->required_plugins);
        g_strfreev (plugins);
    }

    /* parse the optional plugins. */
    if ((plugins = g_key_file_get_string_list (keyfile, "general", "plugins-optional", NULL, NULL)) != NULL) {
        parse_plugins (plugins, &core->optional_plugins);
        g_strfreev (plugins);
    }

    /* load all the event configuration key entries. */

    n_core_parse_keytypes (core, keyfile);

    /* load the sink order. the first sink has the highest priority. */

    n_core_parse_sink_order (core, keyfile);

    g_key_file_free (keyfile);
    g_free          (filename);

    return TRUE;
}
コード例 #16
0
ファイル: plugin.c プロジェクト: kjokinie/ngfd
/*
 * Create a Hash table of effects from a string of semicolon separated keys.
 * Values of keys will be initialized to -1.
 */
static GHashTable *ffm_new_effect_list(const char *effect_data)
{
	GHashTable *list = NULL;
	gchar **effect_names;
	int i = 0;
	struct ffm_effect_data *data;

	if (!effect_data) {
		N_WARNING (LOG_CAT "NULL effect_data pointer");
		return NULL;
	}

	N_DEBUG (LOG_CAT "creating effect list for %s", effect_data);

	effect_names = g_strsplit((const gchar*) effect_data, ";", 0);
	if (!effect_names[0]) {
		N_WARNING (LOG_CAT "Empty effect_data string");
		goto ffm_effect_list_done;
	}

	list = g_hash_table_new_full(g_str_hash,  g_str_equal,
					g_free, g_free);

	for (i = 0; effect_names[i] != NULL; i++) {
		/* Add effect key to effect list with initial data */
		data = g_new(struct ffm_effect_data, 1);
		data->id = -1;
		data->repeat = 1;
		g_hash_table_insert(list, strdup(effect_names[i]), data);
	}

ffm_effect_list_done:
	g_strfreev(effect_names);

	return list;
}
コード例 #17
0
int NativeProxyObject::fireEvent(const char* name, const TiObject* event) const
{
    EventPairSmartPtr ep = events_.value(name);
    if (ep.get() != NULL && ep->container())
    {
        if (event != NULL)
        {
            ep->container()->fireEvent(event);
        }
        else
        {
            ep->container()->fireEvent();
        }
        return NATIVE_ERROR_OK;
    }
    N_WARNING(Native::Msg::Unsupported_event_name_ << name);
    return NATIVE_ERROR_NOTSUPPORTED;
}
コード例 #18
0
ファイル: plugin.c プロジェクト: jusa/ngfd
static int canberra_connect ()
{
    int error;

    if (c_context)
        return TRUE;

    ca_context_create (&c_context);
    error = ca_context_open (c_context);
    if (error) {
        N_WARNING (LOG_CAT "can't connect to canberra! %s", ca_strerror (error));
        ca_context_destroy (c_context);
        c_context = 0;
        return FALSE;
    }

    return TRUE;
}
コード例 #19
0
ファイル: plugin.c プロジェクト: jusa/ngfd
static int
tonegen_sink_initialize (NSinkInterface *iface)
{
    (void) iface;

    DBusError error;

    dbus_error_init (&error);
    system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
    if (!system_bus) {
        N_WARNING (LOG_CAT "failed to get system bus: %s", error.message);
        dbus_error_free (&error);
        return FALSE;
    }

    dbus_connection_setup_with_g_main (system_bus, NULL);

    return TRUE;
}
コード例 #20
0
ファイル: plugin.c プロジェクト: plundstr/ngfd
static ProfileEntry*
parse_profile_entry (const char *value)
{
    g_assert (value != NULL);

    ProfileEntry  *entry         = NULL;
    gchar        **tokens        = NULL;
    gchar        **source_tokens = NULL;

    /* split the profile key and target key */

    tokens = g_strsplit (value, "=>", 2);
    if (tokens[1] == NULL) {
        N_WARNING (LOG_CAT "profile store key missing for '%s'", value);
        g_strfreev (tokens);
        return NULL;
    }

    g_strstrip (tokens[0]);
    g_strstrip (tokens[1]);

    /* figure out the source profile for the key */

    source_tokens = g_strsplit (tokens[0], "@", 2);

    g_strstrip (source_tokens[0]);
    if (source_tokens[1])
        g_strstrip (source_tokens[1]);

    /* new entry */

    entry = g_new0 (ProfileEntry, 1);
    entry->key     = g_strdup (source_tokens[0]);
    entry->profile = g_strdup (source_tokens[1]);
    entry->target  = g_strdup (tokens[1]);

    g_strfreev (source_tokens);
    g_strfreev (tokens);

    return entry;
}
コード例 #21
0
ファイル: core.c プロジェクト: plundstr/ngfd
static void
n_core_parse_sink_order (NCore *core, GKeyFile *keyfile)
{
    g_assert (core != NULL);
    g_assert (keyfile != NULL);

    gchar **sink_list = NULL;
    gchar **item      = NULL;
    gsize   num_items = 0;

    sink_list = g_key_file_get_string_list (keyfile, "general", "sink-order",
        &num_items, NULL);

    if (!sink_list) {
        N_WARNING (LOG_CAT "no sink-order, re-synchronization may be undefined.");
        return;
    }

    for (item = sink_list; *item; ++item)
        core->sink_order = g_list_append (core->sink_order, g_strdup (*item));

    g_strfreev (sink_list);
}
コード例 #22
0
ファイル: volume-controller.c プロジェクト: kjokinie/ngfd
static DBusHandlerResult
filter_cb (DBusConnection *connection, DBusMessage *msg, void *data)
{
    (void) connection;
    (void) data;

    const char *obj_path;
    char *stream_name;
    GList *list, *i;
    SubscribeItem *item;
    int volume = 0;

    if (dbus_message_has_interface (msg, DBUS_INTERFACE_LOCAL) &&
        dbus_message_has_path      (msg, DBUS_PATH_LOCAL) &&
        dbus_message_has_member    (msg, DISCONNECTED_SIG))
    {
        N_DEBUG (LOG_CAT "pulseaudio disconnected, reconnecting in %d seconds",
            RETRY_TIMEOUT);

        disconnect_from_pulseaudio ();

        // After disconnecting re-query stream restore object names.
        if (subscribe_map && object_map) {
            list = g_hash_table_get_values (subscribe_map);

            for (i = g_list_first (list); i; i = g_list_next (i)) {
                SubscribeItem *item = (SubscribeItem*) i->data;
                if (item->object_path) {
                    g_free (item->object_path);
                    item->object_path = NULL;
                }
            }
            g_list_free (list);
            queue_subscribe = TRUE;
        }
        // If PulseAudio is restarting path to runtime files may change so we'll
        // have to request DBus address again.
        if (volume_pulse_address) {
            g_free(volume_pulse_address);
            volume_pulse_address = NULL;
        }
        retry_connect();
    }
    else if (subscribe_callback &&
             dbus_message_has_interface (msg, STREAM_RESTORE_IF) &&
             dbus_message_has_path      (msg, STREAM_RESTORE_PATH) &&
             dbus_message_has_member    (msg, NEW_ENTRY_MEMBER))
    {
        if (!dbus_message_get_args (msg, NULL, DBUS_TYPE_OBJECT_PATH, &obj_path, DBUS_TYPE_INVALID)) {
            N_WARNING (LOG_CAT "failed to get arguments for new entry");
            goto end;
        }

        // If the entry is in subscribe_map but not in object_map, look up the entry
        // and add to object_map
        if (!object_map_complete && !g_hash_table_lookup (object_map, obj_path)) {

            if ((stream_name = get_object_name (obj_path))) {

                if ((item = g_hash_table_lookup (subscribe_map, stream_name))) {
                    item->object_path = g_strdup (obj_path);
                    N_DEBUG (LOG_CAT "stream restore entry for %s appeared (%s)", item->stream_name, item->object_path);
                    update_object_map_listen ();
                }
                g_free (stream_name);
            }
        }
    }
    else if (subscribe_callback &&
             dbus_message_has_interface (msg, STREAM_RESTORE_IF) &&
             dbus_message_has_path      (msg, STREAM_RESTORE_PATH) &&
             dbus_message_has_member    (msg, ENTRY_REMOVED_MEMBER))
    {
        if (!dbus_message_get_args (msg, NULL, DBUS_TYPE_OBJECT_PATH, &obj_path, DBUS_TYPE_INVALID)) {
            N_WARNING (LOG_CAT "failed to get arguments for removed entry");
            goto end;
        }

        if ((item = g_hash_table_lookup (object_map, obj_path))) {
            g_hash_table_remove (object_map, item->object_path);
            g_free (item->object_path);
            item->object_path = NULL;
            update_object_map_listen ();
            N_DEBUG (LOG_CAT "removed entry %s from object map (%s)", item->stream_name, obj_path);
        }
    }
    else if (subscribe_callback &&
             dbus_message_has_interface (msg, STREAM_ENTRY_IF) &&
             dbus_message_has_member    (msg, VOLUME_UPDATED_MEMBER))
    {
        if (!(obj_path = dbus_message_get_path (msg)))
            goto end;

        if ((item = g_hash_table_lookup (object_map, obj_path))) {
            N_DEBUG (LOG_CAT "volume updated for stream %s (%s)", item->stream_name, item->object_path);
            if (get_volume (msg, &volume)) {
                subscribe_callback (item->stream_name, FROM_PA_VOL(volume), item->data, subscribe_userdata);
            }
        }
    }

end:
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
コード例 #23
0
ファイル: volume-controller.c プロジェクト: kjokinie/ngfd
static gchar*
get_object_name (const char *obj_path)
{
    DBusMessage     *msg         = NULL;
    DBusMessage     *reply       = NULL;
    const gchar     *stream_name = NULL;
    gchar           *ret         = NULL;
    const gchar     *iface       = STREAM_ENTRY_IF;
    const gchar     *addr        = "Name";
    DBusError        error;
    DBusMessageIter  iter;
    DBusMessageIter  sub;
    int              current_type;

    g_assert (volume_bus);
    g_assert (obj_path);

    dbus_error_init (&error);

    msg = dbus_message_new_method_call(STREAM_ENTRY_IF,
                                       obj_path,
                                       DBUS_PROPERTIES_IF,
                                       "Get");

    if (msg == NULL)
        goto done;

    if (!dbus_message_append_args(msg,
                                  DBUS_TYPE_STRING, &iface,
                                  DBUS_TYPE_STRING, &addr,
                                  DBUS_TYPE_INVALID))
        goto done;

    reply = dbus_connection_send_with_reply_and_block (volume_bus,
                                                       msg, -1, &error);

    if (!reply) {
        if (dbus_error_is_set (&error)) {
            N_WARNING (LOG_CAT "couldn't get object name for %s: %s",
                       obj_path, error.message);
        }

        goto done;
    }

    dbus_message_iter_init(reply, &iter);

    // Reply string is inside DBUS_TYPE_VARIANT
    while ((current_type = dbus_message_iter_get_arg_type(&iter)) != DBUS_TYPE_INVALID) {

        if (current_type == DBUS_TYPE_VARIANT) {
            dbus_message_iter_recurse(&iter, &sub);

            while ((current_type = dbus_message_iter_get_arg_type(&sub)) != DBUS_TYPE_INVALID) {
                if (current_type == DBUS_TYPE_STRING)
                    dbus_message_iter_get_basic(&sub, &stream_name);
                dbus_message_iter_next(&sub);
            }
        }

        dbus_message_iter_next(&iter);
    }

    if (!stream_name) {
        N_WARNING (LOG_CAT "failed to get stream name");
        goto done;
    }

    ret = g_strdup (stream_name);

done:
    dbus_error_free (&error);

    if (reply) dbus_message_unref (reply);
    if (msg)   dbus_message_unref (msg);

    return ret;
}
コード例 #24
0
ファイル: volume-controller.c プロジェクト: kjokinie/ngfd
static gboolean
connect_get_address()
{
    DBusError error;
    DBusMessage *msg = NULL;
    DBusPendingCall *pending = NULL;
    const char *iface = PULSE_LOOKUP_IF;
    const char *addr = PULSE_LOOKUP_ADDRESS;

    dbus_error_init (&error);

    if (volume_session_bus && !dbus_connection_get_is_connected(volume_session_bus)) {
        dbus_connection_unref(volume_session_bus);
        volume_session_bus = NULL;
    }

    if (!volume_session_bus)
        volume_session_bus = dbus_bus_get(DBUS_BUS_SESSION, &error);

    if (dbus_error_is_set(&error)) {
        N_WARNING(LOG_CAT "failed to open connection to session bus: %s", error.message);
        dbus_error_free (&error);
        goto fail;
    }

    dbus_connection_setup_with_g_main(volume_session_bus, NULL);

    if (!(msg = dbus_message_new_method_call(PULSE_LOOKUP_DEST,
                                             PULSE_LOOKUP_PATH,
                                             DBUS_PROPERTIES_IF,
                                             "Get")))
        goto fail;

    if (!dbus_message_append_args(msg,
                                  DBUS_TYPE_STRING, &iface,
                                  DBUS_TYPE_STRING, &addr,
                                  DBUS_TYPE_INVALID))
        goto fail;

    if (!dbus_connection_send_with_reply(volume_session_bus,
                                         msg,
                                         &pending,
                                         DBUS_TIMEOUT_USE_DEFAULT))
        goto fail;

    if (!pending)
        goto fail;

    if (!dbus_pending_call_set_notify(pending, get_address_reply_cb, NULL, NULL))
        goto fail;

    dbus_message_unref(msg);

    return TRUE;

fail:
    if (pending) {
        dbus_pending_call_cancel(pending);
        dbus_pending_call_unref(pending);
    }
    if (msg)
        dbus_message_unref(msg);

    return FALSE;
}
コード例 #25
0
ファイル: plugin.c プロジェクト: jusa/ngfd
static int
canberra_sink_play (NSinkInterface *iface, NRequest *request)
{
    CanberraData *data = (CanberraData*) n_request_get_data (request, CANBERRA_KEY);
    (void) iface;

    N_DEBUG (LOG_CAT "sink play");

    g_assert (data != NULL);

    if (!data->sound_enabled)
        goto complete;

    if (canberra_connect () == FALSE)
        return FALSE;

    static GHashTable *cached_samples = NULL;
    if (!cached_samples) {
        cached_samples = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
    }

    NProplist *props = props = (NProplist*) n_request_get_properties (request);
    ca_proplist *ca_props = 0;
    int error;
    ca_proplist_create (&ca_props);

    /* TODO: don't hardcode */
    ca_proplist_sets (ca_props, CA_PROP_CANBERRA_XDG_THEME_NAME, "jolla-ambient");
    ca_proplist_sets (ca_props, CA_PROP_EVENT_ID, data->filename);

    /* convert all properties within the request that begin with
       "sound.stream." prefix. */
    n_proplist_foreach (props, proplist_to_structure_cb, ca_props);

    if (g_hash_table_lookup_extended (cached_samples, data->filename, NULL, NULL) == FALSE) {
        N_DEBUG (LOG_CAT "caching sample %s", data->filename);
        error = ca_context_cache_full (c_context, ca_props);
        if (error) {
            N_WARNING (LOG_CAT "canberra couldn't cache sample %s", data->filename);
            return FALSE;
        }

        g_hash_table_add (cached_samples, strdup(data->filename));
    } else {
        N_DEBUG (LOG_CAT "sample %s is cached", data->filename);
    }

    error = ca_context_play_full (c_context, 0, ca_props, NULL, NULL);
    ca_proplist_destroy (ca_props);

    if (error) {
        N_WARNING (LOG_CAT "sink play had a warning: %s", ca_strerror (error));

        if (error == CA_ERROR_NOTAVAILABLE ||
                error == CA_ERROR_DISCONNECTED ||
                error == CA_ERROR_STATE ||
                error == CA_ERROR_DESTROYED) {
            ca_context_destroy (c_context);
            c_context = 0;
        }

        return FALSE;
    }

complete:
    /* We do not know how long our samples play, but let's guess we
     * are done in 200ms. */
    data->complete_cb_id = g_timeout_add (200, canberra_complete_cb, data);

    return TRUE;
}