summaryrefslogtreecommitdiff
path: root/spa
diff options
context:
space:
mode:
authorWim Taymans <wtaymans@redhat.com>2019-04-23 17:34:27 +0200
committerWim Taymans <wtaymans@redhat.com>2019-04-23 17:34:27 +0200
commit2912d2506fd7422201cc76f237786eb05ca37a28 (patch)
tree7701623269e88a040ac5b5dcf1b42f776cf5c408 /spa
parentb7cc9ea10289951786b41efcb9537a69c8a6bdd4 (diff)
audioconvert: improve resampler
Also emit port info the the merger monitor ports. Proxy params and buffers to the right monitor ports. fmtconvert does not always have dsp ports Increase resampler output buffer sizes so that we can up and downsample. Fix little off by one in native resampler. Fix passthrough in speex resampler.
Diffstat (limited to 'spa')
-rw-r--r--spa/plugins/audioconvert/audioconvert.c87
-rw-r--r--spa/plugins/audioconvert/fmtconvert.c9
-rw-r--r--spa/plugins/audioconvert/merger.c4
-rw-r--r--spa/plugins/audioconvert/resample-native.h9
-rw-r--r--spa/plugins/audioconvert/resample-speex.h6
-rw-r--r--spa/plugins/audioconvert/resample.c15
-rw-r--r--spa/plugins/audioconvert/resample.h1
7 files changed, 93 insertions, 38 deletions
diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c
index c588e89b..e6e4b0f7 100644
--- a/spa/plugins/audioconvert/audioconvert.c
+++ b/spa/plugins/audioconvert/audioconvert.c
@@ -568,7 +568,8 @@ static void fmt_input_port_info(void *data,
const struct spa_port_info *info)
{
struct impl *this = data;
- if (direction == SPA_DIRECTION_INPUT)
+ if (direction == SPA_DIRECTION_INPUT ||
+ (this->mode == MODE_MERGE && port > 0))
spa_node_emit_port_info(&this->hooks, direction, port, info);
}
@@ -606,6 +607,7 @@ impl_node_add_listener(struct spa_node *node,
{
struct impl *this;
struct spa_hook_list save;
+ struct spa_hook l[4];
spa_return_val_if_fail(node != NULL, -EINVAL);
@@ -614,22 +616,20 @@ impl_node_add_listener(struct spa_node *node,
spa_log_debug(this->log, "%p: add listener %p", this, listener);
- if (this->listening) {
- spa_hook_remove(&this->listener[0]);
- spa_hook_remove(&this->listener[1]);
- spa_hook_remove(&this->listener[2]);
- spa_hook_remove(&this->listener[3]);
- }
-
+ spa_zero(l);
spa_node_add_listener(this->fmt[SPA_DIRECTION_INPUT],
- &this->listener[0], &fmt_input_events, this);
+ &l[0], &fmt_input_events, this);
spa_node_add_listener(this->channelmix,
- &this->listener[1], &node_events, this);
+ &l[1], &node_events, this);
spa_node_add_listener(this->resample,
- &this->listener[2], &node_events, this);
+ &l[2], &node_events, this);
spa_node_add_listener(this->fmt[SPA_DIRECTION_OUTPUT],
- &this->listener[3], &fmt_output_events, this);
- this->listening = true;
+ &l[3], &fmt_output_events, this);
+
+ spa_hook_remove(&l[0]);
+ spa_hook_remove(&l[1]);
+ spa_hook_remove(&l[2]);
+ spa_hook_remove(&l[3]);
spa_hook_list_join(&this->hooks, &save);
@@ -732,9 +732,18 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
}
break;
default:
- return spa_node_port_enum_params(this->fmt[direction], seq, direction, port_id,
+ {
+ struct spa_node *target;
+
+ if (this->mode == MODE_MERGE && port_id > 0 && direction == SPA_DIRECTION_OUTPUT)
+ target = this->fmt[SPA_DIRECTION_INPUT];
+ else
+ target = this->fmt[direction];
+
+ return spa_node_port_enum_params(target, seq, direction, port_id,
id, start, num, filter);
}
+ }
if (spa_pod_filter(&b, &result.param, param, filter) < 0)
goto next;
@@ -755,12 +764,18 @@ impl_node_port_set_param(struct spa_node *node,
{
struct impl *this;
int res;
+ struct spa_node *target;
spa_return_val_if_fail(node != NULL, -EINVAL);
this = SPA_CONTAINER_OF(node, struct impl, node);
- if ((res = spa_node_port_set_param(this->fmt[direction],
+ if (this->mode == MODE_MERGE && port_id > 0 && direction == SPA_DIRECTION_OUTPUT)
+ target = this->fmt[SPA_DIRECTION_INPUT];
+ else
+ target = this->fmt[direction];
+
+ if ((res = spa_node_port_set_param(target,
direction, port_id, id, flags, param)) < 0)
return res;
@@ -785,12 +800,18 @@ impl_node_port_use_buffers(struct spa_node *node,
{
struct impl *this;
int res;
+ struct spa_node *target;
spa_return_val_if_fail(node != NULL, -EINVAL);
this = SPA_CONTAINER_OF(node, struct impl, node);
- if ((res = spa_node_port_use_buffers(this->fmt[direction],
+ if (this->mode == MODE_MERGE && port_id > 0 && direction == SPA_DIRECTION_OUTPUT)
+ target = this->fmt[SPA_DIRECTION_INPUT];
+ else
+ target = this->fmt[direction];
+
+ if ((res = spa_node_port_use_buffers(target,
direction, port_id, buffers, n_buffers)) < 0)
return res;
@@ -812,12 +833,18 @@ impl_node_port_alloc_buffers(struct spa_node *node,
uint32_t *n_buffers)
{
struct impl *this;
+ struct spa_node *target;
spa_return_val_if_fail(node != NULL, -EINVAL);
this = SPA_CONTAINER_OF(node, struct impl, node);
- return spa_node_port_alloc_buffers(this->fmt[direction], direction, port_id,
+ if (this->mode == MODE_MERGE && port_id > 0 && direction == SPA_DIRECTION_OUTPUT)
+ target = this->fmt[SPA_DIRECTION_INPUT];
+ else
+ target = this->fmt[direction];
+
+ return spa_node_port_alloc_buffers(target, direction, port_id,
params, n_params, buffers, n_buffers);
}
@@ -827,6 +854,7 @@ impl_node_port_set_io(struct spa_node *node,
uint32_t id, void *data, size_t size)
{
struct impl *this;
+ struct spa_node *target;
int res;
spa_return_val_if_fail(node != NULL, -EINVAL);
@@ -840,10 +868,16 @@ impl_node_port_set_io(struct spa_node *node,
res = spa_node_port_set_io(this->resample, direction, 0, id, data, size);
break;
case SPA_IO_Control:
+ res = spa_node_port_set_io(this->resample, direction, 0, id, data, size);
res = spa_node_port_set_io(this->channelmix, direction, 0, id, data, size);
break;
default:
- res = spa_node_port_set_io(this->fmt[direction], direction, port_id, id, data, size);
+ if (this->mode == MODE_MERGE && port_id > 0 && direction == SPA_DIRECTION_OUTPUT)
+ target = this->fmt[SPA_DIRECTION_INPUT];
+ else
+ target = this->fmt[direction];
+
+ res = spa_node_port_set_io(target, direction, port_id, id, data, size);
break;
}
return res;
@@ -852,12 +886,18 @@ impl_node_port_set_io(struct spa_node *node,
static int impl_node_port_reuse_buffer(struct spa_node *node, uint32_t port_id, uint32_t buffer_id)
{
struct impl *this;
+ struct spa_node *target;
spa_return_val_if_fail(node != NULL, -EINVAL);
this = SPA_CONTAINER_OF(node, struct impl, node);
- return spa_node_port_reuse_buffer(this->fmt[SPA_DIRECTION_OUTPUT], port_id, buffer_id);
+ if (this->mode == MODE_MERGE && port_id > 0)
+ target = this->fmt[SPA_DIRECTION_INPUT];
+ else
+ target = this->fmt[SPA_DIRECTION_OUTPUT];
+
+ return spa_node_port_reuse_buffer(target, port_id, buffer_id);
}
static int impl_node_process(struct spa_node *node)
@@ -1060,6 +1100,15 @@ impl_init(const struct spa_handle_factory *factory,
spa_handle_get_interface(this->hnd_fmt[SPA_DIRECTION_OUTPUT], SPA_TYPE_INTERFACE_Node, &iface);
this->fmt[SPA_DIRECTION_OUTPUT] = iface;
+ spa_node_add_listener(this->fmt[SPA_DIRECTION_INPUT],
+ &this->listener[0], &fmt_input_events, this);
+ spa_node_add_listener(this->channelmix,
+ &this->listener[1], &node_events, this);
+ spa_node_add_listener(this->resample,
+ &this->listener[2], &node_events, this);
+ spa_node_add_listener(this->fmt[SPA_DIRECTION_OUTPUT],
+ &this->listener[3], &fmt_output_events, this);
+
return 0;
}
diff --git a/spa/plugins/audioconvert/fmtconvert.c b/spa/plugins/audioconvert/fmtconvert.c
index 077006ac..a0a7dfae 100644
--- a/spa/plugins/audioconvert/fmtconvert.c
+++ b/spa/plugins/audioconvert/fmtconvert.c
@@ -252,11 +252,6 @@ static void emit_port_info(struct impl *this, struct port *port, bool full)
if (full)
port->info.change_mask = port->info_all;
if (port->info.change_mask) {
- struct spa_dict_item items[1];
-
- items[0] = SPA_DICT_ITEM_INIT("port.dsp", "32 bit float mono audio");
- port->info.props = &SPA_DICT_INIT_ARRAY(items);
-
spa_node_emit_port_info(&this->hooks,
port->direction, port->id, &port->info);
port->info.change_mask = 0;
@@ -459,7 +454,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
buffers = 1;
pod = &SPA_POD_INIT_Choice(SPA_CHOICE_Range,
int32_t, SPA_TYPE_Int, 3,
- 1024 * port->stride,
+ 2048 * port->stride,
16 * port->stride,
INT32_MAX / port->stride);
}
@@ -938,7 +933,7 @@ static int init_port(struct impl *this, enum spa_direction direction, uint32_t p
port->id = port_id;
spa_list_init(&port->queue);
- port->info_all = SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_PROPS;
+ port->info_all = SPA_PORT_CHANGE_MASK_FLAGS;
port->info = SPA_PORT_INFO_INIT();
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
SPA_PORT_FLAG_NO_REF |
diff --git a/spa/plugins/audioconvert/merger.c b/spa/plugins/audioconvert/merger.c
index e5e89d17..1ba00665 100644
--- a/spa/plugins/audioconvert/merger.c
+++ b/spa/plugins/audioconvert/merger.c
@@ -447,12 +447,12 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
this = SPA_CONTAINER_OF(node, struct impl, node);
+ spa_log_debug(this->log, "%p: enum params %d %d %u %u", this, seq, direction, port_id, id);
+
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
port = GET_PORT(this, direction, port_id);
- spa_log_debug(this->log, "%p: enum params %d %d %u %u", this, seq, direction, port_id, id);
-
result.id = id;
result.next = start;
next:
diff --git a/spa/plugins/audioconvert/resample-native.h b/spa/plugins/audioconvert/resample-native.h
index 1a8e91fa..c8f15d6a 100644
--- a/spa/plugins/audioconvert/resample-native.h
+++ b/spa/plugins/audioconvert/resample-native.h
@@ -96,10 +96,12 @@ static void impl_native_update_rate(struct resample *r, double rate)
struct native_data *data = r->data;
uint32_t in_rate, out_rate, phase, gcd;
- in_rate = r->i_rate * rate;
+ in_rate = r->i_rate / rate;
out_rate = r->o_rate;
phase = data->phase;
+ spa_log_trace_fp(r->log, "native %p: new rate:%f", r, rate);
+
gcd = calc_gcd(in_rate, out_rate);
gcd = calc_gcd(gcd, phase);
@@ -151,7 +153,7 @@ static void impl_native_process(struct resample *r,
/* we need at least n_taps to completely process the
* history before we can work on the new input. When
* we have less, refill the history. */
- refill = SPA_MIN(*in_len, n_taps);
+ refill = SPA_MIN(*in_len, n_taps-1);
for (c = 0; c < r->channels; c++)
memcpy(&history[c][hist], s[c], refill * sizeof(float));
@@ -294,6 +296,9 @@ static int impl_native_init(struct resample *r)
build_filter(d->filter, d->filter_stride, n_taps, n_phases, scale);
+ spa_log_debug(r->log, "native %p: in:%d out:%d n_taps:%d n_phases:%d",
+ r, in_rate, out_rate, n_taps, n_phases);
+
impl_native_reset(r);
impl_native_update_rate(r, 1.0);
diff --git a/spa/plugins/audioconvert/resample-speex.h b/spa/plugins/audioconvert/resample-speex.h
index 8e924e95..e1d4d2fa 100644
--- a/spa/plugins/audioconvert/resample-speex.h
+++ b/spa/plugins/audioconvert/resample-speex.h
@@ -33,8 +33,9 @@ static void impl_speex_free(struct resample *r)
static void impl_speex_update_rate(struct resample *r, double rate)
{
+ r->rate = rate;
speex_resampler_set_rate_frac(r->data,
- r->i_rate * rate, r->o_rate, r->i_rate, r->o_rate);
+ r->i_rate / rate, r->o_rate, r->i_rate, r->o_rate);
}
static void impl_speex_process(struct resample *r,
@@ -43,7 +44,7 @@ static void impl_speex_process(struct resample *r,
{
uint32_t c, i, o;
- if (r->i_rate == r->o_rate) {
+ if (r->i_rate == r->o_rate && r->rate == 1.0) {
o = i = SPA_MIN(*in_len, *out_len);
for (c = 0; c < r->channels; c++)
spa_memcpy(dst[c], src[c], o * sizeof(float));
@@ -67,6 +68,7 @@ static int impl_speex_init(struct resample *r)
{
int err;
+ r->rate = 1.0;
r->free = impl_speex_free;
r->update_rate = impl_speex_update_rate;
r->process = impl_speex_process;
diff --git a/spa/plugins/audioconvert/resample.c b/spa/plugins/audioconvert/resample.c
index 9e194365..a5d89a91 100644
--- a/spa/plugins/audioconvert/resample.c
+++ b/spa/plugins/audioconvert/resample.c
@@ -157,7 +157,7 @@ static int setup_convert(struct impl *this,
if (this->monitor)
err = impl_peaks_init(&this->resample);
- else if (1)
+ else if (0)
err = impl_native_init(&this->resample);
else
err = impl_speex_init(&this->resample);
@@ -181,8 +181,9 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
SPA_POD_OBJECT_FOREACH(obj, prop) {
switch (prop->key) {
case SPA_PROP_rate:
- if (spa_pod_get_double(&prop->value, &p->rate) == 0)
+ if (spa_pod_get_double(&prop->value, &p->rate) == 0) {
resample_update_rate(&this->resample, p->rate);
+ }
break;
default:
break;
@@ -406,11 +407,11 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
if (other->n_buffers > 0) {
buffers = other->n_buffers;
- size = other->size / other->stride;
+ size = other->size / other->stride * 2;
}
else {
buffers = 1;
- size = 1024;
+ size = 2048 * other->stride;
}
param = spa_pod_builder_add_object(&b,
@@ -647,6 +648,8 @@ impl_node_port_set_io(struct spa_node *node,
spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL);
+ spa_log_trace_fp(this->log, NAME " %p: %d:%d io %d", this, direction, port_id, id);
+
port = GET_PORT(this, direction, port_id);
switch (id) {
@@ -811,10 +814,10 @@ static int impl_node_process(struct spa_node *node)
inio->status = SPA_STATUS_NEED_BUFFER;
inport->offset = 0;
SPA_FLAG_SET(res, SPA_STATUS_NEED_BUFFER);
- if (outport->io_range == NULL)
- maxsize = 0;
}
outport->offset += out_len * sizeof(float);
+ if (outport->io_range == NULL)
+ maxsize = 0;
if (outport->offset > 0 && outport->offset >= maxsize) {
outio->status = SPA_STATUS_HAVE_BUFFER;
outio->buffer_id = dbuf->id;
diff --git a/spa/plugins/audioconvert/resample.h b/spa/plugins/audioconvert/resample.h
index 9b52d19a..0da5d1f2 100644
--- a/spa/plugins/audioconvert/resample.h
+++ b/spa/plugins/audioconvert/resample.h
@@ -34,6 +34,7 @@ struct resample {
uint32_t i_rate;
uint32_t o_rate;
struct spa_log *log;
+ double rate;
void (*free) (struct resample *r);
void (*update_rate) (struct resample *r, double rate);