mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	module-rtp: use timestamps as ringbuffer index
Use the timestamps directly as the ringbuffer index. We can save some conversions to bytes and there is a direct mapping to RTP timestamp, clock position and ringbuffer index. Simplify the source a little. Remove the buffering state, we always start with read and write pointers separted by the target buffering.
This commit is contained in:
		
							parent
							
								
									16e995be26
								
							
						
					
					
						commit
						aed394cf89
					
				
					 2 changed files with 119 additions and 120 deletions
				
			
		| 
						 | 
				
			
			@ -227,7 +227,7 @@ struct impl {
 | 
			
		|||
	bool mcast_loop;
 | 
			
		||||
	float min_ptime;
 | 
			
		||||
	float max_ptime;
 | 
			
		||||
	uint32_t pbytes;
 | 
			
		||||
	uint32_t psamples;
 | 
			
		||||
 | 
			
		||||
	struct sockaddr_storage src_addr;
 | 
			
		||||
	socklen_t src_len;
 | 
			
		||||
| 
						 | 
				
			
			@ -245,7 +245,7 @@ struct impl {
 | 
			
		|||
 | 
			
		||||
	struct spa_audio_info_raw info;
 | 
			
		||||
	const struct format_info *format_info;
 | 
			
		||||
	uint32_t frame_size;
 | 
			
		||||
	uint32_t stride;
 | 
			
		||||
	int payload;
 | 
			
		||||
	uint16_t seq;
 | 
			
		||||
	uint32_t ssrc;
 | 
			
		||||
| 
						 | 
				
			
			@ -282,20 +282,21 @@ set_iovec(struct spa_ringbuffer *rbuf, void *buffer, uint32_t size,
 | 
			
		|||
static void flush_packets(struct impl *impl)
 | 
			
		||||
{
 | 
			
		||||
	int32_t avail;
 | 
			
		||||
	uint32_t index;
 | 
			
		||||
	uint32_t stride, timestamp;
 | 
			
		||||
	struct iovec iov[3];
 | 
			
		||||
	struct msghdr msg;
 | 
			
		||||
	ssize_t n;
 | 
			
		||||
	struct rtp_header header;
 | 
			
		||||
	int32_t tosend;
 | 
			
		||||
 | 
			
		||||
	avail = spa_ringbuffer_get_read_index(&impl->ring, &index);
 | 
			
		||||
 | 
			
		||||
	tosend = impl->pbytes;
 | 
			
		||||
	avail = spa_ringbuffer_get_read_index(&impl->ring, ×tamp);
 | 
			
		||||
	tosend = impl->psamples;
 | 
			
		||||
 | 
			
		||||
	if (avail < tosend)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	stride = impl->stride;
 | 
			
		||||
 | 
			
		||||
	spa_zero(header);
 | 
			
		||||
	header.v = 2;
 | 
			
		||||
	header.pt = impl->payload;
 | 
			
		||||
| 
						 | 
				
			
			@ -314,14 +315,14 @@ static void flush_packets(struct impl *impl)
 | 
			
		|||
 | 
			
		||||
	while (avail >= tosend) {
 | 
			
		||||
		header.sequence_number = htons(impl->seq);
 | 
			
		||||
		header.timestamp = htonl(impl->ts_offset + index / impl->frame_size);
 | 
			
		||||
		header.timestamp = htonl(impl->ts_offset + timestamp);
 | 
			
		||||
 | 
			
		||||
		set_iovec(&impl->ring,
 | 
			
		||||
			impl->buffer, BUFFER_SIZE,
 | 
			
		||||
			index & BUFFER_MASK,
 | 
			
		||||
			&iov[1], tosend);
 | 
			
		||||
			(timestamp * stride) & BUFFER_MASK,
 | 
			
		||||
			&iov[1], tosend * stride);
 | 
			
		||||
 | 
			
		||||
		pw_log_trace("sending %d index:%d", tosend, index);
 | 
			
		||||
		pw_log_trace("sending %d timestamp:%d", tosend, timestamp);
 | 
			
		||||
		n = sendmsg(impl->rtp_fd, &msg, MSG_NOSIGNAL);
 | 
			
		||||
		if (n < 0) {
 | 
			
		||||
			switch (errno) {
 | 
			
		||||
| 
						 | 
				
			
			@ -338,10 +339,10 @@ static void flush_packets(struct impl *impl)
 | 
			
		|||
 | 
			
		||||
		impl->seq++;
 | 
			
		||||
 | 
			
		||||
		index += tosend;
 | 
			
		||||
		timestamp += tosend;
 | 
			
		||||
		avail -= tosend;
 | 
			
		||||
	}
 | 
			
		||||
	spa_ringbuffer_read_update(&impl->ring, index);
 | 
			
		||||
	spa_ringbuffer_read_update(&impl->ring, timestamp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void stream_process(void *data)
 | 
			
		||||
| 
						 | 
				
			
			@ -349,7 +350,7 @@ static void stream_process(void *data)
 | 
			
		|||
	struct impl *impl = data;
 | 
			
		||||
	struct pw_buffer *buf;
 | 
			
		||||
	struct spa_data *d;
 | 
			
		||||
	uint32_t index, expected_index;
 | 
			
		||||
	uint32_t timestamp, expected_timestamp, stride;
 | 
			
		||||
        int32_t filled, wanted;
 | 
			
		||||
 | 
			
		||||
	if ((buf = pw_stream_dequeue_buffer(impl->stream)) == NULL) {
 | 
			
		||||
| 
						 | 
				
			
			@ -358,33 +359,37 @@ static void stream_process(void *data)
 | 
			
		|||
	}
 | 
			
		||||
	d = buf->buffer->datas;
 | 
			
		||||
 | 
			
		||||
	wanted = d[0].chunk->size;
 | 
			
		||||
	stride = impl->stride;
 | 
			
		||||
	wanted = d[0].chunk->size / stride;
 | 
			
		||||
 | 
			
		||||
	filled = spa_ringbuffer_get_write_index(&impl->ring, &expected_index);
 | 
			
		||||
	if (impl->io_position)
 | 
			
		||||
		index = impl->io_position->clock.position * impl->frame_size;
 | 
			
		||||
	filled = spa_ringbuffer_get_write_index(&impl->ring, &expected_timestamp);
 | 
			
		||||
	if (SPA_LIKELY(impl->io_position))
 | 
			
		||||
		timestamp = impl->io_position->clock.position;
 | 
			
		||||
	else
 | 
			
		||||
		index = expected_index;
 | 
			
		||||
		timestamp = expected_timestamp;
 | 
			
		||||
 | 
			
		||||
	if (impl->sync) {
 | 
			
		||||
		if (expected_timestamp != timestamp) {
 | 
			
		||||
			pw_log_warn("expected %u != timestamp %u", expected_timestamp, timestamp);
 | 
			
		||||
			impl->sync = false;
 | 
			
		||||
		} else if ((filled + wanted) * stride > (int32_t)BUFFER_SIZE) {
 | 
			
		||||
			pw_log_warn("overrun %u + %u > %u", filled, wanted, BUFFER_SIZE / stride);
 | 
			
		||||
			impl->sync = false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (!impl->sync) {
 | 
			
		||||
		pw_log_info("sync %u", index);
 | 
			
		||||
		impl->ring.readindex = impl->ring.writeindex = index;
 | 
			
		||||
		pw_log_info("sync to timestamp %u", timestamp);
 | 
			
		||||
		impl->ring.readindex = impl->ring.writeindex = timestamp;
 | 
			
		||||
		impl->sync = true;
 | 
			
		||||
	} else if (expected_index != index) {
 | 
			
		||||
		pw_log_warn("expected %u != index %u", expected_index, index);
 | 
			
		||||
		impl->ring.readindex = impl->ring.writeindex = index;
 | 
			
		||||
	} else if (filled + wanted > (int32_t)BUFFER_SIZE) {
 | 
			
		||||
		pw_log_warn("overrun %u + %u > %u", filled, wanted, BUFFER_SIZE);
 | 
			
		||||
		impl->ring.readindex = impl->ring.writeindex = index;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spa_ringbuffer_write_data(&impl->ring,
 | 
			
		||||
			impl->buffer,
 | 
			
		||||
			BUFFER_SIZE,
 | 
			
		||||
			index & BUFFER_MASK,
 | 
			
		||||
			d[0].data, wanted);
 | 
			
		||||
	index += wanted;
 | 
			
		||||
	spa_ringbuffer_write_update(&impl->ring, index);
 | 
			
		||||
			(timestamp * stride) & BUFFER_MASK,
 | 
			
		||||
			d[0].data, wanted * stride);
 | 
			
		||||
	timestamp += wanted;
 | 
			
		||||
	spa_ringbuffer_write_update(&impl->ring, timestamp);
 | 
			
		||||
 | 
			
		||||
	pw_stream_queue_buffer(impl->stream, buf);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -521,8 +526,7 @@ static int setup_stream(struct impl *impl)
 | 
			
		|||
 | 
			
		||||
	if (pw_properties_get(props, PW_KEY_NODE_LATENCY) == NULL) {
 | 
			
		||||
		pw_properties_setf(props, PW_KEY_NODE_LATENCY,
 | 
			
		||||
				"%d/%d", impl->pbytes / impl->frame_size,
 | 
			
		||||
				impl->info.rate);
 | 
			
		||||
				"%d/%d", impl->psamples, impl->info.rate);
 | 
			
		||||
	}
 | 
			
		||||
	pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%d", impl->info.rate);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -634,7 +638,7 @@ static void send_sap(struct impl *impl, bool bye)
 | 
			
		|||
			impl->port, impl->payload,
 | 
			
		||||
			impl->payload, impl->format_info->mime,
 | 
			
		||||
			impl->info.rate, impl->info.channels,
 | 
			
		||||
			(impl->pbytes / impl->frame_size) * 1000 / impl->info.rate);
 | 
			
		||||
			impl->psamples * 1000 / impl->info.rate);
 | 
			
		||||
 | 
			
		||||
	if (impl->ts_refclk[0] != '\0') {
 | 
			
		||||
		spa_strbuf_append(&buf,
 | 
			
		||||
| 
						 | 
				
			
			@ -837,7 +841,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
 | 
			
		|||
	struct impl *impl;
 | 
			
		||||
	struct pw_properties *props = NULL, *stream_props = NULL;
 | 
			
		||||
	uint32_t id = pw_global_get_id(pw_impl_module_get_global(module));
 | 
			
		||||
	uint32_t pid = getpid(), port, min_bytes, max_bytes;
 | 
			
		||||
	uint32_t pid = getpid(), port, min_samples, max_samples;
 | 
			
		||||
	int64_t ts_offset;
 | 
			
		||||
	char addr[64];
 | 
			
		||||
	const char *str;
 | 
			
		||||
| 
						 | 
				
			
			@ -912,7 +916,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
 | 
			
		|||
		res = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	impl->frame_size = impl->format_info->size * impl->info.channels;
 | 
			
		||||
	impl->stride = impl->format_info->size * impl->info.channels;
 | 
			
		||||
	impl->msg_id_hash = rand();
 | 
			
		||||
	impl->ntp = (uint32_t) time(NULL) + 2208988800U;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -965,11 +969,11 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
 | 
			
		|||
	if (!spa_atof(str, &impl->max_ptime))
 | 
			
		||||
		impl->max_ptime = DEFAULT_MAX_PTIME;
 | 
			
		||||
 | 
			
		||||
	min_bytes = (impl->min_ptime * impl->info.rate / 1000) * impl->frame_size;
 | 
			
		||||
	max_bytes = (impl->max_ptime * impl->info.rate / 1000) * impl->frame_size;
 | 
			
		||||
	min_samples = impl->min_ptime * impl->info.rate / 1000;
 | 
			
		||||
	max_samples = impl->max_ptime * impl->info.rate / 1000;
 | 
			
		||||
 | 
			
		||||
	impl->pbytes = SPA_ROUND_DOWN(impl->mtu, impl->frame_size);
 | 
			
		||||
	impl->pbytes = SPA_CLAMP(impl->pbytes, min_bytes, max_bytes);
 | 
			
		||||
	impl->psamples = impl->mtu / impl->stride;
 | 
			
		||||
	impl->psamples = SPA_CLAMP(impl->psamples, min_samples, max_samples);
 | 
			
		||||
 | 
			
		||||
	if ((str = pw_properties_get(props, "sess.name")) == NULL)
 | 
			
		||||
		pw_properties_setf(props, "sess.name", "PipeWire RTP Stream on %s",
 | 
			
		||||
| 
						 | 
				
			
			@ -986,7 +990,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
 | 
			
		|||
	pw_properties_setf(stream_props, "rtp.mtu", "%u", impl->mtu);
 | 
			
		||||
	pw_properties_setf(stream_props, "rtp.ttl", "%u", impl->ttl);
 | 
			
		||||
	pw_properties_setf(stream_props, "rtp.ptime", "%u",
 | 
			
		||||
			(impl->pbytes / impl->frame_size) * 1000 / impl->info.rate);
 | 
			
		||||
			impl->psamples * 1000 / impl->info.rate);
 | 
			
		||||
 | 
			
		||||
	impl->core = pw_context_get_object(impl->module_context, PW_TYPE_INTERFACE_Core);
 | 
			
		||||
	if (impl->core == NULL) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -250,9 +250,7 @@ struct session {
 | 
			
		|||
	struct spa_io_position *position;
 | 
			
		||||
	struct spa_dll dll;
 | 
			
		||||
	uint32_t target_buffer;
 | 
			
		||||
	uint32_t last_packet_size;
 | 
			
		||||
	float max_error;
 | 
			
		||||
	unsigned buffering:1;
 | 
			
		||||
	unsigned first:1;
 | 
			
		||||
	unsigned receiving:1;
 | 
			
		||||
	unsigned direct_timestamp:1;
 | 
			
		||||
| 
						 | 
				
			
			@ -270,8 +268,8 @@ static void stream_process(void *data)
 | 
			
		|||
	struct session *sess = data;
 | 
			
		||||
	struct pw_buffer *buf;
 | 
			
		||||
	struct spa_data *d;
 | 
			
		||||
	uint32_t index, target_buffer;
 | 
			
		||||
	int32_t avail, wanted;
 | 
			
		||||
	uint32_t wanted, timestamp, target_buffer, stride, maxsize;
 | 
			
		||||
	int32_t avail;
 | 
			
		||||
 | 
			
		||||
	if ((buf = pw_stream_dequeue_buffer(sess->stream)) == NULL) {
 | 
			
		||||
		pw_log_debug("Out of stream buffers: %m");
 | 
			
		||||
| 
						 | 
				
			
			@ -279,42 +277,53 @@ static void stream_process(void *data)
 | 
			
		|||
	}
 | 
			
		||||
	d = buf->buffer->datas;
 | 
			
		||||
 | 
			
		||||
	wanted = buf->requested ?
 | 
			
		||||
		SPA_MIN(buf->requested * sess->info.stride, d[0].maxsize)
 | 
			
		||||
		: d[0].maxsize;
 | 
			
		||||
	stride = sess->info.stride;
 | 
			
		||||
 | 
			
		||||
	maxsize = d[0].maxsize / stride;
 | 
			
		||||
	wanted = buf->requested ? SPA_MIN(buf->requested, maxsize) : maxsize;
 | 
			
		||||
 | 
			
		||||
	if (sess->position && sess->direct_timestamp) {
 | 
			
		||||
		/* in direct mode, read directly from the timestamp index,
 | 
			
		||||
		 * because sender and receiver are in sync, this would keep
 | 
			
		||||
		 * target_buffer of bytes available. */
 | 
			
		||||
		spa_ringbuffer_read_update(&sess->ring,
 | 
			
		||||
				sess->position->clock.position * sess->info.stride);
 | 
			
		||||
				sess->position->clock.position);
 | 
			
		||||
	}
 | 
			
		||||
	avail = spa_ringbuffer_get_read_index(&sess->ring, &index);
 | 
			
		||||
	avail = spa_ringbuffer_get_read_index(&sess->ring, ×tamp);
 | 
			
		||||
 | 
			
		||||
	target_buffer = sess->target_buffer + sess->last_packet_size / 2;
 | 
			
		||||
	target_buffer = sess->target_buffer;
 | 
			
		||||
 | 
			
		||||
	if (avail < wanted || sess->buffering) {
 | 
			
		||||
		memset(d[0].data, 0, wanted);
 | 
			
		||||
		if (!sess->buffering && sess->have_sync) {
 | 
			
		||||
			pw_log_debug("underrun %u/%u < %u, buffering...",
 | 
			
		||||
					avail, target_buffer, wanted);
 | 
			
		||||
			sess->buffering = true;
 | 
			
		||||
	if (avail < (int32_t)wanted) {
 | 
			
		||||
		enum spa_log_level level;
 | 
			
		||||
		memset(d[0].data, 0, wanted * stride);
 | 
			
		||||
		if (sess->have_sync) {
 | 
			
		||||
			sess->have_sync = false;
 | 
			
		||||
			level = SPA_LOG_LEVEL_WARN;
 | 
			
		||||
		} else {
 | 
			
		||||
			level = SPA_LOG_LEVEL_DEBUG;
 | 
			
		||||
		}
 | 
			
		||||
		pw_log(level, "underrun %d/%u < %u",
 | 
			
		||||
					avail, target_buffer, wanted);
 | 
			
		||||
	} else {
 | 
			
		||||
		float error, corr;
 | 
			
		||||
		if (avail > (int32_t)SPA_MIN(target_buffer * 8, BUFFER_SIZE)) {
 | 
			
		||||
		if (avail > (int32_t)SPA_MIN(target_buffer * 8, BUFFER_SIZE / stride)) {
 | 
			
		||||
			pw_log_warn("overrun %u > %u", avail, target_buffer * 8);
 | 
			
		||||
			index += avail - target_buffer;
 | 
			
		||||
			timestamp += avail - target_buffer;
 | 
			
		||||
			avail = target_buffer;
 | 
			
		||||
		} else {
 | 
			
		||||
			if (sess->first) {
 | 
			
		||||
				if ((uint32_t)avail > target_buffer) {
 | 
			
		||||
					uint32_t skip = avail - target_buffer;
 | 
			
		||||
					pw_log_debug("first: avail:%d skip:%u target:%u",
 | 
			
		||||
		} else if (sess->first) {
 | 
			
		||||
			if ((uint32_t)avail > target_buffer) {
 | 
			
		||||
				uint32_t skip = avail - target_buffer;
 | 
			
		||||
				pw_log_debug("first: avail:%d skip:%u target:%u",
 | 
			
		||||
							avail, skip, target_buffer);
 | 
			
		||||
					index += skip;
 | 
			
		||||
					avail = target_buffer;
 | 
			
		||||
				}
 | 
			
		||||
				sess->first = false;
 | 
			
		||||
				timestamp += skip;
 | 
			
		||||
				avail = target_buffer;
 | 
			
		||||
			}
 | 
			
		||||
			sess->first = false;
 | 
			
		||||
		}
 | 
			
		||||
		if (!sess->direct_timestamp) {
 | 
			
		||||
			/* when not using direct timestamp and clocks are not
 | 
			
		||||
			 * in sync, try to adjust our playback rate to keep the
 | 
			
		||||
			 * requested target_buffer bytes in the ringbuffer */
 | 
			
		||||
			error = (float)target_buffer - (float)avail;
 | 
			
		||||
			error = SPA_CLAMP(error, -sess->max_error, sess->max_error);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -323,24 +332,25 @@ static void stream_process(void *data)
 | 
			
		|||
			pw_log_debug("avail:%u target:%u error:%f corr:%f", avail,
 | 
			
		||||
					target_buffer, error, corr);
 | 
			
		||||
 | 
			
		||||
			if (sess->rate_match && !sess->direct_timestamp) {
 | 
			
		||||
				SPA_FLAG_SET(sess->rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE);
 | 
			
		||||
			if (sess->rate_match) {
 | 
			
		||||
				SPA_FLAG_SET(sess->rate_match->flags,
 | 
			
		||||
						SPA_IO_RATE_MATCH_FLAG_ACTIVE);
 | 
			
		||||
				sess->rate_match->rate = 1.0f / corr;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		spa_ringbuffer_read_data(&sess->ring,
 | 
			
		||||
				sess->buffer,
 | 
			
		||||
				BUFFER_SIZE,
 | 
			
		||||
				index & BUFFER_MASK,
 | 
			
		||||
				d[0].data, wanted);
 | 
			
		||||
				(timestamp * stride) & BUFFER_MASK,
 | 
			
		||||
				d[0].data, wanted * stride);
 | 
			
		||||
 | 
			
		||||
		index += wanted;
 | 
			
		||||
		spa_ringbuffer_read_update(&sess->ring, index);
 | 
			
		||||
		timestamp += wanted;
 | 
			
		||||
		spa_ringbuffer_read_update(&sess->ring, timestamp);
 | 
			
		||||
	}
 | 
			
		||||
	d[0].chunk->size = wanted;
 | 
			
		||||
	d[0].chunk->stride = sess->info.stride;
 | 
			
		||||
	d[0].chunk->size = wanted * stride;
 | 
			
		||||
	d[0].chunk->stride = stride;
 | 
			
		||||
	d[0].chunk->offset = 0;
 | 
			
		||||
	buf->size = wanted / sess->info.stride;
 | 
			
		||||
	buf->size = wanted;
 | 
			
		||||
 | 
			
		||||
	pw_stream_queue_buffer(sess->stream, buf);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -374,7 +384,7 @@ on_rtp_io(void *data, int fd, uint32_t mask)
 | 
			
		|||
	uint8_t buffer[2048], *payload;
 | 
			
		||||
 | 
			
		||||
	if (mask & SPA_IO_IN) {
 | 
			
		||||
		uint32_t index, expected_index, timestamp;
 | 
			
		||||
		uint32_t stride, read, timestamp, expected_timestamp, samples;
 | 
			
		||||
		uint16_t seq;
 | 
			
		||||
		int32_t filled;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -405,60 +415,45 @@ on_rtp_io(void *data, int fd, uint32_t mask)
 | 
			
		|||
		sess->expected_seq = seq + 1;
 | 
			
		||||
		sess->have_seq = true;
 | 
			
		||||
 | 
			
		||||
		len = SPA_ROUND_DOWN(len - hlen, sess->info.stride);
 | 
			
		||||
		stride = sess->info.stride;
 | 
			
		||||
		samples = (len - hlen) / stride;
 | 
			
		||||
		payload = &buffer[hlen];
 | 
			
		||||
 | 
			
		||||
		filled = spa_ringbuffer_get_write_index(&sess->ring, &index);
 | 
			
		||||
		filled = spa_ringbuffer_get_write_index(&sess->ring, &expected_timestamp);
 | 
			
		||||
 | 
			
		||||
		timestamp = ntohl(hdr->timestamp) - sess->info.ts_offset;
 | 
			
		||||
		expected_index = timestamp * sess->info.stride;
 | 
			
		||||
 | 
			
		||||
		if (sess->direct_timestamp)
 | 
			
		||||
			expected_index += sess->target_buffer;
 | 
			
		||||
		read = ntohl(hdr->timestamp) - sess->info.ts_offset;
 | 
			
		||||
		/* we always write to timestamp + delay */
 | 
			
		||||
		timestamp = read + sess->target_buffer;
 | 
			
		||||
 | 
			
		||||
		if (!sess->have_sync) {
 | 
			
		||||
			sess->ring.readindex = sess->ring.writeindex =
 | 
			
		||||
				index = expected_index;
 | 
			
		||||
			filled = 0;
 | 
			
		||||
			sess->have_sync = true;
 | 
			
		||||
			sess->buffering = true;
 | 
			
		||||
			pw_log_debug("sync to timestamp %u", index);
 | 
			
		||||
			pw_log_info("sync to timestamp %u", read);
 | 
			
		||||
			/* we read from timestamp, keeping target_buffer of data
 | 
			
		||||
			 * in the ringbuffer. */
 | 
			
		||||
			sess->ring.readindex = read;
 | 
			
		||||
			sess->ring.writeindex = timestamp;
 | 
			
		||||
			filled = sess->target_buffer;
 | 
			
		||||
 | 
			
		||||
			spa_dll_init(&sess->dll);
 | 
			
		||||
			spa_dll_set_bw(&sess->dll, SPA_DLL_BW_MIN, 128, sess->info.info.rate);
 | 
			
		||||
 | 
			
		||||
		} else if (expected_index != index) {
 | 
			
		||||
			sess->have_sync = true;
 | 
			
		||||
		} else if (expected_timestamp != timestamp) {
 | 
			
		||||
			pw_log_debug("unexpected timestamp (%u != %u)",
 | 
			
		||||
					index / sess->info.stride,
 | 
			
		||||
					expected_index / sess->info.stride);
 | 
			
		||||
			index = expected_index;
 | 
			
		||||
			filled = 0;
 | 
			
		||||
					timestamp, expected_timestamp);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (filled + len > BUFFER_SIZE) {
 | 
			
		||||
			pw_log_debug("got rtp, capture overrun %u %zd", filled, len);
 | 
			
		||||
		if (filled + samples > BUFFER_SIZE / stride) {
 | 
			
		||||
			pw_log_debug("capture overrun %u + %u > %u", filled, samples,
 | 
			
		||||
					BUFFER_SIZE / stride);
 | 
			
		||||
			sess->have_sync = false;
 | 
			
		||||
		} else {
 | 
			
		||||
			uint32_t target_buffer;
 | 
			
		||||
 | 
			
		||||
			pw_log_trace("got rtp packet len:%zd", len);
 | 
			
		||||
			pw_log_trace("got samples:%u", samples);
 | 
			
		||||
			spa_ringbuffer_write_data(&sess->ring,
 | 
			
		||||
					sess->buffer,
 | 
			
		||||
					BUFFER_SIZE,
 | 
			
		||||
					index & BUFFER_MASK,
 | 
			
		||||
					payload, len);
 | 
			
		||||
			index += len;
 | 
			
		||||
			filled += len;
 | 
			
		||||
			spa_ringbuffer_write_update(&sess->ring, index);
 | 
			
		||||
 | 
			
		||||
			sess->last_packet_size = len;
 | 
			
		||||
			target_buffer = sess->target_buffer + len/2;
 | 
			
		||||
 | 
			
		||||
			if (sess->buffering && (uint32_t)filled > target_buffer) {
 | 
			
		||||
				sess->buffering = false;
 | 
			
		||||
				pw_log_debug("buffering done %u > %u",
 | 
			
		||||
					filled, target_buffer);
 | 
			
		||||
			}
 | 
			
		||||
					(timestamp * stride) & BUFFER_MASK,
 | 
			
		||||
					payload, (samples * stride));
 | 
			
		||||
			timestamp += samples;
 | 
			
		||||
			spa_ringbuffer_write_update(&sess->ring, timestamp);
 | 
			
		||||
		}
 | 
			
		||||
		sess->receiving = true;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -559,9 +554,9 @@ error:
 | 
			
		|||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t msec_to_bytes(struct sdp_info *info, uint32_t msec)
 | 
			
		||||
static uint32_t msec_to_samples(struct sdp_info *info, uint32_t msec)
 | 
			
		||||
{
 | 
			
		||||
	return msec * info->stride * info->info.rate / 1000;
 | 
			
		||||
	return msec * info->info.rate / 1000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void session_free(struct session *sess)
 | 
			
		||||
| 
						 | 
				
			
			@ -736,12 +731,12 @@ static int session_new(struct impl *impl, struct sdp_info *info)
 | 
			
		|||
	sess_latency_msec = pw_properties_get_uint32(props,
 | 
			
		||||
			"sess.latency.msec", impl->sess_latency_msec);
 | 
			
		||||
 | 
			
		||||
	session->target_buffer = msec_to_bytes(info, sess_latency_msec);
 | 
			
		||||
	session->max_error = msec_to_bytes(info, ERROR_MSEC);
 | 
			
		||||
	session->target_buffer = msec_to_samples(info, sess_latency_msec);
 | 
			
		||||
	session->max_error = msec_to_samples(info, ERROR_MSEC);
 | 
			
		||||
 | 
			
		||||
	pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%d", info->info.rate);
 | 
			
		||||
	pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%d/%d",
 | 
			
		||||
			session->target_buffer / (2 * info->stride), info->info.rate);
 | 
			
		||||
			session->target_buffer / 2, info->info.rate);
 | 
			
		||||
 | 
			
		||||
	spa_dll_init(&session->dll);
 | 
			
		||||
	spa_dll_set_bw(&session->dll, SPA_DLL_BW_MIN, 128, session->info.info.rate);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue