view amrconv/ietf2hex.c @ 589:e414d138c607

amrconv: new program amr-ietf2hexoa
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 06 Nov 2025 21:18:59 +0000
parents miscutil/gsmx-to-tw5a.c@5595293e4f29
children
line wrap: on
line source

/*
 * This program reads an AMR speech recording in RFC 4867 binary storage format,
 * converts each frame to an octet-aligned RTP payload (adds CMR octet), and
 * writes out these payloads as a TW-TS-005 Annex C hex file.
 */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "../libtest/tw5writer.h"
#include "amr_defs.h"

extern const char amr_file_hdr[IETF_HDR_LEN];
extern const uint8_t extra_bytes_per_ft[9];

main(argc, argv)
	char **argv;
{
	FILE *inf, *outf;
	uint8_t frame[MAX_IF1_BYTES + 2];
	unsigned frame_no, ft, frame_len;
	int rc;

	if (argc != 3) {
		fprintf(stderr, "usage: %s input.amr output.hex\n", argv[0]);
		exit(1);
	}
	inf = fopen(argv[1], "r");
	if (!inf) {
		perror(argv[1]);
		exit(1);
	}
	if (fread(frame, 1, IETF_HDR_LEN, inf) != IETF_HDR_LEN ||
	    bcmp(frame, amr_file_hdr, IETF_HDR_LEN)) {
		fprintf(stderr, "error: %s is not in IETF AMR format\n",
			argv[1]);
		exit(1);
	}
	if (strcmp(argv[2], "-")) {
		outf = fopen(argv[2], "w");
		if (!outf) {
			perror(argv[2]);
			exit(1);
		}
	} else
		outf = stdout;
	frame[0] = 0xF0;
	for (frame_no = 0; ; frame_no++) {
		rc = getc(inf);
		if (rc < 0)
			break;
		frame[1] = rc & 0x7C;
		ft = frame[1] >> 3;
		frame_len = 2;
		if (ft != MODE_NO_DATA) {
			if (ft > MRDTX) {
				fprintf(stderr,
					"error in frame #%u: invalid FT=%u\n",
					frame_no, ft);
				exit(1);
			}
			rc = fread(frame + 2, 1, extra_bytes_per_ft[ft], inf);
			if (rc != extra_bytes_per_ft[ft]) {
				fprintf(stderr,
				"error: short read from %s on frame #%u\n",
					argv[1], frame_no);
				exit(1);
			}
			frame_len += extra_bytes_per_ft[ft];
		}
		emit_hex_frame(outf, frame, frame_len);
	}
	exit(0);
}