media-session: improve routing

First check all the routes to see if anything changed. If there is
a change check if we need a profile switch.
Then check all the active routes and restore state when they changed.
This commit is contained in:
Wim Taymans 2021-02-23 11:09:42 +01:00
parent 3b0fcdd525
commit ab45b16a05

View file

@ -140,9 +140,9 @@ struct route_info {
uint32_t available; uint32_t available;
enum spa_direction direction; enum spa_direction direction;
char name[64]; char name[64];
unsigned int restore:1;
unsigned int save:1; unsigned int save:1;
unsigned int valid:1; unsigned int prev_active:1;
unsigned int active:1;
}; };
struct route { struct route {
@ -175,13 +175,12 @@ static struct route_info *find_route_info(struct device *dev, struct route *r)
return NULL; return NULL;
pw_log_info("device %d: new route %d '%s' found", dev->id, r->index, r->name); pw_log_info("device %d: new route %d '%s' found", dev->id, r->index, r->name);
spa_zero(*i);
i->index = r->index; i->index = r->index;
snprintf(i->name, sizeof(i->name), "%s", r->name); snprintf(i->name, sizeof(i->name), "%s", r->name);
i->direction = r->direction; i->direction = r->direction;
i->generation = dev->generation; i->generation = dev->generation;
i->available = r->available; i->available = r->available;
i->restore = true;
i->valid = true;
return i; return i;
} }
@ -233,7 +232,7 @@ static int parse_enum_route(struct sm_param *p, uint32_t device_id, struct route
SPA_PARAM_ROUTE_devices, SPA_POD_OPT_Pod(&devices))) < 0) SPA_PARAM_ROUTE_devices, SPA_POD_OPT_Pod(&devices))) < 0)
return res; return res;
if (!array_contains(devices, device_id)) if (device_id != SPA_ID_INVALID && !array_contains(devices, device_id))
return -ENOENT; return -ENOENT;
r->device_id = device_id; r->device_id = device_id;
@ -518,8 +517,10 @@ static int restore_route(struct device *dev, struct route *r)
pw_log_info("device %d: restore route %d '%s' to %s", dev->id, r->index, key, val); pw_log_info("device %d: restore route %d '%s' to %s", dev->id, r->index, key, val);
restore_route_params(dev, val, r); restore_route_params(dev, val, r);
ri->prev_active = true;
ri->active = true;
ri->generation = dev->generation; ri->generation = dev->generation;
ri->restore = false; ri->available = r->available;
ri->save = r->save; ri->save = r->save;
return 0; return 0;
@ -787,63 +788,88 @@ static int handle_route(struct device *dev, struct route *r)
struct route_info *ri; struct route_info *ri;
int res; int res;
pw_log_info("device %d: port '%s'", dev->id, r->name);
if ((ri = find_route_info(dev, r)) == NULL) if ((ri = find_route_info(dev, r)) == NULL)
return -errno; return -errno;
if (ri->restore) { ri->active = true;
if (!ri->prev_active) {
/* a new port has been found, restore the volume and make sure we /* a new port has been found, restore the volume and make sure we
* save this as a prefered port */ * save this as a prefered port */
pw_log_info("device %d: new port found '%s'", dev->id, r->name); pw_log_info("device %d: new active port found '%s'", dev->id, r->name);
restore_route(dev, r); restore_route(dev, r);
} else if (ri->available != r->available) { } else if (ri->available != r->available && r->available != SPA_PARAM_AVAILABILITY_yes) {
struct profile best; struct route t;
/* an existing port has changed to unavailable */
/* port availability changed, find new best profile and switch pw_log_info("device %d: route '%s' not available", dev->id, r->name);
* to it when needed. */ /* try to find a new best port */
pw_log_info("device %d: route %s available changed %d -> %d", res = find_best_route(dev, r->device_id, &t);
dev->id, r->name, ri->available, r->available); if (res < 0) {
pw_log_info("device %d: can't find best route", dev->id);
ri->available = r->available; } else {
pw_log_info("device %d: found best route '%s'", dev->id,
if ((res = find_best_profile(dev, &best)) < 0) { t.name);
pw_log_info("device %d: can't find best profile", dev->id); restore_route(dev, &t);
return res;
} }
} else if (ri->prev_active && r->props) {
if (dev->active_profile != best.index) {
pw_log_info("device %d: activating best profile %s",
dev->id, best.name);
/* we need to switch profiles */
set_profile(dev, &best);
ri->valid = false;
} else if (r->available != SPA_PARAM_AVAILABILITY_yes) {
struct route t;
/* an existing port has changed to unavailable */
pw_log_info("device %d: route '%s' not available", dev->id, r->name);
/* try to find a new best port */
res = find_best_route(dev, r->device_id, &t);
if (res < 0) {
pw_log_info("device %d: can't find best route", dev->id);
} else {
pw_log_info("device %d: found best route '%s'", dev->id,
t.name);
restore_route(dev, &t);
ri->valid = false;
}
}
} else if (ri->valid && r->props) {
/* just save port properties */ /* just save port properties */
save_route(dev, r); save_route(dev, r);
} }
ri->generation = dev->generation; ri->available = r->available;
return 0; return 0;
} }
static int handle_routes(struct device *dev) static int handle_routes(struct device *dev)
{ {
struct sm_param *p; struct sm_param *p;
bool changed = false;
int res;
/* first look at all routes and see if something changed */
spa_list_for_each(p, &dev->obj->param_list, link) {
struct route r;
struct route_info *ri;
if (p->id != SPA_PARAM_EnumRoute ||
parse_enum_route(p, SPA_ID_INVALID, &r) < 0)
continue;
if ((ri = find_route_info(dev, &r)) == NULL)
continue;
if (ri->available != r.available) {
pw_log_info("device %d: route %s available changed %d -> %d",
dev->id, r.name, ri->available, r.available);
changed = true;
}
ri->generation = dev->generation;
ri->prev_active = ri->active;
ri->active = false;
}
if (changed) {
struct profile best;
pw_log_info("device %d: find best profile", dev->id);
/* port availability changed, find new best profile and switch
* to it when needed. */
if ((res = find_best_profile(dev, &best)) < 0) {
pw_log_info("device %d: can't find best profile", dev->id);
return res;
}
if (dev->active_profile != best.index) {
pw_log_info("device %d: activating best profile %s",
dev->id, best.name);
/* we need to switch profiles */
set_profile(dev, &best);
return 0;
} else {
pw_log_info("device %d: best profile %s already active",
dev->id, best.name);
}
}
/* then check for changes in the active ports */
spa_list_for_each(p, &dev->obj->param_list, link) { spa_list_for_each(p, &dev->obj->param_list, link) {
struct route r; struct route r;
if (p->id != SPA_PARAM_Route || if (p->id != SPA_PARAM_Route ||