mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
Improve negotiation
Try to link ports based on compatible formats Add methods to filter formats.
This commit is contained in:
parent
1370fafd5b
commit
df86fcec10
12 changed files with 229 additions and 95 deletions
|
|
@ -171,8 +171,10 @@ try_link_port (PinosNode *node,
|
|||
ModuleImpl *impl = info->impl;
|
||||
PinosProperties *props;
|
||||
const char *path;
|
||||
uint32_t path_id;
|
||||
char *error = NULL;
|
||||
PinosLink *link;
|
||||
PinosPort *target;
|
||||
|
||||
props = node->properties;
|
||||
if (props == NULL) {
|
||||
|
|
@ -181,34 +183,36 @@ try_link_port (PinosNode *node,
|
|||
}
|
||||
|
||||
path = pinos_properties_get (props, "pinos.target.node");
|
||||
if (path == NULL)
|
||||
path_id = SPA_ID_INVALID;
|
||||
else
|
||||
path_id = atoi (path);
|
||||
|
||||
pinos_log_debug ("module %p: try to find and link to node '%s'", impl, path);
|
||||
|
||||
if (path) {
|
||||
PinosPort *target;
|
||||
target = pinos_core_find_port (impl->core,
|
||||
port,
|
||||
path_id,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
&error);
|
||||
if (target == NULL)
|
||||
goto error;
|
||||
|
||||
target = pinos_core_find_port (impl->core,
|
||||
port,
|
||||
atoi (path),
|
||||
NULL,
|
||||
NULL,
|
||||
&error);
|
||||
if (target == NULL)
|
||||
goto error;
|
||||
if (port->direction == PINOS_DIRECTION_OUTPUT)
|
||||
link = pinos_port_link (port, target, NULL, NULL, &error);
|
||||
else
|
||||
link = pinos_port_link (target, port, NULL, NULL, &error);
|
||||
|
||||
if (port->direction == PINOS_DIRECTION_OUTPUT)
|
||||
link = pinos_port_link (port, target, NULL, NULL, &error);
|
||||
else
|
||||
link = pinos_port_link (target, port, NULL, NULL, &error);
|
||||
if (link == NULL)
|
||||
goto error;
|
||||
|
||||
if (link == NULL)
|
||||
goto error;
|
||||
pinos_signal_add (&link->port_unlinked, &info->port_unlinked, on_link_port_unlinked);
|
||||
pinos_signal_add (&link->state_changed, &info->link_state_changed, on_link_state_changed);
|
||||
|
||||
pinos_signal_add (&link->port_unlinked, &info->port_unlinked, on_link_port_unlinked);
|
||||
pinos_signal_add (&link->state_changed, &info->link_state_changed, on_link_state_changed);
|
||||
pinos_link_activate (link);
|
||||
|
||||
pinos_link_activate (link);
|
||||
}
|
||||
return;
|
||||
|
||||
error:
|
||||
|
|
|
|||
|
|
@ -482,6 +482,7 @@ pinos_core_find_port (PinosCore *core,
|
|||
PinosPort *other_port,
|
||||
uint32_t id,
|
||||
PinosProperties *props,
|
||||
unsigned int n_format_filters,
|
||||
SpaFormat **format_filters,
|
||||
char **error)
|
||||
{
|
||||
|
|
@ -508,6 +509,30 @@ pinos_core_find_port (PinosCore *core,
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
PinosPort *p, *pin, *pout;
|
||||
|
||||
p = pinos_node_get_free_port (n, pinos_direction_reverse (other_port->direction));
|
||||
if (p == NULL)
|
||||
continue;
|
||||
|
||||
if (p->direction == PINOS_DIRECTION_OUTPUT) {
|
||||
pin = other_port;
|
||||
pout = p;
|
||||
} else {
|
||||
pin = p;
|
||||
pout = other_port;
|
||||
}
|
||||
|
||||
if (pinos_core_find_format (core,
|
||||
pout,
|
||||
pin,
|
||||
props,
|
||||
n_format_filters,
|
||||
format_filters,
|
||||
error) == NULL)
|
||||
continue;
|
||||
|
||||
best = p;
|
||||
}
|
||||
}
|
||||
if (best == NULL) {
|
||||
|
|
@ -516,6 +541,89 @@ pinos_core_find_port (PinosCore *core,
|
|||
return best;
|
||||
}
|
||||
|
||||
SpaFormat *
|
||||
pinos_core_find_format (PinosCore *core,
|
||||
PinosPort *output,
|
||||
PinosPort *input,
|
||||
PinosProperties *props,
|
||||
unsigned int n_format_filters,
|
||||
SpaFormat **format_filterss,
|
||||
char **error)
|
||||
{
|
||||
SpaNodeState out_state, in_state;
|
||||
SpaResult res;
|
||||
SpaFormat *filter = NULL, *format;
|
||||
unsigned int iidx = 0, oidx = 0;
|
||||
|
||||
out_state = output->node->node->state;
|
||||
in_state = input->node->node->state;
|
||||
|
||||
if (in_state == SPA_NODE_STATE_CONFIGURE && out_state > SPA_NODE_STATE_CONFIGURE) {
|
||||
/* only input needs format */
|
||||
if ((res = spa_node_port_get_format (output->node->node,
|
||||
SPA_DIRECTION_OUTPUT,
|
||||
output->port_id,
|
||||
(const SpaFormat **)&format)) < 0) {
|
||||
asprintf (error, "error get output format: %d", res);
|
||||
goto error;
|
||||
}
|
||||
} else if (out_state == SPA_NODE_STATE_CONFIGURE && in_state > SPA_NODE_STATE_CONFIGURE) {
|
||||
/* only output needs format */
|
||||
if ((res = spa_node_port_get_format (input->node->node,
|
||||
SPA_DIRECTION_INPUT,
|
||||
input->port_id,
|
||||
(const SpaFormat **)&format)) < 0) {
|
||||
asprintf (error, "error get input format: %d", res);
|
||||
goto error;
|
||||
}
|
||||
} else if (in_state == SPA_NODE_STATE_CONFIGURE && out_state == SPA_NODE_STATE_CONFIGURE) {
|
||||
again:
|
||||
/* both ports need a format */
|
||||
pinos_log_debug ("core %p: finding best format", core);
|
||||
if ((res = spa_node_port_enum_formats (input->node->node,
|
||||
SPA_DIRECTION_INPUT,
|
||||
input->port_id,
|
||||
&filter,
|
||||
NULL,
|
||||
iidx)) < 0) {
|
||||
if (res == SPA_RESULT_ENUM_END && iidx != 0) {
|
||||
asprintf (error, "error input enum formats: %d", res);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
pinos_log_debug ("Try filter: %p", filter);
|
||||
if (pinos_log_level_enabled (SPA_LOG_LEVEL_DEBUG))
|
||||
spa_debug_format (filter);
|
||||
|
||||
if ((res = spa_node_port_enum_formats (output->node->node,
|
||||
SPA_DIRECTION_OUTPUT,
|
||||
output->port_id,
|
||||
&format,
|
||||
filter,
|
||||
oidx)) < 0) {
|
||||
if (res == SPA_RESULT_ENUM_END) {
|
||||
oidx = 0;
|
||||
iidx++;
|
||||
goto again;
|
||||
}
|
||||
asprintf (error, "error output enum formats: %d", res);
|
||||
goto error;
|
||||
}
|
||||
pinos_log_debug ("Got filtered:");
|
||||
if (pinos_log_level_enabled (SPA_LOG_LEVEL_DEBUG))
|
||||
spa_debug_format (format);
|
||||
|
||||
spa_format_fixate (format);
|
||||
} else {
|
||||
asprintf (error, "error node state");
|
||||
goto error;
|
||||
}
|
||||
return format;
|
||||
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PinosNodeFactory *
|
||||
pinos_core_find_node_factory (PinosCore *core,
|
||||
const char *name)
|
||||
|
|
|
|||
|
|
@ -116,12 +116,20 @@ SpaResult pinos_global_bind (PinosGlobal *global,
|
|||
uint32_t id);
|
||||
void pinos_global_destroy (PinosGlobal *global);
|
||||
|
||||
SpaFormat * pinos_core_find_format (PinosCore *core,
|
||||
PinosPort *output,
|
||||
PinosPort *input,
|
||||
PinosProperties *props,
|
||||
unsigned int n_format_filters,
|
||||
SpaFormat **format_filters,
|
||||
char **error);
|
||||
|
||||
PinosPort * pinos_core_find_port (PinosCore *core,
|
||||
PinosPort *other_port,
|
||||
uint32_t id,
|
||||
PinosProperties *props,
|
||||
SpaFormat **format_filter,
|
||||
unsigned int n_format_filters,
|
||||
SpaFormat **format_filters,
|
||||
char **error);
|
||||
|
||||
PinosNodeFactory * pinos_core_find_node_factory (PinosCore *core,
|
||||
|
|
|
|||
|
|
@ -76,9 +76,8 @@ static SpaResult
|
|||
do_negotiate (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
|
||||
{
|
||||
PinosLinkImpl *impl = SPA_CONTAINER_OF (this, PinosLinkImpl, this);
|
||||
SpaResult res;
|
||||
SpaFormat *filter = NULL, *format;
|
||||
unsigned int iidx = 0, oidx = 0;
|
||||
SpaResult res = SPA_RESULT_ERROR;
|
||||
SpaFormat *format;
|
||||
char *error = NULL;
|
||||
|
||||
if (in_state != SPA_NODE_STATE_CONFIGURE && out_state != SPA_NODE_STATE_CONFIGURE)
|
||||
|
|
@ -91,64 +90,15 @@ do_negotiate (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
|
|||
out_state = SPA_NODE_STATE_CONFIGURE;
|
||||
}
|
||||
|
||||
/* both ports need a format */
|
||||
if (in_state == SPA_NODE_STATE_CONFIGURE && out_state == SPA_NODE_STATE_CONFIGURE) {
|
||||
pinos_log_debug ("link %p: doing negotiate format", this);
|
||||
again:
|
||||
if ((res = spa_node_port_enum_formats (this->input->node->node,
|
||||
SPA_DIRECTION_INPUT,
|
||||
this->input->port_id,
|
||||
&filter,
|
||||
NULL,
|
||||
iidx)) < 0) {
|
||||
if (res == SPA_RESULT_ENUM_END && iidx != 0) {
|
||||
asprintf (&error, "error input enum formats: %d", res);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
pinos_log_debug ("Try filter: %p", filter);
|
||||
if (pinos_log_level_enabled (SPA_LOG_LEVEL_DEBUG))
|
||||
spa_debug_format (filter);
|
||||
|
||||
if ((res = spa_node_port_enum_formats (this->output->node->node,
|
||||
SPA_DIRECTION_OUTPUT,
|
||||
this->output->port_id,
|
||||
&format,
|
||||
filter,
|
||||
oidx)) < 0) {
|
||||
if (res == SPA_RESULT_ENUM_END) {
|
||||
oidx = 0;
|
||||
iidx++;
|
||||
goto again;
|
||||
}
|
||||
asprintf (&error, "error output enum formats: %d", res);
|
||||
goto error;
|
||||
}
|
||||
pinos_log_debug ("Got filtered:");
|
||||
if (pinos_log_level_enabled (SPA_LOG_LEVEL_DEBUG))
|
||||
spa_debug_format (format);
|
||||
|
||||
spa_format_fixate (format);
|
||||
} else if (in_state == SPA_NODE_STATE_CONFIGURE && out_state > SPA_NODE_STATE_CONFIGURE) {
|
||||
/* only input needs format */
|
||||
if ((res = spa_node_port_get_format (this->output->node->node,
|
||||
SPA_DIRECTION_OUTPUT,
|
||||
this->output->port_id,
|
||||
(const SpaFormat **)&format)) < 0) {
|
||||
asprintf (&error, "error get output format: %d", res);
|
||||
goto error;
|
||||
}
|
||||
} else if (out_state == SPA_NODE_STATE_CONFIGURE && in_state > SPA_NODE_STATE_CONFIGURE) {
|
||||
/* only output needs format */
|
||||
if ((res = spa_node_port_get_format (this->input->node->node,
|
||||
SPA_DIRECTION_INPUT,
|
||||
this->input->port_id,
|
||||
(const SpaFormat **)&format)) < 0) {
|
||||
asprintf (&error, "error get input format: %d", res);
|
||||
goto error;
|
||||
}
|
||||
} else
|
||||
return SPA_RESULT_OK;
|
||||
format = pinos_core_find_format (this->core,
|
||||
this->output,
|
||||
this->input,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
&error);
|
||||
if (format == NULL)
|
||||
goto error;
|
||||
|
||||
pinos_log_debug ("link %p: doing set format", this);
|
||||
if (pinos_log_level_enabled (SPA_LOG_LEVEL_DEBUG))
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ SpaResult spa_format_audio_init (SpaMediaType type,
|
|||
SpaFormatAudio *format);
|
||||
SpaResult spa_format_audio_parse (const SpaFormat *format,
|
||||
SpaFormatAudio *aformat);
|
||||
SpaResult spa_format_audio_filter (SpaFormatAudio *format,
|
||||
const SpaFormat *filter);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
|
|
|||
|
|
@ -328,7 +328,9 @@ struct _SpaNode {
|
|||
* @index: an index variable, 0 to get the first item
|
||||
*
|
||||
* Enumerate all possible formats on @port_id of @node that are compatible
|
||||
* with @filter..
|
||||
* with @filter. When @port_id is #SPA_ID_INVALID, the enumeration will
|
||||
* list all the formats possible on a port that would be added with
|
||||
* add_port().
|
||||
*
|
||||
* Use @index to retrieve the formats one by one until the function
|
||||
* returns #SPA_RESULT_ENUM_END.
|
||||
|
|
|
|||
|
|
@ -62,6 +62,9 @@ SpaResult spa_format_video_init (SpaMediaType type,
|
|||
SpaResult spa_format_video_parse (const SpaFormat *format,
|
||||
SpaFormatVideo *dest);
|
||||
|
||||
SpaResult spa_format_video_filter (SpaFormatVideo *format,
|
||||
const SpaFormat *filter);
|
||||
|
||||
struct _SpaFormatVideo {
|
||||
SpaFormat format;
|
||||
union {
|
||||
|
|
|
|||
|
|
@ -305,3 +305,19 @@ fallback:
|
|||
|
||||
return res;
|
||||
}
|
||||
|
||||
SpaResult
|
||||
spa_format_audio_filter (SpaFormatAudio *format,
|
||||
const SpaFormat *filter)
|
||||
{
|
||||
SpaFormatAudio af;
|
||||
SpaResult res;
|
||||
|
||||
if (filter == NULL)
|
||||
return SPA_RESULT_OK;
|
||||
|
||||
if ((res = spa_format_audio_parse (filter, &af)) != SPA_RESULT_OK)
|
||||
return res;
|
||||
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -637,3 +637,19 @@ fallback:
|
|||
|
||||
return res;
|
||||
}
|
||||
|
||||
SpaResult
|
||||
spa_format_video_filter (SpaFormatVideo *format,
|
||||
const SpaFormat *filter)
|
||||
{
|
||||
SpaFormatVideo vf;
|
||||
SpaResult res;
|
||||
|
||||
if (filter == NULL)
|
||||
return SPA_RESULT_OK;
|
||||
|
||||
if ((res = spa_format_video_parse (filter, &vf)) != SPA_RESULT_OK)
|
||||
return res;
|
||||
|
||||
return SPA_RESULT_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -366,6 +366,7 @@ spa_alsa_source_node_port_enum_formats (SpaNode *node,
|
|||
unsigned int index)
|
||||
{
|
||||
SpaALSASource *this;
|
||||
SpaResult res;
|
||||
|
||||
if (node == NULL || format == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
|
@ -389,6 +390,10 @@ spa_alsa_source_node_port_enum_formats (SpaNode *node,
|
|||
default:
|
||||
return SPA_RESULT_ENUM_END;
|
||||
}
|
||||
|
||||
if ((res = spa_format_audio_filter (&this->query_format, filter)) != SPA_RESULT_OK)
|
||||
return res;
|
||||
|
||||
*format = &this->query_format.format;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
|
|
|
|||
|
|
@ -468,6 +468,7 @@ spa_audiotestsrc_node_port_enum_formats (SpaNode *node,
|
|||
unsigned int index)
|
||||
{
|
||||
SpaAudioTestSrc *this;
|
||||
SpaResult res;
|
||||
|
||||
if (node == NULL || format == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
|
@ -479,16 +480,16 @@ spa_audiotestsrc_node_port_enum_formats (SpaNode *node,
|
|||
|
||||
switch (index) {
|
||||
case 0:
|
||||
if (filter)
|
||||
spa_format_audio_parse (filter, &this->query_format);
|
||||
else
|
||||
spa_format_audio_init (SPA_MEDIA_TYPE_AUDIO,
|
||||
SPA_MEDIA_SUBTYPE_RAW,
|
||||
&this->query_format);
|
||||
spa_format_audio_init (SPA_MEDIA_TYPE_AUDIO,
|
||||
SPA_MEDIA_SUBTYPE_RAW,
|
||||
&this->query_format);
|
||||
break;
|
||||
default:
|
||||
return SPA_RESULT_ENUM_END;
|
||||
}
|
||||
if ((res = spa_format_audio_filter (&this->query_format, filter)) != SPA_RESULT_OK)
|
||||
return res;
|
||||
|
||||
*format = &this->query_format.format;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
|
|
|
|||
|
|
@ -428,6 +428,7 @@ spa_videotestsrc_node_port_enum_formats (SpaNode *node,
|
|||
unsigned int index)
|
||||
{
|
||||
SpaVideoTestSrc *this;
|
||||
SpaResult res;
|
||||
|
||||
if (node == NULL || format == NULL)
|
||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||
|
|
@ -439,16 +440,34 @@ spa_videotestsrc_node_port_enum_formats (SpaNode *node,
|
|||
|
||||
switch (index) {
|
||||
case 0:
|
||||
if (filter)
|
||||
spa_format_video_parse (filter, &this->query_format);
|
||||
else
|
||||
spa_format_video_init (SPA_MEDIA_TYPE_VIDEO,
|
||||
SPA_MEDIA_SUBTYPE_RAW,
|
||||
&this->query_format);
|
||||
{
|
||||
int idx;
|
||||
static const uint32_t format_values[] = {
|
||||
SPA_VIDEO_FORMAT_RGB,
|
||||
SPA_VIDEO_FORMAT_UYVY,
|
||||
};
|
||||
static const SpaPropRangeInfo format_range[] = {
|
||||
{ "RGB", { sizeof (uint32_t), &format_values[0] } },
|
||||
{ "UYVY", { sizeof (uint32_t), &format_values[1] } },
|
||||
};
|
||||
SpaPropInfo *info;
|
||||
spa_format_video_init (SPA_MEDIA_TYPE_VIDEO,
|
||||
SPA_MEDIA_SUBTYPE_RAW,
|
||||
&this->query_format);
|
||||
|
||||
idx = spa_props_index_for_id (&this->query_format.format.props, SPA_PROP_ID_VIDEO_FORMAT);
|
||||
info = (SpaPropInfo *) &this->query_format.format.props.prop_info[idx];
|
||||
|
||||
info->n_range_values = SPA_N_ELEMENTS (format_range);
|
||||
info->range_values = format_range;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return SPA_RESULT_ENUM_END;
|
||||
}
|
||||
if ((res = spa_format_video_filter (&this->query_format, filter)) != SPA_RESULT_OK)
|
||||
return res;
|
||||
|
||||
*format = &this->query_format.format;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue