view amrconv/hex2ietf.c @ 589:e414d138c607

amrconv: new program amr-ietf2hexoa
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 06 Nov 2025 21:18:59 +0000
parents 4d6ccca0c687
children
line wrap: on
line source

/*
 * This program converts an AMR speech recording from TW-TS-005 Annex C OA/OAX
 * hexadecimal format into the standard binary storage format of RFC 4867.
 */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "../libtest/tw5reader.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 *hexf, *outf;
	unsigned lineno;
	uint8_t frame[TWTS005_MAX_FRAME];
	unsigned frame_len, cmr, ft, if1_len;
	int rc;

	if (argc != 3) {
		fprintf(stderr, "usage: %s input.hex output.amr\n", argv[0]);
		exit(1);
	}
	hexf = fopen(argv[1], "r");
	if (!hexf) {
		perror(argv[1]);
		exit(1);
	}
	lineno = 0;
	outf = fopen(argv[2], "w");
	if (!outf) {
		perror(argv[2]);
		exit(1);
	}
	fwrite(amr_file_hdr, 1, IETF_HDR_LEN, outf);
	for (;;) {
		rc = twts005_read_frame(hexf, &lineno, frame, &frame_len);
		if (rc < 0) {
			fprintf(stderr, "%s line %u: not valid TW-TS-005\n",
				argv[1], lineno);
			exit(1);
		}
		if (!rc)
			break;
		if (frame_len == 0) {
			putc(0x7C, outf);
			continue;
		}
		if (frame_len < 2) {
inv_payload:		fprintf(stderr,
				"%s line %u: payload is not valid AMR OA\n",
				argv[1], lineno);
			exit(1);
		}
		cmr = frame[0] >> 4;
		if (cmr > MR122 && cmr != MODE_NO_DATA)
			goto inv_payload;
		if (frame[1] & 0x80)
			goto inv_payload;
		ft = (frame[1] & 0x78) >> 3;
		if (ft <= MRDTX)
			if1_len = extra_bytes_per_ft[ft];
		else if (ft == MODE_NO_DATA)
			if1_len = 0;
		else
			goto inv_payload;
		if (frame_len < if1_len + 2)
			goto inv_payload;
		frame[1] &= 0xFC;
		fwrite(frame + 1, 1, if1_len + 1, outf);
	}
	exit(0);
}