mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-28 05:40:21 -04:00
introspect: Expose port info per card to clients
For volume control UIs to be able to show ports in inactive profiles, expose all ports together with the card info. This includes updating the protocol and the client API to show the connection between ports and for which profiles the ports are relevant. Update protocol to 26. Signed-off-by: David Henningsson <david.henningsson@canonical.com>
This commit is contained in:
parent
752ae7285e
commit
793f46320e
7 changed files with 207 additions and 7 deletions
23
PROTOCOL
23
PROTOCOL
|
|
@ -299,6 +299,29 @@ The field is added once for every port.
|
|||
When port availability changes, send a subscription event for the
|
||||
owning card.
|
||||
|
||||
## v26, implemented by >= 2.0
|
||||
|
||||
In reply from PA_COMMAND_GET_CARD_INFO (and thus
|
||||
PA_COMMAND_GET_CARD_INFO_LIST), the following is added:
|
||||
|
||||
uint32_t n_ports
|
||||
|
||||
...followed by n_ports extended port entries, which look like this:
|
||||
|
||||
string name
|
||||
string description
|
||||
uint32_t priority
|
||||
uint32_t available
|
||||
uint8_t direction
|
||||
proplist
|
||||
uint32_t n_profiles
|
||||
string profile_name_1
|
||||
...
|
||||
string profile_name_n
|
||||
|
||||
Profile names must match earlier sent profile names for the same card.
|
||||
|
||||
|
||||
#### 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.
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ AC_SUBST(PA_MINOR, pa_minor)
|
|||
AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
|
||||
|
||||
AC_SUBST(PA_API_VERSION, 12)
|
||||
AC_SUBST(PA_PROTOCOL_VERSION, 25)
|
||||
AC_SUBST(PA_PROTOCOL_VERSION, 26)
|
||||
|
||||
# The stable ABI for client applications, for the version info x:y:z
|
||||
# always will hold y=z
|
||||
|
|
|
|||
|
|
@ -124,6 +124,20 @@ typedef enum pa_context_flags {
|
|||
#define PA_CONTEXT_NOFAIL PA_CONTEXT_NOFAIL
|
||||
/** \endcond */
|
||||
|
||||
/** Direction bitfield - while we currently do not expose anything bidirectional,
|
||||
one should test against the bit instead of the value (e g if (d & PA_DIRECTION_OUTPUT)),
|
||||
because we might add bidirectional stuff in the future. \since 2.0
|
||||
*/
|
||||
typedef enum pa_direction {
|
||||
PA_DIRECTION_OUTPUT = 0x0001U, /**< Output direction */
|
||||
PA_DIRECTION_INPUT = 0x0002U /**< Input direction */
|
||||
} pa_direction_t;
|
||||
|
||||
/** \cond fulldocs */
|
||||
#define PA_DIRECTION_OUTPUT PA_DIRECTION_OUTPUT
|
||||
#define PA_DIRECTION_INPUT PA_DIRECTION_INPUT
|
||||
/** \endcond */
|
||||
|
||||
/** The type of device we are dealing with */
|
||||
typedef enum pa_device_type {
|
||||
PA_DEVICE_TYPE_SINK, /**< Playback device */
|
||||
|
|
|
|||
|
|
@ -763,9 +763,101 @@ pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t
|
|||
|
||||
/*** Card info ***/
|
||||
|
||||
static void card_info_free(pa_card_info* i)
|
||||
{
|
||||
if (i->proplist)
|
||||
pa_proplist_free(i->proplist);
|
||||
|
||||
pa_xfree(i->profiles);
|
||||
|
||||
if (i->ports) {
|
||||
uint32_t j;
|
||||
|
||||
for (j = 0; j < i->n_ports; j++) {
|
||||
if (i->ports[j]) {
|
||||
if (i->ports[j]->profiles)
|
||||
pa_xfree(i->ports[j]->profiles);
|
||||
if (i->ports[j]->proplist)
|
||||
pa_proplist_free(i->ports[j]->proplist);
|
||||
}
|
||||
}
|
||||
|
||||
pa_xfree(i->ports[0]);
|
||||
pa_xfree(i->ports);
|
||||
}
|
||||
}
|
||||
|
||||
static int fill_card_port_info(pa_tagstruct* t, pa_card_info* i)
|
||||
{
|
||||
uint32_t j, k, l;
|
||||
|
||||
if (pa_tagstruct_getu32(t, &i->n_ports) < 0)
|
||||
return -PA_ERR_PROTOCOL;
|
||||
|
||||
if (i->n_ports == 0) {
|
||||
i->ports = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
i->ports = pa_xnew0(pa_card_port_info*, i->n_ports+1);
|
||||
i->ports[0] = pa_xnew0(pa_card_port_info, i->n_ports);
|
||||
|
||||
for (j = 0; j < i->n_ports; j++) {
|
||||
uint8_t direction;
|
||||
uint32_t available;
|
||||
pa_card_port_info* port = i->ports[j] = &i->ports[0][j];
|
||||
|
||||
port->proplist = pa_proplist_new();
|
||||
|
||||
if (pa_tagstruct_gets(t, &port->name) < 0 ||
|
||||
pa_tagstruct_gets(t, &port->description) < 0 ||
|
||||
pa_tagstruct_getu32(t, &port->priority) < 0 ||
|
||||
pa_tagstruct_getu32(t, &available) < 0 ||
|
||||
pa_tagstruct_getu8(t, &direction) < 0 ||
|
||||
pa_tagstruct_get_proplist(t, port->proplist) < 0 ||
|
||||
pa_tagstruct_getu32(t, &port->n_profiles) < 0) {
|
||||
|
||||
return -PA_ERR_PROTOCOL;
|
||||
}
|
||||
|
||||
if (available > PA_PORT_AVAILABLE_YES ||
|
||||
direction > PA_DIRECTION_OUTPUT + PA_DIRECTION_INPUT) {
|
||||
|
||||
return -PA_ERR_PROTOCOL;
|
||||
}
|
||||
|
||||
port->direction = direction;
|
||||
port->available = available;
|
||||
|
||||
if (port->n_profiles > 0) {
|
||||
port->profiles = pa_xnew0(pa_card_profile_info*, i->n_profiles+1);
|
||||
|
||||
for (k = 0; k < port->n_profiles; k++) {
|
||||
const char* profilename;
|
||||
|
||||
if (pa_tagstruct_gets(t, &profilename) < 0)
|
||||
return -PA_ERR_PROTOCOL;
|
||||
|
||||
for (l = 0; l < i->n_profiles; l++) {
|
||||
if (pa_streq(i->profiles[l].name, profilename)) {
|
||||
port->profiles[k] = &i->profiles[l];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (l >= i->n_profiles)
|
||||
return -PA_ERR_PROTOCOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void context_get_card_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
||||
pa_operation *o = userdata;
|
||||
int eol = 1;
|
||||
pa_card_info i;
|
||||
|
||||
pa_assert(pd);
|
||||
pa_assert(o);
|
||||
|
|
@ -782,7 +874,6 @@ static void context_get_card_info_callback(pa_pdispatch *pd, uint32_t command, u
|
|||
} else {
|
||||
|
||||
while (!pa_tagstruct_eof(t)) {
|
||||
pa_card_info i;
|
||||
uint32_t j;
|
||||
const char*ap;
|
||||
|
||||
|
|
@ -795,6 +886,7 @@ static void context_get_card_info_callback(pa_pdispatch *pd, uint32_t command, u
|
|||
pa_tagstruct_getu32(t, &i.n_profiles) < 0) {
|
||||
|
||||
pa_context_fail(o->context, PA_ERR_PROTOCOL);
|
||||
card_info_free(&i);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
|
|
@ -810,7 +902,7 @@ static void context_get_card_info_callback(pa_pdispatch *pd, uint32_t command, u
|
|||
pa_tagstruct_getu32(t, &i.profiles[j].priority) < 0) {
|
||||
|
||||
pa_context_fail(o->context, PA_ERR_PROTOCOL);
|
||||
pa_xfree(i.profiles);
|
||||
card_info_free(&i);
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
|
@ -826,8 +918,7 @@ static void context_get_card_info_callback(pa_pdispatch *pd, uint32_t command, u
|
|||
pa_tagstruct_get_proplist(t, i.proplist) < 0) {
|
||||
|
||||
pa_context_fail(o->context, PA_ERR_PROTOCOL);
|
||||
pa_xfree(i.profiles);
|
||||
pa_proplist_free(i.proplist);
|
||||
card_info_free(&i);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
|
|
@ -839,13 +930,20 @@ static void context_get_card_info_callback(pa_pdispatch *pd, uint32_t command, u
|
|||
}
|
||||
}
|
||||
|
||||
if (o->context->version >= 26) {
|
||||
if (fill_card_port_info(t, &i) < 0) {
|
||||
pa_context_fail(o->context, PA_ERR_PROTOCOL);
|
||||
card_info_free(&i);
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
if (o->callback) {
|
||||
pa_card_info_cb_t cb = (pa_card_info_cb_t) o->callback;
|
||||
cb(o->context, &i, 0, o->userdata);
|
||||
}
|
||||
|
||||
pa_proplist_free(i.proplist);
|
||||
pa_xfree(i.profiles);
|
||||
card_info_free(&i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -454,6 +454,20 @@ typedef struct pa_card_profile_info {
|
|||
uint32_t priority; /**< The higher this value is the more useful this profile is as a default */
|
||||
} pa_card_profile_info;
|
||||
|
||||
/** Stores information about a specific port of a card. Please
|
||||
* note that this structure can be extended as part of evolutionary
|
||||
* API updates at any time in any new release. \since 2.0 */
|
||||
typedef struct pa_card_port_info {
|
||||
const char *name; /**< Name of this port */
|
||||
const char *description; /**< Description of this port */
|
||||
uint32_t priority; /**< The higher this value is the more useful this port is as a default */
|
||||
int available; /**< A \link pa_port_available_t, indicating availability status of this port. */
|
||||
int direction; /**< This is a \link pa_direction_t enum, indicating the direction of this port. */
|
||||
uint32_t n_profiles; /**< Number of entries in profile array */
|
||||
pa_card_profile_info** profiles; /**< Array of pointers available profile, or NULL. Array is terminated by an entry set to NULL. */
|
||||
pa_proplist *proplist; /**< Property list */
|
||||
} pa_card_port_info;
|
||||
|
||||
/** Stores information about cards. Please note that this structure
|
||||
* can be extended as part of evolutionary API updates at any time in
|
||||
* any new release. \since 0.9.15 */
|
||||
|
|
@ -466,6 +480,8 @@ typedef struct pa_card_info {
|
|||
pa_card_profile_info* profiles; /**< Array of available profile, or NULL. Array is terminated by an entry with name set to NULL. Number of entries is stored in n_profiles */
|
||||
pa_card_profile_info* active_profile; /**< Pointer to active profile in the array, or NULL */
|
||||
pa_proplist *proplist; /**< Property list */
|
||||
uint32_t n_ports; /**< Number of entries in port array */
|
||||
pa_card_port_info **ports; /**< Array of pointers to ports, or NULL. Array is terminated by an entry set to NULL. */
|
||||
} pa_card_info;
|
||||
|
||||
/** Callback prototype for pa_context_get_card_info_...() \since 0.9.15 */
|
||||
|
|
|
|||
|
|
@ -3258,6 +3258,36 @@ static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_car
|
|||
|
||||
pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
|
||||
pa_tagstruct_put_proplist(t, card->proplist);
|
||||
|
||||
if (c->version < 26)
|
||||
return;
|
||||
|
||||
if (card->ports) {
|
||||
pa_device_port* port;
|
||||
pa_proplist* proplist = pa_proplist_new(); /* For now - push an empty proplist */
|
||||
|
||||
pa_tagstruct_putu32(t, pa_hashmap_size(card->ports));
|
||||
|
||||
PA_HASHMAP_FOREACH(port, card->ports, state) {
|
||||
pa_tagstruct_puts(t, port->name);
|
||||
pa_tagstruct_puts(t, port->description);
|
||||
pa_tagstruct_putu32(t, port->priority);
|
||||
pa_tagstruct_putu32(t, port->available);
|
||||
pa_tagstruct_putu8(t, /* FIXME: port->direction */ (port->is_input ? PA_DIRECTION_INPUT : 0) | (port->is_output ? PA_DIRECTION_OUTPUT : 0));
|
||||
pa_tagstruct_put_proplist(t, proplist);
|
||||
|
||||
if (port->profiles) {
|
||||
void* state2;
|
||||
pa_tagstruct_putu32(t, pa_hashmap_size(port->profiles));
|
||||
PA_HASHMAP_FOREACH(p, port->profiles, state2)
|
||||
pa_tagstruct_puts(t, p->name);
|
||||
} else
|
||||
pa_tagstruct_putu32(t, 0);
|
||||
}
|
||||
|
||||
pa_proplist_free(proplist);
|
||||
} else
|
||||
pa_tagstruct_putu32(t, 0);
|
||||
}
|
||||
|
||||
static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
|
||||
|
|
|
|||
|
|
@ -582,6 +582,25 @@ static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_
|
|||
printf(_("\tActive Profile: %s\n"),
|
||||
i->active_profile->name);
|
||||
|
||||
if (i->ports) {
|
||||
pa_card_port_info **p;
|
||||
|
||||
printf(_("\tPorts:\n"));
|
||||
for (p = i->ports; *p; p++) {
|
||||
pa_card_profile_info **pr = (*p)->profiles;
|
||||
printf(_("\t\t%s: %s (priority %u)\n"), (*p)->name, (*p)->description, (*p)->priority);
|
||||
if (pr) {
|
||||
printf(_("\t\t\tPart of profile(s): %s"), pa_strnull((*pr)->name));
|
||||
pr++;
|
||||
while (*pr) {
|
||||
printf(", %s", pa_strnull((*pr)->name));
|
||||
pr++;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pa_xfree(pl);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue