mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-03-19 05:33:49 -04:00
filter-graph: allow 0 input and output ports
There is no reason to fail when there is no input or output port. We can simply run the graph with what there is. Even if there is no input or output at all, running one instance of the plugins is possible. Add a busy builtin plugin that has no ports and keeps the CPU IDLE or busy for the give percent.
This commit is contained in:
parent
ba3e564e34
commit
a97c4d10af
3 changed files with 144 additions and 18 deletions
|
|
@ -1030,11 +1030,6 @@ static struct descriptor *descriptor_load(struct impl *impl, const char *type,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (desc->n_input == 0 && desc->n_output == 0 && desc->n_control == 0 && desc->n_notify == 0) {
|
||||
spa_log_error(impl->log, "plugin has no input and no output ports");
|
||||
res = -ENOTSUP;
|
||||
goto exit;
|
||||
}
|
||||
for (i = 0; i < desc->n_control; i++) {
|
||||
p = desc->control[i];
|
||||
desc->default_control[i] = get_default(impl, desc, p);
|
||||
|
|
@ -1794,7 +1789,7 @@ static int setup_graph(struct graph *graph)
|
|||
struct port *port;
|
||||
struct graph_port *gp;
|
||||
struct graph_hndl *gh;
|
||||
uint32_t i, j, n, n_input, n_output, n_hndl = 0;
|
||||
uint32_t i, j, n, n_input, n_output, n_hndl = 0, n_out_hndl;
|
||||
int res;
|
||||
struct descriptor *desc;
|
||||
const struct spa_fga_descriptor *d;
|
||||
|
|
@ -1815,16 +1810,11 @@ static int setup_graph(struct graph *graph)
|
|||
SPA_FLAG_IS_SET(first->desc->desc->flags, SPA_FGA_DESCRIPTOR_SUPPORTS_NULL_DATA) &&
|
||||
SPA_FLAG_IS_SET(last->desc->desc->flags, SPA_FGA_DESCRIPTOR_SUPPORTS_NULL_DATA);
|
||||
|
||||
if (n_input == 0) {
|
||||
spa_log_error(impl->log, "no inputs");
|
||||
res = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
if (n_output == 0) {
|
||||
spa_log_error(impl->log, "no outputs");
|
||||
res = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
if (n_input == 0)
|
||||
n_input = n_output;
|
||||
if (n_output == 0)
|
||||
n_output = n_input;
|
||||
|
||||
if (graph->n_inputs == 0)
|
||||
graph->n_inputs = impl->info.n_inputs;
|
||||
if (graph->n_inputs == 0)
|
||||
|
|
@ -1835,12 +1825,14 @@ static int setup_graph(struct graph *graph)
|
|||
|
||||
/* compare to the requested number of inputs and duplicate the
|
||||
* graph n_hndl times when needed. */
|
||||
n_hndl = graph->n_inputs / n_input;
|
||||
n_hndl = n_input ? graph->n_inputs / n_input : 1;
|
||||
|
||||
if (graph->n_outputs == 0)
|
||||
graph->n_outputs = n_output * n_hndl;
|
||||
|
||||
if (n_hndl != graph->n_outputs / n_output) {
|
||||
n_out_hndl = n_output ? graph->n_outputs / n_output : 1;
|
||||
|
||||
if (n_hndl != n_out_hndl) {
|
||||
spa_log_error(impl->log, "invalid ports. The input stream has %1$d ports and "
|
||||
"the filter has %2$d inputs. The output stream has %3$d ports "
|
||||
"and the filter has %4$d outputs. input:%1$d / input:%2$d != "
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <spa/utils/json.h>
|
||||
#include <spa/utils/result.h>
|
||||
|
|
@ -3115,6 +3116,107 @@ static const struct spa_fga_descriptor noisegate_desc = {
|
|||
.cleanup = builtin_cleanup,
|
||||
};
|
||||
|
||||
/* busy */
|
||||
struct busy_impl {
|
||||
struct plugin *plugin;
|
||||
|
||||
struct spa_fga_dsp *dsp;
|
||||
struct spa_log *log;
|
||||
|
||||
unsigned long rate;
|
||||
|
||||
float wait_scale;
|
||||
float cpu_scale;
|
||||
};
|
||||
|
||||
static void *busy_instantiate(const struct spa_fga_plugin *plugin, const struct spa_fga_descriptor * Descriptor,
|
||||
unsigned long SampleRate, int index, const char *config)
|
||||
{
|
||||
struct plugin *pl = SPA_CONTAINER_OF(plugin, struct plugin, plugin);
|
||||
struct busy_impl *impl;
|
||||
struct spa_json it[1];
|
||||
const char *val;
|
||||
char key[256];
|
||||
float wait_percent = 0.0f, cpu_percent = 0.0f;
|
||||
int len;
|
||||
|
||||
if (config != NULL) {
|
||||
if (spa_json_begin_object(&it[0], config, strlen(config)) <= 0) {
|
||||
spa_log_error(pl->log, "busy:config must be an object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) {
|
||||
if (spa_streq(key, "wait-percent")) {
|
||||
if (spa_json_parse_float(val, len, &wait_percent) <= 0) {
|
||||
spa_log_error(pl->log, "busy:wait-percent requires a number");
|
||||
return NULL;
|
||||
}
|
||||
} else if (spa_streq(key, "cpu-percent")) {
|
||||
if (spa_json_parse_float(val, len, &cpu_percent) <= 0) {
|
||||
spa_log_error(pl->log, "busy:cpu-percent requires a number");
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
spa_log_warn(pl->log, "busy: ignoring config key: '%s'", key);
|
||||
}
|
||||
}
|
||||
if (wait_percent <= 0.0f)
|
||||
wait_percent = 0.0f;
|
||||
if (cpu_percent <= 0.0f)
|
||||
cpu_percent = 0.0f;
|
||||
}
|
||||
|
||||
impl = calloc(1, sizeof(*impl));
|
||||
if (impl == NULL)
|
||||
return NULL;
|
||||
|
||||
impl->plugin = pl;
|
||||
impl->dsp = pl->dsp;
|
||||
impl->log = pl->log;
|
||||
impl->rate = SampleRate;
|
||||
impl->wait_scale = wait_percent * SPA_NSEC_PER_SEC / (100.0f * SampleRate);
|
||||
impl->cpu_scale = cpu_percent * SPA_NSEC_PER_SEC / (100.0f * SampleRate);
|
||||
spa_log_info(impl->log, "wait-percent:%f cpu-percent:%f", wait_percent, cpu_percent);
|
||||
|
||||
return impl;
|
||||
}
|
||||
|
||||
static void busy_run(void * Instance, unsigned long SampleCount)
|
||||
{
|
||||
struct busy_impl *impl = Instance;
|
||||
struct timespec ts;
|
||||
uint64_t busy_nsec;
|
||||
|
||||
if (impl->wait_scale > 0.0f) {
|
||||
busy_nsec = (uint64_t)(impl->wait_scale * SampleCount);
|
||||
ts.tv_sec = busy_nsec / SPA_NSEC_PER_SEC;
|
||||
ts.tv_nsec = busy_nsec % SPA_NSEC_PER_SEC;
|
||||
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
|
||||
}
|
||||
if (impl->cpu_scale > 0.0f) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
busy_nsec = SPA_TIMESPEC_TO_NSEC(&ts);
|
||||
busy_nsec += (uint64_t)(impl->cpu_scale * SampleCount);
|
||||
do {
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
} while ((uint64_t)SPA_TIMESPEC_TO_NSEC(&ts) < busy_nsec);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct spa_fga_descriptor busy_desc = {
|
||||
.name = "busy",
|
||||
.flags = SPA_FGA_DESCRIPTOR_SUPPORTS_NULL_DATA,
|
||||
|
||||
.n_ports = 0,
|
||||
.ports = NULL,
|
||||
|
||||
.instantiate = busy_instantiate,
|
||||
.connect_port = builtin_connect_port,
|
||||
.run = busy_run,
|
||||
.cleanup = builtin_cleanup,
|
||||
};
|
||||
|
||||
static const struct spa_fga_descriptor * builtin_descriptor(unsigned long Index)
|
||||
{
|
||||
switch(Index) {
|
||||
|
|
@ -3180,6 +3282,8 @@ static const struct spa_fga_descriptor * builtin_descriptor(unsigned long Index)
|
|||
return &zeroramp_desc;
|
||||
case 30:
|
||||
return &noisegate_desc;
|
||||
case 31:
|
||||
return &busy_desc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue