Skip to content
Snippets Groups Projects
rtp.c 40.5 KiB
Newer Older
Mark Spencer's avatar
Mark Spencer committed
/*
 * 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 <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>
Mark Spencer's avatar
Mark Spencer committed
#include <asterisk/frame.h>
Mark Spencer's avatar
Mark Spencer committed
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/channel.h>
Mark Spencer's avatar
Mark Spencer committed
#include <asterisk/acl.h>
#include <asterisk/channel.h>
#include <asterisk/channel_pvt.h>
#include <asterisk/config.h>
Mark Spencer's avatar
Mark Spencer committed
#define TYPE_HIGH	 0x0
#define TYPE_LOW	 0x1
Mark Spencer's avatar
Mark Spencer committed
#define TYPE_SILENCE	 0x2
#define TYPE_DONTSEND	 0x3
Mark Spencer's avatar
Mark Spencer committed
#define TYPE_MASK	 0x3

static int dtmftimeout = 3000;	/* 3000 samples */
static int rtpstart = 0;
static int rtpend = 0;

// The value of each payload format mapping:
struct rtpPayloadType {
  int isAstFormat; // whether the following code is an AST_FORMAT
  int code;
};

#define MAX_RTP_PT 256

#define FLAG_3389_WARNING (1 << 0)

Mark Spencer's avatar
Mark Spencer committed
struct ast_rtp {
	int s;
	char resp;
	struct ast_frame f;
	unsigned char rawdata[8192 + AST_FRIENDLY_OFFSET];
Mark Spencer's avatar
Mark Spencer committed
	unsigned int ssrc;
	unsigned int lastts;
	unsigned int lastrxts;
	unsigned int lastividtimestamp;
	unsigned int lastovidtimestamp;
	unsigned int lasteventseqn;
Mark Spencer's avatar
Mark Spencer committed
	int lasttxformat;
	int lastrxformat;
Mark Spencer's avatar
Mark Spencer committed
	int dtmfcount;
Mark Spencer's avatar
Mark Spencer committed
	unsigned int dtmfduration;
	int nat;
	int flags;
Mark Spencer's avatar
Mark Spencer committed
	struct sockaddr_in us;
	struct sockaddr_in them;
	struct timeval rxcore;
	struct timeval txcore;
Mark Spencer's avatar
Mark Spencer committed
	struct timeval dtmfmute;
Mark Spencer's avatar
Mark Spencer committed
	struct ast_smoother *smoother;
Mark Spencer's avatar
Mark Spencer committed
	int *ioid;
	unsigned short seqno;
	struct sched_context *sched;
	struct io_context *io;
	void *data;
	ast_rtp_callback callback;
    struct rtpPayloadType current_RTP_PT[MAX_RTP_PT];
    // a cache for the result of rtp_lookup_code():
    int rtp_lookup_code_cache_isAstFormat;
    int rtp_lookup_code_cache_code;
    int rtp_lookup_code_cache_result;
	struct ast_rtcp *rtcp;
};

struct ast_rtcp {
	int s;		/* Socket */
	struct sockaddr_in us;
	struct sockaddr_in them;
static struct ast_rtp_protocol *protos = NULL;

int ast_rtp_fd(struct ast_rtp *rtp)
{
	return rtp->s;
}
int ast_rtcp_fd(struct ast_rtp *rtp)
{
	if (rtp->rtcp)
		return rtp->rtcp->s;
	return -1;
}

Mark Spencer's avatar
Mark Spencer committed
static int g723_len(unsigned char buf)
{
	switch(buf & TYPE_MASK) {
Mark Spencer's avatar
Mark Spencer committed
	case TYPE_DONTSEND:
		return 0;
		break;
Mark Spencer's avatar
Mark Spencer committed
	case TYPE_SILENCE:
		return 4;
		break;
	case TYPE_HIGH:
		return 24;
		break;
	case TYPE_LOW:
		return 20;
		break;
	default:
		ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", buf & TYPE_MASK);
	}
	return -1;
}

static int g723_samples(unsigned char *buf, int maxlen)
{
	int pos = 0;
	int samples = 0;
	int res;
	while(pos < maxlen) {
		res = g723_len(buf[pos]);
		if (res <= 0)
Mark Spencer's avatar
Mark Spencer committed
			break;
		samples += 240;
		pos += res;
	}
	return samples;
}

Mark Spencer's avatar
Mark Spencer committed
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;
}

void ast_rtp_setnat(struct ast_rtp *rtp, int nat)
{
	rtp->nat = nat;
}

static struct ast_frame *send_dtmf(struct ast_rtp *rtp)
Mark Spencer's avatar
Mark Spencer committed
{
Mark Spencer's avatar
Mark Spencer committed
	struct timeval tv;
	static struct ast_frame null_frame = { AST_FRAME_NULL, };
	gettimeofday(&tv, NULL);
	if ((tv.tv_sec < rtp->dtmfmute.tv_sec) ||
	    ((tv.tv_sec == rtp->dtmfmute.tv_sec) && (tv.tv_usec < rtp->dtmfmute.tv_usec))) {
		ast_log(LOG_DEBUG, "Ignore potential DTMF echo from '%s'\n", inet_ntoa(rtp->them.sin_addr));
		rtp->resp = 0;
		rtp->dtmfduration = 0;
		return &null_frame;
	}
	ast_log(LOG_DEBUG, "Sending dtmf: %d (%c), at %s\n", rtp->resp, rtp->resp, inet_ntoa(rtp->them.sin_addr));
Mark Spencer's avatar
Mark Spencer committed
	rtp->f.frametype = AST_FRAME_DTMF;
	rtp->f.subclass = rtp->resp;
	rtp->f.datalen = 0;
Mark Spencer's avatar
Mark Spencer committed
	rtp->f.samples = 0;
Mark Spencer's avatar
Mark Spencer committed
	rtp->f.mallocd = 0;
	rtp->f.src = "RTP";
	rtp->resp = 0;
Mark Spencer's avatar
Mark Spencer committed
	rtp->dtmfduration = 0;
	return &rtp->f;
Mark Spencer's avatar
Mark Spencer committed
static struct ast_frame *process_cisco_dtmf(struct ast_rtp *rtp, unsigned char *data, int len)
{
	unsigned int event;
	char resp = 0;
	struct ast_frame *f = NULL;
	event = ntohl(*((unsigned int *)(data)));
	event &= 0x001F;
Loading
Loading full blame...