mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	pulse-server: improve latency setup a little
Reorganize the latency setup in one place, return a desired device latency for use as quantum. PulseAudio assigns half of the (tlength - minreq) latency to the sink but we can't do that because our sinks have a max-quantum of latency. Fix this by clamping our calculated sink latency to the quantum PulseAudio subtracts the sink latency from the tlength in adjust latency mode, so we need to do the same. This makes PULSE_LATENCY_MSEC values bahave more like pulseaudio. See #1769
This commit is contained in:
		
							parent
							
								
									86ca0f8466
								
							
						
					
					
						commit
						b96f15d2fe
					
				
					 2 changed files with 54 additions and 38 deletions
				
			
		| 
						 | 
					@ -51,6 +51,7 @@ struct defs {
 | 
				
			||||||
	struct spa_fraction min_quantum;
 | 
						struct spa_fraction min_quantum;
 | 
				
			||||||
	struct sample_spec sample_spec;
 | 
						struct sample_spec sample_spec;
 | 
				
			||||||
	struct channel_map channel_map;
 | 
						struct channel_map channel_map;
 | 
				
			||||||
 | 
						uint32_t max_quantum;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct stats {
 | 
					struct stats {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -367,13 +367,14 @@ static uint32_t frac_to_bytes_round_up(struct spa_fraction val, const struct sam
 | 
				
			||||||
	return (uint32_t) u;
 | 
						return (uint32_t) u;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void fix_playback_buffer_attr(struct stream *s, struct buffer_attr *attr)
 | 
					static uint32_t fix_playback_buffer_attr(struct stream *s, struct buffer_attr *attr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint32_t frame_size, max_prebuf, minreq;
 | 
						uint32_t frame_size, max_prebuf, minreq, latency, max_latency;
 | 
				
			||||||
	struct defs *defs = &s->impl->defs;
 | 
						struct defs *defs = &s->impl->defs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	frame_size = s->frame_size;
 | 
						frame_size = s->frame_size;
 | 
				
			||||||
	minreq = frac_to_bytes_round_up(defs->min_req, &s->ss);
 | 
						minreq = frac_to_bytes_round_up(defs->min_req, &s->ss);
 | 
				
			||||||
 | 
						max_latency = defs->max_quantum * frame_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (attr->maxlength == (uint32_t) -1 || attr->maxlength > MAXLENGTH)
 | 
						if (attr->maxlength == (uint32_t) -1 || attr->maxlength > MAXLENGTH)
 | 
				
			||||||
		attr->maxlength = MAXLENGTH;
 | 
							attr->maxlength = MAXLENGTH;
 | 
				
			||||||
| 
						 | 
					@ -401,6 +402,26 @@ static void fix_playback_buffer_attr(struct stream *s, struct buffer_attr *attr)
 | 
				
			||||||
	if (attr->tlength < attr->minreq+frame_size)
 | 
						if (attr->tlength < attr->minreq+frame_size)
 | 
				
			||||||
		attr->tlength = attr->minreq + frame_size;
 | 
							attr->tlength = attr->minreq + frame_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (s->early_requests) {
 | 
				
			||||||
 | 
							latency = attr->minreq;
 | 
				
			||||||
 | 
						} else if (s->adjust_latency) {
 | 
				
			||||||
 | 
							if (attr->tlength > attr->minreq * 2)
 | 
				
			||||||
 | 
								latency = SPA_MIN(max_latency, (attr->tlength - attr->minreq * 2) / 2);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								latency = attr->minreq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (attr->tlength >= latency)
 | 
				
			||||||
 | 
								attr->tlength -= latency;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (attr->tlength > attr->minreq * 2)
 | 
				
			||||||
 | 
								latency = SPA_MIN(max_latency, attr->tlength - attr->minreq * 2);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								latency = attr->minreq;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (attr->tlength < latency + 2 * attr->minreq)
 | 
				
			||||||
 | 
							attr->tlength = latency + 2 * attr->minreq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	attr->minreq -= attr->minreq % frame_size;
 | 
						attr->minreq -= attr->minreq % frame_size;
 | 
				
			||||||
	if (attr->minreq <= 0) {
 | 
						if (attr->minreq <= 0) {
 | 
				
			||||||
		attr->minreq = frame_size;
 | 
							attr->minreq = frame_size;
 | 
				
			||||||
| 
						 | 
					@ -417,9 +438,11 @@ static void fix_playback_buffer_attr(struct stream *s, struct buffer_attr *attr)
 | 
				
			||||||
	s->missing = attr->tlength;
 | 
						s->missing = attr->tlength;
 | 
				
			||||||
	attr->fragsize = 0;
 | 
						attr->fragsize = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_info("%p: [%s] maxlength:%u tlength:%u minreq:%u prebuf:%u", s,
 | 
						pw_log_info("%p: [%s] maxlength:%u tlength:%u minreq:%u/%u prebuf:%u latency:%u", s,
 | 
				
			||||||
			s->client->name, attr->maxlength, attr->tlength,
 | 
								s->client->name, attr->maxlength, attr->tlength,
 | 
				
			||||||
			attr->minreq, attr->prebuf);
 | 
								attr->minreq, minreq, attr->prebuf, latency);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return latency / frame_size;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int reply_create_playback_stream(struct stream *stream, struct pw_manager_object *peer)
 | 
					static int reply_create_playback_stream(struct stream *stream, struct pw_manager_object *peer)
 | 
				
			||||||
| 
						 | 
					@ -438,7 +461,8 @@ static int reply_create_playback_stream(struct stream *stream, struct pw_manager
 | 
				
			||||||
	uint64_t lat_usec;
 | 
						uint64_t lat_usec;
 | 
				
			||||||
	struct defs *defs = &stream->impl->defs;
 | 
						struct defs *defs = &stream->impl->defs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fix_playback_buffer_attr(stream, &stream->attr);
 | 
						lat.denom = stream->ss.rate;
 | 
				
			||||||
 | 
						lat.num = fix_playback_buffer_attr(stream, &stream->attr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stream->buffer = calloc(1, stream->attr.maxlength);
 | 
						stream->buffer = calloc(1, stream->attr.maxlength);
 | 
				
			||||||
	if (stream->buffer == NULL)
 | 
						if (stream->buffer == NULL)
 | 
				
			||||||
| 
						 | 
					@ -446,21 +470,6 @@ static int reply_create_playback_stream(struct stream *stream, struct pw_manager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_ringbuffer_init(&stream->ring);
 | 
						spa_ringbuffer_init(&stream->ring);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (stream->early_requests) {
 | 
					 | 
				
			||||||
		lat.num = stream->attr.minreq;
 | 
					 | 
				
			||||||
	} else if (stream->adjust_latency) {
 | 
					 | 
				
			||||||
		if (stream->attr.tlength > stream->attr.minreq * 2)
 | 
					 | 
				
			||||||
			lat.num = (stream->attr.tlength - stream->attr.minreq * 2) / 2;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			lat.num = stream->attr.minreq;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		if (stream->attr.tlength > stream->attr.minreq * 2)
 | 
					 | 
				
			||||||
			lat.num = stream->attr.tlength - stream->attr.minreq * 2;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			lat.num = stream->attr.minreq;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	lat.denom = stream->ss.rate;
 | 
					 | 
				
			||||||
	lat.num /= stream->frame_size;
 | 
					 | 
				
			||||||
	if (lat.num * defs->min_quantum.denom / lat.denom < defs->min_quantum.num)
 | 
						if (lat.num * defs->min_quantum.denom / lat.denom < defs->min_quantum.num)
 | 
				
			||||||
		lat.num = (defs->min_quantum.num * lat.denom +
 | 
							lat.num = (defs->min_quantum.num * lat.denom +
 | 
				
			||||||
				(defs->min_quantum.denom -1)) / defs->min_quantum.denom;
 | 
									(defs->min_quantum.denom -1)) / defs->min_quantum.denom;
 | 
				
			||||||
| 
						 | 
					@ -535,9 +544,9 @@ static int reply_create_playback_stream(struct stream *stream, struct pw_manager
 | 
				
			||||||
	return client_queue_message(client, reply);
 | 
						return client_queue_message(client, reply);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void fix_record_buffer_attr(struct stream *s, struct buffer_attr *attr)
 | 
					static uint32_t fix_record_buffer_attr(struct stream *s, struct buffer_attr *attr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint32_t frame_size, minfrag;
 | 
						uint32_t frame_size, minfrag, latency;
 | 
				
			||||||
	struct defs *defs = &s->impl->defs;
 | 
						struct defs *defs = &s->impl->defs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	frame_size = s->frame_size;
 | 
						frame_size = s->frame_size;
 | 
				
			||||||
| 
						 | 
					@ -560,8 +569,19 @@ static void fix_record_buffer_attr(struct stream *s, struct buffer_attr *attr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	attr->tlength = attr->minreq = attr->prebuf = 0;
 | 
						attr->tlength = attr->minreq = attr->prebuf = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_info("%p: [%s] maxlength:%u fragsize:%u minfrag:%u", s,
 | 
						if (s->early_requests) {
 | 
				
			||||||
			s->client->name, attr->maxlength, attr->fragsize, minfrag);
 | 
							latency = attr->fragsize;
 | 
				
			||||||
 | 
						} else if (s->adjust_latency) {
 | 
				
			||||||
 | 
							latency = attr->fragsize;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							latency = attr->fragsize;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_info("%p: [%s] maxlength:%u fragsize:%u minfrag:%u latency:%u", s,
 | 
				
			||||||
 | 
								s->client->name, attr->maxlength, attr->fragsize, minfrag,
 | 
				
			||||||
 | 
								latency);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return latency / frame_size;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int reply_create_record_stream(struct stream *stream, struct pw_manager_object *peer)
 | 
					static int reply_create_record_stream(struct stream *stream, struct pw_manager_object *peer)
 | 
				
			||||||
| 
						 | 
					@ -579,7 +599,8 @@ static int reply_create_record_stream(struct stream *stream, struct pw_manager_o
 | 
				
			||||||
	uint64_t lat_usec;
 | 
						uint64_t lat_usec;
 | 
				
			||||||
	struct defs *defs = &stream->impl->defs;
 | 
						struct defs *defs = &stream->impl->defs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fix_record_buffer_attr(stream, &stream->attr);
 | 
						lat.denom = stream->ss.rate;
 | 
				
			||||||
 | 
						lat.num = fix_record_buffer_attr(stream, &stream->attr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stream->buffer = calloc(1, stream->attr.maxlength);
 | 
						stream->buffer = calloc(1, stream->attr.maxlength);
 | 
				
			||||||
	if (stream->buffer == NULL)
 | 
						if (stream->buffer == NULL)
 | 
				
			||||||
| 
						 | 
					@ -587,16 +608,6 @@ static int reply_create_record_stream(struct stream *stream, struct pw_manager_o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_ringbuffer_init(&stream->ring);
 | 
						spa_ringbuffer_init(&stream->ring);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (stream->early_requests) {
 | 
					 | 
				
			||||||
		lat.num = stream->attr.fragsize;
 | 
					 | 
				
			||||||
	} else if (stream->adjust_latency) {
 | 
					 | 
				
			||||||
		lat.num = stream->attr.fragsize;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		lat.num = stream->attr.fragsize;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	lat.num /= stream->frame_size;
 | 
					 | 
				
			||||||
	lat.denom = stream->ss.rate;
 | 
					 | 
				
			||||||
	if (lat.num * defs->min_quantum.denom / lat.denom < defs->min_quantum.num)
 | 
						if (lat.num * defs->min_quantum.denom / lat.denom < defs->min_quantum.num)
 | 
				
			||||||
		lat.num = (defs->min_quantum.num * lat.denom +
 | 
							lat.num = (defs->min_quantum.num * lat.denom +
 | 
				
			||||||
				(defs->min_quantum.denom -1)) / defs->min_quantum.denom;
 | 
									(defs->min_quantum.denom -1)) / defs->min_quantum.denom;
 | 
				
			||||||
| 
						 | 
					@ -691,9 +702,12 @@ static void manager_added(void *data, struct pw_manager_object *o)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcmp(o->type, PW_TYPE_INTERFACE_Core) == 0 && manager->info != NULL) {
 | 
						if (strcmp(o->type, PW_TYPE_INTERFACE_Core) == 0 && manager->info != NULL) {
 | 
				
			||||||
		struct pw_core_info *info = manager->info;
 | 
							struct pw_core_info *info = manager->info;
 | 
				
			||||||
		if (info->props &&
 | 
							if (info->props) {
 | 
				
			||||||
		    (str = spa_dict_lookup(info->props, "default.clock.rate")) != NULL)
 | 
								if ((str = spa_dict_lookup(info->props, "default.clock.rate")) != NULL)
 | 
				
			||||||
				client->impl->defs.sample_spec.rate = atoi(str);
 | 
									client->impl->defs.sample_spec.rate = atoi(str);
 | 
				
			||||||
 | 
								if ((str = spa_dict_lookup(info->props, "default.clock.max-quantum")) != NULL)
 | 
				
			||||||
 | 
									client->impl->defs.max_quantum = atoi(str);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (spa_streq(o->type, PW_TYPE_INTERFACE_Metadata)) {
 | 
						if (spa_streq(o->type, PW_TYPE_INTERFACE_Metadata)) {
 | 
				
			||||||
| 
						 | 
					@ -5043,6 +5057,7 @@ static void load_defaults(struct defs *def, struct pw_properties *props)
 | 
				
			||||||
	parse_format(props, "pulse.default.format", DEFAULT_FORMAT, &def->sample_spec);
 | 
						parse_format(props, "pulse.default.format", DEFAULT_FORMAT, &def->sample_spec);
 | 
				
			||||||
	parse_position(props, "pulse.default.position", DEFAULT_POSITION, &def->channel_map);
 | 
						parse_position(props, "pulse.default.position", DEFAULT_POSITION, &def->channel_map);
 | 
				
			||||||
	def->sample_spec.channels = def->channel_map.channels;
 | 
						def->sample_spec.channels = def->channel_map.channels;
 | 
				
			||||||
 | 
						def->max_quantum = 8192;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pw_protocol_pulse *pw_protocol_pulse_new(struct pw_context *context,
 | 
					struct pw_protocol_pulse *pw_protocol_pulse_new(struct pw_context *context,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue