freeswitch呼叫流程分析
今天翻文档时发现之前整理的关于freeswitch呼叫相关的内容,写成博文分享出来也方便我以后查阅。
整体结构图

FreeswitchCore
模块加载过程
freeswitch主程序初始化时会从modules.conf.xml文件中读取配置,如果配置中如下内容生效:
<load module="mod_sofia"/>
则执行加载sofia模块操作。
具体过程如下:
main
switch_core_init_and_modload
switch_loadable_module_init
switch_loadable_module_load_module_ex : 读取xml文件并加载模块
状态机相关
状态机初始化
switch.c : main switch_core_init_and_modload
=> switch_core_init
=> switch_core_session_init
=> switch_core_session_thread_pool_manager
=> check_queue
=> switch_core_session_thread_pool_worker
=> switch_core_session_thread
=> switch_core_session_run
改变状态
通过调用switch_channel_set_state来实现状态机的状态改变。
处理状态变化
当状态发生变化后,通过switch_channel_set_running_state函数来改变running_state,
并执行相关的回调来通知其状态已经发生改变了:
endpoint_interface->io_routines->state_run
主叫状态变化
- CS_NEW
switch_core_session_run初始状态为CS_NEW
CS_INIT
sofia_handle_sip_i_state
case nua_callstate_received (收到invite请求) 修改状态机的状态 :CS_NEW ==> CS_INIT switch_channel_set_state(channel, CS_INIT);switch_core_session_run
状态机处理状态变化 STATE_MACRO(init, "INIT"); on_init 即 : sofia_on_init
switch_core_standard_on_initCS_ROUTING
sofia_on_init
修改状态机的状态 : CS_INIT == > CS_ROUTING
switch_channel_set_state(channel, CS_ROUTING);
switch_core_session_run
状态机处理状态变化 STATE_MACRO(routing, "ROUTING"); on_routing 即 : sofia_on_routing
switch_core_standard_on_routingCS_EXECUTE
switch_core_standard_on_routing 修改状态机的状态 : CS_ROUTING == > CS_EXECUTE switch_channel_set_state(session->channel, CS_EXECUTE);
switch_core_session_run
状态机处理状态变化 STATE_MACRO(execute, "EXECUTE"); on_execute 即 : sofia_on_execute
switch_core_standard_on_executeCS_HANGUP
sofia_handle_sip_i_bye switch_channel_hangup : 即 switch_channel_perform_hangup 修改状态机的状态 channel->state = CS_HANGUP;
状态机处理状态变化
switch_core_session_hangup_state
STATE_MACRO(hangup, "HANGUP");
被叫状态变化
- CS_NEW
switch_core_session_run初始状态为CS_NEW
CS_INIT
sofia_outgoing_channel 修改状态机的状态 :CS_NEW ==> CS_INIT switch_channel_set_state(nchannel, CS_INIT);
状态机处理逻辑参考主叫。
CS_ROUTING
sofia_on_init
修改状态机的状态 : CS_INIT == > CS_ROUTING switch_channel_set_state(channel, CS_ROUTING);
状态机处理逻辑参考主叫。
CS_CONSUME_MEDIA
originate_on_routing 修改状态机的状态:CS_ROUTING -> CS_CONSUME_MEDIA switch_channel_set_state(channel, CS_CONSUME_MEDIA);
switch_core_session_run
状态机处理状态变化 STATE_MACRO(consume_media, "CONSUME_MEDIA"); on_ consume_media 即 : NULL switch_core_standard_on_consume_mediaCS_EXCHANGE_MEDIA
switch_core_session_run
状态机处理状态变化 STATE_MACRO(exchange_media, "EXCHANGE_MEDIA"); on_exchange_media 即 : sofia_on_exchange_media
switch_core_standard_on_exchange_mediaCS_HANGUP
audio_bridge_on_exchange_media
switch_channel_hangup : 即 switch_channel_perform_hangup 修改状态机的状态 channel->state = CS_HANGUP;状态机处理状态变化
switch_core_session_hangup_state STATE_MACRO(hangup, "HANGUP");
Sofia应用层
模块加载过程
启动事件处理线程池 :
SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
=> sofia_msg_thread_start();
=> sofia_msg_thread_run
=> sofia_process_dispatch_event
=> our_sofia_event_callback : 处理消息
启动服务器监听 :
SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
=> config_sofia(, NULL)
=> launch_sofia_profile_thread
=> sofia_profile_thread_run
=> nua_create
=> su_home_new
=> nua_stack_init
=> nta_agent_create
=> nta_agent_add_tport
=> tport_tbind
=> tport_bind_server
=> tport_listen : 监听客户端发来的数据
数据表
数据库默认路径:/usr/local/freeswitch/db
freeswitch core 相关:
- aliases
- calls
- channels
- complete
- interfaces
- nat
- recovery
- registrations
- tasks
sofia相关:
- sip_authentication
- sip_dialogs
- sip_presence
- sip_registrations
- sip_shared_appearance_dialogs
- sip_shared_appearance_subscriptions
- sip_subscriptions
limit相关:
- db_data
- group_data
- limit_data
fifo相关:
- fifo_bridge
- fifo_callers
- fifo_outbound
语音信箱相关:
- voicemail_msgs
- voicemail_prefs
呼叫流程涉及内容
1、 收到A的nua_i_invite,返回407,具体如下:
sofia_handle_sip_i_invite => sofia_reg_handle_register => sofia_reg_auth_challenge => 407
2、 收到A的nua_i_invite,返回180,具体如下:
sofia_handle_sip_i_invite => sofia_reg_handle_register => sofia_reg_parse_auth
处理nua_i_state消息
sofia.c : sofia_handle_sip_i_state
...
mod_dialplan_xml.c : dialplan_hunt (ring_ready)
解析拨号方案,执行lua脚本,设置通道变量。
…
发送180事件
涉及数据表:
sip_registrations、ip_dialogs
3、 发送invite给B分机,具体如下:
处理nua_r_invite消息
sofia_handle_sip_r_invite => originate_on_routing
涉及数据表:
sip_dialogs
4、 B应答,双方通话,具体如下:
sofia_receive_message : SWITCH_MESSAGE_INDICATE_ANSWER
=> sofia_answer_channel
=> sofia_glue_tech_choose_port
=> sofia_glue_set_local_sdp
=> sofia_glue_activate_rtp
编码协商过程
这里描述下后协商流程
- 先匹配freeswitch默认的codec,从加载的模块中查找支持类型的具体码率信息
sofia_handle_sip_i_invite
=> sofia_glue_tech_prepare_codecs
=> switch_loadable_module_get_codecs_sorted
- 协商发给被叫的sdp
sofia_glue_do_invite
=> sofia_glue_tech_prepare_codecs
=> switch_loadable_module_get_codecs_sorted
ocodec + codec_string
- 产生M头,并发送包含sdp的invite
sofia_glue_do_invite
=> sofia_glue_set_local_sdp
=> generate_m
=> nua_invite
- 协商200 OK的sdp
sofia_answer_channel
=> sofia_glue_tech_prepare_codecs
=> switch_loadable_module_get_codecs_sorted
媒体交互
- RTP数据交互
audio_bridge_on_exchange_media
=> audio_bridge_thread
收发音频数据
=> switch_core_session_read_frame
=> session->endpoint_interface->io_routines->read_frame 即: sofia_read_frame
=> switch_core_session_write_frame
=> perform_write
=> session->endpoint_interface->io_routines->write_frame 即: sofia_write_frame
收发视频数据
1、启动线程
=> launch_video
=> video_bridge_thread
2、收发数据
=> switch_core_session_read_video_frame
=>session->endpoint_interface->io_routines->read_video_frame
即:sofia_read_video_frame
=> switch_core_session_write_video_frame
=> session->endpoint_interface->io_routines->write_video_frame
即:sofia_write_video_frame
- 终止RTP交互
audio_bridge_thread
=> switch_core_session_kill_channel(session_b, SWITCH_SIG_BREAK);
即 :switch_core_session_perform_kill_channel
=> session->endpoint_interface->io_routines->kill_channel
即 : sofia_kill_channel
=> switch_rtp_break
Sofia协议栈
协议栈结构图

NUA : 基本的SIP用户代理的功能,其功能包括呼叫管理,消息和事件检索。
NTA : sofia SIP事务API(NTA)提供了简单的接口的SIP事务,传输和信息处理。
Tport : 该模块包含一个由SIP,RTSP 和HTTP协议使用的通用传输接口,这是一个协议栈和传输协议实现之间的抽象层。
SIP信令具体流程

场景描述: A 呼叫 B ,B接通后通话一段时间后,挂断电话。
- A 发送 INVITE 请求
tport.c : tport_recv_data
nta.c : agent_recv_request
- FS回应100给A分机
nua_server.c : nua_stack_process_request
nua_server.c : SR_STATUS1(sr, SIP_100_TRYING)
nta.c : nta_incoming_treply
nta.c : incoming_reply
tport.c: tport_tsend
- FS发送认证请求给A分机
nua_application_event
处理nua_i_invite 消息
sofia.c : sofia_process_dispatch_event
sofia.c : our_sofia_event_callback
sofia.c : sofia_handle_sip_i_invite
sofia.c : sofia_reg_handle_register
sofia_reg.c : sofia_reg_auth_challenge
回复407
nua.c : nua_respond
nua_stack.c : nua_signal
nua_stack.c : nua_stack_signal
nua_server.c : nua_stack_respond
nua_server.c : nua_server_respond
发送407给A分机
nua_invite_server_respond
nua_base_server_respond
nta_incoming_mreply
incoming_reply
tport_tsend
tport_resolve
tport_by_addrinfo
tport_prepare_and_send
tport_send_msg
tport_vsend
sent 407 Proxy Authentication Required for INVITE (1)
call state(A) : init -> received
call state(A) : received -> terminated
A分机发送ACK
nta.c : agent_recv_message
nta.c : agent_recv_requestA分机重新发送 INVITE 请求,附加认证信息
tport.c : tport_recv_data
nta.c : agent_recv_requestFS回应100给A分机
nua_server.c : nua_stack_process_request
nua_server.c : SR_STATUS1(sr, SIP_100_TRYING)
nta.c : nta_incoming_treply
nta.c : incoming_reply
tport.c: tport_tsend
- FS发送 INVITE 给 B分机
switch_ivr_originate.c : switch_ivr_originate
sofia_on_init
sofia_glue_do_invite
nua_invite : nua_r_invite 消息
nua_signal
sofia.c : sofia_process_dispatch_event
sofia.c : our_sofia_event_callback
sofia.c : sofia_handle_sip_r_invite
...
sofia_on_init
sofia_on_routing
switch_ivr_originate.c :originate_on_routing
...
nua_stack_signal
nua_stack_invite
...
nta_leg_tcreate
...
执行发送invite请求
nta.c : outgoing_send
tport_tsend
call state(B) : init -> calling
- B分机回应180给FS
tport_recv_event
agent_recv_response
处理 nua_r_invite 消息
sofia.c : sofia_process_dispatch_event
sofia.c : our_sofia_event_callback
sofia.c : sofia_handle_sip_r_invite
call state(B) : calling -> proceeding
- FS发送180给A分机
nua_session.c : signal_call_state_change
nua_stack_tevent : nua_i_state
nua_application_event
处理nua_i_invite 消息
sofia.c : sofia_process_dispatch_event
sofia.c : our_sofia_event_callback
sofia.c : sofia_handle_sip_i_invite
sofia_reg.c : sofia_reg_handle_register
sofia_reg.c : sofia_reg_parse_auth
处理nua_i_state消息
sofia.c : sofia_handle_sip_i_state
...
mod_dialplan_xml.c : dialplan_hunt (ring_ready)
解析拨号方案,执行lua脚本,设置通道变量。
…
发送180
switch_channel_mark_ring_ready
nua_invite_server_respond
nua_base_server_respond
nta_incoming_mreply
incoming_reply
tport_tsend
tport_resolve
tport_by_addrinfo
tport_prepare_and_send
tport_send_msg
tport_vsend
call state(A) : init -> received
B发送200 ok
tport_recv_event
agent_recv_response
处理 nua_r_invite 消息
sofia.c : sofia_process_dispatch_event
sofia.c : our_sofia_event_callback
sofia.c : sofia_handle_sip_r_invite
call state(B) : proceeding -> completing
- FS发送ACK给B
nua_ack
nua_signal : nua_r_ack
outgoing_send
tport_tsend
call state(A) : received -> early
call state(B) : completing -> ready
- FS发送200 OK给A
sofia_glue_tech_set_codec
switch_rtp_create
sofia_glue_negotiate_sdp
sofia_glue_activate_rtp
...
switch_channel_perform_answer : SWITCH_MESSAGE_INDICATE_ANSWER
switch_channel_perform_mark_answered
...
auto_record.lua : 执行录音操作B
...
auto_record.lua : 执行录音操作A
...
sofia_receive_message (SWITCH_MESSAGE_INDICATE_ANSWER)
...
发送200 OK
nua_respond : 200
nua_signal : nua_r_respond
nua_stack_signal
nua_stack_respond
nua_server_respond
nta_incoming_treply
nta_incoming_mreply
incoming_reply
tport_tsend
call state(A) : early -> completed
- A回应ACK
nta.c : agent_recv_message
nta.c : agent_recv_request
call state(A) : completed -> ready
通话一段时间后,A主动发送BYE
tport_recv_event
agent_recv_message
agent_recv_request
...
sofia_on_hangupFS发送BYE给B
nua_bye : nua_r_bye
nua_stack_signal
outgoing_send
tport_tsendFS发送200 OK给A
nta : sent 200 OK for BYE
tport_tsend
call state(A) : ready -> terminating
call state(A) : terminated
- B发送200 OK给FS,回应挂断请求
nta: received 200 OK for BYE
状态变化:
call state(B) : ready -> terminating
call state(B) : terminating -> terminated
本文github地址:
https://github.com/mike-zhang/mikeBlogEssays/blob/master/2016/20160907_freeswitch呼叫流程分析.md
欢迎补充
freeswitch呼叫流程分析的更多相关文章
- Android7.0 Phone应用源码分析(一) phone拨号流程分析
1.1 dialer拨号 拨号盘点击拨号DialpadFragment的onClick方法会被调用 public void onClick(View view) { int resId = view. ...
- 8、Struts2 运行流程分析
1.流程分析: 请求发送给 StrutsPrepareAndExecuteFilter StrutsPrepareAndExecuteFilter 询问 ActionMapper: 该请求是否是一个 ...
- u-boot 流程分析
u-boot 介绍: 对于计算机来说 , 从一开始上机通电是无法直接启动操作系统的 , 这中间需要一个引导过程 , 嵌入式Linux系统同样离不开引导程序 , 这个启动程序就叫启动加载程序(Boot ...
- thttpd和cgilua安装与运行流程分析
安装 参考如下博文安装thttpd软件 http://blog.csdn.net/21aspnet/article/details/7045845 http://blog.csdn.net/drago ...
- 【转】Hostapd工作流程分析
[转]Hostapd工作流程分析 转自:http://blog.chinaunix.net/uid-30081165-id-5290531.html Hostapd是一个运行在用户态的守护进程,可以通 ...
- u-boot中nandflash初始化流程分析(转)
u-boot中nandflash初始化流程分析(转) 原文地址http://zhuairlunjj.blog.163.com/blog/static/80050945201092011249136/ ...
- Android7.0 Phone应用源码分析(二) phone来电流程分析
接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析 今天我们再来分析下Android7.0 的phone的来电流程 1.1TelephonyFramework 当有 ...
- runc start container流程分析
1.runc/start.go Action: func(context *cli.Context) error 该函数首先调用container, err := getContainer(conte ...
- 从注册流程 分析如何安全退出多个Activity 多种方式(附DEMO)
退出Activity注册Android遍历 目录(?)[+] 前言 知识结构 具体方案 方案1 方法采用FLAG_ACTIVITY_CLEAR_TOP退出整个程序多activity 方案2 方 ...
随机推荐
- 【Java并发编程实战】----- AQS(三):阻塞、唤醒:LockSupport
在上篇博客([Java并发编程实战]----- AQS(二):获取锁.释放锁)中提到,当一个线程加入到CLH队列中时,如果不是头节点是需要判断该节点是否需要挂起:在释放锁后,需要唤醒该线程的继任节点 ...
- CI Weekly #6 | 再谈 Docker / CI / CD 实践经验
CI Weekly 围绕『 软件工程效率提升』 进行一系列技术内容分享,包括国内外持续集成.持续交付,持续部署.自动化测试. DevOps 等实践教程.工具与资源,以及一些工程师文化相关的程序员 Ti ...
- Memcached和Redis比较
一.存储 Memcached基本只支持简单的key-value存储方式.Redis除key-value之外,还支持list,set,sorted set,hash等数据结构:Redis支持数据的备份, ...
- php使用CI发送qq和163邮件
1.需求 发送邮件 2.介绍 使用CI框架的email类库发送邮件,这里演示QQ和163 3.163使用教程 a.先去163邮件开启smtp邮件. b.在CI的控制器里写下面的代码 $this-> ...
- Entity Framework中使用IEnumerable<T>、IQueryable<T>及IList<T>的区别
1. IEnumerable<T> IEnumerable<T> :对于在内存中集合上运行的方法,返回的可枚举对象将捕获传递到方法的参数.在枚举该对象时,将使用查询运算符的逻辑 ...
- Android浮层点击穿透问题
最近做微信公众号开发的时候遇到一个问题,上线后发现此问题后检查代码没有发现问题,无奈只能回滚到上一个版本. 问题是这样的:页面一个选择的浮层,在浮层点击确定后,下面的页面会自动提交 在测试环境上无法重 ...
- python2.7 内置ConfigParser支持Unicode读写
1 python编码基础 对应 C/C++ 的 char 和 wchar_t, Python 也有两种字符串类型,str 与 unicode: str与unicode # -*- coding: ut ...
- c# 检测操作系统版本
我们通过System.Environment.OSVersion.Version获得操作系统的版本号,然后再根据版本号进行判断操作系统是什么版本 Version 类的属性 Operating syst ...
- linux内核调试技术之自构proc
1.简介 在上一篇中,在内核中使用printk可以讲调试信息保存在log_buf缓冲区中,可以使用命令 #cat /proc/kmsg 将缓冲区的数区的数数据打印出来,今天我们就来研究一下,自己写k ...
- C#基础回顾(一)—C#访问修饰符
一.写在前面的话 好久没有停下来总结自己,转眼间15年过去好些天,回首过去的日子,亦或失去,亦或所得!生活的节奏,常常让我们带着急急忙忙的节奏去追赶,也许这并不是每个人所期望的生活方式!于他人,于自己 ...
