mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
pw-top: improve output
Show the node state in the S column Use the node state to show or hide info, this will only show info for active nodes. Do redraw updates when something important changes Update man page
This commit is contained in:
parent
f5f4be5109
commit
d247db8d26
2 changed files with 90 additions and 30 deletions
|
|
@ -27,13 +27,15 @@ a tree-like representation.
|
||||||
The columns presented are as follows:
|
The columns presented are as follows:
|
||||||
|
|
||||||
S
|
S
|
||||||
Measurement status.
|
Node status.
|
||||||
! representing inactive - no connections
|
E = ERROR
|
||||||
|
C = CREATING
|
||||||
Blank representing active
|
S = SUSPENDED
|
||||||
|
I = IDLE
|
||||||
|
R = RUNNING
|
||||||
|
|
||||||
ID
|
ID
|
||||||
The ID of the pipewire node/device, as found in *pw-dump*
|
The ID of the pipewire node/device, as found in *pw-dump* and *pw-cli*
|
||||||
|
|
||||||
QUANT
|
QUANT
|
||||||
The current quantum (for drivers) and the suggested quantum for follower
|
The current quantum (for drivers) and the suggested quantum for follower
|
||||||
|
|
@ -135,6 +137,8 @@ FORMAT
|
||||||
|
|
||||||
For raw audio formats, the layout is <sampleformat> <channels> <samplerate>.
|
For raw audio formats, the layout is <sampleformat> <channels> <samplerate>.
|
||||||
|
|
||||||
|
For IEC958 passthrough audio formats, the layout is IEC958 <codec> <samplerate>.
|
||||||
|
|
||||||
For DSD formats, the layout is <dsd-rate> <channels>.
|
For DSD formats, the layout is <dsd-rate> <channels>.
|
||||||
|
|
||||||
For Video formats, the layout is <pixelformat> <width>x<height>.
|
For Video formats, the layout is <pixelformat> <width>x<height>.
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,10 @@ struct measurement {
|
||||||
|
|
||||||
struct node {
|
struct node {
|
||||||
struct spa_list link;
|
struct spa_list link;
|
||||||
|
struct data *data;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
char name[MAX_NAME+1];
|
char name[MAX_NAME+1];
|
||||||
|
enum pw_node_state state;
|
||||||
struct measurement measurement;
|
struct measurement measurement;
|
||||||
struct driver info;
|
struct driver info;
|
||||||
struct node *driver;
|
struct node *driver;
|
||||||
|
|
@ -73,6 +75,7 @@ struct node {
|
||||||
char format[MAX_FORMAT+1];
|
char format[MAX_FORMAT+1];
|
||||||
struct pw_proxy *proxy;
|
struct pw_proxy *proxy;
|
||||||
struct spa_hook proxy_listener;
|
struct spa_hook proxy_listener;
|
||||||
|
unsigned int inactive:1;
|
||||||
struct spa_hook object_listener;
|
struct spa_hook object_listener;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -95,7 +98,7 @@ struct data {
|
||||||
int n_nodes;
|
int n_nodes;
|
||||||
struct spa_list node_list;
|
struct spa_list node_list;
|
||||||
uint32_t generation;
|
uint32_t generation;
|
||||||
unsigned have_data:1;
|
unsigned pending_refresh:1;
|
||||||
|
|
||||||
WINDOW *win;
|
WINDOW *win;
|
||||||
};
|
};
|
||||||
|
|
@ -160,12 +163,29 @@ static const struct pw_proxy_events proxy_events = {
|
||||||
.destroy = on_node_destroy,
|
.destroy = on_node_destroy,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void do_refresh(struct data *d);
|
||||||
|
|
||||||
|
static void node_info(void *data, const struct pw_node_info *info)
|
||||||
|
{
|
||||||
|
struct node *n = data;
|
||||||
|
|
||||||
|
if (n->state != info->state) {
|
||||||
|
n->state = info->state;
|
||||||
|
do_refresh(n->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void node_param(void *data, int seq,
|
static void node_param(void *data, int seq,
|
||||||
uint32_t id, uint32_t index, uint32_t next,
|
uint32_t id, uint32_t index, uint32_t next,
|
||||||
const struct spa_pod *param)
|
const struct spa_pod *param)
|
||||||
{
|
{
|
||||||
struct node *n = data;
|
struct node *n = data;
|
||||||
|
|
||||||
|
if (param == NULL) {
|
||||||
|
spa_zero(n->format);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case SPA_PARAM_Format:
|
case SPA_PARAM_Format:
|
||||||
{
|
{
|
||||||
|
|
@ -238,10 +258,13 @@ static void node_param(void *data, int seq,
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
|
do_refresh(n->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pw_node_events node_events = {
|
static const struct pw_node_events node_events = {
|
||||||
PW_VERSION_NODE,
|
PW_VERSION_NODE,
|
||||||
|
.info = node_info,
|
||||||
.param = node_param,
|
.param = node_param,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -256,6 +279,7 @@ static struct node *add_node(struct data *d, uint32_t id, const char *name)
|
||||||
strncpy(n->name, name, MAX_NAME);
|
strncpy(n->name, name, MAX_NAME);
|
||||||
else
|
else
|
||||||
snprintf(n->name, sizeof(n->name), "%u", id);
|
snprintf(n->name, sizeof(n->name), "%u", id);
|
||||||
|
n->data = d;
|
||||||
n->id = id;
|
n->id = id;
|
||||||
n->driver = n;
|
n->driver = n;
|
||||||
n->proxy = pw_registry_bind(d->registry, id, PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, 0);
|
n->proxy = pw_registry_bind(d->registry, id, PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, 0);
|
||||||
|
|
@ -272,6 +296,7 @@ static struct node *add_node(struct data *d, uint32_t id, const char *name)
|
||||||
}
|
}
|
||||||
spa_list_append(&d->node_list, &n->link);
|
spa_list_append(&d->node_list, &n->link);
|
||||||
d->n_nodes++;
|
d->n_nodes++;
|
||||||
|
d->pending_refresh = true;
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
@ -282,6 +307,7 @@ static void remove_node(struct data *d, struct node *n)
|
||||||
pw_proxy_destroy(n->proxy);
|
pw_proxy_destroy(n->proxy);
|
||||||
spa_list_remove(&n->link);
|
spa_list_remove(&n->link);
|
||||||
d->n_nodes--;
|
d->n_nodes--;
|
||||||
|
d->pending_refresh = true;
|
||||||
free(n);
|
free(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -346,7 +372,10 @@ static int process_follower_block(struct data *d, const struct spa_pod *pod, str
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
n->measurement = m;
|
n->measurement = m;
|
||||||
n->driver = point->driver;
|
if (n->driver != point->driver) {
|
||||||
|
n->driver = point->driver;
|
||||||
|
d->pending_refresh = true;
|
||||||
|
}
|
||||||
n->generation = d->generation;
|
n->generation = d->generation;
|
||||||
if (m.status != 3) {
|
if (m.status != 3) {
|
||||||
n->errors++;
|
n->errors++;
|
||||||
|
|
@ -356,9 +385,9 @@ static int process_follower_block(struct data *d, const struct spa_pod *pod, str
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *print_time(char *buf, size_t len, uint64_t val)
|
static const char *print_time(char *buf, bool active, size_t len, uint64_t val)
|
||||||
{
|
{
|
||||||
if (val == (uint64_t)-1)
|
if (val == (uint64_t)-1 || !active)
|
||||||
snprintf(buf, len, " --- ");
|
snprintf(buf, len, " --- ");
|
||||||
else if (val == (uint64_t)-2)
|
else if (val == (uint64_t)-2)
|
||||||
snprintf(buf, len, " +++ ");
|
snprintf(buf, len, " +++ ");
|
||||||
|
|
@ -371,9 +400,9 @@ static const char *print_time(char *buf, size_t len, uint64_t val)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *print_perc(char *buf, size_t len, uint64_t val, float quantum)
|
static const char *print_perc(char *buf, bool active, size_t len, uint64_t val, float quantum)
|
||||||
{
|
{
|
||||||
if (val == (uint64_t)-1) {
|
if (val == (uint64_t)-1 || !active) {
|
||||||
snprintf(buf, len, " --- ");
|
snprintf(buf, len, " --- ");
|
||||||
} else if (val == (uint64_t)-2) {
|
} else if (val == (uint64_t)-2) {
|
||||||
snprintf(buf, len, " +++ ");
|
snprintf(buf, len, " +++ ");
|
||||||
|
|
@ -384,6 +413,23 @@ static const char *print_perc(char *buf, size_t len, uint64_t val, float quantum
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *state_as_string(enum pw_node_state state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case PW_NODE_STATE_ERROR:
|
||||||
|
return "E";
|
||||||
|
case PW_NODE_STATE_CREATING:
|
||||||
|
return "C";
|
||||||
|
case PW_NODE_STATE_SUSPENDED:
|
||||||
|
return "S";
|
||||||
|
case PW_NODE_STATE_IDLE:
|
||||||
|
return "I";
|
||||||
|
case PW_NODE_STATE_RUNNING:
|
||||||
|
return "R";
|
||||||
|
}
|
||||||
|
return "!";
|
||||||
|
}
|
||||||
|
|
||||||
static void print_node(struct data *d, struct driver *i, struct node *n, int y)
|
static void print_node(struct data *d, struct driver *i, struct node *n, int y)
|
||||||
{
|
{
|
||||||
char buf1[64];
|
char buf1[64];
|
||||||
|
|
@ -393,8 +439,13 @@ static void print_node(struct data *d, struct driver *i, struct node *n, int y)
|
||||||
uint64_t waiting, busy;
|
uint64_t waiting, busy;
|
||||||
float quantum;
|
float quantum;
|
||||||
struct spa_fraction frac;
|
struct spa_fraction frac;
|
||||||
|
bool active;
|
||||||
|
|
||||||
if (n->driver == n)
|
active = n->state == PW_NODE_STATE_RUNNING || n->state == PW_NODE_STATE_IDLE;
|
||||||
|
|
||||||
|
if (!active)
|
||||||
|
frac = SPA_FRACTION(0, 0);
|
||||||
|
else if (n->driver == n)
|
||||||
frac = SPA_FRACTION((uint32_t)(i->clock.duration * i->clock.rate.num), i->clock.rate.denom);
|
frac = SPA_FRACTION((uint32_t)(i->clock.duration * i->clock.rate.num), i->clock.rate.denom);
|
||||||
else
|
else
|
||||||
frac = SPA_FRACTION(n->measurement.latency.num, n->measurement.latency.denom);
|
frac = SPA_FRACTION(n->measurement.latency.num, n->measurement.latency.denom);
|
||||||
|
|
@ -419,19 +470,28 @@ static void print_node(struct data *d, struct driver *i, struct node *n, int y)
|
||||||
busy = -1;
|
busy = -1;
|
||||||
|
|
||||||
mvwprintw(d->win, y, 0, "%s %4.1u %6.1u %6.1u %s %s %s %s %3.1u %16.16s %s%s",
|
mvwprintw(d->win, y, 0, "%s %4.1u %6.1u %6.1u %s %s %s %s %3.1u %16.16s %s%s",
|
||||||
n->measurement.status != 3 ? "!" : " ",
|
state_as_string(n->state),
|
||||||
n->id,
|
n->id,
|
||||||
frac.num, frac.denom,
|
frac.num, frac.denom,
|
||||||
print_time(buf1, 64, waiting),
|
print_time(buf1, active, 64, waiting),
|
||||||
print_time(buf2, 64, busy),
|
print_time(buf2, active, 64, busy),
|
||||||
print_perc(buf3, 64, waiting, quantum),
|
print_perc(buf3, active, 64, waiting, quantum),
|
||||||
print_perc(buf4, 64, busy, quantum),
|
print_perc(buf4, active, 64, busy, quantum),
|
||||||
i->xrun_count + n->errors,
|
i->xrun_count + n->errors,
|
||||||
n->measurement.status != 3 ? "" : n->format,
|
active ? n->format : "",
|
||||||
n->driver == n ? "" : " + ",
|
n->driver == n ? "" : " + ",
|
||||||
n->name);
|
n->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void clear_node(struct node *n)
|
||||||
|
{
|
||||||
|
n->driver = n;
|
||||||
|
spa_zero(n->measurement);
|
||||||
|
spa_zero(n->info);
|
||||||
|
n->errors = 0;
|
||||||
|
n->last_error_status = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void do_refresh(struct data *d)
|
static void do_refresh(struct data *d)
|
||||||
{
|
{
|
||||||
struct node *n, *t, *f;
|
struct node *n, *t, *f;
|
||||||
|
|
@ -452,14 +512,8 @@ static void do_refresh(struct data *d)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
spa_list_for_each(f, &d->node_list, link) {
|
spa_list_for_each(f, &d->node_list, link) {
|
||||||
if (d->generation > f->generation + 2) {
|
if (d->generation > f->generation + 22)
|
||||||
f->driver = f;
|
clear_node(f);
|
||||||
spa_zero(f->measurement);
|
|
||||||
spa_zero(f->info);
|
|
||||||
spa_zero(f->format);
|
|
||||||
f->errors = 0;
|
|
||||||
f->last_error_status = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f->driver != n || f == n)
|
if (f->driver != n || f == n)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -476,6 +530,7 @@ static void do_refresh(struct data *d)
|
||||||
wclrtobot(d->win);
|
wclrtobot(d->win);
|
||||||
|
|
||||||
wrefresh(d->win);
|
wrefresh(d->win);
|
||||||
|
d->pending_refresh = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_timeout(void *data, uint64_t expirations)
|
static void do_timeout(void *data, uint64_t expirations)
|
||||||
|
|
@ -521,10 +576,8 @@ static void profiler_profile(void *data, const struct spa_pod *pod)
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!d->have_data) {
|
if (d->pending_refresh)
|
||||||
d->have_data = true;
|
|
||||||
do_refresh(d);
|
do_refresh(d);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pw_profiler_events profiler_events = {
|
static const struct pw_profiler_events profiler_events = {
|
||||||
|
|
@ -563,7 +616,8 @@ static void registry_event_global(void *data, uint32_t id,
|
||||||
d->profiler = proxy;
|
d->profiler = proxy;
|
||||||
pw_proxy_add_object_listener(proxy, &d->profiler_listener, &profiler_events, d);
|
pw_proxy_add_object_listener(proxy, &d->profiler_listener, &profiler_events, d);
|
||||||
}
|
}
|
||||||
|
if (d->pending_refresh)
|
||||||
|
do_refresh(d);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error_proxy:
|
error_proxy:
|
||||||
|
|
@ -577,6 +631,8 @@ static void registry_event_global_remove(void *data, uint32_t id)
|
||||||
struct node *n;
|
struct node *n;
|
||||||
if ((n = find_node(d, id)) != NULL)
|
if ((n = find_node(d, id)) != NULL)
|
||||||
remove_node(d, n);
|
remove_node(d, n);
|
||||||
|
if (d->pending_refresh)
|
||||||
|
do_refresh(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pw_registry_events registry_events = {
|
static const struct pw_registry_events registry_events = {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue