Improve negotiation

Try to link ports based on compatible formats
Add methods to filter formats.
This commit is contained in:
Wim Taymans 2017-02-10 10:17:07 +01:00
parent 1370fafd5b
commit df86fcec10
12 changed files with 229 additions and 95 deletions

View file

@ -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:

View file

@ -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)

View file

@ -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,

View file

@ -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))

View file

@ -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" */

View file

@ -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.

View file

@ -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 {

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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;