diff --git a/openbsc/contrib/testconv/testconv_main.c b/openbsc/contrib/testconv/testconv_main.c
index c2785f2..aee7304 100644
--- a/openbsc/contrib/testconv/testconv_main.c
+++ b/openbsc/contrib/testconv/testconv_main.c
@@ -38,10 +38,10 @@ int mgcp_get_trans_frame_size(void *state_, int nsamples, int dst);
 
 int main(int argc, char **argv)
 {
-	char buf[4096] = {0};
+	char buf[4096] = {0x80, 0};
 	int cc, rc;
-	struct mgcp_rtp_end dst_end = {0};
-	struct mgcp_rtp_end src_end = {0};
+	struct mgcp_rtp_end *dst_end;
+	struct mgcp_rtp_end *src_end;
 	struct mgcp_trunk_config tcfg = {{0}};
 	struct mgcp_endpoint endp = {0};
 	struct mgcp_process_rtp_state *state;
@@ -52,39 +52,63 @@ int main(int argc, char **argv)
 	tcfg.endpoints = &endp;
 	tcfg.number_endpoints = 1;
 	endp.tcfg = &tcfg;
+	mgcp_free_endp(&endp);
+
+	dst_end = &endp.bts_end;
+	src_end = &endp.net_end;
 
 	if (argc <= 2)
 		errx(1, "Usage: {gsm|g729|pcma|l16} {gsm|g729|pcma|l16}");
 
-	if ((src_end.payload_type = audio_name_to_type(argv[1])) == -1)
+	if ((src_end->payload_type = audio_name_to_type(argv[1])) == -1)
 		errx(1, "invalid input format '%s'", argv[1]);
-	if ((dst_end.payload_type = audio_name_to_type(argv[2])) == -1)
+	if ((dst_end->payload_type = audio_name_to_type(argv[2])) == -1)
 		errx(1, "invalid output format '%s'", argv[2]);
 
-	rc = mgcp_transcoding_setup(&endp, &dst_end, &src_end);
+	rc = mgcp_transcoding_setup(&endp, dst_end, src_end);
 	if (rc < 0)
 		errx(1, "setup failed: %s", strerror(-rc));
 
-	state = dst_end.rtp_process_data;
+	state = dst_end->rtp_process_data;
 	OSMO_ASSERT(state != NULL);
 
 	in_size = mgcp_transcoding_get_frame_size(state, 160, 0);
 	OSMO_ASSERT(sizeof(buf) >= in_size + 12);
 
+	buf[1] = src_end->payload_type;
+	*(uint16_t*)(buf+2) = htons(1);
+	*(uint32_t*)(buf+4) = htonl(0);
+	*(uint32_t*)(buf+8) = htonl(0xaabbccdd);
+
 	while ((cc = read(0, buf + 12, in_size))) {
+		int cont;
+		int len;
+
 		if (cc != in_size)
 			err(1, "read");
 
 		cc += 12; /* include RTP header */
 
-		rc = mgcp_transcoding_process_rtp(&endp, &dst_end,
-						  buf, &cc, sizeof(buf));
-		if (rc < 0)
-			errx(1, "processing failed: %s", strerror(-rc));
+		len = cc;
+
+		do {
+			cont = mgcp_transcoding_process_rtp(&endp, dst_end,
+							buf, &len, sizeof(buf));
+			if (cont == -EAGAIN) {
+				fprintf(stderr, "Got EAGAIN\n");
+				break;
+			}
+
+			if (cont < 0)
+				errx(1, "processing failed: %s", strerror(-cont));
+
+			len -= 12; /* ignore RTP header */
+
+			if (write(1, buf + 12, len) != len)
+				err(1, "write");
 
-		cc -= 12; /* ignore RTP header */
-		if (write(1, buf + 12, cc) != cc)
-			err(1, "write");
+			len = cont;
+		} while (len > 0);
 	}
 	return 0;
 }
diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h
index b595aba..eb64e32 100644
--- a/openbsc/include/openbsc/mgcp.h
+++ b/openbsc/include/openbsc/mgcp.h
@@ -87,7 +87,8 @@ typedef int (*mgcp_policy)(struct mgcp_trunk_config *cfg, int endpoint, int stat
 typedef int (*mgcp_reset)(struct mgcp_trunk_config *cfg);
 typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
 
-typedef int (*mgcp_processing)(struct mgcp_rtp_end *dst_end,
+typedef int (*mgcp_processing)(struct mgcp_endpoint *endp,
+			       struct mgcp_rtp_end *dst_end,
 			       char *data, int *len, int buf_size);
 typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp,
 				     struct mgcp_rtp_end *dst_end,
@@ -181,6 +182,8 @@ struct mgcp_config {
 	struct mgcp_port_range transcoder_ports;
 	int endp_dscp;
 
+	int bts_force_ptime;
+
 	mgcp_change change_cb;
 	mgcp_policy policy_cb;
 	mgcp_reset reset_cb;
diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h
index e74b9fa..c7bc2a8 100644
--- a/openbsc/include/openbsc/mgcp_internal.h
+++ b/openbsc/include/openbsc/mgcp_internal.h
@@ -90,6 +90,7 @@ struct mgcp_rtp_end {
 	char *audio_name;
 	char *subtype_name;
 	int output_enabled;
+	int force_output_ptime;
 
 	/* RTP patching */
 	int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
@@ -202,7 +203,7 @@ void mgcp_state_calc_loss(struct mgcp_rtp_state *s, struct mgcp_rtp_end *,
 uint32_t mgcp_state_calc_jitter(struct mgcp_rtp_state *);
 
 /* payload processing default functions */
-int mgcp_rtp_processing_default(struct mgcp_rtp_end *dst_end,
+int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
 				char *data, int *len, int buf_size);
 
 int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c
index dcbb97a..42f0381 100644
--- a/openbsc/src/libmgcp/mgcp_network.c
+++ b/openbsc/src/libmgcp/mgcp_network.c
@@ -348,7 +348,7 @@ static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp,
 	return timestamp_error;
 }
 
-int mgcp_rtp_processing_default(struct mgcp_rtp_end *dst_end,
+int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
 				char *data, int *len, int buf_size)
 {
 	return 0;
@@ -622,12 +622,28 @@ static int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp,
 	if (!rtp_end->output_enabled)
 		rtp_end->dropped_packets += 1;
 	else if (is_rtp) {
-		mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, buf, rc);
-		endp->cfg->rtp_processing_cb(rtp_end, buf, &rc, RTP_BUF_SIZE);
-		forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx], buf, rc);
-		return mgcp_udp_send(rtp_end->rtp.fd,
-				     &rtp_end->addr,
-				     rtp_end->rtp_port, buf, rc);
+		int cont;
+		int nbytes = 0;
+		int len = rc;
+		mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, buf, len);
+		do {
+			cont = endp->cfg->rtp_processing_cb(endp, rtp_end,
+							buf, &len, RTP_BUF_SIZE);
+			if (cont < 0)
+				break;
+
+			forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx],
+				     buf, len);
+			rc = mgcp_udp_send(rtp_end->rtp.fd,
+					   &rtp_end->addr,
+					   rtp_end->rtp_port, buf, len);
+
+			if (rc <= 0)
+				return rc;
+			nbytes += rc;
+			len = cont;
+		} while (len > 0);
+		return nbytes;
 	} else if (!tcfg->omit_rtcp) {
 		return mgcp_udp_send(rtp_end->rtcp.fd,
 				     &rtp_end->addr,
diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c
index f0d94c8..a903e3c 100644
--- a/openbsc/src/libmgcp/mgcp_protocol.c
+++ b/openbsc/src/libmgcp/mgcp_protocol.c
@@ -604,6 +604,12 @@ static int set_audio_info(void *ctx, struct mgcp_rtp_end *rtp,
 	rtp->channels = channels;
 	rtp->subtype_name = talloc_strdup(ctx, audio_codec);
 	rtp->audio_name = talloc_strdup(ctx, audio_name);
+
+	if (!strcmp(audio_codec, "G729")) {
+		rtp->frame_duration_num = 10;
+		rtp->frame_duration_den = 1000;
+	}
+
 	if (channels != 1)
 		LOGP(DMGCP, LOGL_NOTICE,
 		     "Channels != 1 in SDP: '%s'\n", audio_name);
@@ -916,11 +922,16 @@ mgcp_header_done:
 	set_audio_info(p->cfg, &endp->bts_end, tcfg->audio_payload, tcfg->audio_name);
 	endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints,
 						tcfg->audio_fmtp_extra);
-	if (have_sdp) {
+	if (have_sdp)
 		parse_sdp_data(&endp->net_end, p);
-		setup_rtp_processing(endp);
+
+	if (p->cfg->bts_force_ptime) {
+		endp->bts_end.packet_duration_ms = p->cfg->bts_force_ptime;
+		endp->bts_end.force_output_ptime = 1;
 	}
 
+	setup_rtp_processing(endp);
+
 	/* policy CB */
 	if (p->cfg->policy_cb) {
 		int rc;
diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c
index 953d34b..f1afa95 100644
--- a/openbsc/src/libmgcp/mgcp_vty.c
+++ b/openbsc/src/libmgcp/mgcp_vty.c
@@ -362,6 +362,26 @@ ALIAS_DEPRECATED(cfg_mgcp_rtp_ip_dscp, cfg_mgcp_rtp_ip_tos_cmd,
       RTP_STR
       "Apply IP_TOS to the audio stream\n" "The DSCP value\n")
 
+#define FORCE_PTIME_STR "Force a fixed ptime for packets sent to the BTS"
+DEFUN(cfg_mgcp_rtp_force_ptime,
+      cfg_mgcp_rtp_force_ptime_cmd,
+      "rtp force-ptime (10|20|40)",
+      RTP_STR FORCE_PTIME_STR
+      "The required ptime (packet duration) in ms\n")
+{
+	g_cfg->bts_force_ptime = atoi(argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_no_rtp_force_ptime,
+      cfg_mgcp_no_rtp_force_ptime_cmd,
+      "no rtp force-ptime",
+      NO_STR RTP_STR FORCE_PTIME_STR)
+{
+	g_cfg->bts_force_ptime = 0;
+	return CMD_SUCCESS;
+}
+
 DEFUN(cfg_mgcp_sdp_fmtp_extra,
       cfg_mgcp_sdp_fmtp_extra_cmd,
       "sdp audio fmtp-extra .NAME",
@@ -1084,6 +1104,8 @@ int mgcp_vty_init(void)
 	install_element(MGCP_NODE, &cfg_mgcp_rtp_transcoder_base_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd);
+	install_element(MGCP_NODE, &cfg_mgcp_rtp_force_ptime_cmd);
+	install_element(MGCP_NODE, &cfg_mgcp_no_rtp_force_ptime_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_once_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_no_rtp_keepalive_cmd);
diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c
index 67e7e52..edd3178 100644
--- a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c
+++ b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c
@@ -1,5 +1,4 @@
 /*
- * (C) 2014 by Sysmocom s.f.m.c. GmbH
  * (C) 2014 by On-Waves
  * All Rights Reserved
  *
@@ -22,7 +21,8 @@
 #include <string.h>
 #include <errno.h>
 
-#include "bscconfig.h"
+
+#include "../../bscconfig.h"
 
 #include "g711common.h"
 #include <gsm.h>
@@ -70,6 +70,14 @@ struct mgcp_process_rtp_state {
 	} dst;
 	size_t dst_frame_size;
 	size_t dst_samples_per_frame;
+	int dst_packet_duration;
+
+	int is_running;
+	uint16_t next_seq;
+	uint32_t next_time;
+	int16_t samples[10*160];
+	size_t sample_cnt;
+	size_t sample_offs;
 };
 
 int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst)
@@ -302,6 +310,9 @@ int mgcp_transcoding_setup(struct mgcp_endpoint *endp,
 		break;
 	}
 
+	if (dst_end->force_output_ptime)
+		state->dst_packet_duration = mgcp_rtp_packet_duration(endp, dst_end);
+
 	LOGP(DMGCP, LOGL_INFO,
 	     "Initialized RTP processing on: 0x%x "
 	     "conv: %d (%d, %d, %s) -> %d (%d, %d, %s)\n",
@@ -330,44 +341,21 @@ void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp,
 	*audio_name = endp->net_end.audio_name;
 }
 
-
-int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp,
-				 struct mgcp_rtp_end *dst_end,
-				 char *data, int *len, int buf_size)
+static int decode_audio(struct mgcp_process_rtp_state *state,
+			uint8_t **src, size_t *nbytes)
 {
-	struct mgcp_process_rtp_state *state = dst_end->rtp_process_data;
-	size_t rtp_hdr_size = 12;
-	char *payload_data = data + rtp_hdr_size;
-	int payload_len = *len - rtp_hdr_size;
-	size_t sample_cnt = 0;
-	size_t sample_idx;
-	int16_t samples[10*160];
-	uint8_t *src = (uint8_t *)payload_data;
-	uint8_t *dst = (uint8_t *)payload_data;
-	size_t nbytes = payload_len;
-	size_t frame_remainder;
-
-	if (!state)
-		return 0;
-
-	if (state->src_fmt == state->dst_fmt)
-		return 0;
-
-	/* TODO: check payload type (-> G.711 comfort noise) */
-
-	/* Decode src into samples */
-	while (nbytes >= state->src_frame_size) {
-		if (sample_cnt + state->src_samples_per_frame > ARRAY_SIZE(samples)) {
+	while (*nbytes >= state->src_frame_size) {
+		if (state->sample_cnt + state->src_samples_per_frame > ARRAY_SIZE(state->samples)) {
 			LOGP(DMGCP, LOGL_ERROR,
 			     "Sample buffer too small: %d > %d.\n",
-			     sample_cnt + state->src_samples_per_frame,
-			     ARRAY_SIZE(samples));
+			     state->sample_cnt + state->src_samples_per_frame,
+			     ARRAY_SIZE(state->samples));
 			return -ENOSPC;
 		}
 		switch (state->src_fmt) {
 		case AF_GSM:
 			if (gsm_decode(state->src.gsm_handle,
-				       (gsm_byte *)src, samples + sample_cnt) < 0) {
+				       (gsm_byte *)*src, state->samples + state->sample_cnt) < 0) {
 				LOGP(DMGCP, LOGL_ERROR,
 				     "Failed to decode GSM.\n");
 				return -EINVAL;
@@ -375,54 +363,44 @@ int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp,
 			break;
 #ifdef HAVE_BCG729
 		case AF_G729:
-			bcg729Decoder(state->src.g729_dec, src, 0, samples + sample_cnt);
+			bcg729Decoder(state->src.g729_dec, *src, 0, state->samples + state->sample_cnt);
 			break;
 #endif
 		case AF_PCMA:
-			alaw_decode(src, samples + sample_cnt,
+			alaw_decode(*src, state->samples + state->sample_cnt,
 				    state->src_samples_per_frame);
 			break;
 		case AF_S16:
-			memmove(samples + sample_cnt, src,
+			memmove(state->samples + state->sample_cnt, *src,
 				state->src_frame_size);
 			break;
 		case AF_L16:
-			l16_decode(src, samples + sample_cnt,
+			l16_decode(*src, state->samples + state->sample_cnt,
 				   state->src_samples_per_frame);
 			break;
 		default:
 			break;
 		}
-		src        += state->src_frame_size;
-		nbytes     -= state->src_frame_size;
-		sample_cnt += state->src_samples_per_frame;
-	}
-
-	/* Add silence if necessary */
-	frame_remainder = sample_cnt % state->dst_samples_per_frame;
-	if (frame_remainder) {
-		size_t silence = state->dst_samples_per_frame - frame_remainder;
-		if (sample_cnt + silence > ARRAY_SIZE(samples)) {
-			LOGP(DMGCP, LOGL_ERROR,
-			     "Sample buffer too small for silence: %d > %d.\n",
-			     sample_cnt + silence,
-			     ARRAY_SIZE(samples));
-			return -ENOSPC;
-		}
-
-		while (silence > 0) {
-			samples[sample_cnt] = 0;
-			sample_cnt += 1;
-			silence -= 1;
-		}
+		*src        += state->src_frame_size;
+		*nbytes     -= state->src_frame_size;
+		state->sample_cnt += state->src_samples_per_frame;
 	}
+	return 0;
+}
 
+static int encode_audio(struct mgcp_process_rtp_state *state,
+			uint8_t *dst, size_t buf_size, size_t max_samples)
+{
+	int nbytes = 0;
+	size_t nsamples = 0;
 	/* Encode samples into dst */
-	sample_idx = 0;
-	nbytes = 0;
-	while (sample_idx + state->dst_samples_per_frame <= sample_cnt) {
+	while (nsamples + state->dst_samples_per_frame <= max_samples) {
 		if (nbytes + state->dst_frame_size > buf_size) {
-			LOGP(DMGCP, LOGL_ERROR,
+			if (nbytes > 0)
+				break;
+
+			/* Not even one frame fits into the buffer */
+			LOGP(DMGCP, LOGL_INFO,
 			     "Encoding (RTP) buffer too small: %d > %d.\n",
 			     nbytes + state->dst_frame_size, buf_size);
 			return -ENOSPC;
@@ -430,23 +408,24 @@ int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp,
 		switch (state->dst_fmt) {
 		case AF_GSM:
 			gsm_encode(state->dst.gsm_handle,
-				   samples + sample_idx, dst);
+				   state->samples + state->sample_offs, dst);
 			break;
 #ifdef HAVE_BCG729
 		case AF_G729:
 			bcg729Encoder(state->dst.g729_enc,
-				      samples + sample_idx, dst);
+				      state->samples + state->sample_offs, dst);
 			break;
 #endif
 		case AF_PCMA:
-			alaw_encode(samples + sample_idx, dst,
+			alaw_encode(state->samples + state->sample_offs, dst,
 				    state->src_samples_per_frame);
 			break;
 		case AF_S16:
-			memmove(dst, samples + sample_idx, state->dst_frame_size);
+			memmove(dst, state->samples + state->sample_offs,
+				state->dst_frame_size);
 			break;
 		case AF_L16:
-			l16_encode(samples + sample_idx, dst,
+			l16_encode(state->samples + state->sample_offs, dst,
 				   state->src_samples_per_frame);
 			break;
 		default:
@@ -454,12 +433,121 @@ int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp,
 		}
 		dst        += state->dst_frame_size;
 		nbytes     += state->dst_frame_size;
-		sample_idx += state->dst_samples_per_frame;
+		state->sample_offs += state->dst_samples_per_frame;
+		nsamples   += state->dst_samples_per_frame;
 	}
+	state->sample_cnt -= nsamples;
+	return nbytes;
+}
 
-	*len = rtp_hdr_size + nbytes;
-	/* Patch payload type */
-	data[1] = (data[1] & 0x80) | (dst_end->payload_type & 0x7f);
+int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp,
+				struct mgcp_rtp_end *dst_end,
+			     char *data, int *len, int buf_size)
+{
+	struct mgcp_process_rtp_state *state = dst_end->rtp_process_data;
+	size_t rtp_hdr_size = 12;
+	char *payload_data = data + rtp_hdr_size;
+	int payload_len = *len - rtp_hdr_size;
+	// size_t sample_idx;
+	uint8_t *src = (uint8_t *)payload_data;
+	uint8_t *dst = (uint8_t *)payload_data;
+	size_t nbytes = payload_len;
+	// size_t frame_remainder;
+	size_t nsamples;
+	size_t max_samples;
+	uint32_t ts_no;
+	int rc;
 
-	return 0;
+	if (!state)
+		return 0;
+
+	if (state->src_fmt == state->dst_fmt) {
+		if (!state->dst_packet_duration)
+			return 0;
+
+		/* TODO: repackage without transcoding */
+	}
+
+	/* If the remaining samples do not fit into a fixed ptime,
+	 * a) discard them, if the next packet is much later
+	 * b) add silence and * send it, if the current packet is not
+	 *    yet too late
+	 * c) append the sample data, if the timestamp matches exactly
+	 */
+
+	/* TODO: check payload type (-> G.711 comfort noise) */
+
+	if (payload_len > 0) {
+		ts_no = ntohl(*(uint32_t*)(data+4));
+		if (!state->is_running)
+			state->next_seq = ntohs(*(uint32_t*)(data+4));
+
+		state->is_running = 1;
+
+		if (state->sample_cnt > 0) {
+			int32_t delta = ts_no - state->next_time;
+			/* TODO: check sequence? reordering? packet loss? */
+
+			if (delta > state->sample_cnt)
+				/* There is a time gap between the last packet
+				 * and the current one. Just discard the
+				 * partial data that is left in the buffer.
+				 * TODO: This can be improved by adding silence
+				 * instead if the delta is small enough.
+				 */
+				state->sample_cnt = 0;
+			else if (delta < 0) {
+				LOGP(DMGCP, LOGL_NOTICE,
+				     "RTP time jumps backwards, delta = %d, "
+				     "discarding buffered samples\n",
+				     delta);
+				state->sample_cnt = 0;
+				state->sample_offs = 0;
+				return -EAGAIN;
+			}
+
+			/* Make sure the samples start without offset */
+			fprintf(stderr, "Moving %d samples to buffer start (offset %d)\n", state->sample_cnt, state->sample_offs);
+			if (state->sample_offs && state->sample_cnt)
+				memmove(&state->samples[0],
+					&state->samples[state->sample_offs],
+					state->sample_cnt * sizeof(state->samples[0]));
+		}
+
+		state->sample_offs = 0;
+
+		/* Append decoded audio to samples */
+		decode_audio(state, &src, &nbytes);
+
+		if (nbytes > 0)
+			LOGP(DMGCP, LOGL_NOTICE,
+			     "Skipped audio frame in RTP packet: %d octets\n",
+			     nbytes);
+	} else
+		ts_no = state->next_time;
+
+	if (state->sample_cnt < state->dst_packet_duration)
+		return -EAGAIN;
+
+	max_samples =
+		state->dst_packet_duration ?
+		state->dst_packet_duration : state->sample_cnt;
+
+	nsamples = state->sample_cnt;
+
+	rc = encode_audio(state, dst, buf_size, max_samples);
+	if (rc <= 0)
+		return rc;
+
+	nsamples -= state->sample_cnt;
+	fprintf(stderr, "Wrote %d samples to buffer (offset %d)\n", nsamples, state->sample_offs);
+
+	*len = rtp_hdr_size + rc;
+	*(uint16_t*)(data+2) = htonl(state->next_seq);
+	*(uint32_t*)(data+4) = htonl(ts_no);
+
+	state->next_seq += 1;
+	state->next_time = ts_no + nsamples;
+
+	return nsamples ? rtp_hdr_size : 0;
 }
