pulse: don't use endpoints

Revert back to using nodes, ports and devices. Let's first get this
stable until we add endpoints in the mix.
This commit is contained in:
Wim Taymans 2020-01-13 09:30:25 +01:00
parent 9db240e786
commit 3dbcc7808c
4 changed files with 174 additions and 238 deletions

View file

@ -142,7 +142,7 @@ struct global *pa_context_find_global_by_name(pa_context *c, uint32_t mask, cons
(str = pw_properties_get(g->props, PW_KEY_NODE_NAME)) != NULL && (str = pw_properties_get(g->props, PW_KEY_NODE_NAME)) != NULL &&
strcmp(str, name) == 0) strcmp(str, name) == 0)
return g; return g;
if (g->id == id) if (g->id == id || (g->id == (id & PA_IDX_MASK_DSP)))
return g; return g;
} }
return NULL; return NULL;
@ -153,25 +153,26 @@ struct global *pa_context_find_linked(pa_context *c, uint32_t idx)
struct global *g, *f; struct global *g, *f;
spa_list_for_each(g, &c->globals, link) { spa_list_for_each(g, &c->globals, link) {
if (strcmp(g->type, PW_TYPE_INTERFACE_EndpointLink) != 0) uint32_t src_node_id, dst_node_id;
if (strcmp(g->type, PW_TYPE_INTERFACE_Link) != 0)
continue; continue;
pw_log_debug("context %p: %p %d %d:%d %d:%d", c, g, idx, src_node_id = g->link_info.src->port_info.node_id;
g->link_info.output->id, g->link_info.output->endpoint_info.node_id, dst_node_id = g->link_info.dst->port_info.node_id;
g->link_info.input->id, g->link_info.input->endpoint_info.node_id);
if (g->link_info.input->id == idx || pw_log_debug("context %p: %p %d %d %d", c, g, idx,
g->link_info.input->endpoint_info.node_id == idx) src_node_id, dst_node_id);
f = g->link_info.output;
else if (g->link_info.output->id == idx || if (src_node_id == idx)
g->link_info.output->endpoint_info.node_id == idx) f = pa_context_find_global(c, dst_node_id);
f = g->link_info.input; else if (dst_node_id == idx)
f = pa_context_find_global(c, src_node_id);
else else
continue; continue;
if (f == NULL || ((f->mask & (PA_SUBSCRIPTION_MASK_SOURCE | PA_SUBSCRIPTION_MASK_SINK)) == 0)) if (f == NULL)
continue; continue;
return f; return f;
} }
return NULL; return NULL;
@ -185,6 +186,15 @@ static void emit_event(pa_context *c, struct global *g, pa_subscription_event_ty
event | g->event, event | g->event,
g->id, g->id,
c->subscribe_userdata); c->subscribe_userdata);
if (g->mask == (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE)) {
pw_log_debug("context %p: obj %d: emit %d:%d", c, g->node_info.monitor,
event, PA_SUBSCRIPTION_EVENT_SOURCE);
c->subscribe_callback(c,
event | PA_SUBSCRIPTION_EVENT_SOURCE,
g->node_info.monitor,
c->subscribe_userdata);
}
} }
} }
@ -197,16 +207,15 @@ static void update_device_props(struct global *g)
pa_proplist_sets(i->proplist, PA_PROP_DEVICE_ICON_NAME, s); pa_proplist_sets(i->proplist, PA_PROP_DEVICE_ICON_NAME, s);
} }
static void device_event_info(void *object, const struct pw_device_info *update) static void device_event_info(void *object, const struct pw_device_info *info)
{ {
struct global *g = object; struct global *g = object;
pa_card_info *i = &g->card_info.info; pa_card_info *i = &g->card_info.info;
const char *str; const char *str;
uint32_t n; uint32_t n;
struct pw_device_info *info;
pw_log_debug("global %p: id:%d change-mask:%08lx", g, g->id, update->change_mask); pw_log_debug("global %p: id:%d change-mask:%"PRIu64, g, g->id, info->change_mask);
info = g->info = pw_device_info_update(g->info, update); info = g->info = pw_device_info_update(g->info, info);
i->index = g->id; i->index = g->id;
i->name = info->props ? i->name = info->props ?
@ -224,8 +233,7 @@ static void device_event_info(void *object, const struct pw_device_info *update)
} }
update_device_props(g); update_device_props(g);
} }
info->change_mask = update->change_mask; if (info->change_mask & PW_DEVICE_CHANGE_MASK_PARAMS) {
if (update->change_mask & PW_DEVICE_CHANGE_MASK_PARAMS) {
for (n = 0; n < info->n_params; n++) { for (n = 0; n < info->n_params; n++) {
if (!(info->params[n].flags & SPA_PARAM_INFO_READ)) if (!(info->params[n].flags & SPA_PARAM_INFO_READ))
continue; continue;
@ -318,39 +326,20 @@ static void device_destroy(void *data)
pw_device_info_free(global->info); pw_device_info_free(global->info);
} }
static void endpoint_event_info(void *object, const struct pw_endpoint_info *update) static void node_event_info(void *object, const struct pw_node_info *info)
{ {
struct global *g = object; struct global *g = object;
struct pw_endpoint_info *info = g->info;
uint32_t i; uint32_t i;
pw_log_debug("update %d %08x", g->id, update->change_mask); pw_log_debug("update %d %"PRIu64, g->id, info->change_mask);
if (info == NULL) { g->info = pw_node_info_update(g->info, info);
info = g->info = calloc(1, sizeof(*info));
info->id = update->id;
info->name = update->name ? strdup(update->name) : NULL;
info->media_class = update->media_class ? strdup(update->media_class) : NULL;
info->direction = update->direction;
info->flags = update->flags;
}
info->change_mask = update->change_mask;
if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_STREAMS) if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS && !g->subscribed) {
info->n_streams = update->n_streams;
if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_SESSION)
info->session_id = update->session_id;
if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS && !g->subscribed) {
uint32_t subscribed[32], n_subscribed = 0; uint32_t subscribed[32], n_subscribed = 0;
info->n_params = update->n_params;
free(info->params);
info->params = malloc(info->n_params * sizeof(struct spa_param_info));
memcpy(info->params, update->params,
info->n_params * sizeof(struct spa_param_info));
for (i = 0; i < info->n_params; i++) { for (i = 0; i < info->n_params; i++) {
switch (info->params[i].id) { switch (info->params[i].id) {
case SPA_PARAM_EnumRoute: case SPA_PARAM_EnumFormat:
case SPA_PARAM_Props: case SPA_PARAM_Props:
subscribed[n_subscribed++] = info->params[i].id; subscribed[n_subscribed++] = info->params[i].id;
break; break;
@ -359,32 +348,11 @@ static void endpoint_event_info(void *object, const struct pw_endpoint_info *upd
} }
} }
if (n_subscribed > 0) { if (n_subscribed > 0) {
pw_endpoint_subscribe_params((struct pw_endpoint*)g->proxy, pw_node_subscribe_params((struct pw_node*)g->proxy,
subscribed, n_subscribed); subscribed, n_subscribed);
g->subscribed = true; g->subscribed = true;
} }
} }
if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) {
if (info->props)
pw_properties_free ((struct pw_properties *)info->props);
info->props =
(struct spa_dict *) pw_properties_new_dict (update->props);
#if 0
i->name = info->props ?
spa_dict_lookup(info->props, PW_KEY_ENDPOINT_NAME) : "unknown";
str = info->props ? spa_dict_lookup(info->props, PW_KEY_MODULE_ID) : NULL;
i->owner_module = str ? (unsigned)atoi(str) : SPA_ID_INVALID;
i->driver = info->props ?
spa_dict_lookup(info->props, PW_KEY_DEVICE_API) : "unknown";
if (i->proplist)
pa_proplist_update_dict(i->proplist, info->props);
else {
i->proplist = pa_proplist_new_dict(info->props);
}
#endif
}
g->pending_seq = pw_proxy_sync(g->proxy, 0); g->pending_seq = pw_proxy_sync(g->proxy, 0);
} }
@ -396,22 +364,22 @@ static void parse_props(struct global *g, const struct spa_pod *param)
SPA_POD_OBJECT_FOREACH(obj, prop) { SPA_POD_OBJECT_FOREACH(obj, prop) {
switch (prop->key) { switch (prop->key) {
case SPA_PROP_volume: case SPA_PROP_volume:
spa_pod_get_float(&prop->value, &g->endpoint_info.volume); spa_pod_get_float(&prop->value, &g->node_info.volume);
break; break;
case SPA_PROP_mute: case SPA_PROP_mute:
spa_pod_get_bool(&prop->value, &g->endpoint_info.mute); spa_pod_get_bool(&prop->value, &g->node_info.mute);
break; break;
case SPA_PROP_channelVolumes: case SPA_PROP_channelVolumes:
{ {
uint32_t n_vals; uint32_t n_vals;
n_vals = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, n_vals = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
g->endpoint_info.channel_volumes, SPA_AUDIO_MAX_CHANNELS); g->node_info.channel_volumes, SPA_AUDIO_MAX_CHANNELS);
if (n_vals != g->endpoint_info.n_channel_volumes) { if (n_vals != g->node_info.n_channel_volumes) {
emit_event(g->context, g, PA_SUBSCRIPTION_EVENT_REMOVE); emit_event(g->context, g, PA_SUBSCRIPTION_EVENT_REMOVE);
emit_event(g->context, g, PA_SUBSCRIPTION_EVENT_NEW); emit_event(g->context, g, PA_SUBSCRIPTION_EVENT_NEW);
g->endpoint_info.n_channel_volumes = n_vals; g->node_info.n_channel_volumes = n_vals;
} }
break; break;
} }
@ -421,12 +389,7 @@ static void parse_props(struct global *g, const struct spa_pod *param)
} }
} }
/* routing information on the endpoint is mapped to sink/source ports. */ static void node_event_param(void *object, int seq,
static void parse_route(struct global *g, const struct spa_pod *param)
{
}
static void endpoint_event_param(void *object, int seq,
uint32_t id, uint32_t index, uint32_t next, uint32_t id, uint32_t index, uint32_t next,
const struct spa_pod *param) const struct spa_pod *param)
{ {
@ -437,31 +400,22 @@ static void endpoint_event_param(void *object, int seq,
case SPA_PARAM_Props: case SPA_PARAM_Props:
parse_props(g, param); parse_props(g, param);
break; break;
case SPA_PARAM_EnumRoute:
parse_route(g, param);
break;
default: default:
break; break;
} }
} }
static const struct pw_endpoint_events endpoint_events = { static const struct pw_node_events node_events = {
PW_VERSION_ENDPOINT_EVENTS, PW_VERSION_NODE_EVENTS,
.info = endpoint_event_info, .info = node_event_info,
.param = endpoint_event_param, .param = node_event_param,
}; };
static void endpoint_destroy(void *data) static void node_destroy(void *data)
{ {
struct global *global = data; struct global *global = data;
if (global->info) { if (global->info)
struct pw_endpoint_info *info = global->info; pw_node_info_free(global->info);
free(info->name);
free(info->params);
if (info->props)
pw_properties_free ((struct pw_properties *)info->props);
free(info);
}
} }
static void module_event_info(void *object, const struct pw_module_info *info) static void module_event_info(void *object, const struct pw_module_info *info)
@ -574,8 +528,9 @@ static const struct pw_proxy_events proxy_events = {
static int set_mask(pa_context *c, struct global *g) static int set_mask(pa_context *c, struct global *g)
{ {
const char *str; const char *str;
const void *events = NULL; struct global *f;
pw_destroy_t destroy; const void *events = NULL;
pw_destroy_t destroy;
uint32_t client_version; uint32_t client_version;
if (strcmp(g->type, PW_TYPE_INTERFACE_Device) == 0) { if (strcmp(g->type, PW_TYPE_INTERFACE_Device) == 0) {
@ -586,7 +541,6 @@ static int set_mask(pa_context *c, struct global *g)
if (strcmp(str, "Audio/Device") != 0) if (strcmp(str, "Audio/Device") != 0)
return 0; return 0;
/* devices are turned into card objects */
pw_log_debug("found card %d", g->id); pw_log_debug("found card %d", g->id);
g->mask = PA_SUBSCRIPTION_MASK_CARD; g->mask = PA_SUBSCRIPTION_MASK_CARD;
g->event = PA_SUBSCRIPTION_EVENT_CARD; g->event = PA_SUBSCRIPTION_EVENT_CARD;
@ -595,37 +549,28 @@ static int set_mask(pa_context *c, struct global *g)
client_version = PW_VERSION_DEVICE; client_version = PW_VERSION_DEVICE;
destroy = device_destroy; destroy = device_destroy;
spa_list_init(&g->card_info.profiles); spa_list_init(&g->card_info.profiles);
} else if (strcmp(g->type, PW_TYPE_INTERFACE_Endpoint) == 0) { } else if (strcmp(g->type, PW_TYPE_INTERFACE_Node) == 0) {
if (g->props == NULL) if (g->props == NULL)
return 0; return 0;
if ((str = pw_properties_get(g->props, PW_KEY_PRIORITY_SESSION)) != NULL) if ((str = pw_properties_get(g->props, PW_KEY_PRIORITY_MASTER)) != NULL)
g->priority_session = pw_properties_parse_int(str); g->priority_master = pw_properties_parse_int(str);
if ((str = pw_properties_get(g->props, PW_KEY_MEDIA_CLASS)) == NULL) { if ((str = pw_properties_get(g->props, PW_KEY_MEDIA_CLASS)) == NULL) {
pw_log_warn("endpoint %d without "PW_KEY_MEDIA_CLASS, g->id); pw_log_debug("node %d without "PW_KEY_MEDIA_CLASS, g->id);
return 0; return 0;
} }
g->endpoint_info.monitor = SPA_ID_INVALID;
/* endpoints get transformed into sink/source or sink_input/source_output */
if (strcmp(str, "Audio/Sink") == 0) { if (strcmp(str, "Audio/Sink") == 0) {
pw_log_debug("found sink %d", g->id); pw_log_debug("found sink %d", g->id);
g->mask = PA_SUBSCRIPTION_MASK_SINK; g->mask = PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE;
g->event = PA_SUBSCRIPTION_EVENT_SINK; g->event = PA_SUBSCRIPTION_EVENT_SINK;
g->node_info.monitor = g->id | PA_IDX_FLAG_DSP;
} }
else if (strcmp(str, "Audio/Source") == 0) { else if (strcmp(str, "Audio/Source") == 0) {
pw_log_debug("found source %d", g->id); pw_log_debug("found source %d", g->id);
g->mask = PA_SUBSCRIPTION_MASK_SOURCE; g->mask = PA_SUBSCRIPTION_MASK_SOURCE;
g->event = PA_SUBSCRIPTION_EVENT_SOURCE; g->event = PA_SUBSCRIPTION_EVENT_SOURCE;
if ((str = pw_properties_get(g->props, PW_KEY_ENDPOINT_MONITOR)) != NULL) {
struct global *f;
f = pa_context_find_global(c, pw_properties_parse_int(str));
if (f != NULL) {
g->endpoint_info.monitor = f->id;
f->endpoint_info.monitor = g->id;
}
}
} }
else if (strcmp(str, "Stream/Output/Audio") == 0) { else if (strcmp(str, "Stream/Output/Audio") == 0) {
pw_log_debug("found sink input %d", g->id); pw_log_debug("found sink input %d", g->id);
@ -638,36 +583,26 @@ static int set_mask(pa_context *c, struct global *g)
g->event = PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT; g->event = PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT;
} }
if ((str = pw_properties_get(g->props, PW_KEY_ENDPOINT_CLIENT_ID)) != NULL) if ((str = pw_properties_get(g->props, PW_KEY_CLIENT_ID)) != NULL)
g->endpoint_info.client_id = atoi(str); g->node_info.client_id = atoi(str);
else if ((str = pw_properties_get(g->props, PW_KEY_CLIENT_ID)) != NULL)
g->endpoint_info.client_id = atoi(str);
if ((str = pw_properties_get(g->props, PW_KEY_DEVICE_ID)) != NULL) if ((str = pw_properties_get(g->props, PW_KEY_DEVICE_ID)) != NULL)
g->endpoint_info.device_id = atoi(str); g->node_info.device_id = atoi(str);
if ((str = pw_properties_get(g->props, PW_KEY_NODE_ID)) != NULL) {
pa_stream *s;
g->endpoint_info.node_id = atoi(str);
spa_list_for_each(s, &c->streams, link) {
if (pw_stream_get_node_id(s->stream) == g->endpoint_info.node_id)
s->endpoint_id = g->id;
}
}
events = &endpoint_events; events = &node_events;
client_version = PW_VERSION_ENDPOINT; client_version = PW_VERSION_NODE;
destroy = endpoint_destroy; destroy = node_destroy;
g->endpoint_info.volume = 1.0; g->node_info.volume = 1.0;
g->endpoint_info.mute = false; g->node_info.mute = false;
} else if (strcmp(g->type, PW_TYPE_INTERFACE_EndpointStream) == 0) { } else if (strcmp(g->type, PW_TYPE_INTERFACE_Port) == 0) {
if (g->props == NULL) if (g->props == NULL)
return 0; return 0;
if ((str = pw_properties_get(g->props, PW_KEY_ENDPOINT_ID)) == NULL) { if ((str = pw_properties_get(g->props, PW_KEY_NODE_ID)) == NULL) {
pw_log_warn("endpoint stream %d without "PW_KEY_ENDPOINT_ID, g->id); pw_log_warn("port %d without "PW_KEY_NODE_ID, g->id);
return 0; return 0;
} }
/* streams get transformed into profiles on the device */ g->port_info.node_id = atoi(str);
pw_log_debug("found endpoint stream %d", g->id); pw_log_debug("found port %d node %d", g->id, g->port_info.node_id);
} else if (strcmp(g->type, PW_TYPE_INTERFACE_Module) == 0) { } else if (strcmp(g->type, PW_TYPE_INTERFACE_Module) == 0) {
pw_log_debug("found module %d", g->id); pw_log_debug("found module %d", g->id);
g->mask = PA_SUBSCRIPTION_MASK_MODULE; g->mask = PA_SUBSCRIPTION_MASK_MODULE;
@ -682,23 +617,29 @@ static int set_mask(pa_context *c, struct global *g)
events = &client_events; events = &client_events;
client_version = PW_VERSION_CLIENT; client_version = PW_VERSION_CLIENT;
destroy = client_destroy; destroy = client_destroy;
} else if (strcmp(g->type, PW_TYPE_INTERFACE_EndpointLink) == 0) { } else if (strcmp(g->type, PW_TYPE_INTERFACE_Link) == 0) {
if ((str = pw_properties_get(g->props, PW_KEY_ENDPOINT_LINK_OUTPUT_ENDPOINT)) == NULL) if ((str = pw_properties_get(g->props, PW_KEY_LINK_OUTPUT_PORT)) == NULL)
return 0; return 0;
g->link_info.output = pa_context_find_global(c, pw_properties_parse_int(str)); g->link_info.src = pa_context_find_global(c, pw_properties_parse_int(str));
if ((str = pw_properties_get(g->props, PW_KEY_ENDPOINT_LINK_INPUT_ENDPOINT)) == NULL) if ((str = pw_properties_get(g->props, PW_KEY_LINK_INPUT_PORT)) == NULL)
return 0; return 0;
g->link_info.input = pa_context_find_global(c, pw_properties_parse_int(str)); g->link_info.dst = pa_context_find_global(c, pw_properties_parse_int(str));
if (g->link_info.output == NULL || g->link_info.input == NULL) if (g->link_info.src == NULL || g->link_info.dst == NULL)
return 0; return 0;
pw_log_debug("link %d->%d", g->link_info.output->id, g->link_info.input->id); pw_log_debug("link %d:%d->%d:%d",
g->link_info.src->port_info.node_id,
g->link_info.src->id,
g->link_info.dst->port_info.node_id,
g->link_info.dst->id);
if (!g->link_info.output->init) if ((f = pa_context_find_global(c, g->link_info.src->port_info.node_id)) != NULL &&
emit_event(c, g->link_info.output, PA_SUBSCRIPTION_EVENT_CHANGE); !f->init)
if (!g->link_info.input->init) emit_event(c, f, PA_SUBSCRIPTION_EVENT_CHANGE);
emit_event(c, g->link_info.input, PA_SUBSCRIPTION_EVENT_CHANGE); if ((f = pa_context_find_global(c, g->link_info.dst->port_info.node_id)) != NULL &&
!f->init)
emit_event(c, f, PA_SUBSCRIPTION_EVENT_CHANGE);
} else { } else {
return 0; return 0;
@ -729,11 +670,12 @@ static inline void insert_global(pa_context *c, struct global *global)
struct global *g, *t; struct global *g, *t;
spa_list_for_each_safe(g, t, &c->globals, link) { spa_list_for_each_safe(g, t, &c->globals, link) {
if (g->priority_session <= global->priority_session) { if (g->priority_master < global->priority_master) {
g = spa_list_prev(g, link);
break; break;
} }
} }
spa_list_append(&g->link, &global->link); spa_list_prepend(&g->link, &global->link);
} }
static void registry_event_global(void *data, uint32_t id, static void registry_event_global(void *data, uint32_t id,

View file

@ -34,7 +34,6 @@
#include <pulse/version.h> #include <pulse/version.h>
#include <pipewire/pipewire.h> #include <pipewire/pipewire.h>
#include <extensions/session-manager.h>
/* Some PulseAudio API added const qualifiers in 13.0 */ /* Some PulseAudio API added const qualifiers in 13.0 */
#if PA_MAJOR >= 13 #if PA_MAJOR >= 13
@ -216,6 +215,9 @@ struct param {
void *param; void *param;
}; };
#define PA_IDX_FLAG_DSP 0x800000U
#define PA_IDX_MASK_DSP 0x7fffffU
struct global { struct global {
struct spa_list link; struct spa_list link;
uint32_t id; uint32_t id;
@ -226,7 +228,7 @@ struct global {
pa_subscription_mask_t mask; pa_subscription_mask_t mask;
pa_subscription_event_type_t event; pa_subscription_event_type_t event;
int priority_session; int priority_master;
int pending_seq; int pending_seq;
int init:1; int init:1;
int subscribed:1; int subscribed:1;
@ -239,15 +241,12 @@ struct global {
struct spa_hook object_listener; struct spa_hook object_listener;
union { union {
/* for links, globals are endpoints */ /* for links */
struct { struct {
struct global *output; struct global *src;
struct global *input; struct global *dst;
} link_info; } link_info;
struct { /* for sink/source */
uint32_t endpoint_id;
} stream_info;
/* for endpoints */
struct { struct {
uint32_t client_id; uint32_t client_id;
uint32_t monitor; uint32_t monitor;
@ -256,8 +255,10 @@ struct global {
uint32_t n_channel_volumes; uint32_t n_channel_volumes;
float channel_volumes[SPA_AUDIO_MAX_CHANNELS]; float channel_volumes[SPA_AUDIO_MAX_CHANNELS];
uint32_t device_id; uint32_t device_id;
} node_info;
struct {
uint32_t node_id; uint32_t node_id;
} endpoint_info; } port_info;
/* for devices */ /* for devices */
struct { struct {
struct spa_list profiles; struct spa_list profiles;
@ -341,7 +342,6 @@ struct pa_stream {
pa_format_info *req_formats[PA_MAX_FORMATS]; pa_format_info *req_formats[PA_MAX_FORMATS];
pa_format_info *format; pa_format_info *format;
uint32_t endpoint_id;
uint32_t stream_index; uint32_t stream_index;
pa_buffer_attr buffer_attr; pa_buffer_attr buffer_attr;

View file

@ -90,7 +90,7 @@ static int wait_globals(pa_context *c, pa_subscription_mask_t mask, pa_operation
static void sink_callback(struct sink_data *d) static void sink_callback(struct sink_data *d)
{ {
struct global *g = d->global; struct global *g = d->global;
struct pw_endpoint_info *info = g->info; struct pw_node_info *info = g->info;
const char *str; const char *str;
uint32_t n; uint32_t n;
pa_sink_info i; pa_sink_info i;
@ -98,36 +98,31 @@ static void sink_callback(struct sink_data *d)
pa_format_info *ip[1]; pa_format_info *ip[1];
spa_zero(i); spa_zero(i);
if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_ENDPOINT_NAME))) if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_NODE_NAME)))
i.name = str; i.name = str;
else else
i.name = "unknown"; i.name = "unknown";
pw_log_debug("sink %d %s monitor %d", g->id, i.name, g->endpoint_info.monitor); pw_log_debug("sink %d %s monitor %d", g->id, i.name, g->node_info.monitor);
i.index = g->id; i.index = g->id;
if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_ENDPOINT_NAME))) if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_NODE_DESCRIPTION)))
i.description = str; i.description = str;
else else
i.description = "unknown"; i.description = "Unknown";
i.sample_spec.format = PA_SAMPLE_S16LE; i.sample_spec.format = PA_SAMPLE_S16LE;
i.sample_spec.rate = 44100; i.sample_spec.rate = 44100;
if (g->endpoint_info.n_channel_volumes) if (g->node_info.n_channel_volumes)
i.sample_spec.channels = g->endpoint_info.n_channel_volumes; i.sample_spec.channels = g->node_info.n_channel_volumes;
else else
i.sample_spec.channels = 2; i.sample_spec.channels = 2;
pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS); pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS);
i.owner_module = 0; i.owner_module = 0;
i.volume.channels = i.sample_spec.channels; i.volume.channels = i.sample_spec.channels;
for (n = 0; n < i.volume.channels; n++) for (n = 0; n < i.volume.channels; n++)
i.volume.values[n] = g->endpoint_info.volume * g->endpoint_info.channel_volumes[n] * PA_VOLUME_NORM; i.volume.values[n] = g->node_info.volume * g->node_info.channel_volumes[n] * PA_VOLUME_NORM;
i.mute = g->endpoint_info.mute; i.mute = g->node_info.mute;
if (g->endpoint_info.monitor != SPA_ID_INVALID) { i.monitor_source = g->node_info.monitor;
i.monitor_source = g->endpoint_info.monitor; i.monitor_source_name = "unknown";
i.monitor_source_name = "unknown";
} else {
i.monitor_source = PA_INVALID_INDEX;
i.monitor_source_name = NULL;
}
i.latency = 0; i.latency = 0;
i.driver = "PipeWire"; i.driver = "PipeWire";
i.flags = PA_SINK_HARDWARE | i.flags = PA_SINK_HARDWARE |
@ -137,7 +132,7 @@ static void sink_callback(struct sink_data *d)
i.proplist = pa_proplist_new_dict(info->props); i.proplist = pa_proplist_new_dict(info->props);
i.configured_latency = 0; i.configured_latency = 0;
i.base_volume = PA_VOLUME_NORM; i.base_volume = PA_VOLUME_NORM;
//i.state = node_state_to_sink(info->state); i.state = node_state_to_sink(info->state);
i.n_volume_steps = PA_VOLUME_NORM+1; i.n_volume_steps = PA_VOLUME_NORM+1;
i.card = PA_INVALID_INDEX; i.card = PA_INVALID_INDEX;
i.n_ports = 0; i.n_ports = 0;
@ -288,7 +283,7 @@ static void set_stream_volume(pa_context *c, pa_stream *s, const pa_cvolume *vol
} }
} }
static void set_endpoint_volume(pa_context *c, struct global *g, const pa_cvolume *volume, bool mute) static void set_node_volume(pa_context *c, struct global *g, const pa_cvolume *volume, bool mute)
{ {
char buf[1024]; char buf[1024];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
@ -302,22 +297,22 @@ static void set_endpoint_volume(pa_context *c, struct global *g, const pa_cvolum
vols = channel_volumes; vols = channel_volumes;
n_channel_volumes = volume->channels; n_channel_volumes = volume->channels;
if (n_channel_volumes == g->endpoint_info.n_channel_volumes && if (n_channel_volumes == g->node_info.n_channel_volumes &&
memcmp(g->endpoint_info.channel_volumes, vols, n_channel_volumes * sizeof(float)) == 0 && memcmp(g->node_info.channel_volumes, vols, n_channel_volumes * sizeof(float)) == 0 &&
mute == g->endpoint_info.mute) mute == g->node_info.mute)
return; return;
memcpy(g->endpoint_info.channel_volumes, vols, n_channel_volumes * sizeof(float)); memcpy(g->node_info.channel_volumes, vols, n_channel_volumes * sizeof(float));
g->endpoint_info.n_channel_volumes = n_channel_volumes; g->node_info.n_channel_volumes = n_channel_volumes;
} else { } else {
n_channel_volumes = g->endpoint_info.n_channel_volumes; n_channel_volumes = g->node_info.n_channel_volumes;
vols = g->endpoint_info.channel_volumes; vols = g->node_info.channel_volumes;
if (mute == g->endpoint_info.mute) if (mute == g->node_info.mute)
return; return;
} }
g->endpoint_info.mute = mute; g->node_info.mute = mute;
pw_endpoint_set_param((struct pw_endpoint*)g->proxy, pw_node_set_param((struct pw_node*)g->proxy,
SPA_PARAM_Props, 0, SPA_PARAM_Props, 0,
spa_pod_builder_add_object(&b, spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
@ -350,7 +345,7 @@ pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, c
if (!(g->mask & PA_SUBSCRIPTION_MASK_SINK)) if (!(g->mask & PA_SUBSCRIPTION_MASK_SINK))
return NULL; return NULL;
set_endpoint_volume(c, g, volume, g->endpoint_info.mute); set_node_volume(c, g, volume, g->node_info.mute);
o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
d = o->userdata; d = o->userdata;
@ -379,7 +374,7 @@ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name
if ((g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SINK, name)) == NULL) if ((g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SINK, name)) == NULL)
return NULL; return NULL;
set_endpoint_volume(c, g, volume, g->endpoint_info.mute); set_node_volume(c, g, volume, g->node_info.mute);
o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
d = o->userdata; d = o->userdata;
@ -409,7 +404,7 @@ pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int
if (!(g->mask & PA_SUBSCRIPTION_MASK_SINK)) if (!(g->mask & PA_SUBSCRIPTION_MASK_SINK))
return NULL; return NULL;
set_endpoint_volume(c, g, NULL, mute); set_node_volume(c, g, NULL, mute);
o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
d = o->userdata; d = o->userdata;
@ -437,7 +432,7 @@ pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name,
if ((g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SINK, name)) == NULL) if ((g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SINK, name)) == NULL)
return NULL; return NULL;
set_endpoint_volume(c, g, NULL, mute); set_node_volume(c, g, NULL, mute);
o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
d = o->userdata; d = o->userdata;
@ -539,7 +534,7 @@ static pa_source_state_t node_state_to_source(enum pw_node_state s)
static void source_callback(struct source_data *d) static void source_callback(struct source_data *d)
{ {
struct global *g = d->global; struct global *g = d->global;
struct pw_endpoint_info *info = g->info; struct pw_node_info *info = g->info;
const char *str; const char *str;
uint32_t n; uint32_t n;
pa_source_info i; pa_source_info i;
@ -551,30 +546,31 @@ static void source_callback(struct source_data *d)
PA_SOURCE_DECIBEL_VOLUME; PA_SOURCE_DECIBEL_VOLUME;
spa_zero(i); spa_zero(i);
if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_ENDPOINT_NAME))) if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_NODE_NAME)))
i.name = str; i.name = str;
else else
i.name = "unknown"; i.name = "unknown";
i.index = g->id; i.index = g->id;
if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_ENDPOINT_NAME))) if (info->props && (str = spa_dict_lookup(info->props, PW_KEY_NODE_DESCRIPTION)))
i.description = str; i.description = str;
else else
i.description = "unknown"; i.description = "unknown";
i.sample_spec.format = PA_SAMPLE_S16LE; i.sample_spec.format = PA_SAMPLE_S16LE;
i.sample_spec.rate = 44100; i.sample_spec.rate = 44100;
if (g->endpoint_info.n_channel_volumes) if (g->node_info.n_channel_volumes)
i.sample_spec.channels = g->endpoint_info.n_channel_volumes; i.sample_spec.channels = g->node_info.n_channel_volumes;
else else
i.sample_spec.channels = 2; i.sample_spec.channels = 2;
pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS); pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS);
i.owner_module = 0; i.owner_module = 0;
i.volume.channels = i.sample_spec.channels; i.volume.channels = i.sample_spec.channels;
for (n = 0; n < i.volume.channels; n++) for (n = 0; n < i.volume.channels; n++)
i.volume.values[n] = g->endpoint_info.volume * g->endpoint_info.channel_volumes[n] * PA_VOLUME_NORM; i.volume.values[n] = g->node_info.volume * g->node_info.channel_volumes[n] * PA_VOLUME_NORM;
i.mute = g->endpoint_info.mute; i.mute = g->node_info.mute;
if (g->endpoint_info.monitor != SPA_ID_INVALID) { if (g->mask & PA_SUBSCRIPTION_MASK_SINK) {
i.monitor_of_sink = g->endpoint_info.monitor; i.monitor_of_sink = g->id;
i.monitor_of_sink_name = "unknown"; i.monitor_of_sink_name = "unknown";
i.index = g->node_info.monitor;
} else { } else {
i.monitor_of_sink = PA_INVALID_INDEX; i.monitor_of_sink = PA_INVALID_INDEX;
i.monitor_of_sink_name = NULL; i.monitor_of_sink_name = NULL;
@ -586,7 +582,7 @@ static void source_callback(struct source_data *d)
i.proplist = pa_proplist_new_dict(info->props); i.proplist = pa_proplist_new_dict(info->props);
i.configured_latency = 0; i.configured_latency = 0;
i.base_volume = PA_VOLUME_NORM; i.base_volume = PA_VOLUME_NORM;
//i.state = node_state_to_source(info->state); i.state = node_state_to_source(info->state);
i.n_volume_steps = PA_VOLUME_NORM+1; i.n_volume_steps = PA_VOLUME_NORM+1;
i.card = PA_INVALID_INDEX; i.card = PA_INVALID_INDEX;
i.n_ports = 0; i.n_ports = 0;
@ -655,8 +651,10 @@ pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, p
pw_log_debug("context %p: index %d", c, idx); pw_log_debug("context %p: index %d", c, idx);
if ((g = pa_context_find_global(c, idx)) == NULL || if (((g = pa_context_find_global(c, idx)) == NULL ||
!(g->mask & PA_SUBSCRIPTION_MASK_SOURCE)) !(g->mask & PA_SUBSCRIPTION_MASK_SOURCE)) &&
(((g = pa_context_find_global(c, idx & PA_IDX_MASK_DSP)) == NULL ||
!(g->mask & PA_SUBSCRIPTION_MASK_SOURCE))))
return NULL; return NULL;
o = pa_operation_new(c, NULL, source_info, sizeof(struct source_data)); o = pa_operation_new(c, NULL, source_info, sizeof(struct source_data));
@ -731,7 +729,7 @@ pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx,
if (!(g->mask & PA_SUBSCRIPTION_MASK_SOURCE)) if (!(g->mask & PA_SUBSCRIPTION_MASK_SOURCE))
return NULL; return NULL;
set_endpoint_volume(c, g, volume, g->endpoint_info.mute); set_node_volume(c, g, volume, g->node_info.mute);
o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
d = o->userdata; d = o->userdata;
@ -760,7 +758,7 @@ pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *na
if ((g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SOURCE, name)) == NULL) if ((g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SOURCE, name)) == NULL)
return NULL; return NULL;
set_endpoint_volume(c, g, volume, g->endpoint_info.mute); set_node_volume(c, g, volume, g->node_info.mute);
o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
d = o->userdata; d = o->userdata;
@ -790,7 +788,7 @@ pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, i
if (!(g->mask & PA_SUBSCRIPTION_MASK_SOURCE)) if (!(g->mask & PA_SUBSCRIPTION_MASK_SOURCE))
return NULL; return NULL;
set_endpoint_volume(c, g, NULL, mute); set_node_volume(c, g, NULL, mute);
o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
d = o->userdata; d = o->userdata;
@ -818,7 +816,7 @@ pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name
if ((g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SOURCE, name)) == NULL) if ((g = pa_context_find_global_by_name(c, PA_SUBSCRIPTION_MASK_SOURCE, name)) == NULL)
return NULL; return NULL;
set_endpoint_volume(c, g, NULL, mute); set_node_volume(c, g, NULL, mute);
o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
d = o->userdata; d = o->userdata;
@ -1483,8 +1481,8 @@ struct sink_input_data {
static void sink_input_callback(struct sink_input_data *d) static void sink_input_callback(struct sink_input_data *d)
{ {
struct global *g = d->global, *cl; struct global *g = d->global, *cl;
struct pw_endpoint_info *info = g->info; struct pw_node_info *info = g->info;
const char *name; const char *name = NULL;
uint32_t n; uint32_t n;
pa_sink_input_info i; pa_sink_input_info i;
pa_format_info ii[1]; pa_format_info ii[1];
@ -1493,24 +1491,24 @@ static void sink_input_callback(struct sink_input_data *d)
if (info == NULL) if (info == NULL)
return; return;
s = find_stream(d->context, g->endpoint_info.node_id); s = find_stream(d->context, g->id);
if (info->props) { if (info->props) {
if ((name = spa_dict_lookup(info->props, PW_KEY_MEDIA_NAME)) == NULL && if ((name = spa_dict_lookup(info->props, PW_KEY_MEDIA_NAME)) == NULL &&
(name = spa_dict_lookup(info->props, PW_KEY_APP_NAME)) == NULL && (name = spa_dict_lookup(info->props, PW_KEY_APP_NAME)) == NULL &&
(name = spa_dict_lookup(info->props, PW_KEY_ENDPOINT_NAME)) == NULL) (name = spa_dict_lookup(info->props, PW_KEY_NODE_NAME)) == NULL)
name = "unknown"; name = NULL;
} }
else if (name == NULL)
name = "unknown"; name = "unknown";
cl = pa_context_find_global(d->context, g->endpoint_info.client_id); cl = pa_context_find_global(d->context, g->node_info.client_id);
spa_zero(i); spa_zero(i);
i.index = g->id; i.index = g->id;
i.name = name; i.name = name;
i.owner_module = PA_INVALID_INDEX; i.owner_module = PA_INVALID_INDEX;
i.client = g->endpoint_info.client_id; i.client = g->node_info.client_id;
if (s) { if (s) {
i.sink = s->device_index; i.sink = s->device_index;
} }
@ -1531,7 +1529,7 @@ static void sink_input_callback(struct sink_input_data *d)
else { else {
i.sample_spec.format = PA_SAMPLE_S16LE; i.sample_spec.format = PA_SAMPLE_S16LE;
i.sample_spec.rate = 44100; i.sample_spec.rate = 44100;
i.sample_spec.channels = g->endpoint_info.n_channel_volumes; i.sample_spec.channels = g->node_info.n_channel_volumes;
if (i.sample_spec.channels == 0) if (i.sample_spec.channels == 0)
i.sample_spec.channels = 2; i.sample_spec.channels = 2;
pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS); pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS);
@ -1542,9 +1540,9 @@ static void sink_input_callback(struct sink_input_data *d)
pa_cvolume_init(&i.volume); pa_cvolume_init(&i.volume);
i.volume.channels = i.sample_spec.channels; i.volume.channels = i.sample_spec.channels;
for (n = 0; n < i.volume.channels; n++) for (n = 0; n < i.volume.channels; n++)
i.volume.values[n] = g->endpoint_info.volume * g->endpoint_info.channel_volumes[n] * PA_VOLUME_NORM; i.volume.values[n] = g->node_info.volume * g->node_info.channel_volumes[n] * PA_VOLUME_NORM;
i.mute = g->endpoint_info.mute; i.mute = g->node_info.mute;
i.buffer_usec = 0; i.buffer_usec = 0;
i.sink_usec = 0; i.sink_usec = 0;
i.resample_method = "PipeWire resampler"; i.resample_method = "PipeWire resampler";
@ -1699,7 +1697,7 @@ pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, cons
set_stream_volume(c, s, volume, s->mute); set_stream_volume(c, s, volume, s->mute);
} }
else if (g) { else if (g) {
set_endpoint_volume(c, g, volume, g->endpoint_info.mute); set_node_volume(c, g, volume, g->node_info.mute);
} }
o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
d = o->userdata; d = o->userdata;
@ -1731,7 +1729,7 @@ pa_operation* pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mu
set_stream_volume(c, s, NULL, mute); set_stream_volume(c, s, NULL, mute);
} }
else if (g) { else if (g) {
set_endpoint_volume(c, g, NULL, mute); set_node_volume(c, g, NULL, mute);
} }
o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
d = o->userdata; d = o->userdata;
@ -1782,7 +1780,7 @@ struct source_output_data {
static void source_output_callback(struct source_output_data *d) static void source_output_callback(struct source_output_data *d)
{ {
struct global *g = d->global, *l, *cl; struct global *g = d->global, *l, *cl;
struct pw_endpoint_info *info = g->info; struct pw_node_info *info = g->info;
const char *name = NULL; const char *name = NULL;
uint32_t n; uint32_t n;
pa_source_output_info i; pa_source_output_info i;
@ -1793,25 +1791,24 @@ static void source_output_callback(struct source_output_data *d)
if (info == NULL) if (info == NULL)
return; return;
s = find_stream(d->context, g->endpoint_info.node_id); s = find_stream(d->context, g->id);
name = info->name; if (info->props) {
if (name == NULL && info->props) {
if ((name = spa_dict_lookup(info->props, PW_KEY_MEDIA_NAME)) == NULL && if ((name = spa_dict_lookup(info->props, PW_KEY_MEDIA_NAME)) == NULL &&
(name = spa_dict_lookup(info->props, PW_KEY_APP_NAME)) == NULL && (name = spa_dict_lookup(info->props, PW_KEY_APP_NAME)) == NULL &&
(name = spa_dict_lookup(info->props, PW_KEY_ENDPOINT_NAME)) == NULL) (name = spa_dict_lookup(info->props, PW_KEY_NODE_NAME)) == NULL)
name = NULL; name = NULL;
} }
if (name == NULL) if (name == NULL)
name = "unknown"; name = "unknown";
cl = pa_context_find_global(d->context, g->endpoint_info.client_id); cl = pa_context_find_global(d->context, g->node_info.client_id);
spa_zero(i); spa_zero(i);
i.index = g->id; i.index = g->id;
i.name = name ? name : "Unknown"; i.name = name;
i.owner_module = PA_INVALID_INDEX; i.owner_module = PA_INVALID_INDEX;
i.client = g->endpoint_info.client_id; i.client = g->node_info.client_id;
if (s) { if (s) {
i.source = s->device_index; i.source = s->device_index;
} }
@ -1831,7 +1828,7 @@ static void source_output_callback(struct source_output_data *d)
else { else {
i.sample_spec.format = PA_SAMPLE_S16LE; i.sample_spec.format = PA_SAMPLE_S16LE;
i.sample_spec.rate = 44100; i.sample_spec.rate = 44100;
i.sample_spec.channels = g->endpoint_info.n_channel_volumes; i.sample_spec.channels = g->node_info.n_channel_volumes;
if (i.sample_spec.channels == 0) if (i.sample_spec.channels == 0)
i.sample_spec.channels = 2; i.sample_spec.channels = 2;
pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS); pa_channel_map_init_auto(&i.channel_map, i.sample_spec.channels, PA_CHANNEL_MAP_OSS);
@ -1842,9 +1839,9 @@ static void source_output_callback(struct source_output_data *d)
pa_cvolume_init(&i.volume); pa_cvolume_init(&i.volume);
i.volume.channels = i.sample_spec.channels; i.volume.channels = i.sample_spec.channels;
for (n = 0; n < i.volume.channels; n++) for (n = 0; n < i.volume.channels; n++)
i.volume.values[n] = g->endpoint_info.volume * g->endpoint_info.channel_volumes[n] * PA_VOLUME_NORM; i.volume.values[n] = g->node_info.volume * g->node_info.channel_volumes[n] * PA_VOLUME_NORM;
i.mute = g->endpoint_info.mute; i.mute = g->node_info.mute;
i.buffer_usec = 0; i.buffer_usec = 0;
i.source_usec = 0; i.source_usec = 0;
i.resample_method = "PipeWire resampler"; i.resample_method = "PipeWire resampler";
@ -1994,7 +1991,7 @@ pa_operation* pa_context_set_source_output_volume(pa_context *c, uint32_t idx, c
set_stream_volume(c, s, volume, s->mute); set_stream_volume(c, s, volume, s->mute);
} }
else if (g) { else if (g) {
set_endpoint_volume(c, g, volume, g->endpoint_info.mute); set_node_volume(c, g, volume, g->node_info.mute);
} }
o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
d = o->userdata; d = o->userdata;
@ -2024,7 +2021,7 @@ pa_operation* pa_context_set_source_output_mute(pa_context *c, uint32_t idx, int
set_stream_volume(c, s, NULL, mute); set_stream_volume(c, s, NULL, mute);
} }
else if (g) { else if (g) {
set_endpoint_volume(c, g, NULL, mute); set_node_volume(c, g, NULL, mute);
} }
o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack)); o = pa_operation_new(c, NULL, on_success, sizeof(struct success_ack));
d = o->userdata; d = o->userdata;

View file

@ -200,7 +200,7 @@ static void configure_device(pa_stream *s)
else { else {
if (s->direction == PA_STREAM_RECORD) { if (s->direction == PA_STREAM_RECORD) {
if (g->mask == (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE)) if (g->mask == (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE))
s->device_index = g->endpoint_info.monitor; s->device_index = g->node_info.monitor;
else else
s->device_index = g->id; s->device_index = g->id;
} }
@ -208,7 +208,7 @@ static void configure_device(pa_stream *s)
s->device_index = g->id; s->device_index = g->id;
} }
if ((str = pw_properties_get(g->props, PW_KEY_ENDPOINT_NAME)) == NULL) if ((str = pw_properties_get(g->props, PW_KEY_NODE_NAME)) == NULL)
s->device_name = strdup("unknown"); s->device_name = strdup("unknown");
else else
s->device_name = strdup(str); s->device_name = strdup(str);
@ -565,7 +565,6 @@ static pa_stream* stream_new(pa_context *c, const char *name,
s->context = c; s->context = c;
spa_list_init(&s->pending); spa_list_init(&s->pending);
s->endpoint_id = SPA_ID_INVALID;
s->direction = PA_STREAM_NODIRECTION; s->direction = PA_STREAM_NODIRECTION;
s->state = PA_STREAM_UNCONNECTED; s->state = PA_STREAM_UNCONNECTED;
s->flags = 0; s->flags = 0;
@ -737,10 +736,8 @@ uint32_t pa_stream_get_index(PA_CONST pa_stream *s)
spa_assert(s); spa_assert(s);
spa_assert(s->refcount >= 1); spa_assert(s->refcount >= 1);
if (s->endpoint_id != SPA_ID_INVALID)
idx = s->endpoint_id; idx = pw_stream_get_node_id(s->stream);
else
idx = pw_stream_get_node_id(s->stream);
pw_log_debug("stream %p: index %u", s, idx); pw_log_debug("stream %p: index %u", s, idx);
return idx; return idx;
} }