相关数据结构

1.    tsip_dialog_invite_t

描述:

一个invite_dialog代表了一个invite期间的所有的信令流程,因此,它首先是一个普遍的dialog的特殊化结构,在该结构的起始部分,有一个TSIP_DECLARE_DIALOG声明,该声明展开后是一个tsip_dilog_t __dialog字段的定义,这是一种在C中一个具化对象对通用对象的继承机制,tsip_dialog_t对象代表了更通用的实例,而tsip_dialog_invite_t对象则是tsip_dialog_t对象的具化和拓展。

一个dialog本身有自己的有限状态处理机,有自己的当前状态和当前状态应执行的动作,还有一个状态变化时的回调函数。它还需要有一个字段指向它所属的session,这些字段,反应在数据类型上上,分别是:

tsk_fsm_t(有限状态机),tsip_action_t(状态执行动作),tsip_dialog_state_t(当前状态),

tsip_dialog_event_callback_f(回调函数),tsip_ssession_t(所属session)。

创建时机:

tsip_action_INVITE()函数是上层应用与底层协议栈的接口,当上层应用发起一个INVITE时,便会分层调用到该接口。

tsip_dialog_invite_t类型的实例便是在该接口中创建的,对于创建时,还需要在协议栈的全局dialog队列中寻找一遍,看是否相关的dialog已经在之前被创建,若是,则沿用老的实例,若否,则用tsip_dialog_layer_new()函数创建一个新的实例,并链入到协议栈dialog_layer层的全局队列中。

关键点:

2.    tmedia_session_mgr_t

描述:

一个tmedia_session_mgr_t实例是由上述的tsip_dialog_invite_t实例的session_mgr字段记录的,代表了在一个对话期间各种媒体设置的管理者。

当发起一个INVITE时,首先必须存在一个代表信令流程的对象即dialog对象,其次,还要有一个负责管理媒体信息的对象,及该结构的实例。

创建时机:

该结构的首次创建是在invite_dialog的状态转换过程中,c0000_Started_2_Outgoing_X_oINVITE()函数是一个状态转化函数,它代表着当前dialog由初始状态向发起INVITE后状态转化需要执行的操作,在该函数内部,通过tmedia_session_mgr_create()创建tmedia_session_mgr_t实例,然后填写本地媒体信息(即sdp中得各个字段),申请rtp端口号,生成代表rtp的网络传输实例(tnet_transport_t对象),最后在该状态转换函数中,通过协议栈的代表信令的网络传输实例将INVITE消息传递出去。

关键点:

在tmedia_session_mgr_t中,有一个tmedia_sessions_L_t*sessions的字段,这个字段其实是一个队列,挂载的表示代表了各种媒体的信息(音频,视频),每一个队列节点是一个tmedia_session_t的实例。

关键函数:

_tmedia_session_mgr_load_sessions(tmedia_session_mgr_t *mgr)函数

原型:_tmedia_session_mgr_load_sessions(tmedia_session_mgr_t *mgr)

作用:用于生成和加载各种类型的tmedia_session_t实例。

说明:_tmedia_session_mgr_load_sessions()函数在tmedia_session_mgr_create()函数中被调用,在这个函数内,会生成各个tmedia_session_t实例,挂入tmedia_session_mgr_t实例的sessions队列。其中在_tmedia_session_mgr_load_sessions()函数内的处理片段为:

  1. int _tmedia_session_mgr_load_sessions(tmedia_session_mgr_t*self){
  2. const tmedia_session_plugin_def_t* plugin;
  3. if(TSK_LIST_IS_EMPTY(self->sessions)){
  4. /* for each registered plugin create a session instance */
  5. while((i <TMED_SESSION_MAX_PLUGINS) && (plugin =__tmedia_session_plugins[i++])){
  6. if((plugin->type &self->type) ==plugin->type){
  7. if((session =tmedia_session_create(plugin->type))){
  8. tsk_list_push_back_data(self->sessions, (void**)(&session));
  9. }
  10. }
  11. }

}

__tmedia_session_plugins是一个tmedia_session_plugin_def_t类型的全局指针数组,用于存放各种媒体类型的定义。

tmedia_session_create()函数用于更具媒体的类型创建一个tmedia_session_t类型的实例,媒体类型由上层应用指定,记录在tmedia_session_mgr_t实例的type字段,常用的有audio,vedio,audiovideo三个类型。

3.    tmedia_session_t

描述:

这其实也是一个通用结构,被更具体的结构包含着。

而tdav_session_audio_t,tdav_session_video_t等结构便是更具体的结构,在这些结构的其实,包含了该通用的结构。每一个更通用的结构都记录一个trtp_manager_s的实例,这个结构便是代表语音流和视频流的管理者。

在创建tmedia_session_t实例时,是根据plugin->objdef来调用tsk_object_new()的,调用语句为tsk_object_new(plugin->objdef),plugin是上一节所述的__tmedia_session_plugins 所记录的tmedia_session_plugin_def_t 实例,故当plugin->type为audio类型时,创建的真正结构为tdav_session_audio_t,真正的构造函数为tdav_session_audio_ctor(),定义在tdav_session_audio.c中。

这个过程的调用堆栈为:

  1. int _tmedia_session_mgr_load_sessions(tmedia_session_mgr_t*self){
  2. const tmedia_session_plugin_def_t* plugin;
  3. if(TSK_LIST_IS_EMPTY(self->sessions)){
  4. /* for each registered plugin create a session instance */
  5. while((i <TMED_SESSION_MAX_PLUGINS) && (plugin =__tmedia_session_plugins[i++])){
  6. if((plugin->type &self->type) ==plugin->type){
  7. if((session =tmedia_session_create(plugin->type))){
  8. tsk_list_push_back_data(self->sessions, (void**)(&session));
  9. }
  10. }
  11. }

创建时机:

见上一条tmedia_session_mgr_t的关键点。

关键点:

在一个tmedia_session_t结构的实例中,承载了这个tmedia_session_t实际类型的编解码插件,例如tmedia_session_t的type为video时,在tmedia_session_init(tmedia_session_t*self)函数中会初始化一个tmedia_session_t的实例,而根据多态的原理,这个tmedia_session_t实例的真正类型为tdav_session_video_t实例,因此,在初始化时,会从__tmedia_codec_plugins数组中加载所有的type为video的解码模块,__tmedia_codec_plugins数组会在启动协议栈时初始化,具体的初始化函数是tdav_init(),这是也会根据能够加载的编解码模块,将各个编解码插件记录到该__tmedia_codec_plugins全局指针数组中,数组的每一个项都指向了一个plugin,一个plugin代表了一个实际的编解码模块。

关键函数描述:

tmedia_session_init(…)函数:

原型: tmedia_session_init(tmedia_session_t*self,tmedia_type_ttype)

作用: 初始化一个新生成的tmedia_session_t实例,加载各个编解码模块

_tmedia_session_load_codecs(tmedia_session_t  *self)函数;

描述:该函数被tmedia_session_init(…)函数调用,用于加载编解码模块

加载编解码模块的代码片段为:

  1. int _tmedia_session_mgr_load_sessions(tmedia_session_mgr_t*self){
  2. const tmedia_session_plugin_def_t* plugin;
  3. if(TSK_LIST_IS_EMPTY(self->sessions)){
  4. /* for each registered plugin create a session instance */
  5. while((i <TMED_SESSION_MAX_PLUGINS) && (plugin =__tmedia_session_plugins[i++])){
  6. if((plugin->type &self->type) ==plugin->type){
  7. if((session =tmedia_session_create(plugin->type))){
  8. tsk_list_push_back_data(self->sessions, (void**)(&session));
  9. }
  10. }
  11. }

4.    tdav_session_audio_t

5.    tdav_session_video_t

6.tsip_request_t

描述:

在一个tsip_dialog_invite_t实例被创建,进入它的状态机执行时,第一个状态的转化为:

Started -> (oINVITE)-> Outgoing

此时由函数int c0000_Started_2_Outgoing_X_oINVITE(va_list*app)进行该状态的处理,在此函数内部,会为tsip_dialog_invite_t实例创建tmedia_session_mgr_t实例并记录在tsip_dialog_invite_t实例的msession_mgr字段,创建msession_mgr的同时,会建立msession_mgr的sessions队列和加载各种编解码模块。完成这一切后,会调用send_INVITEorUPDATE(…)函数,完成一个sip的invite request。

该函数的原型为:

int send_INVITEorUPDATE(tsip_dialog_invite_t*self,tsk_bool_tis_INVITE,tsk_bool_tforce_sdp)

从名字可以看出,函数除了完成INVITE外,还可以完成一个sip会话的更新操作,例如可能编解码变更,而不想重新发起一个INVITE请求时,便在原有请求的基础上进行UPDATE。

具体是一个新的INVITE还是一个UPDATE,由参数is_INVITE指定。

在一个新的INVITE请求发起时,最重要的结构便是tsip_request_t结构,这个结构代表了一个真正的sip消息。

 

关键点:

在一个INVITE请求发起时,生成一个tsip_request_t实例的过程有以下几步:

a)   用tsip_dialog_request_new(…)函数生成tsip_request_t结构的实例。并做相应的初始化。

b)   当这个dialog的状态为tsip_initial时,需要为SIP_INVITE消息的消息体生成SDP包,此时分解为以下几个小步骤(假设代码中的self为tsip_dialog_invite_t实例):

1)   调用用函数tmedia_session_mgr_get_lo(self->msession_mgr),通过msession_mgr中sessions队列记录的tmedia_session_t实例和每个tmedia_session_t实例codecs队列中记录的编解码模块生成一个tmedia_sdp_t的实例。该实例便携带了媒体协商的所有数据。在这个过程中,还要完成RTP端口的生成,为以后的音视频通话搭建真正的通道,这个过程将在后面解析。

2)   调用tsdp_message_tostring(…)函数将tmedia_sdp_t的实例转化为ASCII字符。假设这一步中得到的字符串为sdp。

3)   调用tsip_message_add_content(…)函数将sdp拷贝到tsip_request_t实例的的message_body中。释放sdp。

RTP端口的生成过程

tmedia_session_mgr_get_lo(…)函数

原型:const tsdp_message_t*tmedia_session_mgr_get_lo(tmedia_session_mgr_t*self)

作用:准备SDP信息,给新的通话开一个RTP端口

内存关系图

doubango(6)--Doubango协议栈中对RTP的管理的更多相关文章

  1. doubango(5)--SIP协议栈传输层的启动

    SIP协议的INVITE消息发起流程 当通过sip协议发起一个会话时,需要通过invite消息实现该流程.而SIP协议是一个基于事务的协议,每一个sip会话的都是通过sip部件间的一系列消息来完成的. ...

  2. doubango(4)--SIP协议栈传输层的启动

    协议栈的默认传输结构 对于一个刚启动的协议栈来说,它需要有一个传输层,支持若干的传输结点.每一个传输结点对应于一个端口,若采用TCP连接,一个传输结点就针对于一个点到点的连接,这个连接负责sip信令的 ...

  3. doubango(2)--底层协议栈结构分析

    tsip_stack_handle_t 实例 1.        tsip_stack_handle_t的创建 在底层,真正运转的协议栈结构式tsip_stack_handle_t的一个实例,它的创建 ...

  4. 蓝牙协议栈中的 OSAL

    蓝牙协议栈里的操作系统叫做 OSAL(操作系统抽象层).它并非一个真正意义上的操作系统,它只是实现了操作系统的一些功能,如任务切换.内存管理. OSAL 产生的根源:基于蓝牙协议栈开发的产品,实际上是 ...

  5. TCP/IP协议栈源码图解分析系列10:linux内核协议栈中对于socket相关API的实现

    题记:本系列文章的目的是抛开书本从Linux内核源代码的角度详细分析TCP/IP协议栈内核相关技术 轻松搞定TCP/IP协议栈,原创文章欢迎交流, byhankswang@gmail.com linu ...

  6. ZigBee协议栈中AES加密算法

    原文地址:ZigBee协议栈中AES加密算法作者:大浪淘沙 Z-stack对Zigbee2006提供了全面的支持,功能之强大,性能稳定.安全性高,说到安全性是我们今天的主题.CC2430硬件支持128 ...

  7. 基于Lwip协议栈中独立模式下回调函数的使用

    一.使用Lwip协议独立模式开发 最近在STM32F4上边移植了Lwip,Lwip是一个小型开源的TCP/IP协议栈,有无操作系统的支持都可以运行.我当前只测试了TCP Server功能,然后对TCP ...

  8. 轻便的gb28181协议中的rtp+ps格式视频流的封装和解析

    streams 轻便的gb28181协议中的rtp+ps格式视频流的封装和解析 packet packet实现ps的相关封装和解析, example/enc 通过joy4来读本地视频文件,然后调用Rt ...

  9. ASP.NET Core 1.0 中的依赖项管理

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

随机推荐

  1. Eclipse 安装插件

    Eclipse 安装插件 本文介绍Eclipse插件的安装方法.Eclipse插件的安装方法大体有三种:直接复制.使用link文件,以及使用eclipse自带的图形界面的插件安装方法. AD: 做为当 ...

  2. copy-on-write学习

    最近知识梳理不够,那就整理点以前blog的东西.这儿就看COW(copy-on-write),cow技术主要是为了提高程序在单步操作时的系统响应速度而设计的,它通过将不是立即必要的空间分配,数据复制等 ...

  3. 如何用70行Java代码实现深度神经网络算法

    http://www.tuicool.com/articles/MfYjQfV 如何用70行Java代码实现深度神经网络算法 时间 2016-02-18 10:46:17  ITeye 原文  htt ...

  4. How to get HTML code of a WebElement in Selenium

    http://stackoverflow.com/questions/32234205/how-to-get-html-code-of-a-webelement-in-selenium WebElem ...

  5. IIS发布WebService的一些常见问题

    安装IIS过程,在控制面板程序à程序功能à打开或关闭windows功能. 将Internet信息服务中的选项全部选中,点击确定. 验证IIS是否正确安装,等待几分钟后IIS配置完成在浏览器输入http ...

  6. Jboss 集群配置

    环境配置:CentOS 7 x64 * 3 IP:  172.24.0.100        172.24.0.101        172.24.0.102 服务器配置: 172.24.0.100 ...

  7. PHP 多线程、多进程

    多线程:PHP其实并不支持多线程,只是通过一些扩展或者socket方式伪装成多线程,实质不是的.在PHP 5.3 以上版本,使用 pthreads PHP扩展,可以使PHP真正地支持多线程:或者使用 ...

  8. CI框架学习——检查用户名与密码是否合法(二)

    检查用户名与密码是否合法 步骤一.编写用户登录的窗体见下面内容 步骤二.编写数据库校验方法 $username = $_POST["username"];            # ...

  9. yum groupinstall "Development Tools" 批量安装软件

    注:可以通过 yum grouplist 来查看可能批量安装哪些列表 从Windows转到Linux下面,一个不习惯的地方就是在图形界面下安装和删除软件的时候非常缓慢.但是如果你掌握了用yum的命令行 ...

  10. 配置Linux Kernel时make menuconfig执行流程分析

       在编译内核前,一般是根据已有的配置文件(一般在内核根目录下的arch/arm/configs/文件夹下,把该目录下的xxx_defconfig文件拷贝到内核根目录下,并重命名为.config)来 ...