http://blog.youkuaiyun.com/ren911/article/details/5724509
一. rtpsend.c主要内容
这个例子主要是表示了PCMU格式的音频文件或者直接从声卡得到的音频流如何发送
#include <ortp/ortp.h>
#include <signal.h>
#include <stdlib.h>
#ifndef _WIN32
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#endif
int runcond=1;
void stophandler(int signum)
{
runcond=0;
}
static const char *help="usage: rtpsend filename dest_ip4addr dest_port [ --with-clockslide <value> ] [ --with-jitter <milliseconds>]\n";
int main(int argc, char *argv[])
{
RtpSession *session;
unsigned char buffer[160];
int i;
FILE *infile;
char *ssrc;
uint32_t user_ts=0;
int clockslide=0;
int jitter=0;
if (argc<4){
printf("%s", help);
return -1;
}
for(i=4;i<argc;i++){
if (strcmp(argv[i],"--with-clockslide")==0){
i++;
if (i>=argc) {
printf("%s", help);
return -1;
}
clockslide=atoi(argv[i]);
ortp_message("Using clockslide of %i milisecond every 50 packets.",clockslide);
}else if (strcmp(argv[i],"--with-jitter")==0){
ortp_message("Jitter will be added to outgoing stream.");
i++;
if (i>=argc) {
printf("%s", help);
return -1;
}
jitter=atoi(argv[i]);
}
}
//初始化oRTP库,应该在使用oRTP API前使用
ortp_init();
/*
设置计划,scheduler可以管理多个session,在接收端可以通过select来接收多个session。
常见的就是音频视频分两路传输,这个和后面结合起来,后面的基本都是对session的设置,
比如对两个session设置不同的payload等 */
ortp_scheduler_init();
//设置log级别
ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR);
/*
创建一个新的rtp会话,如果这个会话能够发送数据(RTP_SESSION_SENDONLY or RTP_SESSION_SENDRECV),
输出流会被赋予一个随机的SSRC数 */
session=rtp_session_new(RTP_SESSION_SENDONLY);
//RtpScheduler管理多个session的调度和收发的控制,本函数设置是否使用该session调度管理功能。
rtp_session_set_scheduling_mode(session,1);
/*
阻塞模式只有在scheduling mode被开启的情况下才能使用,
本函数决定了rtp_session_recv_with_ts() 和 rtp_session_send_with_ts()两个函数的行为,
如果启用了阻塞模式,则rtp_session_recv_with_ts()会一直阻塞直到接收RTP包的时间点到达
(这个时间点由该函数参数中所定义的时间戳来决定),当接收完RTP数据包后,该函数才会返回。
同样,rtp_session_send_with_ts()也会一直阻塞直到需要被发送的RTP包的时间点到达,发送结束后,函数才返回。*/
rtp_session_set_blocking_mode(session,1);
/*
如果为TRUE,一个connect()系统调用将在发送到目的地的socket上使用,
如果会话使用symmetric rtp(见rtp_session_set_symmetric_rtp(),主要用于穿越防火墙),
一个connect()在第一个包接收后将对源地址使用。
连接一个socket会造成拒绝所有不是从在connect()里指定的地址发送过来的包。
它也会造成应用程序可以检测道德ICMP错误。*/
rtp_session_set_connected_mode(session,TRUE);
//设置远端地址
rtp_session_set_remote_addr(session,argv[2],atoi(argv[3]));
/*
设置希望接收的包和将要发送的包的负载类型。
如果接收包中的负载类型和希望的不同,将会发出payload_type_changed信号。可以对这个信号挂载函数处理。
这里设置为0,实际表示payload type为PCMU,ortp里面这个设置不光设置数字就行了,
还需要avprofile中定义的payload结构,负责会报无法识别的type */
rtp_session_set_payload_type(session,0);
ssrc=getenv("SSRC");
if (ssrc!=NULL) {
printf("using SSRC=%i.\n",atoi(ssrc));
// 设置输出流的SSRC。不做此步的话将会给个随机值
rtp_session_set_ssrc(session,atoi(ssrc));
}
#ifndef _WIN32
infile=fopen(argv[1],"r");
#else
infile=fopen(argv[1],"rb");
#endif
if (infile==NULL) {
perror("Cannot open file");
return -1;
}
signal(SIGINT,stophandler);
while( ((i=fread(buffer,1,160,infile))>0) && (runcond) )
{
/*发送一个rtp数据报,通过rtp_session_set_remote_addr()设置目的地,以时间戳发送数据。
发送RTP数据需要自己管理时间戳的递增,每调用一次本函数,请根据实际情况对userts进行递增,
具体递增的规则见RTP协议中的说明。
例如:如果发送的是采样率为90000Hz的视频数据包,每秒25帧,
则时间戳的增量为:90000/25 = 3600时间戳的起始值为随机值,建议设置为0 。*/
rtp_session_send_with_ts(session,buffer,i,user_ts);
user_ts+=160;
if (clockslide!=0 && user_ts%(160*50)==0){
ortp_message("Clock sliding of %i miliseconds now",clockslide);
//设置时间偏移
rtp_session_make_time_distorsion(session,clockslide);
}
/*this will simulate a burst of late packets */
//以下将会模拟一些爆发的延迟包
if (jitter && (user_ts%(8000)==0)) {
struct timespec pausetime, remtime;
ortp_message("Simulating late packets now (%i milliseconds)",jitter);
pausetime.tv_sec=jitter/1000;
pausetime.tv_nsec=(jitter%1000)*1000000;
while(nanosleep(&pausetime,&remtime)==-1 && errno==EINTR){
pausetime=remtime;
}
}
}
fclose(infile);
rtp_session_destroy(session);
ortp_exit();
ortp_global_stats_display();
return 0;
}