changeset 192:f8a33603288f

sip-manual-out: generate outgoing RTP stream with PCM silence
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 17 Mar 2023 13:45:31 -0800
parents 6ac96217c442
children 1f9a6cede2c5
files sip-manual-out/Makefile sip-manual-out/bye_in.c sip-manual-out/disc_cmd.c sip-manual-out/main.c sip-manual-out/rtp.c sip-manual-out/rtp_rx.c sip-manual-out/rtp_tx.c sip-manual-out/sdp_in.c
diffstat 8 files changed, 356 insertions(+), 271 deletions(-) [+]
line wrap: on
line diff
--- a/sip-manual-out/Makefile	Fri Mar 17 12:07:17 2023 -0800
+++ b/sip-manual-out/Makefile	Fri Mar 17 13:45:31 2023 -0800
@@ -1,8 +1,8 @@
 CC=	gcc
 CFLAGS=	-O2
 PROG=	sip-manual-out
-OBJS=	bye_in.o disc_cmd.o main.o readconf.o reinvite.o rtp.o sdp_in.o \
-	sip_log.o sip_udp.o uac.o uas.o
+OBJS=	bye_in.o disc_cmd.o main.o readconf.o reinvite.o rtp_rx.o rtp_tx.o \
+	sdp_in.o sip_log.o sip_udp.o uac.o uas.o
 LIBS=	../libsip/libsip.a ../librtpalloc/librtpalloc.a ../libutil/libutil.a
 INSTBIN=/usr/local/bin
 
--- a/sip-manual-out/bye_in.c	Fri Mar 17 12:07:17 2023 -0800
+++ b/sip-manual-out/bye_in.c	Fri Mar 17 13:45:31 2023 -0800
@@ -14,6 +14,7 @@
 #include "../libsip/out_msg.h"
 
 extern char call_id[];
+extern int rtp_out_enable;
 
 static void
 bye_correct_call(req, ess, sin)
@@ -25,6 +26,7 @@
 	int rc;
 
 	printf("Received BYE for our call, responding with 200\n");
+	rtp_out_enable = 0;
 	start_response_out_msg(&resp, "200 OK");
 	rc = add_resp_basic_headers(&resp, ess, req->req_method);
 	if (rc < 0) {
--- a/sip-manual-out/disc_cmd.c	Fri Mar 17 12:07:17 2023 -0800
+++ b/sip-manual-out/disc_cmd.c	Fri Mar 17 13:45:31 2023 -0800
@@ -14,12 +14,14 @@
 
 extern struct sockaddr_in sip_dest_sin;
 extern char to_uri[];
+extern int rtp_out_enable;
 
 send_cancel_req()
 {
 	struct sip_msg_out msg;
 	int rc;
 
+	rtp_out_enable = 0;
 	rc = start_request_out_msg(&msg, "CANCEL", to_uri);
 	if (rc < 0) {
 msg_size_err:	fprintf(stderr, "composing CANCEL message: size error\n");
@@ -38,6 +40,7 @@
 	struct sip_msg_out msg;
 	int rc;
 
+	rtp_out_enable = 0;
 	rc = start_request_out_msg(&msg, "BYE", to_uri);
 	if (rc < 0) {
 msg_size_err:	fprintf(stderr, "composing BYE message: size error\n");
--- a/sip-manual-out/main.c	Fri Mar 17 12:07:17 2023 -0800
+++ b/sip-manual-out/main.c	Fri Mar 17 13:45:31 2023 -0800
@@ -22,6 +22,7 @@
 extern char sip_dest_domain[];
 extern struct sockaddr_in rtp_local_addr;
 extern int rtp_udp_fd, rtcp_udp_fd;
+extern int rtp_out_enable;
 
 struct sockaddr_in sip_dest_sin;
 char from_uri[128], to_uri[128], call_id[128];
@@ -130,7 +131,8 @@
 	char **argv;
 {
 	fd_set fds;
-	int rc, max_fd;
+	struct timeval next_rtp_out, timeout;
+	int rc, max_fd, rtp_out_running;
 
 	preliminary_proc(argc, argv);
 	gettimeofday(&cur_event_time, 0);
@@ -144,13 +146,39 @@
 		max_fd = rtp_udp_fd;
 	if (rtcp_udp_fd > max_fd)
 		max_fd = rtcp_udp_fd;
+	rtp_out_running = 0;
 	for (;;) {
 		FD_ZERO(&fds);
 		FD_SET(0, &fds);
 		FD_SET(sip_socket, &fds);
 		FD_SET(rtp_udp_fd, &fds);
 		FD_SET(rtcp_udp_fd, &fds);
-		rc = select(max_fd+1, &fds, 0, 0, 0);
+		if (rtp_out_enable) {
+			if (!rtp_out_running) {
+				printf("Starting RTP output\n");
+				bcopy(&cur_event_time, &next_rtp_out,
+					sizeof(struct timeval));
+				rtp_out_running = 1;
+			} else {
+				next_rtp_out.tv_usec += 20000;
+				if (next_rtp_out.tv_usec >= 1000000) {
+					next_rtp_out.tv_sec++;
+					next_rtp_out.tv_usec -= 1000000;
+				}
+			}
+			if (timercmp(&cur_event_time, &next_rtp_out, <))
+				timersub(&next_rtp_out, &cur_event_time,
+					 &timeout);
+			else
+				timerclear(&timeout);
+			rc = select(max_fd+1, &fds, 0, 0, &timeout);
+		} else {
+			if (rtp_out_running) {
+				printf("Stopping RTP output\n");
+				rtp_out_running = 0;
+			}
+			rc = select(max_fd+1, &fds, 0, 0, 0);
+		}
 		if (rc < 0) {
 			if (errno == EINTR)
 				continue;
@@ -166,5 +194,7 @@
 			rtp_rx_select();
 		if (FD_ISSET(rtcp_udp_fd, &fds))
 			rtcp_rx_select();
+		if (rtp_out_running && (rc == 0))
+			generate_rtp_packet();
 	}
 }
--- a/sip-manual-out/rtp.c	Fri Mar 17 12:07:17 2023 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,266 +0,0 @@
-/*
- * In this module we implement our RTP handling: obtaining a PSTN-side
- * RTP endpoint from themwi-rtp-mgr, then handling read select on RTP
- * and RTCP UDP sockets.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include "../include/tmgw_const.h"
-#include "../include/rtp_defs.h"
-#include "../librtpalloc/rtp_alloc_simple.h"
-
-struct sockaddr_in rtp_local_addr;
-int rtp_udp_fd, rtcp_udp_fd;
-
-static int rtp_start_flag, rtp_bad_flag, rtp_ssrc_chg_flag;
-static int rtp_seq_brk_flag, rtp_seq_zero_flag, rtp_seq_neg_flag;
-static int rtp_ts_brk_flag;
-static uint32_t rtp_ssrc;
-static uint32_t rtp_last_ts;
-static uint16_t rtp_last_seq;
-static int got_some_rtcp;
-
-static const uint8_t hdr_pattern[20] =	{0, 1, 0, 1, 0, 1, 1, 0, 1, 0,
-					 0, 1, 1, 0, 1, 0, 1, 0, 0, 1};
-
-static uint8_t is_hunt_buf[320];
-static int is_state;
-static unsigned is_offset, is_bit_count;
-static uint32_t is_rx_word;
-
-static void
-reset_is_hunt()
-{
-	memset(is_hunt_buf, 0xFF, 320);
-	is_state = 0;
-}
-
-static void
-is_rx_hunt(input_pos)
-	unsigned input_pos;
-{
-	unsigned offset, n;
-
-	for (offset = 0; offset < 16; offset++) {
-		for (n = 0; n < 20; n++)
-			if ((is_hunt_buf[offset + n*16] & 1) != hdr_pattern[n])
-				break;
-		if (n == 20)
-			break;
-	}
-	if (n != 20)
-		return;
-	printf("Found IS_Header, last bit offset %u\n",
-		input_pos * 16 + offset);
-	is_offset = offset;
-	is_state = 1;
-	is_bit_count = 0;
-	is_rx_word = 0;
-}
-
-static void
-is_process_cmd()
-{
-	int cont;
-
-	printf("IS_Command: 0x%03X", is_rx_word);
-	switch (is_rx_word) {
-	case 0x05D:
-		printf(" (REQ)\n");
-		cont = 1;
-		break;
-	case 0x0BA:
-		printf(" (ACK)\n");
-		cont = 1;
-		break;
-	case 0x0E7:
-		printf(" (IPE)\n");
-		cont = 1;
-		break;
-	case 0x129:
-		printf(" (FILL)\n");
-		cont = 0;
-		break;
-	case 0x174:
-		printf(" (DUP)\n");
-		cont = 0;
-		break;
-	case 0x193:
-		printf(" (SYL)\n");
-		cont = 0;
-		break;
-	default:
-		printf(" (bad)\n");
-		cont = 0;
-	}
-	if (cont) {
-		is_state = 2;
-		is_bit_count = 0;
-		is_rx_word = 0;
-	} else
-		is_state = 0;
-}
-
-static void
-is_process_ext()
-{
-	printf("IS_Extension: 0x%05X", is_rx_word);
-	if (is_rx_word & 0x80200) {
-		printf(" (bad sync)\n");
-		is_state = 0;
-		return;
-	}
-	switch (is_rx_word & 3) {
-	case 0:
-		printf(" (final)\n");
-		is_state = 0;
-		return;
-	case 3:
-		printf(" (continue)\n");
-		is_state = 2;
-		is_bit_count = 0;
-		is_rx_word = 0;
-		return;
-	default:
-		printf(" (bad EX)\n");
-		is_state = 0;
-	}
-}
-
-static void
-is_rx_process(input, input_pos)
-	uint8_t *input;
-	unsigned input_pos;
-{
-	unsigned new_bit;
-
-	memmove(is_hunt_buf, is_hunt_buf + 16, 304);
-	memcpy(is_hunt_buf + 304, input, 16);
-	if (!is_state) {
-		is_rx_hunt(input_pos);
-		return;
-	}
-	new_bit = input[is_offset] & 1;
-	is_rx_word <<= 1;
-	is_rx_word |= new_bit;
-	is_bit_count++;
-	if (is_state == 1 && is_bit_count == 10)
-		is_process_cmd();
-	else if (is_state == 2 && is_bit_count == 20)
-		is_process_ext();
-}
-
-void
-obtain_rtp_endp()
-{
-	int rc;
-	struct rtp_alloc_simple res;
-
-	rc = rtp_alloc_simple(TMGW_EP_TYPE_PSTN_ONLY, &res);
-	if (rc < 0)
-		exit(1);	/* error msg already printed */
-	bcopy(&res.pstn_addr, &rtp_local_addr, sizeof(struct sockaddr_in));
-	rtp_udp_fd = res.pstn_rtp_fd;
-	rtcp_udp_fd = res.pstn_rtcp_fd;
-	reset_is_hunt();
-}
-
-void
-rtp_rx_select()
-{
-	struct rtp_packet pkt;
-	struct sockaddr_in sin_from;
-	socklen_t addrlen;
-	int16_t seq_delta;
-	int32_t ts_delta;
-	int rc;
-	unsigned is_chunk;
-
-	addrlen = sizeof(struct sockaddr_in);
-	rc = recvfrom(rtp_udp_fd, &pkt, sizeof pkt, 0,
-			(struct sockaddr *) &sin_from, &addrlen);
-	if (rc < 0)
-		return;
-	if (rc != RTP_PACKET_SIZE_PSTN) {
-bad_rtp_pkt:	if (!rtp_bad_flag) {
-			printf("Got a bad RTP packet\n");
-			rtp_bad_flag = 1;
-		}
-		return;
-	}
-	if (pkt.v_p_x_cc != 0x80)
-		goto bad_rtp_pkt;
-	switch (pkt.m_pt & 0x7F) {
-	case PSTN_CODEC_PCMU:
-	case PSTN_CODEC_PCMA:
-		break;
-	default:
-		goto bad_rtp_pkt;
-	}
-	if (rtp_start_flag && pkt.ssrc != rtp_ssrc) {
-		if (!rtp_ssrc_chg_flag) {
-			printf("Rx RTP stream changed SSRC\n");
-			rtp_ssrc_chg_flag = 1;
-		}
-		reset_is_hunt();
-	} else if (rtp_start_flag) {
-		seq_delta = ntohs(pkt.seq) - rtp_last_seq;
-		ts_delta = ntohl(pkt.tstamp) - rtp_last_ts;
-		if (seq_delta == 0) {
-			if (!rtp_seq_zero_flag) {
-				printf("Rx RTP seq zero increment\n");
-				rtp_seq_zero_flag = 1;
-			}
-			return;
-		}
-		if (seq_delta < 0) {
-			if (!rtp_seq_neg_flag) {
-				printf("Rx RTP seq negative increment\n");
-				rtp_seq_neg_flag = 1;
-			}
-			return;
-		}
-		if (seq_delta != 1) {
-			if (!rtp_seq_brk_flag) {
-				printf("Rx RTP stream seq break\n");
-				rtp_seq_brk_flag = 1;
-			}
-			reset_is_hunt();
-		} else if (ts_delta != 160) {
-			if (!rtp_ts_brk_flag) {
-				printf("Rx RTP stream tstamp break\n");
-				rtp_ts_brk_flag = 1;
-			}
-			reset_is_hunt();
-		}
-	}
-	rtp_ssrc = pkt.ssrc;
-	rtp_last_ts = ntohl(pkt.tstamp);
-	rtp_last_seq = ntohs(pkt.seq);
-	if (!rtp_start_flag) {
-		printf("Rx RTP stream begins with seq=%u ts=%u\n",
-			rtp_last_seq, rtp_last_ts);
-		rtp_start_flag = 1;
-	}
-	for (is_chunk = 0; is_chunk < 10; is_chunk++)
-		is_rx_process(pkt.payload + is_chunk * 16, is_chunk);
-}
-
-void
-rtcp_rx_select()
-{
-	u_char buf[512];
-
-	recv(rtcp_udp_fd, buf, sizeof buf, 0);
-	if (!got_some_rtcp) {
-		printf("Got some RTCP\n");
-		got_some_rtcp = 1;
-	}
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sip-manual-out/rtp_rx.c	Fri Mar 17 13:45:31 2023 -0800
@@ -0,0 +1,266 @@
+/*
+ * In this module we implement our RTP handling: obtaining a PSTN-side
+ * RTP endpoint from themwi-rtp-mgr, then handling read select on RTP
+ * and RTCP UDP sockets.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "../include/tmgw_const.h"
+#include "../include/rtp_defs.h"
+#include "../librtpalloc/rtp_alloc_simple.h"
+
+struct sockaddr_in rtp_local_addr;
+int rtp_udp_fd, rtcp_udp_fd;
+
+static int rtp_start_flag, rtp_bad_flag, rtp_ssrc_chg_flag;
+static int rtp_seq_brk_flag, rtp_seq_zero_flag, rtp_seq_neg_flag;
+static int rtp_ts_brk_flag;
+static uint32_t rtp_ssrc;
+static uint32_t rtp_last_ts;
+static uint16_t rtp_last_seq;
+static int got_some_rtcp;
+
+static const uint8_t hdr_pattern[20] =	{0, 1, 0, 1, 0, 1, 1, 0, 1, 0,
+					 0, 1, 1, 0, 1, 0, 1, 0, 0, 1};
+
+static uint8_t is_hunt_buf[320];
+static int is_state;
+static unsigned is_offset, is_bit_count;
+static uint32_t is_rx_word;
+
+static void
+reset_is_hunt()
+{
+	memset(is_hunt_buf, 0xFF, 320);
+	is_state = 0;
+}
+
+static void
+is_rx_hunt(input_pos)
+	unsigned input_pos;
+{
+	unsigned offset, n;
+
+	for (offset = 0; offset < 16; offset++) {
+		for (n = 0; n < 20; n++)
+			if ((is_hunt_buf[offset + n*16] & 1) != hdr_pattern[n])
+				break;
+		if (n == 20)
+			break;
+	}
+	if (n != 20)
+		return;
+	printf("Found IS_Header, last bit offset %u\n",
+		input_pos * 16 + offset);
+	is_offset = offset;
+	is_state = 1;
+	is_bit_count = 0;
+	is_rx_word = 0;
+}
+
+static void
+is_process_cmd()
+{
+	int cont;
+
+	printf("IS_Command: 0x%03X", is_rx_word);
+	switch (is_rx_word) {
+	case 0x05D:
+		printf(" (REQ)\n");
+		cont = 1;
+		break;
+	case 0x0BA:
+		printf(" (ACK)\n");
+		cont = 1;
+		break;
+	case 0x0E7:
+		printf(" (IPE)\n");
+		cont = 1;
+		break;
+	case 0x129:
+		printf(" (FILL)\n");
+		cont = 0;
+		break;
+	case 0x174:
+		printf(" (DUP)\n");
+		cont = 0;
+		break;
+	case 0x193:
+		printf(" (SYL)\n");
+		cont = 0;
+		break;
+	default:
+		printf(" (bad)\n");
+		cont = 0;
+	}
+	if (cont) {
+		is_state = 2;
+		is_bit_count = 0;
+		is_rx_word = 0;
+	} else
+		is_state = 0;
+}
+
+static void
+is_process_ext()
+{
+	printf("IS_Extension: 0x%05X", is_rx_word);
+	if (is_rx_word & 0x80200) {
+		printf(" (bad sync)\n");
+		is_state = 0;
+		return;
+	}
+	switch (is_rx_word & 3) {
+	case 0:
+		printf(" (final)\n");
+		is_state = 0;
+		return;
+	case 3:
+		printf(" (continue)\n");
+		is_state = 2;
+		is_bit_count = 0;
+		is_rx_word = 0;
+		return;
+	default:
+		printf(" (bad EX)\n");
+		is_state = 0;
+	}
+}
+
+static void
+is_rx_process(input, input_pos)
+	uint8_t *input;
+	unsigned input_pos;
+{
+	unsigned new_bit;
+
+	memmove(is_hunt_buf, is_hunt_buf + 16, 304);
+	memcpy(is_hunt_buf + 304, input, 16);
+	if (!is_state) {
+		is_rx_hunt(input_pos);
+		return;
+	}
+	new_bit = input[is_offset] & 1;
+	is_rx_word <<= 1;
+	is_rx_word |= new_bit;
+	is_bit_count++;
+	if (is_state == 1 && is_bit_count == 10)
+		is_process_cmd();
+	else if (is_state == 2 && is_bit_count == 20)
+		is_process_ext();
+}
+
+void
+obtain_rtp_endp()
+{
+	int rc;
+	struct rtp_alloc_simple res;
+
+	rc = rtp_alloc_simple(TMGW_EP_TYPE_PSTN_ONLY, &res);
+	if (rc < 0)
+		exit(1);	/* error msg already printed */
+	bcopy(&res.pstn_addr, &rtp_local_addr, sizeof(struct sockaddr_in));
+	rtp_udp_fd = res.pstn_rtp_fd;
+	rtcp_udp_fd = res.pstn_rtcp_fd;
+	reset_is_hunt();
+}
+
+void
+rtp_rx_select()
+{
+	struct rtp_packet pkt;
+	struct sockaddr_in sin_from;
+	socklen_t addrlen;
+	int16_t seq_delta;
+	int32_t ts_delta;
+	int rc;
+	unsigned is_chunk;
+
+	addrlen = sizeof(struct sockaddr_in);
+	rc = recvfrom(rtp_udp_fd, &pkt, sizeof pkt, 0,
+			(struct sockaddr *) &sin_from, &addrlen);
+	if (rc < 0)
+		return;
+	if (rc != RTP_PACKET_SIZE_PSTN) {
+bad_rtp_pkt:	if (!rtp_bad_flag) {
+			printf("Got a bad RTP packet\n");
+			rtp_bad_flag = 1;
+		}
+		return;
+	}
+	if (pkt.v_p_x_cc != 0x80)
+		goto bad_rtp_pkt;
+	switch (pkt.m_pt & 0x7F) {
+	case PSTN_CODEC_PCMU:
+	case PSTN_CODEC_PCMA:
+		break;
+	default:
+		goto bad_rtp_pkt;
+	}
+	if (rtp_start_flag && pkt.ssrc != rtp_ssrc) {
+		if (!rtp_ssrc_chg_flag) {
+			printf("Rx RTP stream changed SSRC\n");
+			rtp_ssrc_chg_flag = 1;
+		}
+		reset_is_hunt();
+	} else if (rtp_start_flag) {
+		seq_delta = ntohs(pkt.seq) - rtp_last_seq;
+		ts_delta = ntohl(pkt.tstamp) - rtp_last_ts;
+		if (seq_delta == 0) {
+			if (!rtp_seq_zero_flag) {
+				printf("Rx RTP seq zero increment\n");
+				rtp_seq_zero_flag = 1;
+			}
+			return;
+		}
+		if (seq_delta < 0) {
+			if (!rtp_seq_neg_flag) {
+				printf("Rx RTP seq negative increment\n");
+				rtp_seq_neg_flag = 1;
+			}
+			return;
+		}
+		if (seq_delta != 1) {
+			if (!rtp_seq_brk_flag) {
+				printf("Rx RTP stream seq break\n");
+				rtp_seq_brk_flag = 1;
+			}
+			reset_is_hunt();
+		} else if (ts_delta != 160) {
+			if (!rtp_ts_brk_flag) {
+				printf("Rx RTP stream tstamp break\n");
+				rtp_ts_brk_flag = 1;
+			}
+			reset_is_hunt();
+		}
+	}
+	rtp_ssrc = pkt.ssrc;
+	rtp_last_ts = ntohl(pkt.tstamp);
+	rtp_last_seq = ntohs(pkt.seq);
+	if (!rtp_start_flag) {
+		printf("Rx RTP stream begins with seq=%u ts=%u\n",
+			rtp_last_seq, rtp_last_ts);
+		rtp_start_flag = 1;
+	}
+	for (is_chunk = 0; is_chunk < 10; is_chunk++)
+		is_rx_process(pkt.payload + is_chunk * 16, is_chunk);
+}
+
+void
+rtcp_rx_select()
+{
+	u_char buf[512];
+
+	recv(rtcp_udp_fd, buf, sizeof buf, 0);
+	if (!got_some_rtcp) {
+		printf("Got some RTCP\n");
+		got_some_rtcp = 1;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sip-manual-out/rtp_tx.c	Fri Mar 17 13:45:31 2023 -0800
@@ -0,0 +1,48 @@
+/*
+ * In this module we implement outgoing RTP stream generation.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include "../include/tmgw_const.h"
+#include "../include/rtp_defs.h"
+
+extern struct sockaddr_in rtp_local_addr, rtp_remote_addr;
+extern int rtp_udp_fd, rtcp_udp_fd, pcma_selected;
+extern struct timeval cur_event_time;
+
+static uint32_t rtp_ssrc;
+static uint32_t rtp_out_ts;
+static uint16_t rtp_out_seq;
+
+void
+assign_rtpout_ssrc()
+{
+	rtp_ssrc = cur_event_time.tv_sec ^ cur_event_time.tv_usec ^ getpid();
+}
+
+void
+generate_rtp_packet()
+{
+	struct rtp_packet pkt;
+	socklen_t addrlen;
+
+	pkt.v_p_x_cc = 0x80;
+	pkt.m_pt = pcma_selected ? PSTN_CODEC_PCMA : PSTN_CODEC_PCMU;
+	pkt.seq = htons(rtp_out_seq++);
+	pkt.tstamp = htonl(rtp_out_ts);
+	rtp_out_ts += 160;
+	pkt.ssrc = rtp_ssrc;
+	memset(pkt.payload, pcma_selected ? 0xD5 : 0xFF, RTP_MAX_PAYLOAD);
+	addrlen = sizeof(struct sockaddr_in);
+	sendto(rtp_udp_fd, &pkt, RTP_PACKET_SIZE_PSTN, 0,
+		(struct sockaddr *) &rtp_remote_addr, addrlen);
+}
--- a/sip-manual-out/sdp_in.c	Fri Mar 17 12:07:17 2023 -0800
+++ b/sip-manual-out/sdp_in.c	Fri Mar 17 13:45:31 2023 -0800
@@ -17,7 +17,7 @@
 extern char *extract_to_tag();
 
 struct sockaddr_in rtp_remote_addr;
-int pcma_selected;
+int pcma_selected, rtp_out_enable;
 
 static
 check_sdp_present(msg)
@@ -71,4 +71,6 @@
 	rtp_remote_addr.sin_family = AF_INET;
 	rtp_remote_addr.sin_addr = sdp_parse.ip_addr;
 	rtp_remote_addr.sin_port = htons(sdp_parse.audio_port);
+	rtp_out_enable = 1;
+	assign_rtpout_ssrc();
 }