prepare gapk for dealing with variable-length frames

The existing architecture was modelled around fixed-length codec frame
sizes, which of course fails with multi-rate codecs such as AMR.
diff --git a/src/codec_efr.c b/src/codec_efr.c
index a42b2a7..877a9eb 100644
--- a/src/codec_efr.c
+++ b/src/codec_efr.c
@@ -26,6 +26,7 @@
 #ifdef HAVE_OPENCORE_AMRNB
 
 #include <stdlib.h>
+#include <assert.h>
 
 #include <opencore-amrnb/interf_dec.h>
 #include <opencore-amrnb/interf_enc.h>
@@ -64,11 +65,12 @@
 }
 
 static int
-codec_efr_encode(void *state, uint8_t *cod, const uint8_t *pcm)
+codec_efr_encode(void *state, uint8_t *cod, const uint8_t *pcm, unsigned int pcm_len)
 {
 	struct codec_efr_state *st = state;
 	int rv;
 
+	assert(pcm_len == PCM_CANON_LEN);
 	BENCHMARK_START;
 	rv = Encoder_Interface_Encode(
 		st->encoder,
@@ -79,14 +81,18 @@
 	);
 	BENCHMARK_STOP(CODEC_EFR, 1);
 
-	return rv != 32;
+	if (rv != 32)
+		return -1;
+
+	return EFR_CANON_LEN;
 }
 
 static int
-codec_efr_decode(void *state, uint8_t *pcm, const uint8_t *cod)
+codec_efr_decode(void *state, uint8_t *pcm, const uint8_t *cod, unsigned int cod_len)
 {
 	struct codec_efr_state *st = state;
 
+	assert(cod_len == EFR_CANON_LEN);
 	BENCHMARK_START;
 	Decoder_Interface_Decode(
 		st->decoder,
@@ -96,7 +102,7 @@
 	);
 	BENCHMARK_STOP(CODEC_EFR, 0);
 
-	return 0;
+	return PCM_CANON_LEN;
 }
 
 #endif /* HAVE_OPENCORE_AMRNB */
diff --git a/src/codec_fr.c b/src/codec_fr.c
index 182eb73..2ce44b4 100644
--- a/src/codec_fr.c
+++ b/src/codec_fr.c
@@ -17,6 +17,8 @@
  * along with gapk.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <assert.h>
+
 #include <gapk/codecs.h>
 #include <gapk/benchmark.h>
 
@@ -50,28 +52,32 @@
 }
 
 static int
-codec_fr_encode(void *state, uint8_t *cod, const uint8_t *pcm)
+codec_fr_encode(void *state, uint8_t *cod, const uint8_t *pcm, unsigned int pcm_len)
 {
 	gsm gh = (gsm)state;
-	uint8_t pcm_b[2*160];	/* local copy as libgsm src isn't const ! */
-	memcpy(pcm_b, pcm, 2*160);
+	uint8_t pcm_b[PCM_CANON_LEN];	/* local copy as libgsm src isn't const ! */
+	assert(pcm_len == PCM_CANON_LEN);
+	memcpy(pcm_b, pcm, PCM_CANON_LEN);
 	BENCHMARK_START;
 	gsm_encode(gh, (gsm_signal*)pcm, (gsm_byte*)cod);
 	BENCHMARK_STOP(CODEC_FR, 1);
-	return 0;
+	return FR_CANON_LEN;
 }
 
 static int
-codec_fr_decode(void *state, uint8_t *pcm, const uint8_t *cod)
+codec_fr_decode(void *state, uint8_t *pcm, const uint8_t *cod, unsigned int cod_len)
 {
 	gsm gh = (gsm)state;
-	uint8_t cod_b[33];	/* local copy as libgsm src isn't const ! */
+	uint8_t cod_b[FR_CANON_LEN];	/* local copy as libgsm src isn't const ! */
 	int rc;
-	memcpy(cod_b, cod, 33);
+	assert(cod_len == FR_CANON_LEN);
+	memcpy(cod_b, cod, FR_CANON_LEN);
 	BENCHMARK_START;
 	rc = gsm_decode(gh, (gsm_byte*)cod_b, (gsm_signal*)pcm);
 	BENCHMARK_STOP(CODEC_FR, 1);
-	return rc;
+	if (rc < 0)
+		return rc;
+	return PCM_CANON_LEN;
 }
 
 #endif /* HAVE_LIBGSM */
diff --git a/src/codec_hr.c b/src/codec_hr.c
index 4377f19..0b16985 100644
--- a/src/codec_hr.c
+++ b/src/codec_hr.c
@@ -17,6 +17,8 @@
  * along with gapk.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <assert.h>
+
 #include <gapk/codecs.h>
 #include <gapk/benchmark.h>
 
@@ -41,25 +43,31 @@
 }
 
 static int
-codec_hr_encode(void *_state, uint8_t *cod, const uint8_t *pcm)
+codec_hr_encode(void *_state, uint8_t *cod, const uint8_t *pcm, unsigned int pcm_len)
 {
 	struct gsmhr *state = _state;
 	int rc;
+	assert(pcm_len == PCM_CANON_LEN);
 	BENCHMARK_START;
 	rc = gsmhr_encode(state, (int16_t *)cod, (const int16_t *)pcm);
 	BENCHMARK_STOP(CODEC_HR, 1);
-	return rc;
+	if (rc < 0)
+		return rc;
+	return HR_CANON_LEN;
 }
 
 static int
-codec_hr_decode(void *_state, uint8_t *pcm, const uint8_t *cod)
+codec_hr_decode(void *_state, uint8_t *pcm, const uint8_t *cod, unsigned int cod_len)
 {
 	struct gsmhr *state = _state;
 	int rc;
+	assert(cod_len == HR_CANON_LEN);
 	BENCHMARK_START;
 	rc = gsmhr_decode(state, (int16_t *)pcm, (const int16_t *)cod);
 	BENCHMARK_STOP(CODEC_HR, 0);
-	return rc;
+	if (rc < 0)
+		return rc;
+	return PCM_CANON_LEN;
 }
 
 #endif /* HAVE_LIBGSMHR */
diff --git a/src/fmt_amr.c b/src/fmt_amr.c
index 2990d7c..e28024c 100644
--- a/src/fmt_amr.c
+++ b/src/fmt_amr.c
@@ -18,6 +18,7 @@
  */
 
 #include <stdint.h>
+#include <assert.h>
 
 #include <osmocom/codec/codec.h>
 
@@ -25,13 +26,16 @@
 #include <gapk/formats.h>
 #include <gapk/utils.h>
 
+#define EFR_LEN		32
 
 /* conversion function: .amr file -> canonical format */
 static int
-amr_efr_from_canon(uint8_t *dst, const uint8_t *src)
+amr_efr_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 
+	assert(src_len == EFR_CANON_LEN);
+
 	dst[ 0] = 0x3c;
 	dst[31] = 0x00;	/* last nibble won't written, pre-clear it */
 
@@ -41,15 +45,17 @@
 		msb_put_bit(&dst[1], di, msb_get_bit(src, si));
 	}
 
-	return 0;
+	return EFR_LEN;
 }
 
 /* conversion function: canonical format -> .amr file */
 static int
-amr_efr_to_canon(uint8_t *dst, const uint8_t *src)
+amr_efr_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 
+	assert(src_len == EFR_LEN);
+
 	if (src[0] != 0x3c)
 		return -1;
 
@@ -61,7 +67,7 @@
 		msb_put_bit(dst, di, msb_get_bit(&src[1], si));
 	}
 
-	return 0;
+	return EFR_CANON_LEN;
 }
 
 const struct format_desc fmt_amr_efr = {
@@ -70,7 +76,7 @@
 	.name			= "amr-efr",
 	.description		= "Classic .amr file containing EFR (=AMR 12.2k) data",
 
-	.frame_len		= 32,
+	.frame_len		= EFR_LEN,
 	.conv_from_canon	= amr_efr_from_canon,
 	.conv_to_canon		= amr_efr_to_canon,
 
diff --git a/src/fmt_gsm.c b/src/fmt_gsm.c
index 8156bee..604b865 100644
--- a/src/fmt_gsm.c
+++ b/src/fmt_gsm.c
@@ -17,36 +17,41 @@
  * along with gapk.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <assert.h>
 #include <gapk/codecs.h>
 #include <gapk/formats.h>
 
-
+#define GSM_LEN	  33
 #define GSM_MAGIC 0xd
 
 /* convert canonical -> .gsm */
 static int
-gsm_from_canon(uint8_t *dst, const uint8_t *src)
+gsm_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 
+	assert(src_len == FR_CANON_LEN);
+
 	dst[0] = (GSM_MAGIC << 4) | (src[0] >> 4);
-	for (i=1; i<33; i++)
+	for (i=1; i<GSM_LEN; i++)
 		dst[i] = (src[i-1] << 4) | (src[i] >> 4);
 
-	return 0;
+	return GSM_LEN;
 }
 
 /* convert .gsm -> canonical */
 static int
-gsm_to_canon(uint8_t *dst, const uint8_t *src)
+gsm_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 
-	for (i=0; i<32; i++)
-		dst[i] = (src[i] << 4) | (src[i+1] >> 4);
-	dst[32] = src[32] << 4;
+	assert(src_len == GSM_LEN);
 
-	return 0;
+	for (i=0; i<(GSM_LEN-1); i++)
+		dst[i] = (src[i] << 4) | (src[i+1] >> 4);
+	dst[GSM_LEN-1] = src[GSM_LEN-1] << 4;
+
+	return FR_CANON_LEN;
 }
 
 const struct format_desc fmt_gsm = {
@@ -55,7 +60,7 @@
 	.name			= "gsm",
 	.description		= "Classic .gsm file format",
 
-	.frame_len		= 33,
+	.frame_len		= GSM_LEN,
 	.conv_from_canon	= gsm_from_canon,
 	.conv_to_canon		= gsm_to_canon,
 };
diff --git a/src/fmt_hr_ref.c b/src/fmt_hr_ref.c
index 7a96d3e..32e8d48 100644
--- a/src/fmt_hr_ref.c
+++ b/src/fmt_hr_ref.c
@@ -20,10 +20,14 @@
  * along with gapk.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <assert.h>
+
 #include <gapk/codecs.h>
 #include <gapk/formats.h>
 #include <gapk/utils.h>
 
+#define HR_REF_DEC_LEN	(22 * sizeof(uint16_t))
+#define HR_REF_ENC_LEN	(20 * sizeof(uint16_t))
 
 static const int params_unvoiced[] = {
 	5,	/* R0 */
@@ -122,11 +126,13 @@
 }
 
 static int
-hr_ref_dec_from_canon(uint8_t *dst, const uint8_t *src)
+hr_ref_dec_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	uint16_t *hr_ref = (uint16_t *)dst;
 	int rv;
 
+	assert(src_len == HR_CANON_LEN);
+
 	rv = hr_ref_from_canon(hr_ref, src);
 	if (rv)
 		return rv;
@@ -136,28 +142,32 @@
 	hr_ref[20] = 0;		/* SID : 2 bit */
 	hr_ref[21] = 0;		/* TAF : 1 bit */
 
-	return 0;
+	return HR_REF_DEC_LEN;
 }
 
 static int
-hr_ref_dec_to_canon(uint8_t *dst, const uint8_t *src)
+hr_ref_dec_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	const uint16_t *hr_ref = (const uint16_t *)src;
 	int rv;
 
+	assert(src_len == HR_REF_DEC_LEN);
+
 	rv = hr_ref_to_canon(dst, hr_ref);
 	if (rv)
 		return rv;
 
-	return 0;
+	return HR_CANON_LEN;
 }
 
 static int
-hr_ref_enc_from_canon(uint8_t *dst, const uint8_t *src)
+hr_ref_enc_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	uint16_t *hr_ref = (uint16_t *)dst;
 	int rv;
 
+	assert(src_len == HR_CANON_LEN);
+
 	rv = hr_ref_from_canon(hr_ref, src);
 	if (rv)
 		return rv;
@@ -165,20 +175,22 @@
 	hr_ref[18] = 0;		/* SP  : 1 bit */
 	hr_ref[19] = 0;		/* VAD : 1 bit */
 
-	return 0;
+	return HR_REF_ENC_LEN;
 }
 
 static int
-hr_ref_enc_to_canon(uint8_t *dst, const uint8_t *src)
+hr_ref_enc_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	const uint16_t *hr_ref = (const uint16_t *)src;
 	int rv;
 
+	assert(src_len == HR_REF_ENC_LEN);
+
 	rv = hr_ref_to_canon(dst, hr_ref);
 	if (rv)
 		return rv;
 
-	return 0;
+	return HR_CANON_LEN;
 }
 
 
@@ -188,7 +200,7 @@
 	.name			= "hr-ref-dec",
 	.description		= "3GPP HR Reference decoder code parameters file format",
 
-	.frame_len		= 22 * sizeof(uint16_t),
+	.frame_len		= HR_REF_DEC_LEN,
 	.conv_from_canon	= hr_ref_dec_from_canon,
 	.conv_to_canon		= hr_ref_dec_to_canon,
 };
@@ -199,7 +211,7 @@
 	.name			= "hr-ref-enc",
 	.description		= "3GPP HR Reference encoder code parameters file format",
 
-	.frame_len		= 20 * sizeof(uint16_t),
+	.frame_len		= HR_REF_ENC_LEN,
 	.conv_from_canon	= hr_ref_enc_from_canon,
 	.conv_to_canon		= hr_ref_enc_to_canon,
 };
diff --git a/src/fmt_racal.c b/src/fmt_racal.c
index 65f810f..1dbc61d 100644
--- a/src/fmt_racal.c
+++ b/src/fmt_racal.c
@@ -18,6 +18,7 @@
  */
 
 #include <stdint.h>
+#include <assert.h>
 
 #include <osmocom/codec/codec.h>
 
@@ -25,13 +26,18 @@
 #include <gapk/formats.h>
 #include <gapk/utils.h>
 
+#define RACAL_HR_LEN	14
+#define RACAL_FR_LEN	33
+#define RACAL_EFR_LEN	31
 
 static int
-racal_hr_from_canon(uint8_t *dst, const uint8_t *src)
+racal_hr_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i, voiced;
 	const uint16_t *bit_mapping;
 
+	assert(src_len == HR_CANON_LEN);
+
 	voiced = (msb_get_bit(src, 34) << 1) | msb_get_bit(src, 35);
 
 	bit_mapping = voiced ?
@@ -44,15 +50,17 @@
 		lsb_put_bit(dst, di, msb_get_bit(src, si));
 	}
 
-	return 0;
+	return RACAL_HR_LEN;
 }
 
 static int
-racal_hr_to_canon(uint8_t *dst, const uint8_t *src)
+racal_hr_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i, voiced;
 	const uint16_t *bit_mapping;
 
+	assert(src_len == HR_CANON_LEN);
+
 	voiced = (lsb_get_bit(src, 94) << 1) | lsb_get_bit(src, 93);
 
 	bit_mapping = voiced ?
@@ -65,7 +73,7 @@
 		msb_put_bit(dst, di, lsb_get_bit(src, si));
 	}
 
-	return 0;
+	return RACAL_HR_LEN;
 }
 
 const struct format_desc fmt_racal_hr = {
@@ -74,17 +82,19 @@
 	.name			= "racal-hr",
 	.description		= "Racal HR TCH/H recording",
 
-	.frame_len		= 14,
+	.frame_len		= RACAL_HR_LEN,
 	.conv_from_canon	= racal_hr_from_canon,
 	.conv_to_canon		= racal_hr_to_canon,
 };
 
 
 static int
-racal_fr_from_canon(uint8_t *dst, const uint8_t *src)
+racal_fr_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 
+	assert(src_len == FR_CANON_LEN);
+
 	dst[32] = 0x00; /* last nibble won't written, pre-clear it */
 
 	for (i=0; i<260; i++) {
@@ -93,14 +103,16 @@
 		lsb_put_bit(dst, di, msb_get_bit(src, si));
 	}
 
-	return 0;
+	return RACAL_FR_LEN;
 }
 
 static int 
-racal_fr_to_canon(uint8_t *dst, const uint8_t *src)
+racal_fr_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 
+	assert(src_len == RACAL_FR_LEN);
+
 	dst[32] = 0x00; /* last nibble won't written, pre-clear it */
 
 	for (i=0; i<260; i++) {
@@ -109,7 +121,7 @@
 		msb_put_bit(dst, di, lsb_get_bit(src, si));
 	}
 
-	return 0;
+	return FR_CANON_LEN;
 }
 
 const struct format_desc fmt_racal_fr = {
@@ -118,36 +130,40 @@
 	.name			= "racal-fr",
 	.description		= "Racal FR TCH/F recording",
 
-	.frame_len		= 33,
+	.frame_len		= RACAL_FR_LEN,
 	.conv_from_canon	= racal_fr_from_canon,
 	.conv_to_canon		= racal_fr_to_canon,
 };
 
 
 static int
-racal_efr_from_canon(uint8_t *dst, const uint8_t *src)
+racal_efr_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 
+	assert(src_len == EFR_CANON_LEN);
+
 	dst[30] = 0x00; /* last nibble won't written, pre-clear it */
 
 	for (i=0; i<244; i++)
 		lsb_put_bit(dst, i, msb_get_bit(src, i));
 
-	return 0;
+	return RACAL_EFR_LEN;
 }
 
 static int
-racal_efr_to_canon(uint8_t *dst, const uint8_t *src)
+racal_efr_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 
+	assert(src_len == RACAL_EFR_LEN);
+
 	dst[30] = 0x00; /* last nibble won't written, pre-clear it */
 
 	for (i=0; i<244; i++)
 		msb_put_bit(dst, i, lsb_get_bit(src, i));
 
-	return 0;
+	return EFR_CANON_LEN;
 }
 
 const struct format_desc fmt_racal_efr = {
@@ -156,7 +172,7 @@
 	.name			= "racal-efr",
 	.description		= "Racal EFR TCH/F recording",
 
-	.frame_len		= 31,
+	.frame_len		= RACAL_EFR_LEN,
 	.conv_from_canon	= racal_efr_from_canon,
 	.conv_to_canon		= racal_efr_to_canon,
 };
diff --git a/src/fmt_rawpcm.c b/src/fmt_rawpcm.c
index e20fcaf..207708c 100644
--- a/src/fmt_rawpcm.c
+++ b/src/fmt_rawpcm.c
@@ -17,35 +17,40 @@
  * along with gapk.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <assert.h>
+
 #include <gapk/codecs.h>
 #include <gapk/formats.h>
 
-
 static int
-rawpcm_s16le_from_canon(uint8_t *dst, const uint8_t *src)
+rawpcm_s16le_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 	const uint16_t *samples = (const uint16_t *)src;
 
+	assert(src_len == PCM_CANON_LEN);
+
 	for (i=0; i<160; i++) {
 		uint16_t w = samples[i];
 		dst[(i<<1)  ] =  w       & 0xff;
 		dst[(i<<1)+1] = (w >> 8) & 0xff;
 	}
 
-	return 0;
+	return PCM_CANON_LEN;
 }
 
 static int
-rawpcm_s16le_to_canon(uint8_t *dst, const uint8_t *src)
+rawpcm_s16le_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 	uint16_t *samples = (uint16_t *)dst;
 
+	assert(src_len == PCM_CANON_LEN);
+
 	for (i=0; i<160; i++)
 		samples[i] = (src[(i<<1)+1] << 8) | src[(i<<1)];
 
-	return 0;
+	return PCM_CANON_LEN;
 }
 
 const struct format_desc fmt_rawpcm_s16le = {
diff --git a/src/fmt_ti.c b/src/fmt_ti.c
index 646c74a..627593c 100644
--- a/src/fmt_ti.c
+++ b/src/fmt_ti.c
@@ -26,6 +26,7 @@
 
 #include <stdint.h>
 #include <string.h>
+#include <assert.h>
 
 #include <osmocom/codec/codec.h>
 
@@ -33,14 +34,17 @@
 #include <gapk/formats.h>
 #include <gapk/utils.h>
 
+#define TI_LEN	33
 
 static int
-ti_hr_from_canon(uint8_t *dst, const uint8_t *src)
+ti_hr_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i, voiced;
 	const uint16_t *bit_mapping;
 
-	memset(dst, 0x00, 33); /* Not even half the bits are written, so we pre-clear */
+	assert(src_len == HR_CANON_LEN);
+
+	memset(dst, 0x00, TI_LEN); /* Not even half the bits are written, so we pre-clear */
 
 	voiced = (msb_get_bit(src, 34) << 1) | msb_get_bit(src, 35);
 
@@ -54,15 +58,17 @@
 		lsb_put_bit(dst, di, msb_get_bit(src, si));
 	}
 
-	return 0;
+	return TI_LEN;
 }
 
 static int
-ti_hr_to_canon(uint8_t *dst, const uint8_t *src)
+ti_hr_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i, voiced;
 	const uint16_t *bit_mapping;
 
+	assert(src_len == TI_LEN);
+
 	voiced = (msb_get_bit(src, 94) << 1) | msb_get_bit(src, 93);
 
 	bit_mapping = voiced ?
@@ -75,7 +81,7 @@
 		msb_put_bit(dst, di, msb_get_bit(src, si));
 	}
 
-	return 0;
+	return HR_CANON_LEN;
 }
 
 const struct format_desc fmt_ti_hr = {
@@ -84,17 +90,19 @@
 	.name			= "ti-hr",
 	.description		= "Texas Instrument HR TCH/H buffer format",
 
-	.frame_len		= 33,
+	.frame_len		= TI_LEN,
 	.conv_from_canon	= ti_hr_from_canon,
 	.conv_to_canon		= ti_hr_to_canon,
 };
 
 
 static int
-ti_fr_from_canon(uint8_t *dst, const uint8_t *src)
+ti_fr_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 
+	assert(src_len == FR_CANON_LEN);
+
 	dst[22] = dst[23] = 0x00; /* some bits won't be writter, pre-clear them */
 
 	for (i=0; i<260; i++) {
@@ -103,14 +111,16 @@
 		msb_put_bit(dst, di, msb_get_bit(src, si));
 	}
 
-	return 0;
+	return TI_LEN;
 }
 
 static int
-ti_fr_to_canon(uint8_t *dst, const uint8_t *src)
+ti_fr_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 
+	assert(src_len == TI_LEN);
+
 	dst[32] = 0x00; /* last nibble won't written, pre-clear it */
 
 	for (i=0; i<260; i++) {
@@ -119,7 +129,7 @@
 		msb_put_bit(dst, di, msb_get_bit(src, si));
 	}
 
-	return 0;
+	return FR_CANON_LEN;
 }
 
 const struct format_desc fmt_ti_fr = {
@@ -128,17 +138,19 @@
 	.name			= "ti-fr",
 	.description		= "Texas Instrument FR TCH/F buffer format",
 
-	.frame_len		= 33,
+	.frame_len		= TI_LEN,
 	.conv_from_canon	= ti_fr_from_canon,
 	.conv_to_canon		= ti_fr_to_canon,
 };
 
 
 static int
-ti_efr_from_canon(uint8_t *dst, const uint8_t *src)
+ti_efr_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 
+	assert(src_len == EFR_CANON_LEN);
+
 	memset(dst, 0x00, 33); /* pre-clear */
 
 	for (i=0; i<244; i++) {
@@ -169,14 +181,16 @@
 		msb_put_bit(dst, di, msb_get_bit(src, si));
 	}
 
-	return 0;
+	return TI_LEN;
 }
 
 static int
-ti_efr_to_canon(uint8_t *dst, const uint8_t *src)
+ti_efr_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len)
 {
 	int i;
 
+	assert(src_len == TI_LEN);
+
 	dst[30] = 0x00; /* last nibble won't written, pre-clear it */
 
 	for (i=0; i<244; i++) {
@@ -207,7 +221,7 @@
 		msb_put_bit(dst, di, msb_get_bit(src, si));
 	}
 
-	return 0;
+	return EFR_CANON_LEN;
 }
 
 const struct format_desc fmt_ti_efr = {
@@ -216,7 +230,7 @@
 	.name			= "ti-efr",
 	.description		= "Texas Instrument EFR TCH/F buffer format",
 
-	.frame_len		= 33,
+	.frame_len		= TI_LEN,
 	.conv_from_canon	= ti_efr_from_canon,
 	.conv_to_canon		= ti_efr_to_canon,
 };
diff --git a/src/pq_alsa.c b/src/pq_alsa.c
index b17faa8..563452e 100644
--- a/src/pq_alsa.c
+++ b/src/pq_alsa.c
@@ -40,20 +40,22 @@
 };
 
 static int
-pq_cb_alsa_input(void *_state, uint8_t *out, const uint8_t *in)
+pq_cb_alsa_input(void *_state, uint8_t *out, const uint8_t *in, unsigned int in_len)
 {
 	struct pq_state_alsa *state = _state;
 	unsigned int num_samples = state->blk_len/2;
 	int rv;
 	rv = snd_pcm_readi(state->pcm_handle, out, num_samples);
-	return rv == num_samples ? 0 : -1;
+	if (rv < 0)
+		return rv;
+	return rv * sizeof(uint16_t);
 }
 
 static int
-pq_cb_alsa_output(void *_state, uint8_t *out, const uint8_t *in)
+pq_cb_alsa_output(void *_state, uint8_t *out, const uint8_t *in, unsigned int in_len)
 {
 	struct pq_state_alsa *state = _state;
-	unsigned int num_samples = state->blk_len/2;
+	unsigned int num_samples = in_len/2;
 	int rv;
 	rv = snd_pcm_writei(state->pcm_handle, in, num_samples);
 	return rv == num_samples ? 0 : -1;
diff --git a/src/pq_file.c b/src/pq_file.c
index 7b9e356..dd82697 100644
--- a/src/pq_file.c
+++ b/src/pq_file.c
@@ -34,20 +34,22 @@
 
 
 static int
-pq_cb_file_input(void *_state, uint8_t *out, const uint8_t *in)
+pq_cb_file_input(void *_state, uint8_t *out, const uint8_t *in, unsigned int in_len)
 {
 	struct pq_state_file *state = _state;
 	int rv;
 	rv = fread(out, state->blk_len, 1, state->fh);
-	return rv == 1 ? 0 : -1;
+	if (rv < 0)
+		return rv;
+	return rv * state->blk_len;
 }
 
 static int
-pq_cb_file_output(void *_state, uint8_t *out, const uint8_t *in)
+pq_cb_file_output(void *_state, uint8_t *out, const uint8_t *in, unsigned int in_len)
 {
 	struct pq_state_file *state = _state;
 	int rv;
-	rv = fwrite(in, state->blk_len, 1, state->fh);
+	rv = fwrite(in, in_len, 1, state->fh);
 	return rv == 1 ? 0 : -1;
 }
 
diff --git a/src/pq_format.c b/src/pq_format.c
index 4e9515a..2089218 100644
--- a/src/pq_format.c
+++ b/src/pq_format.c
@@ -26,10 +26,10 @@
 
 
 static int
-pq_cb_fmt_convert(void *_state, uint8_t *out, const uint8_t *in)
+pq_cb_fmt_convert(void *_state, uint8_t *out, const uint8_t *in, unsigned int in_len)
 {
 	fmt_conv_cb_t f = _state;
-	return f(out, in);
+	return f(out, in, in_len);
 }
 
 /*! Add format conversion to processing queue
diff --git a/src/pq_rtp.c b/src/pq_rtp.c
index 1a7edde..99e77bc 100644
--- a/src/pq_rtp.c
+++ b/src/pq_rtp.c
@@ -88,7 +88,7 @@
 
 
 static int
-pq_cb_rtp_input(void *_state, uint8_t *out, const uint8_t *in)
+pq_cb_rtp_input(void *_state, uint8_t *out, const uint8_t *in, unsigned int in_len)
 {
 	struct pq_state_rtp *state = _state;
 	uint8_t buf[state->blk_len+256];
@@ -153,14 +153,14 @@
 
 	memcpy(out, payload, payload_len);
 
-	return 0;
+	return payload_len;
 }
 
 static int
-pq_cb_rtp_output(void *_state, uint8_t *out, const uint8_t *in)
+pq_cb_rtp_output(void *_state, uint8_t *out, const uint8_t *in, unsigned int in_len)
 {
 	struct pq_state_rtp *state = _state;
-	int len = state->blk_len + sizeof(struct rtp_hdr);
+	int len = in_len + sizeof(struct rtp_hdr);
 	uint8_t buf[len];
 	struct rtp_hdr *rtph = (struct rtp_hdr *)buf;
 	uint8_t *payload;
@@ -178,7 +178,7 @@
 	rtph->ssrc = htonl(state->ssrc);
 
 	payload = buf + sizeof(*rtph);
-	memcpy(payload, in, state->blk_len);
+	memcpy(payload, in, in_len);
 
 	rv = write(state->fd, buf, len);
 	return rv == len ? 0 : -1;
diff --git a/src/procqueue.c b/src/procqueue.c
index 2451399..66c2967 100644
--- a/src/procqueue.c
+++ b/src/procqueue.c
@@ -23,7 +23,7 @@
 
 #include <gapk/procqueue.h>
 
-
+#define VAR_BUF_SIZE	320
 #define MAX_PQ_ITEMS	8
 
 struct pq {
@@ -98,11 +98,16 @@
 	for (i=0; i<pq->n_items; i++) {
 		struct pq_item *item = pq->items[i];
 
-		if (item->len_in != len_prev)
+		if (item->len_in && item->len_in != len_prev)
 			return -EINVAL;
 
 		if (i < (pq->n_items-1)) {
-			pq->buffers[i] = malloc(item->len_out);
+			unsigned int buf_size = item->len_out;
+			/* variable-length codec output, use maximum
+			 * known buffer size */
+			if (!buf_size)
+				buf_size = VAR_BUF_SIZE;
+			pq->buffers[i] = malloc(buf_size);
 			if (!pq->buffers[i])
 				return -ENOMEM;
 		} else{
@@ -124,8 +129,10 @@
 {
 	int i;
 	void *buf_prev, *buf;
+	unsigned int len_prev;
 
 	buf_prev = NULL;
+	len_prev = 0;
 
 	for (i=0; i<pq->n_items; i++) {
 		int rv;
@@ -133,11 +140,14 @@
 
 		buf = i < (pq->n_items-1) ? pq->buffers[i] : NULL;
 
-		rv = item->proc(item->state, buf, buf_prev);
-		if (rv)
+		rv = item->proc(item->state, buf, buf_prev, len_prev);
+		if (rv < 0) {
+			fprintf(stderr, "pq_execute(): abort, item returned %d\n", rv);
 			return rv;
+		}
 
 		buf_prev = buf;
+		len_prev = rv;
 	}
 
 	return 0;