context: handle route changes better

Track the current route and the properties independently. Else we
might skip parsing the volumes/mute properties when the current
route didn't change.

Fixes #281
This commit is contained in:
Wim Taymans 2020-09-07 16:52:42 +02:00
parent d995df95f8
commit 0d1b01147f

View file

@ -295,8 +295,10 @@ static void do_global_sync(struct global *g)
{ {
pa_subscription_event_type_t event; pa_subscription_event_type_t event;
pw_log_debug("global %p sync", g);
if (g->ginfo && g->ginfo->sync) if (g->ginfo && g->ginfo->sync)
g->ginfo->sync(g); g->ginfo->sync(g);
if (g->init) { if (g->init) {
if ((g->mask & (PA_SUBSCRIPTION_MASK_SINK_INPUT | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT))) { if ((g->mask & (PA_SUBSCRIPTION_MASK_SINK_INPUT | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT))) {
if (g->node_info.device_index == SPA_ID_INVALID || if (g->node_info.device_index == SPA_ID_INVALID ||
@ -308,7 +310,6 @@ static void do_global_sync(struct global *g)
} else { } else {
event = PA_SUBSCRIPTION_EVENT_CHANGE; event = PA_SUBSCRIPTION_EVENT_CHANGE;
} }
pw_log_debug("emit because of pending");
emit_event(g->context, g, event); emit_event(g->context, g, event);
} }
@ -436,6 +437,7 @@ static void device_event_info(void *object, const struct pw_device_info *info)
g->card_info.pending_ports = true; g->card_info.pending_ports = true;
break; break;
} }
pw_log_debug("global %p: do enum:%d", g, id);
pw_device_enum_params((struct pw_device*)g->proxy, pw_device_enum_params((struct pw_device*)g->proxy,
0, id, 0, -1, NULL); 0, id, 0, -1, NULL);
} }
@ -446,31 +448,47 @@ static void device_event_info(void *object, const struct pw_device_info *info)
global_sync(g); global_sync(g);
} }
static void parse_props(struct global *g, const struct spa_pod *param, bool device) static int parse_props(struct global *g, const struct spa_pod *param, bool device)
{ {
int changed = 0;
struct spa_pod_prop *prop; struct spa_pod_prop *prop;
struct spa_pod_object *obj = (struct spa_pod_object *) param; struct spa_pod_object *obj = (struct spa_pod_object *) 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->node_info.volume); {
float vol;
if (spa_pod_get_float(&prop->value, &vol) >= 0 &&
g->node_info.volume != vol) {
g->node_info.volume = vol;
changed++;
}
SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_DEVICE_VOLUME, device); SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_DEVICE_VOLUME, device);
SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_HW_VOLUME, SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_HW_VOLUME,
prop->flags & SPA_POD_PROP_FLAG_HARDWARE); prop->flags & SPA_POD_PROP_FLAG_HARDWARE);
break; break;
}
case SPA_PROP_mute: case SPA_PROP_mute:
spa_pod_get_bool(&prop->value, &g->node_info.mute); {
bool mute;
if (spa_pod_get_bool(&prop->value, &mute) >= 0 &&
g->node_info.mute != mute) {
g->node_info.mute = mute;
changed++;
}
SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_DEVICE_MUTE, device); SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_DEVICE_MUTE, device);
SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_HW_MUTE, SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_HW_MUTE,
prop->flags & SPA_POD_PROP_FLAG_HARDWARE); prop->flags & SPA_POD_PROP_FLAG_HARDWARE);
break; break;
}
case SPA_PROP_channelVolumes: case SPA_PROP_channelVolumes:
{ {
uint32_t n_vals; uint32_t n_vals;
float vol[SPA_AUDIO_MAX_CHANNELS];
n_vals = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, n_vals = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
g->node_info.channel_volumes, SPA_AUDIO_MAX_CHANNELS); vol, SPA_AUDIO_MAX_CHANNELS);
if (n_vals != g->node_info.n_channel_volumes) { if (n_vals != g->node_info.n_channel_volumes) {
pw_log_debug("channel change %d->%d, trigger remove", pw_log_debug("channel change %d->%d, trigger remove",
@ -480,7 +498,12 @@ static void parse_props(struct global *g, const struct spa_pod *param, bool devi
g->node_info.n_channel_volumes = n_vals; g->node_info.n_channel_volumes = n_vals;
/* mark as init, this will emit the NEW event when the /* mark as init, this will emit the NEW event when the
* params are updated */ * params are updated */
g->init = true; g->init = g->sync = true;
changed++;
}
if (memcmp(g->node_info.channel_volumes, vol, n_vals * sizeof(float)) != 0) {
memcpy(g->node_info.channel_volumes, vol, n_vals * sizeof(float));
changed++;
} }
SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_DEVICE_VOLUME, device); SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_DEVICE_VOLUME, device);
SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_HW_VOLUME, SPA_FLAG_UPDATE(g->node_info.flags, NODE_FLAG_HW_VOLUME,
@ -497,6 +520,7 @@ static void parse_props(struct global *g, const struct spa_pod *param, bool devi
break; break;
} }
} }
return changed;
} }
static struct global *find_node_for_route(pa_context *c, struct global *card, uint32_t device) static struct global *find_node_for_route(pa_context *c, struct global *card, uint32_t device)
@ -834,10 +858,16 @@ static void device_sync_ports(struct global *g)
} }
ng = find_node_for_route(c, g, device); ng = find_node_for_route(c, g, device);
if (props && ng && ng->node_info.active_port != index) { if (ng) {
ng->node_info.active_port = index; int changed = 0;
parse_props(ng, props, true); if (ng->node_info.active_port != index) {
emit_event(c, ng, PA_SUBSCRIPTION_EVENT_CHANGE); ng->node_info.active_port = index;
changed++;
}
if (props)
changed += parse_props(ng, props, true);
if (changed)
emit_event(c, ng, PA_SUBSCRIPTION_EVENT_CHANGE);
} }
} }
} }