/* Called from main thread */
static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
    struct userdata *u;

    pa_source_output_assert_ref(o);
    pa_assert_ctl_context();
    pa_assert_se(u = o->userdata);

    if (dest) {
        pa_source_set_asyncmsgq(u->source, dest->asyncmsgq);
        pa_source_update_flags(u->source, PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY, dest->flags);
    } else
        pa_source_set_asyncmsgq(u->source, NULL);

    if (u->auto_desc && dest) {
        const char *z;
        pa_proplist *pl;

        pl = pa_proplist_new();
        z = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION);
        pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s",
                         pa_proplist_gets(u->source->proplist, "device.vsource.name"), z ? z : dest->name);

        pa_source_update_proplist(u->source, PA_UPDATE_REPLACE, pl);
        pa_proplist_free(pl);
    }
}
/* When a source is created, loopback it to default sink */
static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, void* userdata) {
    const char *s;
    const char *role;
    char *args;

    pa_assert(c);
    pa_assert(source);

    /* Only consider bluetooth sinks and sources */
    s = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_BUS);
    if (!s)
        return PA_HOOK_OK;

    if (!pa_streq(s, "bluetooth"))
        return PA_HOOK_OK;

    /* Restrict to A2DP profile (sink role) */
    s = pa_proplist_gets(source->proplist, "bluetooth.protocol");
    if (!s)
        return PA_HOOK_OK;

    if (pa_streq(s, "a2dp_source"))
        role = "music";
    else {
        pa_log_debug("Profile %s cannot be selected for loopback", s);
        return PA_HOOK_OK;
    }

    /* Load module-loopback */
    args = pa_sprintf_malloc("source=\"%s\" source_dont_move=\"true\" sink_input_properties=\"media.role=%s\"", source->name, role);
    (void) pa_module_load(c, "module-loopback", args);
    pa_xfree(args);

    return PA_HOOK_OK;
}
/* Called from main context */
static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
    struct userdata *u;

    pa_sink_input_assert_ref(i);
    pa_assert_se(u = i->userdata);

    if (dest) {
        pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq);
        pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags);
    } else
        pa_sink_set_asyncmsgq(u->sink, NULL);

    if (u->auto_desc && dest) {
        const char *z;
        pa_proplist *pl;

        pl = pa_proplist_new();
        z = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION);
        pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "Virtual Sink %s on %s",
                         pa_proplist_gets(u->sink->proplist, "device.vsink.name"), z ? z : dest->name);

        pa_sink_update_proplist(u->sink, PA_UPDATE_REPLACE, pl);
        pa_proplist_free(pl);
    }
}
/* Called from main thread */
static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
    struct userdata *u;
    char *output_description;
    const char *n;

    if (!dest)
        return;

    pa_sink_input_assert_ref(i);
    pa_assert_ctl_context();
    pa_assert_se(u = i->userdata);

    output_description = pa_sprintf_malloc("Loopback to %s",
                                           pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION)));
    pa_source_output_set_property(u->source_output, PA_PROP_MEDIA_NAME, output_description);
    pa_xfree(output_description);

    if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
        pa_source_output_set_property(u->source_output, PA_PROP_MEDIA_ICON_NAME, n);

    if (pa_sink_get_state(dest) == PA_SINK_SUSPENDED)
        pa_source_output_cork(u->source_output, true);
    else
        pa_source_output_cork(u->source_output, false);

    update_adjust_timer(u);
}
Exemple #5
0
/* Called from main thread */
static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
    struct userdata *u;
    pa_proplist *p;
    const char *n;

    if (!dest)
        return;

    pa_sink_input_assert_ref(i);
    pa_assert_ctl_context();
    pa_assert_se(u = i->userdata);

    p = pa_proplist_new();
    pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback to %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION)));

    if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
        pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);

    pa_source_output_update_proplist(u->source_output, PA_UPDATE_REPLACE, p);
    pa_proplist_free(p);

    if (pa_sink_get_state(dest) == PA_SINK_SUSPENDED)
        pa_source_output_cork(u->source_output, true);
    else
        pa_source_output_cork(u->source_output, false);

    update_adjust_timer(u);
}
static struct service *get_service(struct userdata *u, pa_object *device) {
    struct service *s;
    char *hn, *un;
    const char *n;

    pa_assert(u);
    pa_object_assert_ref(device);

    if ((s = pa_hashmap_get(u->services, device)))
        return s;

    s = pa_xnew0(struct service, 1);
    s->userdata = u;
    s->device = device;

    if (pa_sink_isinstance(device)) {
        if (!(n = pa_proplist_gets(PA_SINK(device)->proplist, PA_PROP_DEVICE_DESCRIPTION)))
            n = PA_SINK(device)->name;
    } else {
        if (!(n = pa_proplist_gets(PA_SOURCE(device)->proplist, PA_PROP_DEVICE_DESCRIPTION)))
            n = PA_SOURCE(device)->name;
    }

    hn = pa_get_host_name_malloc();
    un = pa_get_user_name_malloc();

    s->service_name = pa_truncate_utf8(pa_sprintf_malloc("%s@%s: %s", un, hn, n), kDNSServiceMaxDomainName-1);

    pa_xfree(un);
    pa_xfree(hn);

    pa_hashmap_put(u->services, s->device, s);

    return s;
}
int cmtspeech_check_source_api(pa_source *s) {
    if (strcmp(PA_PROP_SOURCE_API_EXTENSION_PROPERTY_VALUE,
                pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_SOURCE_API_EXTENSION_PROPERTY_NAME)))) {
        pa_log_error("Source \"%s\" does not support %s version %s", s->name,
                     PA_PROP_SOURCE_API_EXTENSION_PROPERTY_NAME,
                     PA_PROP_SOURCE_API_EXTENSION_PROPERTY_VALUE);
        pa_log_debug("'%s' != '%s'", PA_PROP_SOURCE_API_EXTENSION_PROPERTY_VALUE,
                     pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_SOURCE_API_EXTENSION_PROPERTY_NAME)));
        return -1;
    }
    return 0;
}
Exemple #8
0
int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) {
    const char *str = NULL;
    json_object *o;

    pa_assert(f);
    pa_assert(key);
    pa_assert(v);

    str = pa_proplist_gets(f->plist, key);
    if (!str)
        return -PA_ERR_NOENTITY;

    o = json_tokener_parse(str);
    if (is_error(o)) {
        pa_log_debug("Failed to parse format info property '%s'.", key);
        return -PA_ERR_INVALID;
    }

    if (json_object_get_type(o) != json_type_string) {
        pa_log_debug("Format info property '%s' type is not string.", key);
        json_object_put(o);
        return -PA_ERR_INVALID;
    }

    *v = pa_xstrdup(json_object_get_string(o));
    json_object_put(o);

    return 0;
}
Exemple #9
0
int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) {
    const char *str = NULL;
    pa_json_object *o;

    pa_assert(f);
    pa_assert(key);
    pa_assert(v);

    str = pa_proplist_gets(f->plist, key);
    if (!str)
        return -PA_ERR_NOENTITY;

    o = pa_json_parse(str);
    if (!o) {
        pa_log_debug("Failed to parse format info property '%s'.", key);
        return -PA_ERR_INVALID;
    }

    if (pa_json_object_get_type(o) != PA_JSON_TYPE_STRING) {
        pa_log_debug("Format info property '%s' type is not string.", key);
        pa_json_object_free(o);
        return -PA_ERR_INVALID;
    }

    *v = pa_xstrdup(pa_json_object_get_string(o));
    pa_json_object_free(o);

    return 0;
}
Exemple #10
0
pa_client *pa_client_new(pa_core *core, pa_client_new_data *data) {
    pa_client *c;

    pa_core_assert_ref(core);
    pa_assert(data);

    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_NEW], data) < 0)
        return NULL;

    c = pa_xnew(pa_client, 1);
    c->core = core;
    c->proplist = pa_proplist_copy(data->proplist);
    c->driver = pa_xstrdup(pa_path_get_filename(data->driver));
    c->module = data->module;

    c->sink_inputs = pa_idxset_new(NULL, NULL);
    c->source_outputs = pa_idxset_new(NULL, NULL);

    c->userdata = NULL;
    c->kill = NULL;
    c->send_event = NULL;

    pa_assert_se(pa_idxset_put(core->clients, c, &c->index) >= 0);

    pa_log_info("Created %u \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME)));
    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index);

    pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_PUT], c);

    pa_core_check_idle(core);

    return c;
}
Exemple #11
0
void pa_client_free(pa_client *c) {
    pa_core *core;

    pa_assert(c);
    pa_assert(c->core);

    core = c->core;

    pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_UNLINK], c);

    pa_idxset_remove_by_data(c->core->clients, c, NULL);

    pa_log_info("Freed %u \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME)));
    pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);

    pa_assert(pa_idxset_isempty(c->sink_inputs));
    pa_idxset_free(c->sink_inputs, NULL);
    pa_assert(pa_idxset_isempty(c->source_outputs));
    pa_idxset_free(c->source_outputs, NULL);

    pa_proplist_free(c->proplist);
    pa_xfree(c->driver);
    pa_xfree(c);

    pa_core_check_idle(core);
}
Exemple #12
0
int pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) {
    const char *str = NULL;
    json_object *o;

    pa_assert(f);
    pa_assert(key);
    pa_assert(v);

    str = pa_proplist_gets(f->plist, key);
    if (!str)
        return -PA_ERR_NOENTITY;

    o = json_tokener_parse(str);
    if (is_error(o))
        return -PA_ERR_INVALID;

    if (json_object_get_type(o) != json_type_string) {
        json_object_put(o);
        return -PA_ERR_INVALID;
    }

    *v = pa_xstrdup(json_object_get_string(o));
    json_object_put(o);

    return 0;
}
static void apply_rule(struct rule *r, pa_proplist *p) {
    pa_assert(r);
    pa_assert(p);

    if (!r->good)
        return;

    if (r->proplist)
        pa_proplist_update(p, PA_UPDATE_MERGE, r->proplist);

    if (r->icon_name)
        if (!pa_proplist_contains(p, PA_PROP_APPLICATION_ICON_NAME))
            pa_proplist_sets(p, PA_PROP_APPLICATION_ICON_NAME, r->icon_name);

    if (r->application_name) {
        const char *t;

        t = pa_proplist_gets(p, PA_PROP_APPLICATION_NAME);

        if (!t || pa_streq(t, r->process_name))
            pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, r->application_name);
    }

    if (r->role)
        if (!pa_proplist_contains(p, PA_PROP_MEDIA_ROLE))
            pa_proplist_sets(p, PA_PROP_MEDIA_ROLE, r->role);
}
static struct pa_policy_group* get_group(struct userdata *u, const char *group_name, pa_proplist *sinp_proplist, uint32_t *flags_ret)
{
    struct pa_policy_group *group = NULL;
    const void *flags;
    size_t len_flags = 0;

    pa_assert(u);
    pa_assert(sinp_proplist);

    /* If group name is provided use that, otherwise check sink input proplist. */
    if (!group_name)
        /* Just grab the group name from the proplist to avoid classifying multiple
         * times (and to avoid classifying incorrectly if properties are
         * overwritten when handling PA_CORE_HOOK_SINK_INPUT_NEW).*/
        group_name = pa_proplist_gets(sinp_proplist, PA_PROP_POLICY_GROUP);

    if (group_name && (group = pa_policy_group_find(u, group_name)) != NULL) {
        /* Only update flags if flags_ret is non null */
        if (flags_ret) {
            if (pa_proplist_get(sinp_proplist, PA_PROP_POLICY_STREAM_FLAGS, &flags, &len_flags) < 0 ||
                len_flags != sizeof(uint32_t)) {

                pa_log_warn("No stream flags in proplist or malformed flags.");
                *flags_ret = 0;
            } else
                *flags_ret = *(uint32_t *)flags;
        }
    }

    return group;
}
void pa_source_output_cb(pa_context *c, const pa_source_output_info *i, int eol, void *userdata)
{
    if (eol > 0) {
        return;
    }
    char buf[1024];
    const char *prop_key = NULL;
    void *prop_state = NULL;
    printf("index: %d\n", i->index);
    printf("name: %s\n", i->name);
    printf("module: %d\n", i->owner_module);
    printf("client: %d\n", i->client);
    printf("source: %d\n", i->source);
    printf("volume: channels:%d, min:%d, max:%d\n",
           i->volume.channels,
           pa_cvolume_min(&i->volume),
           pa_cvolume_max(&i->volume));
    printf("resample_method: %s", i->resample_method);
    printf("driver: %s\n", i->driver);
    printf("mute: %d\n", i->mute);
    printf("corked: %d\n", i->corked);
    printf("has_volume: %d\n", i->has_volume);
    printf("volume_writable: %d\n", i->volume_writable);
    while ((prop_key=pa_proplist_iterate(i->proplist, &prop_state))) {
        printf("  %s: %s\n", prop_key, pa_proplist_gets(i->proplist, prop_key));
    }
    printf("format_info: %s\n", pa_format_info_snprint(buf, 1000, i->format));
    printf("------------------------------\n");
}
static char *pid_hash_get_group(struct pa_classify_pid_hash **hash,
                                pid_t pid, pa_proplist *proplist)
{
    struct pa_classify_pid_hash *st;
    int idx;
    char *propval;
    char *group = NULL;

    pa_assert(hash);
 
    if (pid) {
        idx = pid & PA_POLICY_PID_HASH_MASK;

        for (st = hash[idx];  st != NULL;  st = st->next) {
            if (pid == st->pid) {
                if (!st->prop) {
                    group = st->group;
                    break;
                }

                if ((propval = (char *)pa_proplist_gets(proplist, st->prop)) &&
                    st->method.func(propval, &st->arg.value))
                {
                    group = st->group;
                    break;
                }
            }
        }
    }

    return group;
}
std::string PulseAudioSinksManager::getPulseAudioIconName(pa_proplist *properties)
{
    const char* name;
    if((name=pa_proplist_gets(properties,PA_PROP_DEVICE_ICON_NAME))) {
        return std::string(name);
    }
    if((name=pa_proplist_gets(properties,PA_PROP_MEDIA_ICON_NAME))) {
        return std::string(name);
    }
    if((name=pa_proplist_gets(properties,PA_PROP_WINDOW_ICON_NAME))) {
        return std::string(name);
    }
    if((name=pa_proplist_gets(properties,PA_PROP_APPLICATION_ICON_NAME))) {
        return std::string(name);
    }
    return "";
}
Exemple #18
0
/* Called from main thread */
static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
    pa_proplist *p;
    const char *n;
    struct userdata *u;

    pa_source_output_assert_ref(o);
    pa_assert_ctl_context();
    pa_assert_se(u = o->userdata);

    p = pa_proplist_new();
    pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback of %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION)));

    if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
        pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);

    pa_sink_input_update_proplist(u->sink_input, PA_UPDATE_REPLACE, p);
    pa_proplist_free(p);
}
Exemple #19
0
void pa_client_set_name(pa_client *c, const char *name) {
    pa_assert(c);
    pa_assert(name);

    pa_log_info("Client %u changed name from \"%s\" to \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME)), name);
    pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);

    pa_client_update_proplist(c, 0, NULL);
}
Exemple #20
0
static void m_pa_sink_info_cb(pa_context *c, 
                              const pa_sink_info *i, 
                              int eol, 
                              void *userdata)
{
    if (!c || !i || eol > 0) {
        return;
    }

    pa_sink_port_info **ports  = NULL;
    pa_sink_port_info *port = NULL;
    pa_sink_port_info *active_port = NULL;
    const char *prop_key = NULL;
    void *prop_state = NULL;
    int j;

    while ((prop_key = pa_proplist_iterate(i->proplist, &prop_state))) {
        printf("DEBUG %s %s\n", prop_key, pa_proplist_gets(i->proplist, prop_key));
    }

    m_channel_num = i->channel_map.channels;
    printf("DEBUG channel_map_can_balance %s, channel_map_count %d\n", 
           pa_channel_map_can_balance(&i->channel_map) ? "TRUE" : "FALSE", 
           i->channel_map.channels);
    for (j = 0; j < i->channel_map.channels; j++) {
        printf("DEBUG channel_map %d\n", i->channel_map.map[j]);
    }

    ports = i->ports;
    for (j = 0; j < i->n_ports; j++) {
        port = ports[j];
        printf("DEBUG port %s %s %s\n", 
               port->name, 
               port->description, 
               port->available ? "TRUE" : "FALSE");
    }

    active_port = i->active_port;
    if (active_port) {
        printf("DEBUG active_port %s %s %s\n", 
               active_port->name, 
               active_port->description, 
               active_port->available ? "TRUE" : "FALSE");
    }

    for (j = 0; j < i->volume.channels; j++) {
        printf("DEBUG volume_channel_value %d\n", i->volume.values[j]);
    }
    gtk_adjustment_set_value(m_adjust, i->volume.values[0]);

    printf("DEBUG sink %s %s base_volume %d muted %s\n", 
           i->name, 
           i->description, 
           i->base_volume, 
           i->mute ? "TRUE" : "FALSE");
}
char *pa_client_ext_args(struct pa_client *client)
{
    const char *args;

    assert(client);

    args = pa_proplist_gets(client->proplist,PA_PROP_APPLICATION_PROCESS_ARGS);

    return (char *)args;
}
char *pa_client_ext_name(struct pa_client *client)
{
    const char *name;

    assert(client);

    name = pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME);

    return (char *)name;
}
char *pa_client_ext_id(struct pa_client *client)
{
    const char *id;

    assert(client);

    id = pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_ID);

    return (char *)id;
}
Exemple #24
0
int pa_stream_connect_upload(pa_stream *s, size_t length) {
    pa_tagstruct *t;
    uint32_t tag;
    const char *name;

    pa_assert(s);
    pa_assert(PA_REFCNT_VALUE(s) >= 1);

    PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
    PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE);
    PA_CHECK_VALIDITY(s->context, length > 0, PA_ERR_INVALID);
    PA_CHECK_VALIDITY(s->context, length == (size_t) (uint32_t) length, PA_ERR_INVALID);
    PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);

    if (!(name = pa_proplist_gets(s->proplist, PA_PROP_EVENT_ID)))
        name = pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME);

    PA_CHECK_VALIDITY(s->context, name && *name && pa_utf8_valid(name), PA_ERR_INVALID);

    pa_stream_ref(s);

    s->direction = PA_STREAM_UPLOAD;
    s->flags = 0;

    t = pa_tagstruct_command(s->context, PA_COMMAND_CREATE_UPLOAD_STREAM, &tag);

    pa_tagstruct_puts(t, name);
    pa_tagstruct_put_sample_spec(t, &s->sample_spec);
    pa_tagstruct_put_channel_map(t, &s->channel_map);
    pa_tagstruct_putu32(t, (uint32_t) length);

    if (s->context->version >= 13)
        pa_tagstruct_put_proplist(t, s->proplist);

    pa_pstream_send_tagstruct(s->context->pstream, t);
    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL);

    pa_stream_set_state(s, PA_STREAM_CREATING);

    pa_stream_unref(s);
    return 0;
}
char *pa_client_ext_exe(struct pa_client *client)
{
    const char *exe;

    assert(client);

    exe = pa_proplist_gets(client->proplist,
                           PA_PROP_APPLICATION_PROCESS_BINARY);

    return (char *)exe;
}
static pa_hook_result_t source_output_move_finish_cb(pa_core *core, pa_source_output *i, struct userdata *u) {
    pa_core_assert_ref(core);
    pa_source_output_assert_ref(i);
    pa_assert(u);

    /* module-filter-apply triggered this move, ignore */
    if (pa_proplist_gets(i->proplist, PA_PROP_FILTER_APPLY_MOVING))
        return PA_HOOK_OK;

    return process(u, PA_OBJECT(i), FALSE);
}
static void source_sink(const char * name, const char * descr, pa_proplist * props, PyObject * pylist) {
	const char * value;
	char buf300[300];
	PyObject * pytup;

	pytup = PyTuple_New(3);
	PyList_Append(pylist, pytup);
	PyTuple_SET_ITEM(pytup, 0, PyString_FromString(name));
	PyTuple_SET_ITEM(pytup, 1, PyString_FromString(descr));
	value = pa_proplist_gets(props, "device.api");
    
	if (value && ! strcmp(value, "alsa")) {
		snprintf(buf300, 300, "%s %s (hw:%s,%s)", pa_proplist_gets(props, "alsa.card_name"), pa_proplist_gets(props, "alsa.name"),
			 pa_proplist_gets(props, "alsa.card"), pa_proplist_gets(props, "alsa.device"));

		PyTuple_SET_ITEM(pytup, 2, PyString_FromString(buf300));
	}
	else {
		PyTuple_SET_ITEM(pytup, 2, PyString_FromString(""));
	}
}
void print_properties(pa_proplist *props) {
    void *state = NULL;

    printf("  Properties are: \n");
    while (1) {
	char *key;
	if ((key = pa_proplist_iterate(props, &state)) == NULL) {
	    return;
	}
	char *value = pa_proplist_gets(props, key);
	printf("   key: %s, value: %s\n", key, value);
    }
}
const char *sink_input_ext_get_name(pa_proplist *sinp_proplist)
{
    const char *name;

    pa_assert(sinp_proplist);

    name = pa_proplist_gets(sinp_proplist, PA_PROP_MEDIA_NAME);

    if (name == NULL)
        name = "<unknown>";

    return name;
}
const char *pa_sink_input_ext_get_policy_group(struct pa_sink_input *sinp)
{
    const char *group;

    pa_assert(sinp);

    group = pa_proplist_gets(sinp->proplist, PA_PROP_POLICY_GROUP);

    if (group == NULL)
        group = PA_POLICY_DEFAULT_GROUP_NAME;

    return group;
}