RTPProxy是纯C语言开发,使用面向对象的思路实现的对stream、session等的抽象,另外对象的构造、析构和引用计数机制都有实现,和doubango中对象的实现思路类似,每个对象一个c文件,提供类似rtpp_server_ctor和rtpp_server_dtor的构造和析构方法,然后提供一个结构体的实例化对象,结构体对象中第一个对象是该对象的公共接口方法指针,类似如下代码:
static const struct rtpp_server_smethods rtpp_server_smethods = {
.get = &rtpp_server_get,
.get_ssrc = &rtpp_server_get_ssrc,
.set_ssrc = &rtpp_server_set_ssrc,
.get_seq = &rtpp_server_get_seq,
.set_seq = &rtpp_server_set_seq,
.start = &rtpp_server_start
};
并在ctor方法中设置指针变量指向这个全局的变量地址:
rp->pub.smethods = &rtpp_server_smethods;
RTPProxy的实现比想象中简单,完全符合SIP呼叫通话建立规则,一个端口申请一个在RTPProxy的代理端口,一个一对一的通话申请两个RTPProxy的端口,然后RTPProxy在接收到包后转给对应的端口。其中每个session有两个stream对象,一个是caller,一个callee,这样就完成了一对一的包转发和通话流程。
为了调试方便,我修改了输入命令的的分割字符串:改为#号分割,便于通过一个客户端的socket发送指令:
struct rtpp_command *
get_command(struct cfg *cf, int controlfd, int *rval, double dtime,
struct rtpp_command_stats *csp, int umode,
struct rtpp_cmd_rcache *rcache_obj){
//...
//for (ap = cmd->argv; (*ap = rtpp_strsep(&cp, "\r\n\t ")) != NULL;) {
for (ap = cmd->argv; (*ap = rtpp_strsep(&cp, "#")) != NULL;) {
//...
}
rtpproxy的启动:
rtpproxy -F -f -s udp:0.0.0.0 12221 -d DBUG
写一个UDP Socket的客户端连接到RtpProxy的12221端口,然后发送指令:
sendToServer: len [63] – content [#t#U#30044995-03030-3030-3031-34#11.12.112.10#19393#123@11.com#]
input message to others : Read: len [8] – content [t 47868]
#dd#L#30044995-03030-3030-3031-34#11.12.112.10#19398#123@11.com#
sendToServer: len [64] – content [#dd#L#30044995-03030-3030-3031-34#11.12.112.10#19398#123@11.com#]
input message to others : Read: len [9] – content [dd 40888]
整体文件的引用关系如下图:
测试程序,依赖libevent
//event test udp socket server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <event.h>
#include <event2/listener.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/resource.h>
#define LOCAL_IP "11.12.115.139"
#define LOCAL_PORT 19393
#define SVR_IP "11.12.115.200"
#define SVR_PORT 22222
#define BUF_SIZE 1024
#define UR_CLIENT_SOCK_BUF_SIZE (65536)
#define UR_SERVER_SOCK_BUF_SIZE (UR_CLIENT_SOCK_BUF_SIZE * 32)
void read_cb(int fd, short event, void *arg) {
char buf[BUF_SIZE];
int len;
int size = sizeof(struct sockaddr);
struct sockaddr_in client_addr;
memset(buf, 0, sizeof(buf));
len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &size);
if (len == -1) {
perror("recvfrom()");
} else if (len == 0) {
printf("Connection Closed\n");
} else {
printf("Read: len [%d] – content [%s]\n", len, buf);
/* Echo */
//sendto(fd, buf, len, 0, (struct sockaddr *)&client_addr, size);
}
}
typedef struct _RTPHeader {
#if 0
//rtp header
unsigned int version:2; /* protocol version */
unsigned int p:1; /* padding flag */
unsigned int x:1; /* header extension flag */
unsigned int cc:4; /* CSRC count */
unsigned int m:1; /* marker bit */
unsigned int pt:7; /* payload type */
#else
unsigned short int rtpheader;
#endif
unsigned short int seq; /* sequence number */
unsigned int ts; /* timestamp */
unsigned int ssrc; /* synchronization source */
//UInt32 csrc[1]; /* optional CSRC list */
}RTPHeader;
void sendToServer(int fd, char* msg, int len, struct sockaddr_in *server){
int newLen = len + sizeof(RTPHeader);
char *rtpBuffer = (char *)malloc(newLen);
printf("sendToServer: len [%d] – content [%s], rtplen[%d]\n", len, msg, newLen);
static unsigned short seqNum = 1;
static unsigned long SSRC = 0x99999;
RTPHeader rtppacket;
rtppacket.seq = htons(seqNum++);
rtppacket.ssrc = htonl(SSRC);
rtppacket.rtpheader = htons(0x8000 | 0x08 | 0x80);//96 => 0x60 0x08=> pcma
memcpy(rtpBuffer, &rtppacket, sizeof(RTPHeader));
memcpy(rtpBuffer+sizeof(RTPHeader), msg, len);
sendto(fd, rtpBuffer, newLen, 0, (struct sockaddr *)server, sizeof(struct sockaddr_in));
free(rtpBuffer);
}
typedef struct AAA{
struct sockaddr_in *server;
int fd;
}ServerInfo;
int set_sock_buf_size(int fd, int sz0)
{
int sz;
sz = sz0;
while (sz > 0) {
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const void*) (&sz), (socklen_t) sizeof(sz)) < 0) {
sz = sz / 2;
} else {
break;
}
}
if (sz < 1) {
perror("Cannot set socket rcv size");
}
sz = sz0;
while (sz > 0) {
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void*) (&sz), (socklen_t) sizeof(sz)) < 0) {
sz = sz / 2;
} else {
break;
}
}
if (sz < 1) {
perror("Cannot set socket snd size");
}
return 0;
}
//recv user input value
static void * recv_input_thread(void *arg) {
if (arg == NULL){
return NULL;
}
ServerInfo *serverInfo = (ServerInfo *) arg;
char input;
char msg[1024];
do{
printf("input message to others[lenth<1024]:");
memset(msg, 0x00, 1024);
//scanf("%s", &msg);
gets(msg);
msg[1023] = '\0';
sendToServer(serverInfo->fd, msg, strlen(msg), serverInfo->server);
}while(input != '0');
printf("Done!\n");
free(serverInfo);
return NULL;
}
int bind_socket(struct event *ev, int sock_fd, int local_port) {
int flag = 1;
struct sockaddr_in sin;
/* Set IP, port */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(LOCAL_IP);
sin.sin_port = htons(local_port);
#ifdef IP_RECVERR
if (sin.sin_family != AF_INET6) {
int on = 0;
#ifdef TURN_IP_RECVERR
on = 1;
#endif
if(setsockopt(sock_fd, IPPROTO_IP, IP_RECVERR, (void *)&on, sizeof(on))<0)
perror("IP_RECVERR");
}
#endif
#ifdef IPV6_RECVERR
if (sin.sin_family == AF_INET6) {
int on = 0;
#ifdef TURN_IP_RECVERR
on = 1;
#endif
if(setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVERR, (void *)&on, sizeof(on))<0)
perror("IPV6_RECVERR");
}
#endif
if (fcntl(sock_fd, F_SETFL, O_NONBLOCK) == -1) {
perror("O_NONBLOCK");
return -1;
}
set_sock_buf_size(sock_fd, UR_SERVER_SOCK_BUF_SIZE);
/* Bind */
if (bind(sock_fd, (struct sockaddr *)&sin, sizeof(struct sockaddr)) < 0) {
perror("bind()");
return -1;
} else {
printf("bind() success – [%s] [%u]\n", SVR_IP, local_port);
}
/* Init one event and add to active events */
event_set(ev, sock_fd, EV_READ | EV_PERSIST, &read_cb, NULL);
if (event_add(ev, NULL) == -1) {
printf("event_add() failed\n");
}
return 0;
}
//[root@localhost sample]# gcc -o send_rtp_test_udp_client send_rtp_test_udp_client.c -levent -lpthread
//[root@localhost sample]# ./send_rtp_test_udp_client 11.12.115.200 12221 19394
int
main(int argc, char **argv)
{
struct event udp_event;
if (argc < 4){
printf("event_init() failed\n");
return -1;
}
char *serverIp;
int serverPort = 0;
int localPort = 0;
int len = strlen(argv[1]);
serverIp = (char *)malloc(len + 1);
memcpy(serverIp, argv[1], len);
serverIp[len] = '\0';
serverPort = atoi(argv[2]);
localPort = atoi(argv[3]);
printf("input serverIp:%s, port:%d, localPort:%d\n", serverIp, serverPort, localPort);
/* Init. event */
if (event_init() == NULL) {
printf("event_init() failed\n");
return -1;
}
int sock_fd;
int flag = 1;
struct sockaddr_in server;
/* Create endpoint */
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket()");
return -1;
}
/* Set socket option */
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)) < 0) {
perror("setsockopt()");
return 1;
}
/* Bind socket */
if (bind_socket(&udp_event, sock_fd, localPort) != 0) {
printf("bind_socket() failed\n");
return -1;
}
/* Set IP, port */
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(serverIp);
server.sin_port = htons(serverPort);
ServerInfo *serverInfo = (ServerInfo *)malloc(sizeof(ServerInfo));
serverInfo->server = &server;
serverInfo->fd = sock_fd;
pthread_t tidp;
if ((pthread_create(&tidp, NULL, recv_input_thread, (void*)serverInfo)) == -1){
printf("create error!\n");
return 1;
}
/* Enter the event loop; does not return. */
event_dispatch();
close(sock_fd);
printf("done\n");
return 0;
}
编译:gcc -o send_rtp_test_udp_client send_rtp_test_udp_client.c -levent -lpthread
运行:./send_rtp_test_udp_client 11.12.115.200 12221 19993
input serverIp:11.12.115.200, port:12221, localPort:19993
bind() success ?.[11.12.115.200] [19993]
input message to others[lenth<1024]: