view mtctest/rtp_play.c @ 10:395c56969bc4

mtctest: implement guts of RTP play mechanism
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 09 Jun 2024 04:24:53 +0000
parents
children aa2ba9b432af
line wrap: on
line source

/*
 * In this module we implement RTP play command, emitting a test sequence
 * of encoded speech frames toward the MS.
 */

#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <themwi/rtp/rtp_defs.h>
#include <themwi/rtp/rtp_alloc_simple.h>

extern struct rtp_alloc_simple rtp_info;
extern int got_msc_rtp_info;
extern struct sockaddr_storage msc_rtp_addr;
extern uint8_t rtp_payload_type;
extern struct timeval cur_event_time;

int rtp_play_active;

static uint8_t play_buffer[33*50*30];	/* max 30 s of GSM-FR play */

static uint32_t rtp_ssrc;
static uint32_t rtp_out_ts;
static uint16_t rtp_out_seq;

static unsigned play_frame_len;
static unsigned play_buf_nframes, play_buf_ptr;
static int play_loop;

static void
assign_rtpout_ssrc()
{
	rtp_ssrc = cur_event_time.tv_sec ^ cur_event_time.tv_usec ^ getpid();
}

static void
fill_with_play(outbuf)
	uint8_t *outbuf;
{
	memcpy(outbuf, play_buffer + play_buf_ptr * play_frame_len,
		play_frame_len);
	play_buf_ptr++;
	if (play_buf_ptr < play_buf_nframes)
		return;
	play_buf_ptr = 0;
	if (!play_loop)
		rtp_play_active = 0;
}

void
generate_rtp_packet()
{
	struct rtp_packet pkt;
	socklen_t addrlen;

	pkt.v_p_x_cc = 0x80;
	pkt.m_pt = rtp_payload_type;
	pkt.seq = htons(rtp_out_seq++);
	pkt.tstamp = htonl(rtp_out_ts);
	rtp_out_ts += 160;
	pkt.ssrc = rtp_ssrc;
	fill_with_play(pkt.payload);
	addrlen = sizeof(struct sockaddr_in);
	sendto(rtp_info.gsm_rtp_fd, &pkt, RTP_PACKET_HDR_SIZE + play_frame_len,
		0, (struct sockaddr *) &msc_rtp_addr, addrlen);
}

void
play_file_cmdop(filename, frame_len, loop)
	unsigned frame_len;
	char *filename;
{
	int fd;
	struct stat st;

	if (rtp_play_active) {
		fprintf(stderr, "error: file play already in progress\n");
		return;
	}
	if (!got_msc_rtp_info) {
		fprintf(stderr, "error: no RTP info received from MSC\n");
		return;
	}
	fd = open(filename, O_RDONLY);
	if (fd < 0) {
		perror(filename);
		return;
	}
	fstat(fd, &st);
	if (!S_ISREG(st.st_mode)) {
		close(fd);
		fprintf(stderr, "error: %s is not a regular file\n", filename);
		return;
	}
	if (!st.st_size) {
		close(fd);
		fprintf(stderr, "error: %s is an empty file\n", filename);
		return;
	}
	if (st.st_size % frame_len) {
		close(fd);
		fprintf(stderr,
			"error: size of %s is not a multiple of %u bytes\n",
			filename, frame_len);
		return;
	}
	if (st.st_size > sizeof play_buffer) {
		close(fd);
		fprintf(stderr,
			"error: size of %s exceeds compiled-in buffer size\n",
			filename);
		return;
	}
	read(fd, play_buffer, st.st_size);
	close(fd);
	play_buf_nframes = st.st_size / frame_len;
	play_buf_ptr = 0;
	play_frame_len = frame_len;
	play_loop = loop;
	assign_rtpout_ssrc();
	rtp_out_ts = 0;
	rtp_out_seq = 0;
	rtp_play_active = 1;
}

void
play_file_stop()
{
	rtp_play_active = 0;
}