今天翻文档时发现之前整理的关于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_init

  • CS_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_routing

  • CS_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_execute

  • CS_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_media

  • CS_EXCHANGE_MEDIA

    switch_core_session_run
    状态机处理状态变化 STATE_MACRO(exchange_media, "EXCHANGE_MEDIA"); on_exchange_media 即 : sofia_on_exchange_media
    switch_core_standard_on_exchange_media

  • CS_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_request

  • 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发送 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_hangup

  • FS发送BYE给B
    nua_bye : nua_r_bye
    nua_stack_signal
    outgoing_send
    tport_tsend

  • FS发送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呼叫流程分析的更多相关文章

  1. Android7.0 Phone应用源码分析(一) phone拨号流程分析

    1.1 dialer拨号 拨号盘点击拨号DialpadFragment的onClick方法会被调用 public void onClick(View view) { int resId = view. ...

  2. 8、Struts2 运行流程分析

    1.流程分析: 请求发送给 StrutsPrepareAndExecuteFilter StrutsPrepareAndExecuteFilter 询问 ActionMapper: 该请求是否是一个 ...

  3. u-boot 流程分析

    u-boot 介绍: 对于计算机来说 , 从一开始上机通电是无法直接启动操作系统的 , 这中间需要一个引导过程 , 嵌入式Linux系统同样离不开引导程序 ,  这个启动程序就叫启动加载程序(Boot ...

  4. thttpd和cgilua安装与运行流程分析

    安装 参考如下博文安装thttpd软件 http://blog.csdn.net/21aspnet/article/details/7045845 http://blog.csdn.net/drago ...

  5. 【转】Hostapd工作流程分析

    [转]Hostapd工作流程分析 转自:http://blog.chinaunix.net/uid-30081165-id-5290531.html Hostapd是一个运行在用户态的守护进程,可以通 ...

  6. u-boot中nandflash初始化流程分析(转)

    u-boot中nandflash初始化流程分析(转) 原文地址http://zhuairlunjj.blog.163.com/blog/static/80050945201092011249136/ ...

  7. Android7.0 Phone应用源码分析(二) phone来电流程分析

    接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析 今天我们再来分析下Android7.0 的phone的来电流程 1.1TelephonyFramework 当有 ...

  8. runc start container流程分析

    1.runc/start.go Action: func(context *cli.Context) error 该函数首先调用container, err := getContainer(conte ...

  9. 从注册流程 分析如何安全退出多个Activity 多种方式(附DEMO)

      退出Activity注册Android遍历   目录(?)[+] 前言 知识结构 具体方案 方案1 方法采用FLAG_ACTIVITY_CLEAR_TOP退出整个程序多activity 方案2 方 ...

随机推荐

  1. Bash 脚本编程语言中的美学与哲学

    我承认,我再一次地当了标题党.但是不可否认,这一定是一篇精华随笔.在这一篇中,我将探讨 Bash 脚本语言中的美学与哲学. 这不是一篇 Bash 脚本编程的教程,但是却能让人更加深入地了解 Bash ...

  2. 如何用Dockerfile创建镜像

    本文原创,原文地址为:http://www.cnblogs.com/fengzheng/p/5181222.html 创建镜像的目的 首先说DockerHub或其它一些镜像仓库已经提供了够多的镜像,有 ...

  3. Linux下常见的IO模型

    前言 阻塞IO(blocking IO) 非阻塞IO(nonblocking IO) IO复用(IO multiplexing) 异步IO(asynchronous IO (the POSIX aio ...

  4. backup1:开始数据库备份

    数据库备份分为数据文件备份和日志文件备份,数据文件的备份分为:完整备份和差异备份.在SQL Server 2012中,能够将数据分布式备份到不同的存储设备上,一般情况,只将数据备份到一个备份文件(.b ...

  5. 06.移动先行之谁主沉浮----我的代码我来写(Xaml的优势)

    如果移动方向有任何问题请参考===> 异常处理汇总-移动系列(点) 前面几节课,我们都是在前台创建对象,进行一些设置,那么我们为什么不用传统的方法来编程呢? 我们今天来试试你就明了了~~ 打开M ...

  6. 【.NET深呼吸】基础:自定义类型转换

    照例,老周在开始吹牛之前,先讲讲小故事,这是朋友提出的建议,老TMD写技术有什么了不起的,人人都会写.后来老周想想,也确实,代码谁不会写,能写到有品位有感悟,就不容易做到.于是,老周接受了该朋友的建议 ...

  7. nginx源码分析之hash的实现

    nginx实现了自己的hash数据结构,正如数据结构中讲述的那样,nginx用开放链表法解决冲突,不过不同的是一旦一个hash表被初始化后就不会被修改,即插入和删除,只进行查询操作,所以nginx通过 ...

  8. 全球PM25实时可视化

    星期一的早上,我在办公区鸟瞰窗外,目光所到之处,用顾城的那首"你看天时很近,看我时很远"倒是格外的应景.作为一名父亲,看着工位上3M的口罩,想想此刻还在熟睡的孩子,多少有些无奈-- ...

  9. 【分布式】Zookeeper客户端

    一.前言 前篇博客分析了Zookeeper的序列化和通信协议,接着继续学习客户端,客户端是开发人员使用Zookeeper最主要的途径,很有必要弄懂客户端是如何与服务端通信的. 二.客户端 2.1 客户 ...

  10. 使用Autolayout实现UITableView的Cell动态布局和高度动态改变

    本文翻译自:stackoverflow 有人在stackoverflow上问了一个问题: 1 如何在UITableViewCell中使用Autolayout来实现Cell的内容和子视图自动计算行高,并 ...