mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	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:
		
							parent
							
								
									3b0fcdd525
								
							
						
					
					
						commit
						ab45b16a05
					
				
					 1 changed files with 72 additions and 46 deletions
				
			
		| 
						 | 
					@ -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,38 +788,19 @@ 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;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* port availability changed, find new best profile and switch
 | 
					 | 
				
			||||||
		 * to it when needed. */
 | 
					 | 
				
			||||||
		pw_log_info("device %d: route %s available changed %d -> %d",
 | 
					 | 
				
			||||||
				dev->id, r->name, ri->available, r->available);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ri->available = r->available;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		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);
 | 
					 | 
				
			||||||
			ri->valid = false;
 | 
					 | 
				
			||||||
		} else if (r->available != SPA_PARAM_AVAILABILITY_yes) {
 | 
					 | 
				
			||||||
		struct route t;
 | 
							struct route t;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* an existing port has changed to unavailable */
 | 
							/* an existing port has changed to unavailable */
 | 
				
			||||||
		pw_log_info("device %d: route '%s' not available", dev->id, r->name);
 | 
							pw_log_info("device %d: route '%s' not available", dev->id, r->name);
 | 
				
			||||||
		/* try to find a new best port */
 | 
							/* try to find a new best port */
 | 
				
			||||||
| 
						 | 
					@ -829,21 +811,65 @@ static int handle_route(struct device *dev, struct route *r)
 | 
				
			||||||
			pw_log_info("device %d: found best route '%s'", dev->id,
 | 
								pw_log_info("device %d: found best route '%s'", dev->id,
 | 
				
			||||||
					t.name);
 | 
										t.name);
 | 
				
			||||||
			restore_route(dev, &t);
 | 
								restore_route(dev, &t);
 | 
				
			||||||
				ri->valid = false;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		}
 | 
						} else if (ri->prev_active && r->props) {
 | 
				
			||||||
	} 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 ||
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue