mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	native: Add node querying to the protocol
This commit is contained in:
		
							parent
							
								
									7aec90fb41
								
							
						
					
					
						commit
						fd8578a557
					
				
					 6 changed files with 224 additions and 12 deletions
				
			
		
							
								
								
									
										31
									
								
								PROTOCOL
									
										
									
									
									
								
							
							
						
						
									
										31
									
								
								PROTOCOL
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -343,7 +343,7 @@ SUBCOMMAND_SAVE_FORMATS, in reply from SUBCOMMAND_READ_FORMATS[_ALL]
 | 
			
		|||
    (uint8_t ) PA_ENCODING_MPEG2_AAC_IEC61937 := 6
 | 
			
		||||
 | 
			
		||||
## v29, implemented by >= 5.0
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
New field in all commands that send/receive profile introspection data
 | 
			
		||||
(PA_COMMAND_GET_CARD_INFO)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -351,6 +351,35 @@ New field in all commands that send/receive profile introspection data
 | 
			
		|||
 | 
			
		||||
The field is added once for every profile.
 | 
			
		||||
 | 
			
		||||
New client->server commands:
 | 
			
		||||
    GET_NODE_INFO
 | 
			
		||||
    GET_NODE_INFO_LIST
 | 
			
		||||
 | 
			
		||||
GET_NODE_INFO parameters:
 | 
			
		||||
    uint32_t index
 | 
			
		||||
    string name
 | 
			
		||||
 | 
			
		||||
When getting the node info by index, the index parameter must not be
 | 
			
		||||
PA_INVALID_INDEX and the name parameter must be NULL.
 | 
			
		||||
 | 
			
		||||
When getting the node info by name, the index parameter must be
 | 
			
		||||
PA_INVALID_INDEX and the name parameter must not be NULL or an empty string.
 | 
			
		||||
 | 
			
		||||
GET_NODE_INFO_LIST doesn't have parameters.
 | 
			
		||||
 | 
			
		||||
GET_NODE_INFO reply parameters:
 | 
			
		||||
    uint32_t index
 | 
			
		||||
    string name
 | 
			
		||||
    string description
 | 
			
		||||
    pa_direction_t direction
 | 
			
		||||
 | 
			
		||||
The index must not be PA_INVALID_INDEX. The name must not be NULL or empty. The
 | 
			
		||||
description must not be NULL or empty. The direction must be either OUTPUT or
 | 
			
		||||
INPUT, not both.
 | 
			
		||||
 | 
			
		||||
GET_NODE_INFO_LIST reply parameters are otherwise the same as with
 | 
			
		||||
GET_NODE_INFO, but the parameter list is repeated for each node.
 | 
			
		||||
 | 
			
		||||
#### If you just changed the protocol, read this
 | 
			
		||||
## module-tunnel depends on the sink/source/sink-input/source-input protocol
 | 
			
		||||
## internals, so if you changed these, you might have broken module-tunnel.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,6 +42,9 @@ pa_context_get_client_info_list;
 | 
			
		|||
pa_context_get_index;
 | 
			
		||||
pa_context_get_module_info;
 | 
			
		||||
pa_context_get_module_info_list;
 | 
			
		||||
pa_context_get_node_info_by_index;
 | 
			
		||||
pa_context_get_node_info_by_name;
 | 
			
		||||
pa_context_get_node_info_list;
 | 
			
		||||
pa_context_get_protocol_version;
 | 
			
		||||
pa_context_get_sample_info_by_index;
 | 
			
		||||
pa_context_get_sample_info_by_name;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1780,6 +1780,117 @@ pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t
 | 
			
		|||
    return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, (pa_operation_cb_t) cb, userdata);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*** Routing node info ***/
 | 
			
		||||
 | 
			
		||||
static void context_get_node_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
 | 
			
		||||
    pa_operation *o = userdata;
 | 
			
		||||
    int eol = 1;
 | 
			
		||||
 | 
			
		||||
    pa_assert(pd);
 | 
			
		||||
    pa_assert(o);
 | 
			
		||||
 | 
			
		||||
    if (!o->context)
 | 
			
		||||
        goto finish;
 | 
			
		||||
 | 
			
		||||
    if (command != PA_COMMAND_REPLY) {
 | 
			
		||||
        if (pa_context_handle_error(o->context, command, t, false) < 0)
 | 
			
		||||
            goto finish;
 | 
			
		||||
 | 
			
		||||
        eol = -1;
 | 
			
		||||
    } else {
 | 
			
		||||
 | 
			
		||||
        while (!pa_tagstruct_eof(t)) {
 | 
			
		||||
            pa_node_info info;
 | 
			
		||||
 | 
			
		||||
            pa_zero(info);
 | 
			
		||||
 | 
			
		||||
            if (pa_tagstruct_getu32(t, &info.index) < 0 ||
 | 
			
		||||
                info.index == PA_INVALID_INDEX ||
 | 
			
		||||
                pa_tagstruct_gets(t, &info.name) < 0 ||
 | 
			
		||||
                !info.name || !*info.name ||
 | 
			
		||||
                pa_tagstruct_gets(t, &info.description) < 0 ||
 | 
			
		||||
                !info.description || !*info.description ||
 | 
			
		||||
                pa_tagstruct_get_direction(t, &info.direction) ||
 | 
			
		||||
                (info.direction != PA_DIRECTION_OUTPUT && info.direction != PA_DIRECTION_INPUT)) {
 | 
			
		||||
 | 
			
		||||
                pa_context_fail(o->context, PA_ERR_PROTOCOL);
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (o->callback) {
 | 
			
		||||
                pa_node_info_cb_t cb = (pa_node_info_cb_t) o->callback;
 | 
			
		||||
                cb(o->context, &info, 0, o->userdata);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (o->callback) {
 | 
			
		||||
        pa_node_info_cb_t cb = (pa_node_info_cb_t) o->callback;
 | 
			
		||||
        cb(o->context, NULL, eol, o->userdata);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    pa_operation_done(o);
 | 
			
		||||
    pa_operation_unref(o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_operation *pa_context_get_node_info_by_name(pa_context *c, const char *name, pa_node_info_cb_t cb, void *userdata) {
 | 
			
		||||
    pa_operation *o;
 | 
			
		||||
    pa_tagstruct *t;
 | 
			
		||||
    uint32_t tag;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(name);
 | 
			
		||||
    pa_assert(*name);
 | 
			
		||||
    pa_assert(cb);
 | 
			
		||||
 | 
			
		||||
    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
 | 
			
		||||
    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
 | 
			
		||||
    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 29, PA_ERR_NOTSUPPORTED);
 | 
			
		||||
 | 
			
		||||
    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
 | 
			
		||||
 | 
			
		||||
    t = pa_tagstruct_command(c, PA_COMMAND_GET_NODE_INFO, &tag);
 | 
			
		||||
    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
 | 
			
		||||
    pa_tagstruct_puts(t, name);
 | 
			
		||||
    pa_pstream_send_tagstruct(c->pstream, t);
 | 
			
		||||
    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_node_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
 | 
			
		||||
 | 
			
		||||
    return o;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_operation *pa_context_get_node_info_by_index(pa_context *c, uint32_t idx, pa_node_info_cb_t cb, void *userdata) {
 | 
			
		||||
    pa_operation *o;
 | 
			
		||||
    pa_tagstruct *t;
 | 
			
		||||
    uint32_t tag;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(idx != PA_INVALID_INDEX);
 | 
			
		||||
    pa_assert(cb);
 | 
			
		||||
 | 
			
		||||
    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
 | 
			
		||||
    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
 | 
			
		||||
    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 29, PA_ERR_NOTSUPPORTED);
 | 
			
		||||
 | 
			
		||||
    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
 | 
			
		||||
 | 
			
		||||
    t = pa_tagstruct_command(c, PA_COMMAND_GET_NODE_INFO, &tag);
 | 
			
		||||
    pa_tagstruct_putu32(t, idx);
 | 
			
		||||
    pa_tagstruct_puts(t, NULL);
 | 
			
		||||
    pa_pstream_send_tagstruct(c->pstream, t);
 | 
			
		||||
    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_node_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
 | 
			
		||||
 | 
			
		||||
    return o;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_operation *pa_context_get_node_info_list(pa_context *c, pa_node_info_cb_t cb, void *userdata) {
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 29, PA_ERR_NOTSUPPORTED);
 | 
			
		||||
 | 
			
		||||
    return pa_context_send_simple_command(c, PA_COMMAND_GET_NODE_INFO_LIST, context_get_node_info_callback, (pa_operation_cb_t) cb, userdata);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, pa_context_success_cb_t cb, void *userdata) {
 | 
			
		||||
    pa_operation *o;
 | 
			
		||||
    pa_tagstruct *t;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -671,6 +671,47 @@ pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t
 | 
			
		|||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
/** @{ \name Routing Nodes */
 | 
			
		||||
 | 
			
		||||
/** Routing node information. Please note that this structure can be extended
 | 
			
		||||
 * as part of evolutionary API updates at any time in any new release.
 | 
			
		||||
 *
 | 
			
		||||
 * \since 5.0 */
 | 
			
		||||
typedef struct pa_node_info {
 | 
			
		||||
    /** The index of this node. */
 | 
			
		||||
    uint32_t index;
 | 
			
		||||
 | 
			
		||||
    /** The name of this node. While one name can refer to only one node at any
 | 
			
		||||
     * given time, the same name can still refer to multiple nodes over time,
 | 
			
		||||
     * and the same node may have a different name e.g. after server restart.
 | 
			
		||||
     * This means that nodes don't have any identifier that could be e.g. saved
 | 
			
		||||
     * to disk for referring to the same node later. There may be some nodes in
 | 
			
		||||
     * the future that have a fixed name, but currently there are none. */
 | 
			
		||||
    const char *name;
 | 
			
		||||
 | 
			
		||||
    /** The human-readable description of this node. This is localized and
 | 
			
		||||
     * suitable to be shown in user interfaces as the label for this node. */
 | 
			
		||||
    const char *description;
 | 
			
		||||
 | 
			
		||||
    /** The direction of this node. */
 | 
			
		||||
    pa_direction_t direction;
 | 
			
		||||
} pa_node_info;
 | 
			
		||||
 | 
			
		||||
/** Callback prototype for pa_context_get_node_info_by_name() and friends.
 | 
			
		||||
 * \since 5.0 */
 | 
			
		||||
typedef void (*pa_node_info_cb_t)(pa_context *c, const pa_node_info *info, int eol, void *userdata);
 | 
			
		||||
 | 
			
		||||
/** Get information about a node by its name. \since 5.0 */
 | 
			
		||||
pa_operation *pa_context_get_node_info_by_name(pa_context *c, const char *name, pa_node_info_cb_t cb, void *userdata);
 | 
			
		||||
 | 
			
		||||
/** Get information about a node by its index. \since 5.0 */
 | 
			
		||||
pa_operation *pa_context_get_node_info_by_index(pa_context *c, uint32_t idx, pa_node_info_cb_t cb, void *userdata);
 | 
			
		||||
 | 
			
		||||
/** Get a list of all nodes. \since 5.0 */
 | 
			
		||||
pa_operation *pa_context_get_node_info_list(pa_context *c, pa_node_info_cb_t cb, void *userdata);
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
/** \cond fulldocs */
 | 
			
		||||
 | 
			
		||||
/** @{ \name Autoload Entries */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -176,6 +176,10 @@ enum {
 | 
			
		|||
    /* Supported since protocol v27 (3.0) */
 | 
			
		||||
    PA_COMMAND_SET_PORT_LATENCY_OFFSET,
 | 
			
		||||
 | 
			
		||||
    /* Supported since protocol v29 (5.0) */
 | 
			
		||||
    PA_COMMAND_GET_NODE_INFO,
 | 
			
		||||
    PA_COMMAND_GET_NODE_INFO_LIST,
 | 
			
		||||
 | 
			
		||||
    PA_COMMAND_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -325,6 +325,7 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
 | 
			
		|||
    [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
 | 
			
		||||
    [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
 | 
			
		||||
    [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
 | 
			
		||||
    [PA_COMMAND_GET_NODE_INFO] = command_get_info,
 | 
			
		||||
    [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
 | 
			
		||||
    [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
 | 
			
		||||
    [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
 | 
			
		||||
| 
						 | 
				
			
			@ -333,6 +334,7 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
 | 
			
		|||
    [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
 | 
			
		||||
    [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
 | 
			
		||||
    [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
 | 
			
		||||
    [PA_COMMAND_GET_NODE_INFO_LIST] = command_get_info_list,
 | 
			
		||||
    [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
 | 
			
		||||
    [PA_COMMAND_SUBSCRIBE] = command_subscribe,
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3455,6 +3457,16 @@ static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s
 | 
			
		|||
        pa_tagstruct_put_proplist(t, e->proplist);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void node_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_node *node) {
 | 
			
		||||
    pa_assert(t);
 | 
			
		||||
    pa_assert(node);
 | 
			
		||||
 | 
			
		||||
    pa_tagstruct_putu32(t, node->index);
 | 
			
		||||
    pa_tagstruct_puts(t, node->name);
 | 
			
		||||
    pa_tagstruct_puts(t, node->description);
 | 
			
		||||
    pa_tagstruct_put_direction(t, node->direction);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
 | 
			
		||||
    pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
 | 
			
		||||
    uint32_t idx;
 | 
			
		||||
| 
						 | 
				
			
			@ -3466,6 +3478,7 @@ static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, p
 | 
			
		|||
    pa_sink_input *si = NULL;
 | 
			
		||||
    pa_source_output *so = NULL;
 | 
			
		||||
    pa_scache_entry *sce = NULL;
 | 
			
		||||
    pa_node *node = NULL;
 | 
			
		||||
    const char *name = NULL;
 | 
			
		||||
    pa_tagstruct *reply;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3519,15 +3532,20 @@ static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, p
 | 
			
		|||
        si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
 | 
			
		||||
    else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
 | 
			
		||||
        so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
 | 
			
		||||
    else {
 | 
			
		||||
        pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
 | 
			
		||||
    else if (command == PA_COMMAND_GET_SAMPLE_INFO) {
 | 
			
		||||
        if (idx != PA_INVALID_INDEX)
 | 
			
		||||
            sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
 | 
			
		||||
        else
 | 
			
		||||
            sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
 | 
			
		||||
    }
 | 
			
		||||
    } else if (command == PA_COMMAND_GET_NODE_INFO) {
 | 
			
		||||
        if (idx != PA_INVALID_INDEX)
 | 
			
		||||
            node = pa_idxset_get_by_index(c->protocol->core->nodes, idx);
 | 
			
		||||
        else
 | 
			
		||||
            node = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_NODE);
 | 
			
		||||
    } else
 | 
			
		||||
        pa_assert_not_reached();
 | 
			
		||||
 | 
			
		||||
    if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
 | 
			
		||||
    if (!sink && !source && !client && !card && !module && !si && !so && !sce && !node) {
 | 
			
		||||
        pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -3547,8 +3565,10 @@ static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, p
 | 
			
		|||
        sink_input_fill_tagstruct(c, reply, si);
 | 
			
		||||
    else if (so)
 | 
			
		||||
        source_output_fill_tagstruct(c, reply, so);
 | 
			
		||||
    else
 | 
			
		||||
    else if (sce)
 | 
			
		||||
        scache_fill_tagstruct(c, reply, sce);
 | 
			
		||||
    else if (node)
 | 
			
		||||
        node_fill_tagstruct(c, reply, node);
 | 
			
		||||
    pa_pstream_send_tagstruct(c->pstream, reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3585,10 +3605,12 @@ static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t t
 | 
			
		|||
        i = c->protocol->core->sink_inputs;
 | 
			
		||||
    else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
 | 
			
		||||
        i = c->protocol->core->source_outputs;
 | 
			
		||||
    else {
 | 
			
		||||
        pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
 | 
			
		||||
    else if (command == PA_COMMAND_GET_SAMPLE_INFO_LIST)
 | 
			
		||||
        i = c->protocol->core->scache;
 | 
			
		||||
    }
 | 
			
		||||
    else if (command == PA_COMMAND_GET_NODE_INFO_LIST)
 | 
			
		||||
        i = c->protocol->core->nodes;
 | 
			
		||||
    else
 | 
			
		||||
        pa_assert_not_reached();
 | 
			
		||||
 | 
			
		||||
    if (i) {
 | 
			
		||||
        PA_IDXSET_FOREACH(p, i, idx) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3606,10 +3628,12 @@ static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t t
 | 
			
		|||
                sink_input_fill_tagstruct(c, reply, p);
 | 
			
		||||
            else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
 | 
			
		||||
                source_output_fill_tagstruct(c, reply, p);
 | 
			
		||||
            else {
 | 
			
		||||
                pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
 | 
			
		||||
            else if (command == PA_COMMAND_GET_SAMPLE_INFO_LIST)
 | 
			
		||||
                scache_fill_tagstruct(c, reply, p);
 | 
			
		||||
            }
 | 
			
		||||
            else if (command == PA_COMMAND_GET_NODE_INFO_LIST)
 | 
			
		||||
                node_fill_tagstruct(c, reply, p);
 | 
			
		||||
            else
 | 
			
		||||
                pa_assert_not_reached();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue