mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-03 09:01:54 -05:00
media-session: rework linking nodes
Rework how nodes are linked. score each port pair and link the highest score taking into account the type, direction, channels, and number of linked ports.
This commit is contained in:
parent
5f9a8a82ab
commit
03c2185efe
2 changed files with 85 additions and 38 deletions
|
|
@ -1496,6 +1496,52 @@ static const struct pw_proxy_events proxy_link_events = {
|
|||
.destroy = proxy_link_destroy
|
||||
};
|
||||
|
||||
static int score_ports(struct sm_port *out, struct sm_port *in)
|
||||
{
|
||||
int score = 0;
|
||||
|
||||
if (in->direction != PW_DIRECTION_INPUT || out->direction != PW_DIRECTION_OUTPUT)
|
||||
return 0;
|
||||
|
||||
if (out->type != SM_PORT_TYPE_UNKNOWN && in->type != SM_PORT_TYPE_UNKNOWN &&
|
||||
in->type != out->type)
|
||||
return 0;
|
||||
|
||||
if (!in->visited)
|
||||
score += 5;
|
||||
if (out->channel == in->channel)
|
||||
score += 100;
|
||||
else if ((out->channel == SPA_AUDIO_CHANNEL_SL && in->channel == SPA_AUDIO_CHANNEL_RL) ||
|
||||
(out->channel == SPA_AUDIO_CHANNEL_RL && in->channel == SPA_AUDIO_CHANNEL_SL) ||
|
||||
(out->channel == SPA_AUDIO_CHANNEL_SR && in->channel == SPA_AUDIO_CHANNEL_RR) ||
|
||||
(out->channel == SPA_AUDIO_CHANNEL_RR && in->channel == SPA_AUDIO_CHANNEL_SR))
|
||||
score += 50;
|
||||
else if ((out->channel == SPA_AUDIO_CHANNEL_FC && in->channel == SPA_AUDIO_CHANNEL_MONO) ||
|
||||
(out->channel == SPA_AUDIO_CHANNEL_MONO && in->channel == SPA_AUDIO_CHANNEL_FC))
|
||||
score += 40;
|
||||
else if (in->channel == SPA_AUDIO_CHANNEL_UNKNOWN)
|
||||
score += 30;
|
||||
else if (in->channel == SPA_AUDIO_CHANNEL_MONO)
|
||||
score += 20;
|
||||
return score;
|
||||
}
|
||||
|
||||
static struct sm_port *find_input_port(struct impl *impl, struct sm_node *outnode,
|
||||
struct sm_port *outport, struct sm_node *innode)
|
||||
{
|
||||
struct sm_port *inport, *best_port = NULL;
|
||||
int score, best_score = 0;
|
||||
|
||||
spa_list_for_each(inport, &innode->port_list, link) {
|
||||
score = score_ports(outport, inport);
|
||||
if (score > best_score) {
|
||||
best_score = score;
|
||||
best_port = inport;
|
||||
}
|
||||
}
|
||||
return best_port;
|
||||
}
|
||||
|
||||
static int link_nodes(struct impl *impl, struct endpoint_link *link,
|
||||
struct sm_node *outnode, struct sm_node *innode)
|
||||
{
|
||||
|
|
@ -1508,20 +1554,28 @@ static int link_nodes(struct impl *impl, struct endpoint_link *link,
|
|||
pw_properties_setf(props, PW_KEY_LINK_OUTPUT_NODE, "%d", outnode->obj.id);
|
||||
pw_properties_setf(props, PW_KEY_LINK_INPUT_NODE, "%d", innode->obj.id);
|
||||
|
||||
for (outport = spa_list_first(&outnode->port_list, struct sm_port, link),
|
||||
inport = spa_list_first(&innode->port_list, struct sm_port, link);
|
||||
!spa_list_is_end(outport, &outnode->port_list, link) &&
|
||||
!spa_list_is_end(inport, &innode->port_list, link);) {
|
||||
spa_list_for_each(inport, &innode->port_list, link)
|
||||
inport->visited = false;
|
||||
|
||||
spa_list_for_each(outport, &outnode->port_list, link) {
|
||||
struct link *l;
|
||||
struct pw_proxy *p;
|
||||
|
||||
if (outport->direction != PW_DIRECTION_OUTPUT)
|
||||
continue;
|
||||
|
||||
inport = find_input_port(impl, outnode, outport, innode);
|
||||
if (inport == NULL) {
|
||||
pw_log_debug(NAME" %p: port %d:%d can't be linked", impl,
|
||||
outport->direction, outport->obj.id);
|
||||
continue;
|
||||
}
|
||||
inport->visited = true;
|
||||
|
||||
pw_log_debug(NAME" %p: port %d:%d -> %d:%d", impl,
|
||||
outport->direction, outport->obj.id,
|
||||
inport->direction, inport->obj.id);
|
||||
|
||||
if (outport->direction == PW_DIRECTION_OUTPUT &&
|
||||
inport->direction == PW_DIRECTION_INPUT) {
|
||||
struct link *l;
|
||||
struct pw_proxy *p;
|
||||
|
||||
pw_properties_setf(props, PW_KEY_LINK_OUTPUT_PORT, "%d", outport->obj.id);
|
||||
pw_properties_setf(props, PW_KEY_LINK_INPUT_PORT, "%d", inport->obj.id);
|
||||
|
||||
|
|
@ -1547,15 +1601,6 @@ static int link_nodes(struct impl *impl, struct endpoint_link *link,
|
|||
} else {
|
||||
spa_list_append(&impl->link_list, &l->link);
|
||||
}
|
||||
|
||||
outport = spa_list_next(outport, link);
|
||||
inport = spa_list_next(inport, link);
|
||||
} else {
|
||||
if (outport->direction != PW_DIRECTION_OUTPUT)
|
||||
outport = spa_list_next(outport, link);
|
||||
if (inport->direction != PW_DIRECTION_INPUT)
|
||||
inport = spa_list_next(inport, link);
|
||||
}
|
||||
}
|
||||
pw_properties_free(props);
|
||||
|
||||
|
|
|
|||
|
|
@ -163,6 +163,8 @@ struct sm_port {
|
|||
|
||||
#define SM_PORT_CHANGE_MASK_INFO (SM_OBJECT_CHANGE_MASK_LAST<<0)
|
||||
struct pw_port_info *info;
|
||||
|
||||
unsigned int visited:1;
|
||||
};
|
||||
|
||||
struct sm_session {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue