mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	filter-graph: warn about unaligned streams
Keep track of min/max latencies and warn when streams are unaligned.
This commit is contained in:
		
							parent
							
								
									8e4c211a80
								
							
						
					
					
						commit
						46f5740604
					
				
					 1 changed files with 44 additions and 16 deletions
				
			
		| 
						 | 
					@ -116,9 +116,10 @@ struct node {
 | 
				
			||||||
	void *hndl[MAX_HNDL];
 | 
						void *hndl[MAX_HNDL];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int n_deps;
 | 
						unsigned int n_deps;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t latency_index;
 | 
						uint32_t latency_index;
 | 
				
			||||||
	float latency;
 | 
					
 | 
				
			||||||
 | 
						float min_latency;
 | 
				
			||||||
 | 
						float max_latency;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int disabled:1;
 | 
						unsigned int disabled:1;
 | 
				
			||||||
	unsigned int control_changed:1;
 | 
						unsigned int control_changed:1;
 | 
				
			||||||
| 
						 | 
					@ -198,7 +199,8 @@ struct graph {
 | 
				
			||||||
	uint32_t outputs_position[SPA_AUDIO_MAX_CHANNELS];
 | 
						uint32_t outputs_position[SPA_AUDIO_MAX_CHANNELS];
 | 
				
			||||||
	uint32_t n_outputs_position;
 | 
						uint32_t n_outputs_position;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float latency;
 | 
						float min_latency;
 | 
				
			||||||
 | 
						float max_latency;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned activated:1;
 | 
						unsigned activated:1;
 | 
				
			||||||
	unsigned setup:1;
 | 
						unsigned setup:1;
 | 
				
			||||||
| 
						 | 
					@ -273,7 +275,8 @@ static void emit_filter_graph_info(struct impl *impl, bool full)
 | 
				
			||||||
			items[dict.n_items++] = SPA_DICT_ITEM("outputs.audio.position", out_pos);
 | 
								items[dict.n_items++] = SPA_DICT_ITEM("outputs.audio.position", out_pos);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		items[dict.n_items++] = SPA_DICT_ITEM("latency",
 | 
							items[dict.n_items++] = SPA_DICT_ITEM("latency",
 | 
				
			||||||
				spa_dtoa(latency, sizeof(latency), graph->latency));
 | 
									spa_dtoa(latency, sizeof(latency),
 | 
				
			||||||
 | 
										(graph->min_latency + graph->max_latency) / 2.0f));
 | 
				
			||||||
		impl->info.props = &dict;
 | 
							impl->info.props = &dict;
 | 
				
			||||||
		spa_filter_graph_emit_info(&impl->hooks, &impl->info);
 | 
							spa_filter_graph_emit_info(&impl->hooks, &impl->info);
 | 
				
			||||||
		impl->info.props = NULL;
 | 
							impl->info.props = NULL;
 | 
				
			||||||
| 
						 | 
					@ -1535,7 +1538,7 @@ static int impl_activate(void *object, const struct spa_dict *props)
 | 
				
			||||||
	const struct spa_fga_plugin *p;
 | 
						const struct spa_fga_plugin *p;
 | 
				
			||||||
	uint32_t i, j, max_samples = impl->quantum_limit, n_ports;
 | 
						uint32_t i, j, max_samples = impl->quantum_limit, n_ports;
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
	float *sd, *dd, *data, latency;
 | 
						float *sd, *dd, *data, min_latency, max_latency;
 | 
				
			||||||
	const char *rate, *str;
 | 
						const char *rate, *str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (graph->activated)
 | 
						if (graph->activated)
 | 
				
			||||||
| 
						 | 
					@ -1661,30 +1664,55 @@ static int impl_activate(void *object, const struct spa_dict *props)
 | 
				
			||||||
	/* calculate latency */
 | 
						/* calculate latency */
 | 
				
			||||||
	sort_reset(graph);
 | 
						sort_reset(graph);
 | 
				
			||||||
	while ((node = sort_next_node(graph)) != NULL) {
 | 
						while ((node = sort_next_node(graph)) != NULL) {
 | 
				
			||||||
		latency = 0.0f;
 | 
							min_latency = FLT_MAX;
 | 
				
			||||||
 | 
							max_latency = 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (i = 0; i < node->desc->n_input; i++) {
 | 
							for (i = 0; i < node->desc->n_input; i++) {
 | 
				
			||||||
			spa_list_for_each(link, &node->input_port[i].link_list, input_link)
 | 
								spa_list_for_each(link, &node->input_port[i].link_list, input_link) {
 | 
				
			||||||
				latency = fmaxf(latency, link->output->node->latency);
 | 
									min_latency = fminf(min_latency, link->output->node->min_latency);
 | 
				
			||||||
 | 
									max_latency = fmaxf(max_latency, link->output->node->max_latency);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							min_latency = min_latency == FLT_MAX ? 0.0f : min_latency;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (node->latency_index != SPA_IDX_INVALID) {
 | 
							if (node->latency_index != SPA_IDX_INVALID) {
 | 
				
			||||||
			port = &node->notify_port[node->latency_index];
 | 
								port = &node->notify_port[node->latency_index];
 | 
				
			||||||
			latency += port->control_data[0];
 | 
								min_latency += port->control_data[0];
 | 
				
			||||||
 | 
								max_latency += port->control_data[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		node->latency = latency;
 | 
							node->min_latency = min_latency;
 | 
				
			||||||
		spa_log_debug(impl->log, "%s latency:%f", node->name, latency);
 | 
							node->max_latency = max_latency;
 | 
				
			||||||
 | 
							spa_log_info(impl->log, "%s latency:%f-%f", node->name, min_latency, max_latency);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	latency = 0.0f;
 | 
						min_latency = FLT_MAX;
 | 
				
			||||||
 | 
						max_latency = 0.0f;
 | 
				
			||||||
	for (i = 0; i < graph->n_outputs; i++) {
 | 
						for (i = 0; i < graph->n_outputs; i++) {
 | 
				
			||||||
		struct graph_port *port = &graph->output[i];
 | 
							struct graph_port *port = &graph->output[i];
 | 
				
			||||||
		latency = fmaxf(latency, port->node->latency);
 | 
							max_latency = fmaxf(max_latency, port->node->max_latency);
 | 
				
			||||||
 | 
							min_latency = fminf(min_latency, port->node->min_latency);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						min_latency = min_latency == FLT_MAX ? 0.0f : min_latency;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_log_info(impl->log, "graph latency min:%f max:%f", min_latency, max_latency);
 | 
				
			||||||
 | 
						if (min_latency != max_latency) {
 | 
				
			||||||
 | 
							spa_log_warn(impl->log, "graph has unaligned latency min:%f max:%f, "
 | 
				
			||||||
 | 
									"consider adding delays or tweak node latency to "
 | 
				
			||||||
 | 
									"align the signals", min_latency, max_latency);
 | 
				
			||||||
 | 
							for (i = 0; i < graph->n_outputs; i++) {
 | 
				
			||||||
 | 
								struct graph_port *port = &graph->output[i];
 | 
				
			||||||
 | 
								if (min_latency != port->node->min_latency ||
 | 
				
			||||||
 | 
								    max_latency != port->node->max_latency)
 | 
				
			||||||
 | 
									spa_log_warn(impl->log, "output port %d from %s min:%f max:%f",
 | 
				
			||||||
 | 
											i, port->node->name,
 | 
				
			||||||
 | 
											port->node->min_latency, port->node->max_latency);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (graph->latency != latency) {
 | 
						}
 | 
				
			||||||
		graph->latency = latency;
 | 
						if (graph->min_latency != min_latency || graph->max_latency != max_latency) {
 | 
				
			||||||
 | 
							graph->min_latency = min_latency;
 | 
				
			||||||
 | 
							graph->max_latency = max_latency;
 | 
				
			||||||
		impl->info.change_mask |= SPA_FILTER_GRAPH_CHANGE_MASK_PROPS;
 | 
							impl->info.change_mask |= SPA_FILTER_GRAPH_CHANGE_MASK_PROPS;
 | 
				
			||||||
		spa_log_info(impl->log, "graph latency:%f", latency);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	emit_filter_graph_info(impl, false);
 | 
						emit_filter_graph_info(impl, false);
 | 
				
			||||||
	spa_filter_graph_emit_props_changed(&impl->hooks, SPA_DIRECTION_INPUT);
 | 
						spa_filter_graph_emit_props_changed(&impl->hooks, SPA_DIRECTION_INPUT);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue