From d3c203b744c883569ac691f8dd2601c021d04b26 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 17 Jul 2018 17:37:55 +0200 Subject: [PATCH] spa: use clock info Use the port clock io area to get timing info and use this as the time in the graph when we wake up. --- spa/include/spa/param/io.h | 9 ++++++++ spa/plugins/alsa/alsa-sink.c | 40 +++++++++++++++++++++++++++++++++- spa/plugins/alsa/alsa-source.c | 24 ++++++++++++++++++++ spa/plugins/alsa/alsa-utils.h | 3 +++ spa/plugins/v4l2/v4l2-source.c | 32 ++++++++++++++++++++++++--- spa/plugins/v4l2/v4l2-utils.c | 14 ++++++------ src/examples/export-source.c | 2 +- src/pipewire/node.c | 15 ++++++++++--- src/pipewire/port.c | 8 +++++++ src/pipewire/private.h | 2 ++ 10 files changed, 134 insertions(+), 15 deletions(-) diff --git a/spa/include/spa/param/io.h b/spa/include/spa/param/io.h index 4eeafea3b..22585c0d6 100644 --- a/spa/include/spa/param/io.h +++ b/spa/include/spa/param/io.h @@ -56,6 +56,11 @@ extern "C" { #define SPA_TYPE_PARAM_IO__Prop SPA_TYPE_PARAM_IO_BASE "Prop" #define SPA_TYPE_PARAM_IO_PROP_BASE SPA_TYPE_PARAM_IO__Prop ":" +/** enumerate clock io areas */ +#define SPA_TYPE_PARAM_ID_IO__Clock SPA_TYPE_PARAM_ID_IO_BASE "Clock" +/* an io area to exchange clock information */ +#define SPA_TYPE_PARAM_IO__Clock SPA_TYPE_PARAM_IO_BASE "Clock" + struct spa_type_param_io { uint32_t id; /**< id to configure the io area */ uint32_t size; /**< size of io area */ @@ -66,6 +71,8 @@ struct spa_type_param_io { uint32_t idPropsIn; /**< id to enumerate input properties io */ uint32_t idPropsOut; /**< id to enumerate output properties io */ uint32_t Prop; /**< object type of property area */ + uint32_t idClock; /**< id to enumerate clock io */ + uint32_t Clock; /**< object type of clock io area */ }; static inline void @@ -82,6 +89,8 @@ spa_type_param_io_map(struct spa_type_map *map, type->idPropsIn = spa_type_map_get_id(map, SPA_TYPE_PARAM_ID_IO_PROPS__In); type->idPropsOut = spa_type_map_get_id(map, SPA_TYPE_PARAM_ID_IO_PROPS__Out); type->Prop = spa_type_map_get_id(map, SPA_TYPE_PARAM_IO__Prop); + type->idClock = spa_type_map_get_id(map, SPA_TYPE_PARAM_ID_IO__Clock); + type->Clock = spa_type_map_get_id(map, SPA_TYPE_PARAM_IO__Clock); } } diff --git a/spa/plugins/alsa/alsa-sink.c b/spa/plugins/alsa/alsa-sink.c index efb6387c6..78602a457 100644 --- a/spa/plugins/alsa/alsa-sink.c +++ b/spa/plugins/alsa/alsa-sink.c @@ -317,7 +317,9 @@ impl_node_port_enum_params(struct spa_node *node, uint32_t list[] = { t->param.idEnumFormat, t->param.idFormat, t->param.idBuffers, - t->param.idMeta }; + t->param.idMeta, + t->param_io.idBuffers, + t->param_io.idClock, }; if (*index < SPA_N_ELEMENTS(list)) param = spa_pod_builder_object(&b, id, t->param.List, @@ -375,6 +377,42 @@ impl_node_port_enum_params(struct spa_node *node, return 0; } } + else if (id == t->param_io.idBuffers) { + switch (*index) { + case 0: + param = spa_pod_builder_object(&b, + id, t->param_io.Buffers, + ":", t->param_io.id, "I", t->io.Buffers, + ":", t->param_io.size, "i", sizeof(struct spa_io_buffers)); + break; + default: + return 0; + } + } + else if (id == t->param_io.idControl) { + switch (*index) { + case 0: + param = spa_pod_builder_object(&b, + id, t->param_io.Control, + ":", t->param_io.id, "I", t->io.ControlRange, + ":", t->param_io.size, "i", sizeof(struct spa_io_control_range)); + break; + default: + return 0; + } + } + else if (id == t->param_io.idClock) { + switch (*index) { + case 0: + param = spa_pod_builder_object(&b, + id, t->param_io.Clock, + ":", t->param_io.id, "I", t->io.Clock, + ":", t->param_io.size, "i", sizeof(struct spa_io_clock)); + break; + default: + return 0; + } + } else return -ENOENT; diff --git a/spa/plugins/alsa/alsa-source.c b/spa/plugins/alsa/alsa-source.c index c4961980c..9dd922000 100644 --- a/spa/plugins/alsa/alsa-source.c +++ b/spa/plugins/alsa/alsa-source.c @@ -401,6 +401,30 @@ impl_node_port_enum_params(struct spa_node *node, return 0; } } + else if (id == t->param_io.idBuffers) { + switch (*index) { + case 0: + param = spa_pod_builder_object(&b, + id, t->param_io.Buffers, + ":", t->param_io.id, "I", t->io.Buffers, + ":", t->param_io.size, "i", sizeof(struct spa_io_buffers)); + break; + default: + return 0; + } + } + else if (id == t->param_io.idClock) { + switch (*index) { + case 0: + param = spa_pod_builder_object(&b, + id, t->param_io.Clock, + ":", t->param_io.id, "I", t->io.Clock, + ":", t->param_io.size, "i", sizeof(struct spa_io_clock)); + break; + default: + return 0; + } + } else return -ENOENT; diff --git a/spa/plugins/alsa/alsa-utils.h b/spa/plugins/alsa/alsa-utils.h index 79ebe6bdf..97cc92d75 100644 --- a/spa/plugins/alsa/alsa-utils.h +++ b/spa/plugins/alsa/alsa-utils.h @@ -36,6 +36,7 @@ extern "C" { #include #include #include +#include #include #include @@ -82,6 +83,7 @@ struct type { struct spa_type_format_audio format_audio; struct spa_type_param_buffers param_buffers; struct spa_type_param_meta param_meta; + struct spa_type_param_io param_io; }; static inline void init_type(struct type *type, struct spa_type_map *map) @@ -108,6 +110,7 @@ static inline void init_type(struct type *type, struct spa_type_map *map) spa_type_format_audio_map(map, &type->format_audio); spa_type_param_buffers_map(map, &type->param_buffers); spa_type_param_meta_map(map, &type->param_meta); + spa_type_param_io_map(map, &type->param_io); } struct state { diff --git a/spa/plugins/v4l2/v4l2-source.c b/spa/plugins/v4l2/v4l2-source.c index cce6697e4..5799541a2 100644 --- a/spa/plugins/v4l2/v4l2-source.c +++ b/spa/plugins/v4l2/v4l2-source.c @@ -158,6 +158,7 @@ struct port { bool have_format; struct spa_video_info current_format; + struct spa_fraction rate; int fd; bool opened; @@ -178,9 +179,7 @@ struct port { struct spa_port_info info; struct spa_io_buffers *io; - - int64_t last_ticks; - int64_t last_monotonic; + struct spa_io_clock *clock; }; struct impl { @@ -562,6 +561,30 @@ static int impl_node_port_enum_params(struct spa_node *node, else if (id == t->param_io.idPropsIn) { return spa_v4l2_enum_controls(this, index, filter, result, builder); } + else if (id == t->param_io.idBuffers) { + switch (*index) { + case 0: + param = spa_pod_builder_object(&b, + id, t->param_io.Buffers, + ":", t->param_io.id, "I", t->io.Buffers, + ":", t->param_io.size, "i", sizeof(struct spa_io_buffers)); + break; + default: + return 0; + } + } + else if (id == t->param_io.idClock) { + switch (*index) { + case 0: + param = spa_pod_builder_object(&b, + id, t->param_io.Clock, + ":", t->param_io.id, "I", t->io.Clock, + ":", t->param_io.size, "i", sizeof(struct spa_io_clock)); + break; + default: + return 0; + } + } else return -ENOENT; @@ -767,6 +790,9 @@ static int impl_node_port_set_io(struct spa_node *node, if (id == t->io.Buffers) { port->io = data; } + else if (id == t->io.Clock) { + port->clock = data; + } else if ((control = find_control(port, id))) { if (data && size >= sizeof(struct spa_pod_double)) control->io = &SPA_POD_VALUE(struct spa_pod_double, data); diff --git a/spa/plugins/v4l2/v4l2-utils.c b/spa/plugins/v4l2/v4l2-utils.c index bf23ce581..74106bb06 100644 --- a/spa/plugins/v4l2/v4l2-utils.c +++ b/spa/plugins/v4l2/v4l2-utils.c @@ -911,6 +911,7 @@ static int spa_v4l2_set_format(struct impl *this, struct spa_video_info *format, SPA_PORT_INFO_FLAG_PHYSICAL | SPA_PORT_INFO_FLAG_TERMINAL; port->info.rate = streamparm.parm.capture.timeperframe.denominator; + port->rate = *framerate; return 0; } @@ -1156,14 +1157,13 @@ static int mmap_read(struct impl *this) if (xioctl(port->fd, VIDIOC_DQBUF, &buf) < 0) return -errno; - port->last_ticks = (int64_t) buf.timestamp.tv_sec * SPA_USEC_PER_SEC + - (uint64_t) buf.timestamp.tv_usec; - pts = port->last_ticks * 1000; + pts = SPA_TIMEVAL_TO_TIME(&buf.timestamp); - if (buf.flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) - port->last_monotonic = pts; - else - port->last_monotonic = SPA_TIME_INVALID; + if (port->clock) { + port->clock->nsec = pts; + port->clock->rate = port->rate; + port->clock->position = buf.sequence; + } b = &port->buffers[buf.index]; if (b->h) { diff --git a/src/examples/export-source.c b/src/examples/export-source.c index 88e473ed5..f49cc0a4b 100644 --- a/src/examples/export-source.c +++ b/src/examples/export-source.c @@ -33,7 +33,7 @@ #define M_PI_M2 ( M_PI + M_PI ) -#define BUFFER_SAMPLES 48 +#define BUFFER_SAMPLES 128 struct type { uint32_t prop_volume; diff --git a/src/pipewire/node.c b/src/pipewire/node.c index 796757a8e..65a5b8057 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -629,11 +629,20 @@ static void node_process(void *data, int status) struct pw_driver_quantum *q; q = node->rt.quantum; - q->position = impl->next_position; + if (node->rt.clock) { + q->nsec = node->rt.clock->nsec; + q->rate = node->rt.clock->rate; + q->position = node->rt.clock->position; + } + else { + clock_gettime(CLOCK_MONOTONIC, &ts); + q->nsec = SPA_TIMESPEC_TO_TIME(&ts); + q->position = impl->next_position; + } impl->next_position += q->size; - clock_gettime(CLOCK_MONOTONIC, &ts); - q->nsec = ts.tv_sec * SPA_NSEC_PER_SEC + ts.tv_nsec; + pw_log_trace("node %p: run %"PRIu64" %d %d", node, + q->nsec, q->position, q->size); spa_graph_run(node->rt.driver); } diff --git a/src/pipewire/port.c b/src/pipewire/port.c index 19b690fa5..c56df0946 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -479,6 +479,14 @@ int pw_port_add(struct pw_port *port, struct pw_node *node) t->io.Buffers, &port->rt.io, sizeof(port->rt.io)); + if (spa_node_port_set_io(node->node, + port->direction, port_id, + t->io.Clock, + &port->rt.clock, sizeof(port->rt.clock)) >= 0) { + node->rt.clock = &port->rt.clock; + pw_log_debug("port %p: set node clock %p", port, node->rt.clock); + } + if (node->global) pw_port_register(port, node->global->owner, node->global, pw_properties_copy(port->properties)); diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 51e90d41c..3fd1607d5 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -290,6 +290,7 @@ struct pw_node { struct pw_loop *data_loop; /**< the data loop for this node */ struct { + struct spa_io_clock *clock; /**< io area of the clock or NULL */ struct pw_driver_quantum *quantum; struct spa_graph *driver; struct spa_graph_node root; @@ -355,6 +356,7 @@ struct pw_port { struct { struct spa_io_buffers io; /**< io area of the port */ + struct spa_io_clock clock; /**< io area of the clock */ struct spa_graph_port port; /**< this graph port, linked to mix_port */ struct spa_graph_port mix_port; /**< port from the mixer */ struct spa_graph_node mix_node; /**< mixer node */