一、源代码的构建框架
Ortp是一种开源软件,实现了RTP 与RTCP 协议。首先在RTP中有几种重要的结构体,第一种比较重要的结构体是payload type,该结构用于指定编码类型,以及与其相关的时钟速率、采样率等一些参数,参见下图。
struct _PayloadType
{
int type; /**< one of PAYLOAD_* macros*/
int clock_rate; /**< rtp clock rate*/
char bits_per_sample; /* in case of continuous audio data */
char *zero_pattern;
int pattern_length;
/* other useful information for the application*/
int normal_bitrate; /*in bit/s */
char *mime_type; /**<actually the submime, ex: pcm, pcma, gsm*/
int channels; /**< number of channels of audio */
char *recv_fmtp; /* various format parameters for the incoming stream */ char *send_fmtp; /* various format parameters for the outgoing stream */ int flags;
void *user_data;
};
在代码中,不同的媒体类型有不同的 payloadtype 结构体与之对应,h263,g729,MPEG4等。因为每种编码都有其独有的特点,而且许多参数也不一样,所以 RTP 包头中使用payload 域标记负载的类型,一方面接收端可以就此判断负载的类型,从而选择对应的解码器进行解码播放;另一方面,代码在进行时间戳等方面的计算时可以更加方便一点。
所有系统当前支持的payload 类型都被放在一个数组中, 由全局变量 av_profile 这个结构体实例统领。
除了 payloadtype 结构体外,一个更重要的结构体是 rtpsession。该结构体即是一个会
话的抽象,与会话相关的各种信息都定义在该结构体上或者能够通过该结构体到。要使用oRTP 进行媒体数据的传输,需要先创建一个会话,之后所有数据的传输都在会话上完成或
基于会话完成。rtpsession结构体的定义如下:
struct _RtpSession
{
RtpSession *next; /* next RtpSession, when the session are enqueued by the scheduler */
int mask_pos; /* the position in the scheduler mask of RtpSession : do not move this field: it is part of the ABI since the session_set macros use it*/ struct {
RtpProfile *profile;
int pt;
unsigned int ssrc;
WaitPoint wp;
int telephone_events_pt; /* the payload type used for telephony events */
} snd,rcv;
unsigned int inc_ssrc_candidate;
int inc_same_ssrc_count;
int hw_recv_pt; /* recv payload type before jitter buffer */
int recv_buf_size;
RtpSignalTable on_ssrc_changed;
RtpSignalTable on_payload_type_changed;
RtpSignalTable on_telephone_event_packet;
RtpSignalTable on_telephone_event;
RtpSignalTable on_timestamp_jump;
RtpSignalTable on_network_error;
RtpSignalTable on_rtcp_bye;
struct _OList *signal_tables;
struct _OList *eventqs;
msgb_allocator_t allocator;
RtpStream rtp;
RtcpStream rtcp;
RtpSessionMode mode;
struct _RtpScheduler *sched;
uint32_t flags;
int dscp;
int multicast_ttl;
int multicast_loopback;
void * user_data;
/* FIXME: Should be a table for all session participants. */
struct timeval last_recv_time; /* Time of receiving the RTP/RTCP packet. */ mblk_t *pending;
/* telephony events extension */
mblk_t *current_tev; /* the pending telephony events */
mblk_t *sd;
queue_t contributing_sources;
unsigned int lost_packets_test_vector;
unsigned int interarrival_jitter_test_vector;
unsigned int delay_test_vector;
float rtt;/*last round trip delay calculated*/
OrtpNetworkSimulatorCtx *net_sim_ctx;
bool_t symmetric_rtp;
bool_t permissive; /*use the permissive algorithm*/
bool_t use_connect; /* use connect() on the socket */recv函数
bool_t ssrc_set;
};
Session 的初始化通过接口 rtp_session_init 完成,外部获得一个新的 session是
通过调用接口rtp_session_new 完成。关于 session 的其他有关配置和获取信息的操作都可以在文件 rtpsession.c 中到定义。
使用 oRTP 进行数据传输时,可以在一个任务上完成多个会话流的接收和发送。这得益于oRTP 中调度模块的支持。要使用调度模块,应用需要在进行 oRTP 的初始化时对调度进行初始化,将需要调度管理的会话注册到调度模块中,这样当进行接收和发送操作时,先向调度询问当前会话是否可以进行发送和接收,如果不能进行收发操作,则处理下一个会话。这有点类似I/O 接口上的 select 操作。调度模块使用的数据结构主要为 rtpscheduler,定义如下:
struct _RtpScheduler {
RtpSession *list; /* list of scheduled sessions*/
SessionSet all_sessions;  /* mask of scheduled sessions */
int  all_max; /* the highest pos in the all mask */
SessionSet  r_sessions;  /* mask of sessions that have a recv event */ int  r_max;
SessionSet w_sessions;  /* mask of sessions that have a send event */ int  w_max;
SessionSet e_sessions; /* mask of session that have error event */
int  e_max;
int max_sessions; /* the number of position in the masks */
/* GMutex  *unblock_select_mutex; */
ortp_cond_t  unblock_select_cond;
ortp_mutex_t lock;
ortp_thread_t thread;
int thread_running;
struct _RtpTimer *timer;
uint32_t time_;      /*number of miliseconds elapsed since the start of the thread */
uint32_t timer_inc; /* the timer increment in milisec */
};
调度结构体中的r/w/e分别代表接收,发送,异常。
Avprofile.c文件中定义了一些负载类型。
接收的 rtp和 rtcp 包的解析处理函数在文件 rtpparse.c 和 rtcpparse.c 文件中实现。实现的是将包中的事件包取出放入列队中。
rtpsession_inet.c 文件中定义了数据在网络中传输的过程,利用socket 接口完成了。介绍了socket ,远程地址,端口的建立等设置。其相关的声明在rtpsession_priv.h 中定义,Rtpsignaltable.c主要实现一些信号量的初始化,加入一个信号量,以及发射信号量。定义一些回调函数等。
rtptimer.c,scheduler.c,sessionset.c等文件实现了调度模块。
port.c 文件中实现常用的任务(如分配内存)的创建及销毁,条件变量及互斥锁,进程间的管道通信机制等。
文件utils.c 文件中讲述了一些数据结构,讲述了一些链表的操作。
Str_utils.c文件中讲述了一些队列的操作。首先,队列数据结构由三部分组成:队列头、消息块以及数据块队列头指向消息块,消息块之间可以构成双向链表,这是队列的基本要素。消息块本身不带buffer,数据是由专门的数据块来保存的, 并被消息块指向。在发送上层应用的 payload 数据之前,oRTP 会构造一个消息块,数据指针会指向payload, 这避免了数
据拷贝。较低层的接口处理数据时依赖于消息块结构。接收后的数据从消息块中拷贝到用户buffer。接收的 rtp和 rtcp 包的解析处理函数在文件 rtpparse.c 和 rtcpparse.c 文件中实现。
在使用oRTP 提供的 rtp 库之前,需要先对其进行初始化,这部分的实现在 oRTP.c 文件中。oRTP的初始化主要调用两个接口:ortp_init 和 ortp_scheduler_init。其中
ortp_init完成了 payload 的注册,ortp_scheduler_init完成了调度任务的初始化。
写程序首先你要了解你的程序是干什么,要解决的什么问题,需要那些变量,以及各变量的关系。我们RTP的目的是实现对数据的打包输出,以及对数据的接收,我们前期的工作就是实现各种初始化,将我们的想要的传输的数据,地址信息等通过调用库函数提供的接口将我们的数据传入内部,在做这些以前,我们还需要判断我们的系统参数个数是否正确,同时还要注意数据类型的一致性。一系列的初始化结束后就要进行数据的发送与接收了,这些数据都是要经过缓冲区的,再写入我们的文件系统的,或者发送出去。整个过程结束后,就是要进行资源的释放。编程的难点是消息是怎样交换。
二、主要函数介绍

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。