logo资料库

linphone源码分析.pdf

第1页 / 共10页
第2页 / 共10页
第3页 / 共10页
第4页 / 共10页
第5页 / 共10页
第6页 / 共10页
第7页 / 共10页
第8页 / 共10页
资料共10页,剩余部分请下载后查看
Linphone的编译
Linphone在arm上的编译环境说明
Linphone依赖的库
Linphone编译脚本
编译过程中的问题
Linphone代码分析
Linphone的初始化分析
linphonec的初始化
linphone_core的初始化
Ortp的初始化
mediastream2的初始化
eXosip的初始化
Linphone的通话过程分析
Linphone的命令处理分析
Linphone的呼叫过程分析
Linphone的通话过程分析
Linphone的响应过程分析
Linphone中创建以及应用自定义过滤器
过滤器的基本功能
过滤器的通用接口
自定义过滤器
Linphone 的编译与代码分析 2008-12-14 updatedb@gmail.com
目 录 1 LINP HONE 的编译 1.1 LINPHONE 在 ARM 上的编译环境说明 1.2 LINPHONE 依赖的库 1.3 LINPHONE 编译脚本 1.4 编译过程中的问题 2 LINP HONE 代码分析 2.1 LINPHONE 的初始化分析 2.1.1 LINPHONEC 的初始化 2.1.2 LINPHONE_CORE 的初始化 2.1.3 ORTP 的初始化 2.1.4 MEDIASTREAM2 的初始化 2.1.5 EXOSIP 的初始化 2.2 LINPHONE 的通话过程分析 2.2.1 LINPHONE 的命令处理分析 2.2.2 LINPHONE 的呼叫过程分析 2.2.3 LINPHONE 的通话过程分析 2.2.4 LINPHONE 的响应过程分析 2.3 LINPHONE 中创建以及应用自定义过滤器 2.3.1 过滤器的基本功能 2.3.2 过滤器的通用接口 2.3.3 自定义过滤器 3 3 3 3 4 4 4 5 5 5 6 6 6 7 7 8 8 9 9 10 10
Linphone 的编译与代码分析 1 Linphone 的编译 1.1 Linphone 在 arm 上的编译环境说明 Linphone 在 arm 上编译的时候,时常会碰到一些问题,有时候想办法解决了相关的问 题,但编译出来的 Linphone 在板子上的运行仍然不稳定,或者不能通话。 如果条件允许的话,当碰到这些问题之后,可以换其它的工具链进行编译。我最初编译 Linphone 的时候采用的是 xscale270 板子自带的工具链,GCC3.4.3 以及 uclibc。经过很痛苦 的一番折腾之后,所以的代码最终都编译通过,但是编译出来的 linphonec 在板子上运行在 通话开始之后总是崩溃。通过 GDB 调试,发现是多线程的问题引起的,于是编译了一个线 程结构相当的程序,但是测试没有发现问题。 最后,我改用 GCC4.0.0 以及 Glibc-2.3.5 基本上没有碰到什么问题,直接编译通过,并 且在板子上正常运行。 1.2 Linphone 依赖的库 除了上面所提到的 Gcc,Glibc 以及系统的基本库外我主要编译了下面的程序包。 序号 1 2 3 4 5 6 7 8 9 10 库名称 ReadLine ffmpeg Speex libtheora libfaac libfaad2 SDL libosip2 libeXosip2 linphone-3.0 说明 一个终端显示库,Linphone 会用到它时里面的事件循环机制来读取会话事件。 音视频编解码库 专为通话过程设计的音频编码库 视频压缩编码库 mpeg4 的音频编码器 AAC 音频解码器 简单的视频支持层 SIP 的简单实现 对libosip2 的调用进行封装,隐藏了多媒体会话建立过程中 SIP 的细节 linphone 的主程序,包括 mediastream, oRtp,coreapi 以及console 四个部分 1.3 Linphone 编译脚本 见附件。
1.4 编译过程中的问题 1、ffmpeg 的编译问题 在编译 ffmpeg 的时候会发现有不少编解码码器不能编译能过,在configure 的时候禁用 的就行了。 2、linphone 的编译 linphone 的编译过程中可能会出现 mediastream2 下面的 test 不能编译能过的问题,在 mediastream2 下面找到 Makefile 文件,找到 SUBDIRS 将 tests 删掉即可。 linphone 下面的所有的库编译完成之后,linphonec 的编译可能不能能过,原因是几个库 不能找到,这时候其它那几个库用不着,重新修改 Makefile 即可(详见附件)。 2 Linphone 代码分析 Linphone 代码的分析主要分为三个部分。在整个分析过程主要是对音频通话相关的内 容进行分析,视频的流程类似,但有细节有很大的区别,请自行分析。如果在看代码的过程 中碰到一些问题不能理解,推荐先看看 SIP/RTP/RTCP 等协议的基本内容,或者通过抓数据 包对整个会话过程进行分析。 2.1 Linphone 的初始化分析 首先主要的流程在流程图里面都有表现,图是边看代码,边画出来的,不是很好。下面 的分析主要是对图中的内容进行讲述。 先对图里面的标识解释一下: 实心箭头表示流程走向; 空心箭头表示调用关系; 指向出发点箭头表示循环调用; 黄色的框表示代相对独立的码块,红色表示关键函数,绿色表示成功; 虚线指向表示有相关性,但并非调用关系; 虚线框表示主要数据结构。
对 Linphone 的整个初始化过程进行分析可以分为下面的个部分。 2.1.1 linphonec 的初始化 在 linphonec 的初始化过程中,一共做了两件事。首先初始化linphone_core,如果成功, 则进入 linphonec 的主循环,等待用户输入,如果有用户输入就会调用相应的命令处理函数。 处理函数被注册在静态的数组 LPC_COMMAND commands 中。如果你想增加 linphone 处理 其它的命令,最好在这儿添加。 2.1.2 linphone_core 的初始化 Linphone_core 的初始化概括的讲的就产生一个唯一的 linphone 实例,该实例包括了显 示,配置,数据流等内容。在配置 linphone_core 的实例的过程中,linphone 会读取并分析配 置文件,并调用相关的初始化函数。 Linphone_core 初 始 化 完 成 之 后 , 会 调 用 linphonec_initalize_readline, 该 函 数 将 linphonec_idel_call 注册到readline 的事件循环中,并且每隔1 秒调用一次,检查是否有等待 处理的 osip 事件(比如有人发送 INVITE 消息)。 2.1.3 Ortp 的初始化 Ortp 的初始化除了对数据结构的初始化外,主要的工作就是加载相关的 PayloadType.
2.1.4 mediastream2 的初始化 主要是对 filter 以及声卡,网卡的初始化。详细解释见函数调用图,以及函数解释。 2.1.5 eXosip 的初始化 eXosip 的核心是初始化 osip,打开相关的网络接口,进入监听状态。 下面列出流程中主要的函数调用的用途: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 LinphonecoreVtable ortp_init ms_init lp_config_new XXX_config linphone_core_set_sip_port exosip_init osip_init eXosip_set_callbacks eXosip_listen_addr osip_thread_create osip_execute eXosip_read_message osip_timers_XiXt_execute osip_XiXst_execute 用于初始化屏幕相关,以及输出相关 初始华 ortp,并加载默认的PayloadType(在avprofile.c定义)。如果要定义新的过滤 器,在这儿也要注册相应的PayloadType,当然,自定义的 PayloadType 可以只 在需要的时候再即用。 mediastreamer2 的初始化,首先注册所有的 filter,这些 filter 在 alldescs.h 中被表态保 存在 ms_filter_desc 数组中。注册新的过滤器时,过滤器的描述结构应该被注册到 该数组中。同时也注册了声卡与摄像头,并且初始化每个设备,放到全局静态变量 MSSndCardManager 和 MSWebCamManager 中。 读取并分析配置文件 读取配置文件中 XXX 相关的配置到linphone_core中,包括读取网络配置,RTP 配 置,解码器配置以及 sip/view/ui的配置。 用于打开 sip 端口,等待并接收 sip 信息。 这个函数在libeXosip 中,而不是在linphone 中。用于寢化eXosip 变量,在初始化 时 eXosip 和osip 互相指向,用于后面的访问。eXosip_call_t和void *j_thread 没有 被初始化。接着对四种extl_protocol进行初始化,为 osip 数据包传输做好准备。 这个函数初始化了 osip_t 数据结构,被启动了四个用于 osip 数据处理的状态机。 每个新状态机都是一个transition 列表,每一个transition 时面包括 state,type,处理 函数 method.四个状机代表四个不同的会话事务。每个会话事务,根据状态机不同 的状态,调用相应事务中eXosip_set_callbacks 中注册的处理函数,并改变事务状态。 调用osip_set_cb_send_message 和osip_set_XXX_callback 为osip 注册处理各种状态 数 据 包 的 回 调 函 数 。 初 始 化 了 osip 中 msg_callbacks, kill_callbacks, tp_error_callbacks,cb_send_message 几个最重要的数据。cb_send_message这个函数 最终会根据协议的不同,调用不同的eXtl_protocol对像发送数据。 打开一个监听端口,用于接收连接,并启动一个线程专门牏sip 数据包。根据不同 的数据传输类型打开不同的数据接收端口。 创建一个线程,循环执行osip_execute 直至接收到退出或者异常信息。 这个函数会读取eXtl_XXX 打开的 socket,然后遍历所有的状态机,看是否有事件 需要处理。 如果可以读取数据,那么将得到的数据交给数据处理函数,数据处理函数对数据进 行格式化,构造成为osip 数据结构及以 osip_event,然后再通过 osip_evnet_t 的类 型查找是那个transaction 及对应的状态机。并且将事件加到transation 所对应的 osip_fifo_t *transactionff 中。 依次检查 四个状态机的所 有transaction,判断是否需要注册一 个 TIMEOUT_I / TIMEOUT_H / TIMEOUT_G 事件,如果需要则注册相应的事件。 依次检查四个状态机的所有的transaction,看是否有需要执行的事件,如果有事件 要执行,则在状态机中调用相应的在 set_callbacks 中注册的函数。 2.2 Linphone 的通话过程分析 在分析 Linphone 的通话过程之前,我们首先分析看看当前的状态: linphonec_main_loop 在等待用户输入。从而用户可以在自己的控制端进行操作,比如发 起呼叫。 eXosip_listen_addr 在监听端口,等远程连接。如果有数据,即可以接收,并解析数据,
放到事件队列中。 linphonec_idel_call 每秒被调用一次,查看在有 eXosip 中是否有事件要处理。可以发现 事件队列中的事件,并对其做出响应。 当通话双方都做好了通话准备的时候,双方都进入了上面所描述的状态。下面我们对通 话过程的分析我们只对最主要的两个部分,即呼叫和应答进行分析。在流程图中,分为三个 部门左上角为通话双方都相同的部分,命令处理。右上方是发起呼叫的过程。左下方是响应 的过程。右下方是双方一致的通话过程。 对我 Linphone 的能话过程分析分为以下几个部分: 2.2.1 Linphone 的命令处理分析 该部分的主要功能是对用通输入的命令进行分析,然后通过在 lpc_find_command 找到 对应的函数,并调用相应的函数。 比如当用户输入 call sip:192.168.1.1 的时候,linphone_call_invite 命令将被调用。而当 用户输入 answer 的时候,linphone_call_answer 命令将会被调用。 主要调用的函数说明列表如下: 2.2.2 Linphone 的呼叫过程分析 1 2 3 4 5 6 linphone_core_invite eXosip_call_build_initial_invite linphone_call_new_outgoing eXosip_call_send_initial_invite eXosip_call_init osip_new_outgoing_sipmessage 该函数会解析 sipURL,并构造一个发送一个INVITE 消息。 创建最简单的 INVITE 请求。 该函数将已经构造好的INVITE 信息发送。首先有eXosip_call_t 对 象,然后根据状态机的类型,以及初始化过程中创建的osip,以及 INVITE 请求信息,去初始化一个transaction。 初始化一个LinphoneCall对象,并对该对象进行基本的初始化。每 个通话过程中保持一个 LinphoneCall 对象。 该函数能过Invite 的内容,为用户分创建一个新的事件。事件中
7 osip_transaction_init 8 9 osip_transaction_add_event linphone_set_sdp transaction 的 ID 由osip_transaction_init 中初始化得到。 初始化 transaction。transaction 的id 是一个静态的递增值,在整个系 统运行的过程中是其值是唯一的。transaction 的初始化过程中的三个 最 重要 的 动 作是 :1、将 系 统 初始 化 时创 建 的 osip 对 象附 给 transaction。2、初始化transaction 的事件队列。3、根据状态机的类 型将transaction 加入到状态机中。 该函数将事件加入到transaction 的事件队列中。 将构造好的SDP 数据包打包进入到通信数据中。 Linphone 的呼叫从这儿正式开始了,但是我们可以看到请求事件还没有发送。但是这 个不用担心,我们在系统初始化时的创建的eXosip_execute 线程会不断的查询是否有数据需 要处理。当它发现要状态机(ICT)中有需要处理的数据的时候,它会调用在系统初始化时 eXosip_set_callbacks 注册的事件处理函数。这些注册函数处理完数据后,发送 eXosip_event, 从而linphone 可以调用 eXosip_event 对应的相应的处理函数。处理函数会将数据发送给通话 的另一方。 在这个过程中 linphone 调用了函数 linphone_core_init_media_stream,这个函数完成了对 音视频通话的准备工作,我们将在响应过程分析中对其作详细的分析。 2.2.3 Linphone 的通话过程分析 通话的接收方在系统初始化完成之后,有着与呼叫方相同的状态。当 eXosip_execute 线 程不断查询数据的过程中,发会接收到 SIP 数据,Linphone 将 SIP 数据交给 libosip 进行分 析与处理。处理的结果就是通过分析数据,将一个 RCV_REQINVITE 事件加入到(IST)状态 机中等待处理。接着状态机奖被调用。 接下来的过程类似,双方利用 sip 完成下面的通话过程。 从上图我们可以看到双方通话过程包括发送 SND_REQINVITE,收到 RCV_STATUS_ 1XX 建 立 会 话 , 然 后 再 次 接 收 到 RCV_STATUS_1XX 响 铃 事 件 ,然 后 会 接 收 到 RCV_STATUS_2XX 的200 事件,发送确认开始通话。这一部的的主要执行的代码就是在初 始化时建立的 eXosip_execute 处理线程。 2.2.4 Linphone 的响应过程分析 对响应过程的分析我们从被呼叫方接收呼叫开始分析。调用过程中主要用的函数如下: 1 2 3 4 5 linphone_core_answer linphone_core_accept_call eXosip_call_build_answer linphone_core_init_media_streams audio_stream_new 命令行调用该函数,用于响应 自动应答以及命令行调用,以响应用户行命令处理。它会首先停止响铃,然后 发送一个 OK 的信息给呼叫方。接着初始化音视频,开始通话。 该函数会构建一个 200 的响应 sip 包 用于初始化AudioStream以及VideoStream。 创建新的 AudioStream,并对RtpSession 和filter rtpsend 进行初始化。
分享到:
收藏