diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mtctest/rtp_play.c	Sun Jun 09 04:24:53 2024 +0000
@@ -0,0 +1,140 @@
+/*
+ * 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;
+}