mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
audioconvert: improve passthrough mode
When in passthrough mode, use the position io to update the io_rate_match fields for the follower. This makes it possible for the follower to also provide the right amount of data when the converter is not selected in passthrough. Add an option to configure the converter in None port config where it removes all the ports. We can use this when removing the converter to make sure all it's ports are removed. When we remove the converter, make sure we expose the follower ports directly so we can use them for passthrough.
This commit is contained in:
parent
24f61deefd
commit
9090f19b0a
2 changed files with 97 additions and 55 deletions
|
|
@ -75,6 +75,7 @@ struct impl {
|
|||
|
||||
struct spa_io_buffers io_buffers;
|
||||
struct spa_io_rate_match io_rate_match;
|
||||
struct spa_io_position *io_position;
|
||||
|
||||
uint64_t info_all;
|
||||
struct spa_node_info info;
|
||||
|
|
@ -419,33 +420,68 @@ static int configure_format(struct impl *this, uint32_t flags, const struct spa_
|
|||
return res;
|
||||
}
|
||||
|
||||
static int configure_convert(struct impl *this, uint32_t mode)
|
||||
{
|
||||
struct spa_pod_builder b = { 0 };
|
||||
uint8_t buffer[1024];
|
||||
struct spa_pod *param;
|
||||
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
spa_log_debug(this->log, "%p: configure convert %p", this, this->target);
|
||||
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig,
|
||||
SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(this->direction),
|
||||
SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(mode));
|
||||
|
||||
return spa_node_set_param(this->convert, SPA_PARAM_PortConfig, 0, param);
|
||||
}
|
||||
|
||||
extern const struct spa_handle_factory spa_audioconvert_factory;
|
||||
|
||||
static const struct spa_node_events follower_node_events;
|
||||
|
||||
static int reconfigure_mode(struct impl *this, bool passthrough,
|
||||
enum spa_direction direction, struct spa_audio_info *info)
|
||||
{
|
||||
int res = 0;
|
||||
int res = 0;
|
||||
char buf[1024];
|
||||
struct spa_pod_builder b = { 0 };
|
||||
struct spa_pod *format = NULL;
|
||||
|
||||
spa_log_debug(this->log, NAME " %p: passthrough mode %d", this, passthrough);
|
||||
spa_log_debug(this->log, NAME " %p: passthrough mode %d", this, passthrough);
|
||||
|
||||
if (passthrough)
|
||||
configure_convert(this, SPA_PARAM_PORT_CONFIG_MODE_none);
|
||||
else
|
||||
configure_convert(this, SPA_PARAM_PORT_CONFIG_MODE_dsp);
|
||||
|
||||
/* set new target */
|
||||
this->target = passthrough ? this->follower : this->convert;
|
||||
|
||||
if (info) {
|
||||
char buf[1024];
|
||||
struct spa_pod_builder b = { 0 };
|
||||
struct spa_pod *format;
|
||||
spa_pod_builder_init(&b, buf, sizeof(buf));
|
||||
format = spa_format_audio_raw_build(&b, SPA_PARAM_Format, &info->info.raw);
|
||||
if ((res = configure_format (this, 0, format)) < 0)
|
||||
return res;
|
||||
spa_pod_builder_init(&b, buf, sizeof(buf));
|
||||
if (info)
|
||||
format = spa_format_audio_raw_build(&b, SPA_PARAM_Format, &info->info.raw);
|
||||
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS | SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->info.flags &= ~SPA_NODE_FLAG_NEED_CONFIGURE;
|
||||
this->params[IDX_Props].user++;
|
||||
}
|
||||
if ((res = configure_format (this, 0, format)) < 0)
|
||||
return res;
|
||||
|
||||
emit_node_info(this, false);
|
||||
if (passthrough) {
|
||||
struct spa_hook l;
|
||||
|
||||
return 0;
|
||||
spa_zero(l);
|
||||
spa_node_add_listener(this->follower, &l, &follower_node_events, this);
|
||||
spa_hook_remove(&l);
|
||||
}
|
||||
|
||||
this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS | SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
this->info.flags &= ~SPA_NODE_FLAG_NEED_CONFIGURE;
|
||||
this->params[IDX_Props].user++;
|
||||
|
||||
emit_node_info(this, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
||||
|
|
@ -483,8 +519,10 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
|||
struct spa_audio_info info = { 0, }, *infop = NULL;
|
||||
int monitor = false;
|
||||
|
||||
if (this->started)
|
||||
if (this->started) {
|
||||
spa_log_error(this->log, "was started");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_ParamPortConfig, NULL,
|
||||
|
|
@ -562,6 +600,14 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
|
|||
|
||||
spa_return_val_if_fail(this != NULL, -EINVAL);
|
||||
|
||||
switch (id) {
|
||||
case SPA_IO_Position:
|
||||
this->io_position = data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->target)
|
||||
res = spa_node_set_io(this->target, id, data, size);
|
||||
|
||||
|
|
@ -667,15 +713,17 @@ static int impl_node_send_command(void *object, const struct spa_command *comman
|
|||
}
|
||||
|
||||
if ((res = spa_node_send_command(this->target, command)) < 0) {
|
||||
spa_log_error(this->log, NAME " %p: can't send command: %s",
|
||||
this, spa_strerror(res));
|
||||
spa_log_error(this->log, NAME " %p: can't send command %d: %s",
|
||||
this, SPA_NODE_COMMAND_ID(command),
|
||||
spa_strerror(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
if (this->target != this->follower) {
|
||||
if ((res = spa_node_send_command(this->follower, command)) < 0) {
|
||||
spa_log_error(this->log, NAME " %p: can't send command: %s",
|
||||
this, spa_strerror(res));
|
||||
spa_log_error(this->log, NAME " %p: can't send command %d: %s",
|
||||
this, SPA_NODE_COMMAND_ID(command),
|
||||
spa_strerror(res));
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
@ -1163,8 +1211,11 @@ static int impl_node_process(void *object)
|
|||
spa_log_trace_fp(this->log, "%p: process convert:%p driver:%d",
|
||||
this, this->convert, this->driver);
|
||||
|
||||
if (this->target == this->follower)
|
||||
if (this->target == this->follower) {
|
||||
if (this->io_position)
|
||||
this->io_rate_match.size = this->io_position->clock.duration;
|
||||
return spa_node_process(this->follower);
|
||||
}
|
||||
|
||||
if (this->direction == SPA_DIRECTION_INPUT) {
|
||||
/* an input node (sink).
|
||||
|
|
@ -1304,25 +1355,6 @@ static int impl_clear(struct spa_handle *handle)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int configure_adapt(struct impl *this)
|
||||
{
|
||||
struct spa_pod_builder b = { 0 };
|
||||
uint8_t buffer[1024];
|
||||
struct spa_pod *param;
|
||||
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
spa_log_debug(this->log, "%p: configure convert %p", this, this->target);
|
||||
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig,
|
||||
SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(this->direction),
|
||||
SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp));
|
||||
|
||||
return spa_node_set_param(this->target, SPA_PARAM_PortConfig, 0, param);
|
||||
}
|
||||
|
||||
extern const struct spa_handle_factory spa_audioconvert_factory;
|
||||
|
||||
static size_t
|
||||
impl_get_size(const struct spa_handle_factory *factory,
|
||||
|
|
@ -1410,7 +1442,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
spa_node_add_listener(this->convert,
|
||||
&this->convert_listener, &convert_node_events, this);
|
||||
|
||||
configure_adapt(this);
|
||||
configure_convert(this, SPA_PARAM_PORT_CONFIG_MODE_dsp);
|
||||
|
||||
link_io(this);
|
||||
|
||||
|
|
|
|||
|
|
@ -580,14 +580,16 @@ static void fmt_input_port_info(void *data,
|
|||
const struct spa_port_info *info)
|
||||
{
|
||||
struct impl *this = data;
|
||||
bool is_monitor = IS_MONITOR_PORT(this, direction, port);
|
||||
|
||||
if (this->fmt_removing[direction])
|
||||
info = NULL;
|
||||
if (is_monitor && this->fmt_removing[SPA_DIRECTION_INPUT])
|
||||
info = NULL;
|
||||
|
||||
spa_log_debug(this->log, "%p: %d.%d info", this, direction, port);
|
||||
|
||||
if (direction == SPA_DIRECTION_INPUT ||
|
||||
IS_MONITOR_PORT(this, direction, port))
|
||||
if (direction == SPA_DIRECTION_INPUT || is_monitor)
|
||||
spa_node_emit_port_info(&this->hooks, direction, port, info);
|
||||
}
|
||||
|
||||
|
|
@ -687,11 +689,13 @@ static int reconfigure_mode(struct impl *this, enum spa_param_port_config_mode m
|
|||
case SPA_PARAM_PORT_CONFIG_MODE_dsp:
|
||||
new = direction == SPA_DIRECTION_INPUT ? this->merger : this->splitter;
|
||||
break;
|
||||
case SPA_PARAM_PORT_CONFIG_MODE_none:
|
||||
new = NULL;
|
||||
break;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
this->mode[direction] = mode;
|
||||
clean_convert(this);
|
||||
|
||||
this->fmt[direction] = new;
|
||||
|
|
@ -700,7 +704,7 @@ static int reconfigure_mode(struct impl *this, enum spa_param_port_config_mode m
|
|||
do_signal = this->fmt[direction] != old ||
|
||||
mode == SPA_PARAM_PORT_CONFIG_MODE_dsp;
|
||||
|
||||
if (do_signal) {
|
||||
if (do_signal && old != NULL) {
|
||||
/* change, remove old ports. We trigger a new port_info event
|
||||
* on the old node with info set to NULL to mark delete */
|
||||
if (this->have_fmt_listener[direction]) {
|
||||
|
|
@ -719,7 +723,9 @@ static int reconfigure_mode(struct impl *this, enum spa_param_port_config_mode m
|
|||
}
|
||||
}
|
||||
|
||||
if (info) {
|
||||
this->mode[direction] = mode;
|
||||
|
||||
if (info && new != NULL) {
|
||||
struct spa_pod_builder b = { 0 };
|
||||
uint8_t buffer[1024];
|
||||
struct spa_pod *param;
|
||||
|
|
@ -752,7 +758,7 @@ static int reconfigure_mode(struct impl *this, enum spa_param_port_config_mode m
|
|||
}
|
||||
|
||||
/* notify ports of new node */
|
||||
if (do_signal) {
|
||||
if (do_signal && new != NULL) {
|
||||
if (this->have_fmt_listener[direction])
|
||||
spa_hook_remove(&this->fmt_listener[direction]);
|
||||
|
||||
|
|
@ -816,10 +822,10 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
|||
spa_log_debug(this->log, "mode:%d direction:%d %d", mode, dir, monitor);
|
||||
|
||||
switch (mode) {
|
||||
case SPA_PARAM_PORT_CONFIG_MODE_none:
|
||||
case SPA_PARAM_PORT_CONFIG_MODE_passthrough:
|
||||
return -ENOTSUP;
|
||||
|
||||
case SPA_PARAM_PORT_CONFIG_MODE_none:
|
||||
case SPA_PARAM_PORT_CONFIG_MODE_convert:
|
||||
break;
|
||||
|
||||
|
|
@ -912,19 +918,23 @@ impl_node_add_listener(void *object,
|
|||
this->add_listener = true;
|
||||
|
||||
spa_zero(l);
|
||||
spa_node_add_listener(this->fmt[SPA_DIRECTION_INPUT],
|
||||
&l[0], &fmt_input_events, this);
|
||||
if (this->fmt[SPA_DIRECTION_INPUT])
|
||||
spa_node_add_listener(this->fmt[SPA_DIRECTION_INPUT],
|
||||
&l[0], &fmt_input_events, this);
|
||||
spa_node_add_listener(this->channelmix,
|
||||
&l[1], &channelmix_events, this);
|
||||
spa_node_add_listener(this->resample,
|
||||
&l[2], &resample_events, this);
|
||||
spa_node_add_listener(this->fmt[SPA_DIRECTION_OUTPUT],
|
||||
&l[3], &fmt_output_events, this);
|
||||
if (this->fmt[SPA_DIRECTION_OUTPUT])
|
||||
spa_node_add_listener(this->fmt[SPA_DIRECTION_OUTPUT],
|
||||
&l[3], &fmt_output_events, this);
|
||||
|
||||
spa_hook_remove(&l[0]);
|
||||
if (this->fmt[SPA_DIRECTION_INPUT])
|
||||
spa_hook_remove(&l[0]);
|
||||
spa_hook_remove(&l[1]);
|
||||
spa_hook_remove(&l[2]);
|
||||
spa_hook_remove(&l[3]);
|
||||
if (this->fmt[SPA_DIRECTION_OUTPUT])
|
||||
spa_hook_remove(&l[3]);
|
||||
|
||||
this->add_listener = false;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue