From ede7bca2a7f0c64b0244626bbbbfbcc4dbd946eb Mon Sep 17 00:00:00 2001
From: Mark Spencer <markster@digium.com>
Date: Sun, 16 Jun 2002 16:06:38 +0000
Subject: [PATCH] Version 0.1.12 from FTP

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@461 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 CREDITS                 |  14 +-
 channels/Makefile       |   9 +-
 configs/sip.conf.sample |  36 ++++
 include/asterisk/rtp.h  |  54 ++++++
 rtp.c                   | 364 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 471 insertions(+), 6 deletions(-)
 create mode 100755 configs/sip.conf.sample
 create mode 100755 include/asterisk/rtp.h
 create mode 100755 rtp.c

diff --git a/CREDITS b/CREDITS
index fe8543042f..7f7ed249d8 100755
--- a/CREDITS
+++ b/CREDITS
@@ -1,7 +1,3 @@
-=== HARDWARE DONORS === 
-* Thanks to QuickNet Technologies for their donation of an Internet
-PhoneJack and Linejack card to the project.  (http://www.quicknet.net)
-
 
 === DEVELOPMENT SUPPORT ===
 I'd like to thank the following companies for helping fund development of
@@ -9,6 +5,16 @@ Asterisk:
 
 Pilosoft, Inc. - for supporting ADSI development in Asterisk
 
+GFS - for supporting ALSA development
+
+Telesthetic - for supporting SIP development
+
+=== HARDWARE DONORS === 
+* Thanks to QuickNet Technologies for their donation of an Internet
+PhoneJack and Linejack card to the project.  (http://www.quicknet.net)
+
+=== MISCELLANEOUS PATCHES ===
+Oliver Daudey - ISDN4Linux fixes
 
 === OTHER SOURCE CODE IN ASTERISK ===
 
diff --git a/channels/Makefile b/channels/Makefile
index ca91618eb4..dc5cabba42 100755
--- a/channels/Makefile
+++ b/channels/Makefile
@@ -11,10 +11,15 @@
 # the GNU General Public License
 #
 
-CHANNEL_LIBS=chan_vofr.so chan_modem.so \
-	     chan_modem_aopen.so chan_iax.so chan_oss.so \
+CHANNEL_LIBS=chan_modem.so chan_iax.so chan_sip.so \
+	     chan_modem_aopen.so chan_oss.so \
              chan_modem_bestdata.so chan_modem_i4l.so
 
+#
+# If you really want VoFR you can have it :-P
+#
+#CHANNEL_LIBS+=chan_vofr
+
 CHANNEL_LIBS+=$(shell [ -f /usr/include/linux/ixjuser.h ] && echo chan_phone.so)
 
 CFLAGS+=-Wno-missing-prototypes -Wno-missing-declarations
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
new file mode 100755
index 0000000000..992aa07b15
--- /dev/null
+++ b/configs/sip.conf.sample
@@ -0,0 +1,36 @@
+;
+; SIP Configuration for Asterisk
+;
+[general]
+port = 5060			; Port to bind to
+bindaddr = 0.0.0.0		; Address to bind to
+context = default		; Default for incoming calls
+
+;[snomsip]
+;type=friend
+;secret=blah
+;host=dynamic
+;defaultip=192.168.0.59
+
+;[pingtel]
+;type=friend
+;insecure=yes			; Pingtel sends from different portno
+;username=pingtel
+;secret=blah
+;host=dynamic
+;defaultip=192.168.0.60
+
+;[cisco]
+;type=friend
+;username=cisco
+;secret=blah
+;host=dynamic
+;defaultip=192.168.0.4
+
+;[cisco1]
+;type=friend
+;insecure=yes
+;username=cisco1
+;secret=blah
+;host=dynamic
+;defaultip=192.168.0.4
diff --git a/include/asterisk/rtp.h b/include/asterisk/rtp.h
new file mode 100755
index 0000000000..7c66a85dab
--- /dev/null
+++ b/include/asterisk/rtp.h
@@ -0,0 +1,54 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Real-time Transport Protocol support
+ * 
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster@linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+
+#ifndef _ASTERISK_RTP_H
+#define _ASTERISK_RTP_H
+
+#include <asterisk/frame.h>
+#include <asterisk/io.h>
+#include <asterisk/sched.h>
+
+#include <netinet/in.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+struct ast_rtp;
+
+typedef int (*ast_rtp_callback)(struct ast_rtp *rtp, struct ast_frame *f, void *data);
+
+struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io);
+
+void ast_rtp_set_peer(struct ast_rtp *rtp, struct sockaddr_in *them);
+
+void ast_rtp_get_us(struct ast_rtp *rtp, struct sockaddr_in *us);
+
+void ast_rtp_destroy(struct ast_rtp *rtp);
+
+void ast_rtp_set_callback(struct ast_rtp *rtp, ast_rtp_callback callback);
+
+void ast_rtp_set_data(struct ast_rtp *rtp, void *data);
+
+int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *f);
+
+int ast2rtp(int id);
+
+int rtp2ast(int id);
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/rtp.c b/rtp.c
new file mode 100755
index 0000000000..3a87ad43fd
--- /dev/null
+++ b/rtp.c
@@ -0,0 +1,364 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Real-time Protocol Support
+ * 
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster@linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+
+#include <asterisk/rtp.h>
+#include <asterisk/logger.h>
+#include <asterisk/options.h>
+#include <asterisk/channel.h>
+
+static int dtmftimeout = 300;	/* 300 samples */
+
+struct ast_rtp {
+	int s;
+	char resp;
+	struct ast_frame f;
+	unsigned char rawdata[1024 + AST_FRIENDLY_OFFSET];
+	unsigned int ssrc;
+	unsigned int lastts;
+	unsigned int lastrxts;
+	int dtmfcount;
+	struct sockaddr_in us;
+	struct sockaddr_in them;
+	struct timeval rxcore;
+	struct timeval txcore;
+	int *ioid;
+	unsigned short seqno;
+	struct sched_context *sched;
+	struct io_context *io;
+	void *data;
+	ast_rtp_callback callback;
+};
+
+
+void ast_rtp_set_data(struct ast_rtp *rtp, void *data)
+{
+	rtp->data = data;
+}
+
+void ast_rtp_set_callback(struct ast_rtp *rtp, ast_rtp_callback callback)
+{
+	rtp->callback = callback;
+}
+
+static void send_dtmf(struct ast_rtp *rtp)
+{
+	printf("Sending dtmf: %d (%c)\n", rtp->resp, rtp->resp);
+	rtp->f.frametype = AST_FRAME_DTMF;
+	rtp->f.subclass = rtp->resp;
+	rtp->f.datalen = 0;
+	rtp->f.timelen = 0;
+	rtp->f.mallocd = 0;
+	rtp->f.src = "RTP";
+	rtp->resp = 0;
+	if (rtp->callback)
+		rtp->callback(rtp, &rtp->f, rtp->data);
+	
+}
+
+static void process_rfc2833(struct ast_rtp *rtp, unsigned char *data, int len)
+{
+	unsigned int event;
+	char resp = 0;
+	event = ntohl(*((unsigned int *)(data)));
+	event >>= 24;
+#if 0
+	printf("Event: %08x (len = %d)\n", event, len);
+#endif	
+	if (event < 10) {
+		resp = '0' + event;
+	} else if (event < 11) {
+		resp = '*';
+	} else if (event < 12) {
+		resp = '#';
+	} else if (event < 16) {
+		resp = 'A' + (event - 12);
+	}
+	if (rtp->resp && (rtp->resp != resp)) {
+		send_dtmf(rtp);
+	}
+	rtp->resp = resp;
+	rtp->dtmfcount = dtmftimeout;
+}
+
+static int rtpread(int *id, int fd, short events, void *cbdata)
+{
+	struct ast_rtp *rtp = cbdata;
+	int res;
+	struct sockaddr_in sin;
+	int len;
+	unsigned int seqno;
+	int payloadtype;
+	int hdrlen = 12;
+	unsigned int timestamp;
+	
+	unsigned int *rtpheader;
+	
+	len = sizeof(sin);
+	
+	res = recvfrom(rtp->s, rtp->rawdata + AST_FRIENDLY_OFFSET, sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET,
+					0, (struct sockaddr *)&sin, &len);
+
+	rtpheader = (unsigned int *)(rtp->rawdata + AST_FRIENDLY_OFFSET);
+	if (res < 0) {
+		ast_log(LOG_WARNING, "RTP Read error: %s\n", strerror(errno));
+		if (errno == EBADF)
+			CRASH;
+		return 1;
+	}
+	if (res < hdrlen) {
+		ast_log(LOG_WARNING, "RTP Read too short\n");
+		return 1;
+	}
+	/* Get fields */
+	seqno = ntohl(rtpheader[0]);
+	payloadtype = (seqno & 0x7f0000) >> 16;
+	seqno &= 0xffff;
+	timestamp = ntohl(rtpheader[1]);
+#if 0
+	printf("Got RTP packet from %s:%d (type %d, seq %d, ts %d, len = %d)\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), payloadtype, seqno, timestamp,res - hdrlen);
+#endif	
+	rtp->f.frametype = AST_FRAME_VOICE;
+	rtp->f.subclass = rtp2ast(payloadtype);
+	if (rtp->f.subclass < 0) {
+		if (payloadtype == 101) {
+			/* It's special -- rfc2833 process it */
+			process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
+		} else
+			ast_log(LOG_NOTICE, "Unknown RTP codec %d received\n", payloadtype);
+		return 1;
+	}
+
+	if (!rtp->lastrxts)
+		rtp->lastrxts = timestamp;
+
+	if (rtp->dtmfcount) {
+#if 0
+		printf("dtmfcount was %d\n", rtp->dtmfcount);
+#endif		
+		rtp->dtmfcount -= (timestamp - rtp->lastrxts);
+		if (rtp->dtmfcount < 0)
+			rtp->dtmfcount = 0;
+#if 0
+		if (dtmftimeout != rtp->dtmfcount)
+			printf("dtmfcount is %d\n", rtp->dtmfcount);
+#endif
+	}
+	rtp->lastrxts = timestamp;
+
+	/* Send any pending DTMF */
+	if (rtp->resp && !rtp->dtmfcount) {
+		send_dtmf(rtp);
+		/* Setup the voice frame again */
+		rtp->f.frametype = AST_FRAME_VOICE;
+		rtp->f.subclass = rtp2ast(payloadtype);
+	}
+	rtp->f.mallocd = 0;
+	rtp->f.datalen = res - hdrlen;
+	rtp->f.data = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
+	rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
+	switch(rtp->f.subclass) {
+	case AST_FORMAT_ULAW:
+	case AST_FORMAT_ALAW:
+		rtp->f.timelen = rtp->f.datalen / 8;
+		break;
+	case AST_FORMAT_SLINEAR:
+		rtp->f.timelen = rtp->f.datalen / 16;
+		break;
+	case AST_FORMAT_GSM:
+		rtp->f.timelen = 20 * (rtp->f.datalen / 33);
+		break;
+	case AST_FORMAT_ADPCM:
+		rtp->f.timelen = rtp->f.datalen / 8;
+		break;
+	default:
+		ast_log(LOG_NOTICE, "Unable to calculate timelen for format %d\n", rtp->f.subclass);
+		break;
+	}
+	rtp->f.src = "RTP";
+	if (rtp->callback)
+		rtp->callback(rtp, &rtp->f, rtp->data);
+	return 1;
+}
+
+static struct {
+	int rtp;
+	int ast;
+} cmap[] = {
+	{ 0, AST_FORMAT_ULAW },
+	{ 3, AST_FORMAT_GSM },
+	{ 4, AST_FORMAT_G723_1 },
+	{ 5, AST_FORMAT_ADPCM },
+	{ 8, AST_FORMAT_ALAW },
+	{ 18, AST_FORMAT_G729A },
+};
+
+int rtp2ast(int id)
+{
+	int x;
+	for (x=0;x<sizeof(cmap) / sizeof(cmap[0]); x++) {
+		if (cmap[x].rtp == id)
+			return cmap[x].ast;
+	}
+	return -1;
+}
+
+int ast2rtp(int id)
+{
+	int x;
+	for (x=0;x<sizeof(cmap) / sizeof(cmap[0]); x++) {
+		if (cmap[x].ast == id)
+			return cmap[x].rtp;
+	}
+	return -1;
+}
+
+struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io)
+{
+	struct ast_rtp *rtp;
+	int x;
+	int flags;
+	rtp = malloc(sizeof(struct ast_rtp));
+	if (!rtp)
+		return NULL;
+	memset(rtp, 0, sizeof(struct ast_rtp));
+	rtp->them.sin_family = AF_INET;
+	rtp->us.sin_family = AF_INET;
+	rtp->s = socket(AF_INET, SOCK_DGRAM, 0);
+	rtp->ssrc = rand();
+	rtp->seqno = rand() & 0xffff;
+	if (rtp->s < 0) {
+		free(rtp);
+		ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno));
+		return NULL;
+	}
+	flags = fcntl(rtp->s, F_GETFL);
+	fcntl(rtp->s, F_SETFL, flags | O_NONBLOCK);
+	for (;;) {
+		/* Find us a place */
+		x = (rand() % (65000-1025)) + 1025;
+		/* Must be an even port number by RTP spec */
+		x = x & ~1;
+		rtp->us.sin_port = htons(x);
+		if (!bind(rtp->s, &rtp->us, sizeof(rtp->us)))
+			break;
+		if (errno != EADDRINUSE) {
+			ast_log(LOG_WARNING, "Unexpected bind error: %s\n", strerror(errno));
+			close(rtp->s);
+			free(rtp);
+			return NULL;
+		}
+	}
+	rtp->io = io;
+	rtp->sched = sched;
+	rtp->ioid = ast_io_add(rtp->io, rtp->s, rtpread, AST_IO_IN, rtp);
+	return rtp;
+}
+
+void ast_rtp_set_peer(struct ast_rtp *rtp, struct sockaddr_in *them)
+{
+	rtp->them.sin_port = them->sin_port;
+	rtp->them.sin_addr = them->sin_addr;
+}
+
+void ast_rtp_get_us(struct ast_rtp *rtp, struct sockaddr_in *us)
+{
+	memcpy(us, &rtp->us, sizeof(rtp->us));
+}
+
+void ast_rtp_destroy(struct ast_rtp *rtp)
+{
+	if (rtp->ioid)
+		ast_io_remove(rtp->io, rtp->ioid);
+	if (rtp->s > -1)
+		close(rtp->s);
+	free(rtp);
+}
+
+static unsigned int calc_txstamp(struct ast_rtp *rtp)
+{
+	struct timeval now;
+	unsigned int ms;
+	if (!rtp->txcore.tv_sec && !rtp->txcore.tv_usec) {
+		gettimeofday(&rtp->txcore, NULL);
+	}
+	gettimeofday(&now, NULL);
+	ms = (now.tv_sec - rtp->txcore.tv_sec) * 1000;
+	ms += (now.tv_usec - rtp->txcore.tv_usec);
+	return ms;
+}
+
+int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
+{
+	int hdrlen = 12;
+	struct ast_frame *f;
+	int codec;
+	int res;
+	unsigned int ms;
+	unsigned int *rtpheader;
+	
+	/* Make sure we have enough space for RTP header */
+	
+	if (_f->frametype != AST_FRAME_VOICE) {
+		ast_log(LOG_WARNING, "RTP can only send voice\n");
+		return -1;
+	}
+
+	codec = ast2rtp(_f->subclass);
+	if (codec < 0) {
+		ast_log(LOG_WARNING, "Don't know how to send format %d packets with RTP\n", _f->subclass);
+		return -1;
+	}
+
+	if (_f->offset < hdrlen) {
+		f = ast_frdup(_f);
+	} else
+		f = _f;
+		
+	ms = calc_txstamp(rtp) * 8;
+	switch(f->subclass) {
+	case AST_FORMAT_ULAW:
+	case AST_FORMAT_ALAW:
+		break;
+	default:
+		ast_log(LOG_WARNING, "Not sure about timestamp format for codec format %d\n", f->subclass);
+	}
+	rtp->lastts += f->datalen;
+	/* Get a pointer to the header */
+	rtpheader = (unsigned int *)(f->data - hdrlen);
+	rtpheader[0] = htonl((2 << 30) | (codec << 16) | (rtp->seqno++));
+	rtpheader[1] = htonl(rtp->lastts);
+	rtpheader[2] = htonl(rtp->ssrc); 
+	if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
+		res = sendto(rtp->s, (void *)rtpheader, f->datalen + hdrlen, 0, &rtp->them, sizeof(rtp->them));
+		if (res <0) 
+			ast_log(LOG_NOTICE, "RTP Transmission error to %s:%d: %s\n", inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
+#if 0
+		printf("Sent %d bytes of RTP data to %s:%d\n", res, inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port));
+#endif		
+	}
+	return 0;
+}
-- 
GitLab