io: add offset for clock times

Add an offset to apply to the clock time before we can compare to the
segment values. This way we can keep the segment start independent of the
clock values and we only need to adjust the offset when paused. It's
like the base_time in GStreamer to calculate the running time.
This commit is contained in:
Wim Taymans 2019-08-28 10:28:06 +02:00
parent 2805713da3
commit 0a15e1f804
4 changed files with 31 additions and 19 deletions

@ -1 +1 @@
Subproject commit 796278b207e686403638d1c850ce01fa0a0fee48 Subproject commit a52ad27a169ffd6abb4090e1d77385bd879a1d43

View file

@ -136,20 +136,20 @@ struct spa_io_segment_video {
}; };
/** /**
* A segment converts a raw clock time to a segment (stream) position. * A segment converts a running time to a segment (stream) position.
* *
* The segment position is valid when the current clock position is between * The segment position is valid when the current running time is between
* start and start + duration. The position is then * start and start + duration. The position is then
* calculated as: * calculated as:
* *
* (start - clock.position) * rate + position; * (running time - start) * rate + position;
* *
* Support for looping is done by specifying a non-zero duration. When the * Support for looping is done by specifying the LOOPING flags with a
* clock reaches start + duration, duration is added to start and the * non-zero duration. When the running time reaches start + duration,
* loop repeats. * duration is added to start and the loop repeats.
* *
* Care has to be taken when the clock.duration extends past the * Care has to be taken when the running time + clock.duration extends
* start + duration from the segment; the user should correctly * past the start + duration from the segment; the user should correctly
* wrap around and partially repeat the loop in the current cycle. * wrap around and partially repeat the loop in the current cycle.
* *
* Extra information can be placed in the segment by setting the valid flags * Extra information can be placed in the segment by setting the valid flags
@ -162,15 +162,16 @@ struct spa_io_segment {
#define SPA_IO_SEGMENT_VALID_BAR (1<<1) #define SPA_IO_SEGMENT_VALID_BAR (1<<1)
#define SPA_IO_SEGMENT_VALID_VIDEO (1<<2) #define SPA_IO_SEGMENT_VALID_VIDEO (1<<2)
uint32_t valid; /**< indicates what fields are valid below */ uint32_t valid; /**< indicates what fields are valid below */
uint64_t start; /**< position against clock position when this uint64_t start; /**< value of running time when this
* info is active. Can be in the future for * info is active. Can be in the future for
* pending changes. It does not have to be in * pending changes. It does not have to be in
* exact multiples of the clock duration. */ * exact multiples of the clock duration. */
uint64_t duration; /**< duration when this info becomes invalid. If uint64_t duration; /**< duration when this info becomes invalid expressed
* the duration is 0, this segment extends to the * in running time. If the duration is 0, this
* next segment. If the segment becomes invalid and * segment extends to the next segment. If the
* the looping flag is set, the segment is repeats. */ * segment becomes invalid and the looping flag is
uint64_t position; /**< The position when the clock == start. */ * set, the segment repeats. */
uint64_t position; /**< The position when the running time == start. */
double rate; /**< overal rate of the graph, can be negative for double rate; /**< overal rate of the graph, can be negative for
* backwards time reporting. */ * backwards time reporting. */
@ -202,6 +203,11 @@ enum spa_io_position_state {
struct spa_io_position { struct spa_io_position {
struct spa_io_clock clock; /**< clock position of driver, always valid and struct spa_io_clock clock; /**< clock position of driver, always valid and
* read only */ * read only */
int64_t offset; /**< an offset to subtract from the clock position
* to get a running time. This is the time that
* the state has been in the RUNNING state and the
* time that should be used to compare the segment
* start values against. */
uint32_t state; /**< one of enum spa_io_position_state */ uint32_t state; /**< one of enum spa_io_position_state */
uint32_t n_segments; /**< number of segments */ uint32_t n_segments; /**< number of segments */

View file

@ -963,6 +963,7 @@ struct pw_node *pw_node_new(struct pw_core *core,
this->rt.activation->position.clock.rate = SPA_FRACTION(1, 48000); this->rt.activation->position.clock.rate = SPA_FRACTION(1, 48000);
this->rt.activation->position.clock.duration = DEFAULT_QUANTUM; this->rt.activation->position.clock.duration = DEFAULT_QUANTUM;
this->rt.activation->position.offset = INT64_MIN;
this->rt.activation->position.n_segments = 1; this->rt.activation->position.n_segments = 1;
this->rt.activation->position.segments[0].flags = 0; this->rt.activation->position.segments[0].flags = 0;
this->rt.activation->position.segments[0].valid = SPA_IO_SEGMENT_VALID_POSITION; this->rt.activation->position.segments[0].valid = SPA_IO_SEGMENT_VALID_POSITION;
@ -1174,6 +1175,9 @@ static void update_position(struct pw_node *node)
uint32_t seq1, seq2, change_mask; uint32_t seq1, seq2, change_mask;
enum spa_io_position_state state; enum spa_io_position_state state;
if (a->position.offset == INT64_MIN)
a->position.offset = a->position.clock.position;
seq1 = SEQ_READ(&a->pending.seq); seq1 = SEQ_READ(&a->pending.seq);
change_mask = a->pending.change_mask; change_mask = a->pending.change_mask;
state = a->pending.state; state = a->pending.state;
@ -1207,6 +1211,8 @@ static void update_position(struct pw_node *node)
seg->duration = segment.duration; seg->duration = segment.duration;
seg->position = segment.position; seg->position = segment.position;
seg->rate = segment.rate; seg->rate = segment.rate;
if (seg->start == 0)
seg->start = a->position.clock.position - a->position.offset;
} }
if (change_mask & PW_NODE_ACTIVATION_UPDATE_STATE) { if (change_mask & PW_NODE_ACTIVATION_UPDATE_STATE) {
switch (state) { switch (state) {
@ -1219,11 +1225,9 @@ static void update_position(struct pw_node *node)
break; break;
} }
} }
if (seg->start == 0)
seg->start = a->position.clock.position;
if (a->position.state == SPA_IO_POSITION_STATE_STOPPED) if (a->position.state == SPA_IO_POSITION_STATE_STOPPED)
seg->start += a->position.clock.duration; a->position.offset += a->position.clock.duration;
} }
static int node_ready(void *data, int status) static int node_ready(void *data, int status)

View file

@ -381,8 +381,10 @@ struct pw_node_activation {
#define PW_NODE_ACTIVATION_UPDATE_STATE (1<<0) #define PW_NODE_ACTIVATION_UPDATE_STATE (1<<0)
#define PW_NODE_ACTIVATION_UPDATE_SEGMENT (1<<1) #define PW_NODE_ACTIVATION_UPDATE_SEGMENT (1<<1)
#define PW_NODE_ACTIVATION_UPDATE_REPOSITION (1<<2) #define PW_NODE_ACTIVATION_UPDATE_REPOSITION (1<<2)
#define PW_NODE_ACTIVATION_UPDATE_FLUSH (1<<3) /* flush out current segments and immediately
* start the new one */
uint32_t change_mask; uint32_t change_mask;
enum spa_io_position_state state; enum spa_io_position_state state; /* when change_mask & PW_NODE_ACTIVATION_UPDATE_STATE */
struct spa_io_segment segment; /* update for the extra segment info struct spa_io_segment segment; /* update for the extra segment info
* fields. When REPOSITION update, the segment * fields. When REPOSITION update, the segment
* position field will contain the desired * position field will contain the desired