整體結構圖
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(0); => sofia_msg_thread_run => sofia_process_dispatch_event => our_sofia_event_callback : 處理消息
啟動服務器監聽 :
SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) => config_sofia(0, 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