changeset 106:028307356ba9

trau-decode: new program trau-amr8-dump
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 21 Nov 2025 06:37:46 +0000
parents 699afc9ef063
children c6ffb176eaed
files .hgignore trau-decode/Makefile trau-decode/amr8-common.c trau-decode/amr8-readbin.c
diffstat 4 files changed, 170 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Nov 20 22:28:45 2025 +0000
+++ b/.hgignore	Fri Nov 21 06:37:46 2025 +0000
@@ -19,6 +19,7 @@
 
 ^trau-decode/dump-1bit$
 ^trau-decode/tfo-parse-fr16$
+^trau-decode/trau-amr8-dump$
 ^trau-decode/trau-amr8-dump-hex$
 ^trau-decode/trau-extr$
 ^trau-decode/trau-hr-dump$
--- a/trau-decode/Makefile	Thu Nov 20 22:28:45 2025 +0000
+++ b/trau-decode/Makefile	Fri Nov 21 06:37:46 2025 +0000
@@ -1,7 +1,7 @@
 CC=	gcc
 CFLAGS=	-O2
-PROGS=	dump-1bit tfo-parse-fr16 trau-amr8-dump-hex trau-extr trau-hr-dump \
-	trau-hr-dump-hex trau-parse trau-parse-hex trau-sync8
+PROGS=	dump-1bit tfo-parse-fr16 trau-amr8-dump trau-amr8-dump-hex trau-extr \
+	trau-hr-dump trau-hr-dump-hex trau-parse trau-parse-hex trau-sync8
 
 FR_OBJS=parse-fr.o parse-fr-common.o parse-efr.o
 HR_OBJS=gsmhr_unpack.o hr-guts.o
@@ -16,6 +16,9 @@
 tfo-parse-fr16:	crc8gen.o parse-tfo16.o ${FR_OBJS}
 	${CC} ${CFLAGS} -o $@ $^ -lgsmfr2 -lgsmefr
 
+trau-amr8-dump:	amr8-common.o amr8-readbin.o crc8gen.o
+	${CC} ${CFLAGS} -o $@ $^
+
 trau-amr8-dump-hex:	amr8-common.o amr8-readhex.o crc8gen.o
 	${CC} ${CFLAGS} -o $@ $^
 
--- a/trau-decode/amr8-common.c	Thu Nov 20 22:28:45 2025 +0000
+++ b/trau-decode/amr8-common.c	Fri Nov 21 06:37:46 2025 +0000
@@ -58,7 +58,7 @@
 static const ubit_t bit8_0[8] = { 0, };
 
 /*!< check sync pattern for AMR No_Speech + low bit rate */
-static bool is_amr_low(const ubit_t *bits)
+bool is_amr_low(const ubit_t *bits)
 {
 	int i;
 
@@ -79,7 +79,7 @@
 }
 
 /*!< check sync pattern for AMR 6.7kBit/s */
-static bool is_amr_67(const ubit_t *bits)
+bool is_amr_67(const ubit_t *bits)
 {
 	int i;
 
@@ -104,7 +104,7 @@
 }
 
 /*!< check sync pattern for AMR 7.4kBit/s */
-static bool is_amr_74(const ubit_t *bits)
+bool is_amr_74(const ubit_t *bits)
 {
 	if (bits[0] != 0 || bits[1] != 0 || bits[2] != 1)
 		return false;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trau-decode/amr8-readbin.c	Fri Nov 21 06:37:46 2025 +0000
@@ -0,0 +1,161 @@
+/*
+ * This program reads a 64 kbit/s timeslot recording file, examines one
+ * of the eight 8 kbit/s subslots (selected), looks for 3 possible sync
+ * patterns of TRAU-AMR-8k, and decodes whatever it finds.
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+static uint8_t *filebuf;
+static unsigned total_size;
+static int include_raw;
+
+static void
+read_ts_file(filename, subslot_arg)
+	char *filename, *subslot_arg;
+{
+	FILE *inf;
+	struct stat st;
+	int subslot, right_shift;
+	unsigned n;
+	uint8_t *dp;
+	int b;
+
+	inf = fopen(filename, "r");
+	if (!inf) {
+		perror(filename);
+		exit(1);
+	}
+	fstat(fileno(inf), &st);
+	if (!S_ISREG(st.st_mode)) {
+		fprintf(stderr, "error: %s is not a regular file\n", filename);
+		exit(1);
+	}
+	total_size = st.st_size;
+	if (total_size < 160) {
+		fprintf(stderr, "error: %s is too short\n", filename);
+		exit(1);
+	}
+	filebuf = malloc(total_size);
+	if (!filebuf) {
+		perror("malloc of file size");
+		exit(1);
+	}
+	subslot = atoi(subslot_arg);
+	if (subslot < 0 || subslot > 7) {
+		fprintf(stderr, "error: invalid subslot argument\n");
+		exit(1);
+	}
+	right_shift = 7 - subslot;
+	dp = filebuf;
+	for (n = 0; n < total_size; n++) {
+		b = getc(inf);
+		if (b < 0) {
+			fprintf(stderr,
+			"error: getc() returned EOF contrary to st_size\n");
+			exit(1);
+		}
+		*dp++ = (b >> right_shift) & 1;
+	}
+	fclose(inf);
+}
+
+static int
+check_sync(pos)
+	unsigned pos;
+{
+	uint8_t *cand = filebuf + pos;
+
+	if (is_amr_low(cand))
+		return 1;
+	if (is_amr_67(cand))
+		return 1;
+	if (is_amr_74(cand))
+		return 1;
+	return 0;
+}
+
+static void
+dump_raw_frame(frame_bits)
+	uint8_t *frame_bits;
+{
+	uint8_t *sp = frame_bits;
+	unsigned n, m, d;
+
+	for (n = 0; n < 40; n++) {
+		d = 0;
+		for (m = 0; m < 4; m++) {
+			d <<= 1;
+			d |= *sp++;
+		}
+		printf("%x", d);
+	}
+	putchar('\n');
+}
+
+static void
+process_frame(pos)
+	unsigned pos;
+{
+	uint8_t *frame = filebuf + pos;
+
+	printf("Frame at 0x%x:\n", pos);
+	if (include_raw)
+		dump_raw_frame(frame);
+	print_amr8_frame(frame);
+}
+
+static void
+process_filebuf()
+{
+	unsigned p, endp;
+	int sync = 0, match;
+
+	endp = total_size - 160;
+	for (p = 0; p <= endp; ) {
+		match = check_sync(p);
+		if (match != sync) {
+			printf("# %s frame sync at file offset 0x%x\n",
+				match ? "Acquired" : "Lost", p);
+		}
+		if (match) {
+			process_frame(p);
+			p += 160;
+		} else
+			p++;
+		sync = match;
+	}
+}
+
+main(argc, argv)
+	char **argv;
+{
+	extern int optind;
+	int c;
+
+	while ((c = getopt(argc, argv, "r")) != EOF) {
+		switch (c) {
+		case 'r':
+			include_raw = 1;
+			continue;
+		default:
+		usage:
+			fprintf(stderr, "usage: %s [-r] binfile subslot\n",
+				argv[0]);
+			exit(1);
+		}
+	}
+	if (argc != optind + 2)
+		goto usage;
+	read_ts_file(argv[optind], argv[optind + 1]);
+	process_filebuf();
+	exit(0);
+}