📄 rtptrans.c
字号:
/** RTP translator.** Usage:* rtptrans host/port/ttl host/port/ttl [...]** Forwards RTP/RTCP packets from one of the named sockets to all* others. Addresses can be a multicast or unicast. TTL values for* unicast addresses are ignored. (Actually, doesn't check whether* packets are RTP or not.)** It would be easy to add transcoding on a packet-by-packet basis (as* long as the sampling rate doesn't change).** Author: Henning Schulzrinne* GMD Fokus, Berlin*** Additionally, the translator can translate VAT packets into RTP packets. * Thereby, the VAT control packets are translated into RTCP SDES packets with* a CNAME and a NAME entry. However, this is only entended to be used in the * following configuration:* VAT packets arriving on a multicast connection are translated into RTP and* sent over a unicast link. RTP packets are not translated -not yet at least-* into VAT packets and and all packets arriving on unicast links are not* changed at all. Therefore, currently mainly the following topology is * supported:** multicast VAT -> translator -> unicast RTP** and on the way back it should lokk like this** multicast VAT <- translator <- unicast VAT*** This means that the audio agent on the unicast link should be able to use* both VAT and RTP.** Author: Dorgham Sisalem* GMD Fokus, Berlin** Bug fixes and supstantial improvements by * Stephen Casner <casner@precept.com>* */#include <sys/types.h>#include <sys/uio.h>#include <sys/socket.h>#include <netinet/in.h> /* struct sockaddr_in */#include <sys/time.h> /* gettimeofday() */#include <arpa/inet.h> /* inet_ntoa() */#include <string.h>#include <stdio.h>#include <signal.h>#include <errno.h>#include <values.h>#include <unistd.h> /* select(), perror() */#include <stdlib.h> /* getopt(), atoi() */#include <memory.h> /* memset() */#include "rtp.h"#include "rtpdump.h"#include "ansi.h"#include "notify.h"#include "multimer.h"#include "vat.h"#define PAD(x,n) (((n) - ((x) & (n-1))) & (n-1))#define MAX_HOST 10extern int gettimeofday();static int debug = 0;static int hostc = 0;static multi_sock[3] = {0,0,0};static struct { int sock; struct sockaddr_in sin;} side[MAX_HOST][3]; /* [host][proto] *//* * create a linked list for traversing the sequence numbers of the different * streams arriving over a multicast link to a unicast network */typedef struct stream_id{ int seq; int addr; int next_ts; struct stream_id* next;} STREAM;typedef struct stream_id stream;/* * We need to keep in memory the sequence number of the last sent packet * for each data stream. */static stream *head; /* start of list */static stream *middle; /* middle of the list, keeping this pointer reduces the * avarage searching path to a 1/4 of the list instead of * 1/2. */static stream *last; /* Last seen stream, as the probability that the next * packet will belong to the last seen one this reduces * the searching path even further. */static int list_len;int create_stream(int addr, int next){ stream *elem; int i; stream* new_stream=( stream *) malloc(sizeof( stream)); if(new_stream==NULL) { perror("can not create a new steam identifier "); exit (0); } /* init created stream */ new_stream->next=NULL; new_stream->addr=addr; new_stream->seq=addr; new_stream->next_ts=next; if(head==NULL) { /* initialize the list */ head=new_stream; middle=new_stream; list_len=1;#if !defined(nextstep) srand48(rand()); /* initialize random number generator */#else srand(rand()); /* (fred) This is surprising */#endif new_stream->seq=rand(); last=new_stream; return new_stream->seq; } new_stream->seq=rand(); /* init the first sequence number for this stream */ if((list_len++)%2) { for(elem=head, i=1; i<(list_len/2)+(list_len%2);i++,elem=elem->next); middle=elem; } /* organize the list in order of the ssrc */ if(head->addr>addr) { new_stream->next=head; head=new_stream; last=new_stream; return new_stream->seq; } for(elem=head;elem->next!=NULL;elem=elem->next) { if(elem->next->addr>addr) { new_stream->next=elem->next; elem->next=new_stream; last=new_stream; return new_stream->seq; } } ; if(elem->next==NULL) { elem->next=new_stream; last=new_stream; return new_stream->seq; } return new_stream->seq;}/* * Add a stream to the list. */int find_stream(int addr, int ts, int next, int m){ stream *element; /* packet belongs to the last seen stream */ if ((last!=NULL)&&(addr==last->addr)) { last->seq+=1; if (ts != last->next_ts && !m) last->seq+=1; /* approximate missing some packets */ last->next_ts = next; return(last->seq); } if((middle!=NULL)&&(addr>=middle->addr)) element=middle; else element=head; for(; (element!=NULL)&&(element->addr<=addr); element=element->next) { if(element->addr==addr) { element->seq+=1; if (ts != element->next_ts && !m) element->seq += 1; /* approximate missing some packets */ element->next_ts = next; return (element->seq); } } return(create_stream(addr, next));}struct sdes_msg { rtcp_common_t header; struct rtcp_sdes sdes;};/** Handle file input events from network sockets.*/static Notify_value socket_handler(Notify_client client, int sock){ int len, addr_len; int proto; struct sockaddr_in sin_from; char packet[8192]; int i; const int VAT_LEN=8; vat_hdr_t *vat_hdr; rtp_hdr_t *rtp_hdr; rtp_hdr_t rtp_hdr_send; proto = ((int)client & 1); /* Read packet data from socket. */ addr_len = sizeof(sin_from); len = recvfrom(sock, packet, sizeof(packet), 0, (struct sockaddr *)&sin_from, &addr_len); rtp_hdr=(rtp_hdr_t *)packet; if (debug) { struct timeval now; gettimeofday(&now, 0); printf("%0.3f %s %4d [%s/%d]\n", now.tv_sec + now.tv_usec/1e6, rtp_hdr->version==2 ? (proto ? "RTCP" : "RTP ") : rtp_hdr->version==0 ? (proto ? "vatC" : "vat ") : "UKWN", len, inet_ntoa(sin_from.sin_addr), ntohs(sin_from.sin_port)); } /* do not translate packets that already use RTP or arrive over the unicast link*/ if((rtp_hdr->version==2)||((sock!=multi_sock[0])&&(sock!=multi_sock[1]))) { rtp_hdr=(rtp_hdr_t *)packet; for (i = 0; i < hostc; i++) { if (side[i][proto].sock != sock) { if (sendto(side[i][2].sock, packet, len, 0, (struct sockaddr *)&side[i][proto].sin,sizeof(side[i][proto].sin))<0) perror("sendto RTCP"); } } } else { struct msghdr msg; if (!proto) { /*translate VAT packets */ struct iovec iov[2]; char type; int samples = len-VAT_LEN; vat_hdr=(vat_hdr_t *)packet; if(vat_hdr->flags&VATHF_NEWTS) rtp_hdr_send.m=1; else rtp_hdr_send.m=0; type= vat_hdr->flags&VATHF_FMTMASK; switch (type) { case VAT_AUDF_GSM: samples = (samples/33)*160; case VAT_AUDF_MULAW8: case VAT_AUDF_G721: /* samples not right for this */ case VAT_AUDF_G723: /* samples not right for this */ rtp_hdr_send.pt=type; break; case VAT_AUDF_IDVI: samples = (samples-4)*2; rtp_hdr_send.pt=5; break; case VAT_AUDF_L16_16: case VAT_AUDF_L16_44: case VAT_AUDF_LPC4: case VAT_AUDF_CELP: case VAT_AUDF_LPC1: case VAT_AUDF_UNDEF :
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -