mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	jack: implement transport support
This commit is contained in:
		
							parent
							
								
									42f144e097
								
							
						
					
					
						commit
						f8c3126b52
					
				
					 1 changed files with 281 additions and 75 deletions
				
			
		| 
						 | 
				
			
			@ -261,11 +261,12 @@ struct client {
 | 
			
		|||
	void *xrun_arg;
 | 
			
		||||
	JackSyncCallback sync_callback;
 | 
			
		||||
	void *sync_arg;
 | 
			
		||||
	unsigned int sync_emit:1;
 | 
			
		||||
	JackTimebaseCallback timebase_callback;
 | 
			
		||||
	void *timebase_arg;
 | 
			
		||||
	unsigned int timebase_emit:1;
 | 
			
		||||
 | 
			
		||||
	struct spa_io_position *position;
 | 
			
		||||
	double rate_diff;
 | 
			
		||||
	uint32_t sample_rate;
 | 
			
		||||
	uint32_t buffer_size;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -285,10 +286,8 @@ struct client {
 | 
			
		|||
	struct pw_node_activation *activation;
 | 
			
		||||
	uint32_t xrun_count;
 | 
			
		||||
 | 
			
		||||
	bool started;
 | 
			
		||||
	int status;
 | 
			
		||||
	unsigned int started:1;
 | 
			
		||||
 | 
			
		||||
	jack_position_t jack_position;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -670,11 +669,126 @@ static void process_tee(struct client *c)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void debug_position(struct client *c, jack_position_t *p)
 | 
			
		||||
{
 | 
			
		||||
	pw_log_trace("usecs:       %lu", p->usecs);
 | 
			
		||||
	pw_log_trace("frame_rate:  %u", p->frame_rate);
 | 
			
		||||
	pw_log_trace("frame:       %u", p->frame);
 | 
			
		||||
	pw_log_trace("valid:       %08x", p->valid);
 | 
			
		||||
 | 
			
		||||
	if (p->valid & JackPositionBBT) {
 | 
			
		||||
		pw_log_trace("BBT");
 | 
			
		||||
		pw_log_trace(" bar:              %u", p->bar);
 | 
			
		||||
		pw_log_trace(" beat:             %u", p->beat);
 | 
			
		||||
		pw_log_trace(" tick:             %u", p->tick);
 | 
			
		||||
		pw_log_trace(" bar_start_tick:   %f", p->bar_start_tick);
 | 
			
		||||
		pw_log_trace(" beats_per_bar:    %f", p->beats_per_bar);
 | 
			
		||||
		pw_log_trace(" beat_type:        %f", p->beat_type);
 | 
			
		||||
		pw_log_trace(" ticks_per_beat:   %f", p->ticks_per_beat);
 | 
			
		||||
		pw_log_trace(" beats_per_minute: %f", p->beats_per_minute);
 | 
			
		||||
	}
 | 
			
		||||
	if (p->valid & JackPositionTimecode) {
 | 
			
		||||
		pw_log_trace("Timecode:");
 | 
			
		||||
		pw_log_trace(" frame_time:       %f", p->frame_time);
 | 
			
		||||
		pw_log_trace(" next_time:        %f", p->next_time);
 | 
			
		||||
	}
 | 
			
		||||
	if (p->valid & JackBBTFrameOffset) {
 | 
			
		||||
		pw_log_trace("BBTFrameOffset:");
 | 
			
		||||
		pw_log_trace(" bbt_offset:       %u", p->bbt_offset);
 | 
			
		||||
	}
 | 
			
		||||
	if (p->valid & JackAudioVideoRatio) {
 | 
			
		||||
		pw_log_trace("AudioVideoRatio:");
 | 
			
		||||
		pw_log_trace(" audio_frames_per_video_frame: %f", p->audio_frames_per_video_frame);
 | 
			
		||||
	}
 | 
			
		||||
	if (p->valid & JackVideoFrameOffset) {
 | 
			
		||||
		pw_log_trace("JackVideoFrameOffset:");
 | 
			
		||||
		pw_log_trace(" video_offset:     %u", p->video_offset);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void jack_to_position(jack_position_t *s, struct spa_io_position *d)
 | 
			
		||||
{
 | 
			
		||||
	d->valid = 0;
 | 
			
		||||
	if (s->valid & JackPositionBBT) {
 | 
			
		||||
		SPA_FLAG_SET(d->valid, SPA_IO_POSITION_VALID_BAR);
 | 
			
		||||
 | 
			
		||||
		if (s->valid & JackBBTFrameOffset)
 | 
			
		||||
			d->bar.offset = s->bbt_offset;
 | 
			
		||||
		else
 | 
			
		||||
			d->bar.offset = 0;
 | 
			
		||||
		d->bar.signature_num = s->beats_per_bar;
 | 
			
		||||
		d->bar.signature_denom = s->beat_type;
 | 
			
		||||
		d->bar.bpm = s->beats_per_minute;
 | 
			
		||||
		d->bar.beat = (s->bar - 1) * s->beats_per_bar + (s->beat - 1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void position_to_jack(struct spa_io_position *s, jack_position_t *d, jack_transport_state_t *state)
 | 
			
		||||
{
 | 
			
		||||
	switch (s->state) {
 | 
			
		||||
	default:
 | 
			
		||||
	case SPA_IO_POSITION_STATE_STOPPED:
 | 
			
		||||
		*state = JackTransportStopped;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPA_IO_POSITION_STATE_STARTING:
 | 
			
		||||
		*state = JackTransportStarting;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPA_IO_POSITION_STATE_RUNNING:
 | 
			
		||||
		*state = JackTransportRolling;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPA_IO_POSITION_STATE_LOOPING:
 | 
			
		||||
		*state = JackTransportLooping;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	d->unique_1++;
 | 
			
		||||
	d->usecs = s->clock.nsec / SPA_NSEC_PER_USEC;
 | 
			
		||||
	d->frame_rate = s->clock.rate.denom;
 | 
			
		||||
 | 
			
		||||
	if (s->clock.position >= s->clock_start &&
 | 
			
		||||
	    (s->clock_duration == 0 || s->clock.position < s->clock_start + s->clock_duration))
 | 
			
		||||
		d->frame = (s->clock.position - s->clock_start) * s->rate + s->position;
 | 
			
		||||
	else
 | 
			
		||||
		d->frame = s->position;
 | 
			
		||||
 | 
			
		||||
	d->valid = 0;
 | 
			
		||||
 | 
			
		||||
	if (s->valid & SPA_IO_POSITION_VALID_BAR) {
 | 
			
		||||
		double min;
 | 
			
		||||
		long abs_tick, abs_beat;
 | 
			
		||||
 | 
			
		||||
		d->valid |= JackPositionBBT;
 | 
			
		||||
 | 
			
		||||
		d->bbt_offset = s->bar.offset;
 | 
			
		||||
		if (s->bar.offset)
 | 
			
		||||
			d->valid |= JackBBTFrameOffset;
 | 
			
		||||
 | 
			
		||||
		d->beats_per_bar = s->bar.signature_num;
 | 
			
		||||
		d->beat_type = s->bar.signature_denom;
 | 
			
		||||
		d->ticks_per_beat = 1920.0f;
 | 
			
		||||
		d->beats_per_minute = s->bar.bpm;
 | 
			
		||||
 | 
			
		||||
		min = d->frame / ((double) d->frame_rate * 60.0);
 | 
			
		||||
                abs_tick = min * d->beats_per_minute * d->ticks_per_beat;
 | 
			
		||||
		abs_beat = s->bar.beat;
 | 
			
		||||
 | 
			
		||||
		d->bar = abs_beat / d->beats_per_bar;
 | 
			
		||||
		d->beat = abs_beat - (d->bar * d->beats_per_bar) + 1;
 | 
			
		||||
		d->tick = abs_tick - (abs_beat * d->ticks_per_beat);
 | 
			
		||||
		d->bar_start_tick = d->bar * d->beats_per_bar *
 | 
			
		||||
			d->ticks_per_beat;
 | 
			
		||||
		d->bar++;
 | 
			
		||||
	}
 | 
			
		||||
	d->unique_2 = d->unique_1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_rtsocket_condition(void *data, int fd, uint32_t mask)
 | 
			
		||||
{
 | 
			
		||||
	struct client *c = data;
 | 
			
		||||
	struct timespec ts;
 | 
			
		||||
	jack_position_t jack_position;
 | 
			
		||||
	jack_transport_state_t jack_state;
 | 
			
		||||
 | 
			
		||||
	if (mask & (SPA_IO_ERR | SPA_IO_HUP)) {
 | 
			
		||||
		pw_log_warn(NAME" %p: got error", c);
 | 
			
		||||
| 
						 | 
				
			
			@ -683,42 +797,26 @@ on_rtsocket_condition(void *data, int fd, uint32_t mask)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & SPA_IO_IN) {
 | 
			
		||||
		uint64_t cmd, nsec, frame;
 | 
			
		||||
		int64_t delay;
 | 
			
		||||
		uint64_t cmd, nsec;
 | 
			
		||||
		uint32_t buffer_size, sample_rate;
 | 
			
		||||
		struct link *l;
 | 
			
		||||
		struct spa_io_position *pos = c->position;
 | 
			
		||||
 | 
			
		||||
		if (read(fd, &cmd, sizeof(cmd)) != sizeof(cmd))
 | 
			
		||||
			pw_log_warn(NAME" %p: read failed %m", c);
 | 
			
		||||
		if (cmd > 1)
 | 
			
		||||
			pw_log_warn(NAME" %p: missed %"PRIu64" wakeups", c, cmd - 1);
 | 
			
		||||
 | 
			
		||||
		if (c->position) {
 | 
			
		||||
			struct spa_io_position *pos = c->position;
 | 
			
		||||
		if (pos == NULL) {
 | 
			
		||||
			pw_log_error(NAME" %p: missing position", c);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
			buffer_size = pos->size;
 | 
			
		||||
			if (pos->clock.rate.num != 0 && pos->clock.rate.denom != 0)
 | 
			
		||||
				sample_rate = pos->clock.rate.denom / pos->clock.rate.num;
 | 
			
		||||
			else
 | 
			
		||||
				sample_rate = c->sample_rate;
 | 
			
		||||
			c->rate_diff = pos->clock.rate_diff;
 | 
			
		||||
			frame = pos->clock.position;
 | 
			
		||||
			delay = pos->clock.delay;
 | 
			
		||||
		nsec = pos->clock.nsec;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			buffer_size = DEFAULT_BUFFER_SIZE;
 | 
			
		||||
			sample_rate = DEFAULT_SAMPLE_RATE;
 | 
			
		||||
			c->rate_diff = 1.0;
 | 
			
		||||
			frame = c->jack_position.frame + buffer_size;
 | 
			
		||||
			delay = 0;
 | 
			
		||||
			clock_gettime(CLOCK_MONOTONIC, &ts);
 | 
			
		||||
			nsec = SPA_TIMESPEC_TO_NSEC(&ts);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c->activation->status = AWAKE;
 | 
			
		||||
		c->activation->awake_time = nsec;
 | 
			
		||||
 | 
			
		||||
		buffer_size = pos->clock.duration;
 | 
			
		||||
		if (buffer_size != c->buffer_size) {
 | 
			
		||||
			pw_log_info(NAME" %p: buffersize %d", c, buffer_size);
 | 
			
		||||
			c->buffer_size = buffer_size;
 | 
			
		||||
| 
						 | 
				
			
			@ -726,6 +824,7 @@ on_rtsocket_condition(void *data, int fd, uint32_t mask)
 | 
			
		|||
				c->bufsize_callback(c->buffer_size, c->bufsize_arg);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sample_rate = pos->clock.rate.denom;
 | 
			
		||||
		if (sample_rate != c->sample_rate) {
 | 
			
		||||
			pw_log_info(NAME" %p: sample_rate %d", c, sample_rate);
 | 
			
		||||
			c->sample_rate = sample_rate;
 | 
			
		||||
| 
						 | 
				
			
			@ -733,16 +832,12 @@ on_rtsocket_condition(void *data, int fd, uint32_t mask)
 | 
			
		|||
				c->srate_callback(c->sample_rate, c->srate_arg);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c->jack_position.unique_1++;
 | 
			
		||||
		c->jack_position.usecs = nsec / SPA_NSEC_PER_USEC;
 | 
			
		||||
		c->jack_position.frame_rate = sample_rate;
 | 
			
		||||
		c->jack_position.frame = frame;
 | 
			
		||||
		c->jack_position.valid = 0;
 | 
			
		||||
		c->jack_position.unique_2 = c->jack_position.unique_1;
 | 
			
		||||
		position_to_jack(pos, &jack_position, &jack_state);
 | 
			
		||||
 | 
			
		||||
		if (c->sync_callback) {
 | 
			
		||||
			c->sync_callback(JackTransportRolling,
 | 
			
		||||
					 &c->jack_position, c->sync_arg);
 | 
			
		||||
		if (c->sync_callback && c->sync_emit) {
 | 
			
		||||
			c->sync_callback(jack_state,
 | 
			
		||||
					 &jack_position, c->sync_arg);
 | 
			
		||||
			c->sync_emit = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (c->driver_activation) {
 | 
			
		||||
| 
						 | 
				
			
			@ -753,20 +848,24 @@ on_rtsocket_condition(void *data, int fd, uint32_t mask)
 | 
			
		|||
			c->xrun_count = a->xrun_count;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pw_log_trace(NAME" %p: do process %"PRIu64" %d %d %d %"PRIi64" %f %p", c,
 | 
			
		||||
		pw_log_trace(NAME" %p: do process %"PRIu64" %d %d %d %"PRIi64" %f", c,
 | 
			
		||||
				nsec, c->buffer_size, c->sample_rate,
 | 
			
		||||
				c->jack_position.frame, delay, c->rate_diff,
 | 
			
		||||
				c->position);
 | 
			
		||||
				jack_position.frame, pos->clock.delay, pos->clock.rate_diff);
 | 
			
		||||
 | 
			
		||||
		if (c->process_callback)
 | 
			
		||||
			c->process_callback(c->buffer_size, c->process_arg);
 | 
			
		||||
 | 
			
		||||
		if (c->timebase_callback) {
 | 
			
		||||
			c->timebase_callback(JackTransportRolling,
 | 
			
		||||
			c->timebase_callback(jack_state,
 | 
			
		||||
					     buffer_size,
 | 
			
		||||
					     &c->jack_position,
 | 
			
		||||
					     false,
 | 
			
		||||
					     &jack_position,
 | 
			
		||||
					     c->timebase_emit,
 | 
			
		||||
					     c->timebase_arg);
 | 
			
		||||
 | 
			
		||||
			c->timebase_emit = false;
 | 
			
		||||
 | 
			
		||||
			debug_position(c, &jack_position);
 | 
			
		||||
			jack_to_position(&jack_position, pos);
 | 
			
		||||
		}
 | 
			
		||||
		process_tee(c);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1695,7 +1794,7 @@ jack_client_t * jack_client_open (const char *client_name,
 | 
			
		|||
	struct client *client;
 | 
			
		||||
	bool busy = true;
 | 
			
		||||
	struct spa_dict props;
 | 
			
		||||
	struct spa_dict_item items[5];
 | 
			
		||||
	struct spa_dict_item items[6];
 | 
			
		||||
	const struct spa_support *support;
 | 
			
		||||
	uint32_t n_support;
 | 
			
		||||
	const char *str;
 | 
			
		||||
| 
						 | 
				
			
			@ -1802,6 +1901,7 @@ jack_client_t * jack_client_open (const char *client_name,
 | 
			
		|||
	if ((str = getenv("PIPEWIRE_LATENCY")) == NULL)
 | 
			
		||||
		str = DEFAULT_LATENCY;
 | 
			
		||||
	items[props.n_items++] = SPA_DICT_ITEM_INIT(PW_KEY_NODE_LATENCY, str);
 | 
			
		||||
	items[props.n_items++] = SPA_DICT_ITEM_INIT(PW_KEY_NODE_ALWAYS_PROCESS, "1");
 | 
			
		||||
 | 
			
		||||
	client->node_proxy = pw_core_proxy_create_object(client->core_proxy,
 | 
			
		||||
				"client-node",
 | 
			
		||||
| 
						 | 
				
			
			@ -1965,6 +2065,8 @@ int jack_activate (jack_client_t *client)
 | 
			
		|||
	pw_thread_loop_lock(c->context.loop);
 | 
			
		||||
	pw_client_node_proxy_set_active(c->node_proxy, true);
 | 
			
		||||
 | 
			
		||||
	c->timebase_emit = true;
 | 
			
		||||
 | 
			
		||||
	res = do_sync(c);
 | 
			
		||||
 | 
			
		||||
	pw_thread_loop_unlock(c->context.loop);
 | 
			
		||||
| 
						 | 
				
			
			@ -1984,6 +2086,8 @@ int jack_deactivate (jack_client_t *client)
 | 
			
		|||
	pw_thread_loop_lock(c->context.loop);
 | 
			
		||||
	pw_client_node_proxy_set_active(c->node_proxy, false);
 | 
			
		||||
 | 
			
		||||
	c->timebase_emit = false;
 | 
			
		||||
 | 
			
		||||
	res = do_sync(c);
 | 
			
		||||
 | 
			
		||||
	pw_thread_loop_unlock(c->context.loop);
 | 
			
		||||
| 
						 | 
				
			
			@ -2010,8 +2114,7 @@ jack_native_thread_t jack_client_thread_id (jack_client_t *client)
 | 
			
		|||
SPA_EXPORT
 | 
			
		||||
int jack_is_realtime (jack_client_t *client)
 | 
			
		||||
{
 | 
			
		||||
	pw_log_warn(NAME" %p: not implemented", client);
 | 
			
		||||
	return -ENOTSUP;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
| 
						 | 
				
			
			@ -3041,12 +3144,16 @@ SPA_EXPORT
 | 
			
		|||
jack_nframes_t jack_frames_since_cycle_start (const jack_client_t *client)
 | 
			
		||||
{
 | 
			
		||||
	struct client *c = (struct client *) client;
 | 
			
		||||
	struct spa_io_position *pos = c->position;
 | 
			
		||||
	struct timespec ts;
 | 
			
		||||
	uint64_t diff;
 | 
			
		||||
 | 
			
		||||
	if (pos == NULL)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	clock_gettime(CLOCK_MONOTONIC, &ts);
 | 
			
		||||
	diff = SPA_TIMESPEC_TO_USEC(&ts) - c->jack_position.usecs;
 | 
			
		||||
	return (jack_nframes_t) floor(((float)c->sample_rate * diff) / 1000000000.0f);
 | 
			
		||||
	diff = SPA_TIMESPEC_TO_NSEC(&ts) - pos->clock.nsec;
 | 
			
		||||
	return (jack_nframes_t) floor(((float)c->sample_rate * diff) / SPA_NSEC_PER_SEC);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
| 
						 | 
				
			
			@ -3061,7 +3168,12 @@ SPA_EXPORT
 | 
			
		|||
jack_nframes_t jack_last_frame_time (const jack_client_t *client)
 | 
			
		||||
{
 | 
			
		||||
	struct client *c = (struct client *) client;
 | 
			
		||||
	return c->jack_position.frame;
 | 
			
		||||
	struct spa_io_position *pos = c->position;
 | 
			
		||||
 | 
			
		||||
	if (pos == NULL)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	return pos->clock.position;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
| 
						 | 
				
			
			@ -3072,11 +3184,16 @@ int jack_get_cycle_times(const jack_client_t *client,
 | 
			
		|||
                        float          *period_usecs)
 | 
			
		||||
{
 | 
			
		||||
	struct client *c = (struct client *) client;
 | 
			
		||||
	struct spa_io_position *pos = c->position;
 | 
			
		||||
 | 
			
		||||
	if (pos == NULL)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	*current_frames = pos->clock.position;
 | 
			
		||||
	*current_usecs = pos->clock.nsec / SPA_NSEC_PER_USEC;
 | 
			
		||||
	*period_usecs = pos->clock.duration * (float)SPA_USEC_PER_SEC / (c->sample_rate * pos->clock.rate_diff);
 | 
			
		||||
	*next_usecs = pos->clock.next_nsec / SPA_NSEC_PER_USEC;
 | 
			
		||||
 | 
			
		||||
	*current_frames = c->jack_position.frame;
 | 
			
		||||
	*current_usecs = c->jack_position.usecs;
 | 
			
		||||
	*period_usecs = c->buffer_size / (c->sample_rate * c->rate_diff);
 | 
			
		||||
	*next_usecs = c->jack_position.usecs + (*period_usecs * 1000000.0f);
 | 
			
		||||
	pw_log_trace(NAME" %p: %d %"PRIu64" %"PRIu64" %f", c, *current_frames,
 | 
			
		||||
			*current_usecs, *next_usecs, *period_usecs);
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -3086,16 +3203,28 @@ SPA_EXPORT
 | 
			
		|||
jack_time_t jack_frames_to_time(const jack_client_t *client, jack_nframes_t frames)
 | 
			
		||||
{
 | 
			
		||||
	struct client *c = (struct client *) client;
 | 
			
		||||
	double df = (frames - c->jack_position.frame) * (double)SPA_USEC_PER_SEC / c->sample_rate;
 | 
			
		||||
	return c->jack_position.usecs + (int64_t)rint(df);
 | 
			
		||||
	struct spa_io_position *pos = c->position;
 | 
			
		||||
	double df;
 | 
			
		||||
 | 
			
		||||
	if (pos == NULL)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	df = (frames - pos->clock.position) * (double)SPA_NSEC_PER_SEC / c->sample_rate;
 | 
			
		||||
	return (pos->clock.nsec + (int64_t)rint(df)) / SPA_NSEC_PER_USEC;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
jack_nframes_t jack_time_to_frames(const jack_client_t *client, jack_time_t usecs)
 | 
			
		||||
{
 | 
			
		||||
	struct client *c = (struct client *) client;
 | 
			
		||||
	double du = (usecs - c->jack_position.usecs) * (double)c->sample_rate / SPA_USEC_PER_SEC;
 | 
			
		||||
	return c->jack_position.frame + (int32_t)rint(du);
 | 
			
		||||
	struct spa_io_position *pos = c->position;
 | 
			
		||||
	double du;
 | 
			
		||||
 | 
			
		||||
	if (pos == NULL)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	du = (usecs - pos->clock.nsec/SPA_NSEC_PER_USEC) * (double)c->sample_rate / SPA_USEC_PER_SEC;
 | 
			
		||||
	return pos->clock.position + (int32_t)rint(du);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
| 
						 | 
				
			
			@ -3127,8 +3256,11 @@ void jack_free(void* ptr)
 | 
			
		|||
SPA_EXPORT
 | 
			
		||||
int jack_release_timebase (jack_client_t *client)
 | 
			
		||||
{
 | 
			
		||||
	pw_log_warn(NAME" %p: not implemented", client);
 | 
			
		||||
	return -ENOTSUP;
 | 
			
		||||
	struct client *c = (struct client *) client;
 | 
			
		||||
	c->timebase_callback = NULL;
 | 
			
		||||
	c->timebase_arg = NULL;
 | 
			
		||||
	c->timebase_emit = false;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
| 
						 | 
				
			
			@ -3139,6 +3271,7 @@ int jack_set_sync_callback (jack_client_t *client,
 | 
			
		|||
	struct client *c = (struct client *) client;
 | 
			
		||||
	c->sync_callback = sync_callback;
 | 
			
		||||
	c->sync_arg = arg;
 | 
			
		||||
	c->sync_emit = true;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3159,6 +3292,7 @@ int  jack_set_timebase_callback (jack_client_t *client,
 | 
			
		|||
	struct client *c = (struct client *) client;
 | 
			
		||||
	c->timebase_callback = timebase_callback;
 | 
			
		||||
	c->timebase_arg = arg;
 | 
			
		||||
	c->timebase_emit = true;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3166,8 +3300,10 @@ SPA_EXPORT
 | 
			
		|||
int  jack_transport_locate (jack_client_t *client,
 | 
			
		||||
			    jack_nframes_t frame)
 | 
			
		||||
{
 | 
			
		||||
	pw_log_warn(NAME" %p: not implemented %d", client, frame);
 | 
			
		||||
	return -ENOTSUP;
 | 
			
		||||
	jack_position_t pos;
 | 
			
		||||
	pos.frame = frame;
 | 
			
		||||
	pos.valid = (jack_position_bits_t)0;
 | 
			
		||||
	return jack_transport_reposition(client, &pos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
| 
						 | 
				
			
			@ -3175,52 +3311,122 @@ jack_transport_state_t jack_transport_query (const jack_client_t *client,
 | 
			
		|||
					     jack_position_t *pos)
 | 
			
		||||
{
 | 
			
		||||
	struct client *c = (struct client *) client;
 | 
			
		||||
	if (pos != NULL)
 | 
			
		||||
		memcpy(pos, &c->jack_position, sizeof(jack_position_t));
 | 
			
		||||
	return JackTransportRolling;
 | 
			
		||||
	struct pw_node_activation *a = c->driver_activation;
 | 
			
		||||
	jack_transport_state_t jack_state = JackTransportStopped;
 | 
			
		||||
 | 
			
		||||
	if (a != NULL && pos != NULL)
 | 
			
		||||
		position_to_jack(&a->position, pos, &jack_state);
 | 
			
		||||
	else
 | 
			
		||||
		memset(pos, 0, sizeof(jack_position_t));
 | 
			
		||||
 | 
			
		||||
	return jack_state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
jack_nframes_t jack_get_current_transport_frame (const jack_client_t *client)
 | 
			
		||||
{
 | 
			
		||||
	pw_log_warn(NAME" %p: not implemented", client);
 | 
			
		||||
	return 0;
 | 
			
		||||
	struct client *c = (struct client *) client;
 | 
			
		||||
	struct pw_node_activation *a = c->driver_activation;
 | 
			
		||||
	struct spa_io_position *pos;
 | 
			
		||||
	uint64_t clock_position;
 | 
			
		||||
	if (!a)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	pos = &a->position;
 | 
			
		||||
 | 
			
		||||
	if (pos->state == SPA_IO_POSITION_STATE_RUNNING ||
 | 
			
		||||
	    pos->state == SPA_IO_POSITION_STATE_LOOPING) {
 | 
			
		||||
		struct timespec ts;
 | 
			
		||||
		clock_gettime(CLOCK_MONOTONIC, &ts);
 | 
			
		||||
		uint64_t nsecs = SPA_TIMESPEC_TO_NSEC(&ts) - pos->clock.nsec;
 | 
			
		||||
		uint64_t elapsed = (uint64_t)floor((((float) c->sample_rate) / SPA_NSEC_PER_SEC) * nsecs);
 | 
			
		||||
		clock_position = pos->clock.position + elapsed;
 | 
			
		||||
	} else {
 | 
			
		||||
		clock_position = pos->clock.position;
 | 
			
		||||
	}
 | 
			
		||||
	return (pos->clock_start - clock_position) * pos->rate + pos->position;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
int  jack_transport_reposition (jack_client_t *client,
 | 
			
		||||
				const jack_position_t *pos)
 | 
			
		||||
{
 | 
			
		||||
	pw_log_warn(NAME" %p: not implemented", client);
 | 
			
		||||
	return -ENOTSUP;
 | 
			
		||||
	struct client *c = (struct client *) client;
 | 
			
		||||
	struct pw_node_activation *a = c->driver_activation;
 | 
			
		||||
	uint32_t seq1, seq2;
 | 
			
		||||
	if (!a)
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	if (pos->valid & ~(JackPositionBBT|JackPositionTimecode))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	pw_log_debug("frame:%u", pos->frame);
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		seq1 = SEQ_WRITE(&a->pending.seq);
 | 
			
		||||
		a->pending.change_mask |= UPDATE_POSITION;
 | 
			
		||||
		a->pending.position.position = pos->frame;
 | 
			
		||||
		a->pending.position.clock_start = 0;
 | 
			
		||||
		a->pending.position.clock_duration = 0;
 | 
			
		||||
		a->pending.position.rate = 1.0;
 | 
			
		||||
		seq2 = SEQ_WRITE(&a->pending.seq);
 | 
			
		||||
	} while (!SEQ_WRITE_SUCCESS(seq1, seq2));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
void jack_transport_start (jack_client_t *client)
 | 
			
		||||
{
 | 
			
		||||
	pw_log_warn(NAME" %p: not implemented", client);
 | 
			
		||||
	struct client *c = (struct client *) client;
 | 
			
		||||
	struct pw_node_activation *a = c->driver_activation;
 | 
			
		||||
	uint32_t seq1, seq2;
 | 
			
		||||
 | 
			
		||||
	if (!a)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		seq1 = SEQ_WRITE(&a->pending.seq);
 | 
			
		||||
		a->pending.change_mask |= UPDATE_STATE;
 | 
			
		||||
		a->pending.state = SPA_IO_POSITION_STATE_STARTING;
 | 
			
		||||
		seq2 = SEQ_WRITE(&a->pending.seq);
 | 
			
		||||
	} while (!SEQ_WRITE_SUCCESS(seq1, seq2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
void jack_transport_stop (jack_client_t *client)
 | 
			
		||||
{
 | 
			
		||||
	pw_log_warn(NAME" %p: not implemented", client);
 | 
			
		||||
	struct client *c = (struct client *) client;
 | 
			
		||||
	struct pw_node_activation *a = c->driver_activation;
 | 
			
		||||
	uint32_t seq1, seq2;
 | 
			
		||||
 | 
			
		||||
	if (!a)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		seq1 = SEQ_WRITE(&a->pending.seq);
 | 
			
		||||
		a->pending.change_mask |= UPDATE_STATE;
 | 
			
		||||
		a->pending.state = SPA_IO_POSITION_STATE_STOPPED;
 | 
			
		||||
		seq2 = SEQ_WRITE(&a->pending.seq);
 | 
			
		||||
	} while (!SEQ_WRITE_SUCCESS(seq1, seq2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
void jack_get_transport_info (jack_client_t *client,
 | 
			
		||||
			      jack_transport_info_t *tinfo)
 | 
			
		||||
{
 | 
			
		||||
	static jack_transport_info_t dummy;
 | 
			
		||||
	memcpy(tinfo, &dummy, sizeof(jack_transport_info_t));
 | 
			
		||||
	pw_log_warn(NAME" %p: not implemented", client);
 | 
			
		||||
	pw_log_error(NAME" %p: deprecated", client);
 | 
			
		||||
	if (tinfo)
 | 
			
		||||
		memset(tinfo, 0, sizeof(jack_transport_info_t));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
void jack_set_transport_info (jack_client_t *client,
 | 
			
		||||
			      jack_transport_info_t *tinfo)
 | 
			
		||||
{
 | 
			
		||||
	pw_log_warn(NAME" %p: not implemented", client);
 | 
			
		||||
	pw_log_error(NAME" %p: deprecated", client);
 | 
			
		||||
	if (tinfo)
 | 
			
		||||
		memset(tinfo, 0, sizeof(jack_transport_info_t));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
| 
						 | 
				
			
			@ -3260,7 +3466,7 @@ SPA_EXPORT
 | 
			
		|||
int jack_client_real_time_priority (jack_client_t * client)
 | 
			
		||||
{
 | 
			
		||||
	pw_log_warn(NAME" %p: not implemented", client);
 | 
			
		||||
	return -ENOTSUP;
 | 
			
		||||
	return 20;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue