sip配置解析
//解析配置
load_module->reload_config->build_peer
sip_settings保存全局配置
sip_peer 保存帐号配置
rtp
重要的接口函数
chan_sip.c/ struct ast_channel_techsip_tech = {
chan_sip.c/ static struct ast_rtp_gluesip_rtp_glue = {
res_rtp_asterisk.c/static struct ast_rtp_engineasterisk_rtp_engine = {//定义了处理ast_rtp结构体的回调函数。
/*! Structure that represents an RTPsession (instance) */
struct ast_rtp_instance {
/*!Engine that is handling this RTP instance */
struct ast_rtp_engine *engine;
/*!Data unique to the RTP engine */
void *data;//sometimes is structast_rtp
/*!RTP properties that have been set and their value */
intproperties[AST_RTP_PROPERTY_MAX];
/*!Address that we are expecting RTP to come in to */
structast_sockaddr local_address;
/*!Address that we are sending RTP to */
structast_sockaddr remote_address;
/*!Alternate address that we are receiving RTP from */
structast_sockaddr alt_remote_address;
/*!Instance that we are bridged to if doing remote or local bridging */
structast_rtp_instance *bridged;
/*!Payload and packetization information */
structast_rtp_codecs codecs;
/*!RTP timeout time (negative or zero means disabled, negative value meanstemporarily disabled) */
inttimeout;
/*!RTP timeout when on hold (negative or zero means disabled, negative value meanstemporarily disabled). */
intholdtimeout;
/*!RTP keepalive interval */
int keepalive;
/*!Glue currently in use */
struct ast_rtp_glue *glue;
/*!Channel associated with the instance */
struct ast_channel *chan;
/*!SRTP info associated with the instance */
struct ast_srtp *srtp;
};
extern struct ast_srtp_res *res_srtp;
res_rtp_asterisk.c/ static structast_rtp_engine asterisk_rtp_engine//设置回调函数
rtp_engine.c/ ast_rtp_engine_init
收到一个invite时的处理函数:
收到一个invite时的处理函数:
sipsock_read-> ast_recvfrom
-> handle_request_do
handle_request_do->parse_request//解析了消息的头部和体部,解析方法名
-> find_sip_method//找到方法名对应的ID
-> find_call->sip_alloc//找不到/不存在,就分配一个,这里的是主叫的sip_pvt
//当收到响应消息时,会调用handle_response
->handle_incoming->handle_response->handle_response_refer
-> handle_response_publish
-> handle_response_info
-> handle_response_message
-> handle_response_notify
//收到被叫回的200 ok
-> handle_response_invite-> find_sdp
->process_sdp
->ast_rtp_instance_activate
->ast_queue_control//seewait_for_answer
->transmit_request//回ACK
->check_pendingstransmit_reinvite_with_sdp//这里是第三次发送reinvite
-> handle_request_options
-> handle_request_refer
-> handle_request_cancel
-> handle_request_bye
-> handle_request_message
-> handle_request_subscribe
-> handle_request_register
-> handle_request_info
-> handle_request_notify
//SIP_UPDATE
-> handle_request_update
//SIP_ACK
-> __sip_ack
-> check_pendings-> transmit_request(SIP_CANCEL)
-> transmit_request_with_auth(SIP_BYE)
->transmit_reinvite_with_sdp//这里是第二次发送reinvite,主叫的针对200OK消息的ack来的时候。
//当收到invite时,会调用handle_request_invite
->handle_request_invite->check_user_full-> check_peer_ok-> check_auth//如果没有鉴权,asterisk会发送401
->dialog_initialize_rtp-> ast_rtp_instance_new-> ast_rtp_new(instance->engine->new)
-> do_setnat
->find_sdp
->process_sdp->get_sdp_iterate
->process_sdp_c
->process_sdp_a_audio
->process_sdp_a_ice
->process_crypto-> setup_srtp//分配主叫的structsip_srtp。但是当被叫回的200运行到这里时,不会再为被叫分配。
->sdp_crypto_setup//产生主叫的Srtp的密钥,并存入srtp-> crypto,在asterisk的200消息中回给主叫。
-> sdp_crypto_process->sdp_crypto_activate
-> sdp_crypto_offer
->ast_queue_control(AST_CONTROL_UNHOLD)
->ast_queue_control_data(AST_CONTROL_HOLD)
->ast_rtp_instance_stop
->ast_queue_frame(ast_null_frame)
->change_hold_state
-> ast_queue_control-> ast_queue_frame-> __ast_queue_frame
->get_destination
-> build_contact
->sip_new//分配主叫的ast_channel,这里会确定跟主叫之间的codec
-> build_route
->ast_pbx_start创建一个线程运行pbx_thread,第一次收到invite才会运行到这里。
//收到reinvite,hold和unhold时
-> transmit_response_with_sdp(200)
->ast_queue_control(AST_CONTROL_UPDATE_RTP_PEER)//然后看ast_generic_bridge或者remote_bridge_loop
pbx_thread-> __ast_pbx_run->ast_exists_extension-> pbx_extension_helper
-> ast_spawn_extension->pbx_extension_helper-> pbx_exec->执行到Dial时,调用回调函数dial_exec,这个是通过load_module->ast_register_application注册的
-> ast_pbx_start
//这里是被叫的sip_pvt
dial_exec->dial_exec_full->ast_request(sip_request_call)->sip_alloc-> do_setnat
->build_via
-> create_addr
-> ast_sip_ouraddrfor->ast_ouraddrfor
-> check_for_nat
-> do_setnat
-> build_via
//分配被叫的ast_channel,codec nego,这里会确定跟被叫之间的codec
->sip_new->ast_format_cap_is_empty
->ast_codec_choose
->ast_format_cap_remove_bytype
->ast_format_cap_add
->ast_getformatname_multiple
->ast_getformatname
->enable_dsp_detect
->ast_channel_set_fd
-> ast_rtp_instance_set_write_format
-> ast_rtp_instance_set_read_format
-> ast_exists_extension->pbx_extension_helper
->ast_rtp_instance_early_bridge_make_compatible
//sip_call函数在发出invite后返回,这里是把重新生成的invite发给被叫,被叫是指上面使用ast_request分配资源的那个刚刚创建的被叫
-> ast_call(sip_call)-> transmit_invite->build_via
-> initreqprep
-> reqprep
-> try_suggested_sip_codec
-> add_sdp-> get_our_media_address
//产生被叫的Srtp的密钥,并存入srtp-> crypto,在asterisk的invite消息中发给被叫。
->get_crypto_attrib-> sdp_crypto_setup->res_srtp/get_random
->sdp_crypto_offer
-> initialize_initreq
-> send_request
// wait_for_answer,收到被叫回的200 OK后,这个函数才返回
-> wait_for_answer
->ast_bridge_call->ast_raw_answer-> set_config_flags
->sip_answer-> try_suggested_sip_codec
->ast_rtp_instance_update_source//下一个package打上marker bit
//向主叫回200 ok
->transmit_response_with_sdp-> ast_rtp_codecs_packetization_set
->ast_rtp_instance_activate(ast_rtp_activate)-> SSL_do_handshake
-> dtls_srtp_check_pending->__rtp_sendto
->add_sdp-> get_crypto_attrib//这里不再产生Srtp的密钥,因为主叫的密钥之前已经产生。
->send_response
//ast_channel_bridge是被循环调用的。下面也是循环调用。
->channel.c /ast_channel_bridge-> ast_indicate->ast_indicate_data-> sip_indicate
->bridge_play_sounds
->rtp_engine.c/ast_rtp_instance_bridge-> get_rtp_info(chan_sip.c/sip_get_rtp_peer)
//查看主被叫是否都配置了directmedia=yes
->allow_rtp_remote(chan_sip.c/sip_allow_rtp_remote)
->local_bridge_loop
这个就是p2p //这里是第一次发送reinvite
->remote_bridge_loop->update_peer(chan_sip.c/sip_set_rtp_peer)->transmit_reinvite_with_sdp
//事件处理,下面是循环,直到呼叫结束
// AST_CONTROL_HOLD//向被叫发出invite,rtp ip为ast的ip
-> update_peer (chan_sip.c/sip_set_rtp_peer)->transmit_reinvite_with_sdp
->ast_indicate_data(AST_CONTROL_HOLD)->sip_indicate-> ast_moh_start
-> update_peer (chan_sip.c/sip_set_rtp_peer)->transmit_reinvite_with_sdp
-> ast_indicate_data(AST_CONTROL_UNHOLD)-> sip_indicate->ast_moh_stop
//但不需要发送reinvite时,会运行到这里,媒体经asterisk中转都会运行到这里
->ast_generic_bridge->ast_indicate_data(AST_CONTROL_HOLD)->sip_indicate-> ast_moh_start
-> ast_indicate_data(AST_CONTROL_UNHOLD)->sip_indicate-> ast_moh_stop
上面的rtp_engine.c/ast_rtp_instance_bridge,是主要的判断是否发送reinvite的函数:
首先判断主被叫是否配置了srtp,如果是就不会发送reinvite。
然后判断主被叫的标志位SIP_DIRECT_MEDIA是否置位(即是否都配置了directmedia=yes或者nonat等),如果有一个不置位就不发送reinvite。
然后判断音视频的rtp流中,如果有一个不可以p2p,就都不p2p。
然后判断地址族是否一样。
然后判断是否需要截取dtmf,比如dialplan中有Tt(Dial(SIP/${EXTEN},30,Tt),表示呼叫转移),就表示需要截取dtmf以获取转移的第三方的号码。如果需要截取DTMF,就不发reinvite。
然后判断codec是否一样,打包间隔是否一样。
上面有一个不满足,就会调用ast_generic_bridge,不会发送reinvite。如果都满足的话,就会调用remote_bridge_loop,发出reinvite。
ast_indicate_dataast_queue_frame
ast_indicate_data是用于对远端的操作,比如AST_CONTROL_HOLD时,是播放背景音乐。一般是用户线程使用这个函数。
ast_queue_frame(ast_queue_control、ast_queue_control_data)是主线程向用户线程发送事件。一般是主线程使用这个函数。
flag用法
#define SIP_REINVITE (7 << 20) /*!< DP: foursettings, uses three bits */
#define SIP_REINVITE_NONE (0 << 20) /*!< DP: no reinviteallowed */
#define SIP_DIRECT_MEDIA (1 << 20) /*!< DP: allow peers tobe reinvited to send media directly p2p */
#define SIP_DIRECT_MEDIA_NAT (2 <<20) /*!< DP: allow media reinvite when new peer is behind NAT */
#define SIP_REINVITE_UPDATE (4 << 20) /*!< DP: use UPDATE(RFC3311) when reinviting this peer */
//2 << 20 = 1 << 21、4 << 20 = 1 << 22,所以下面就直接用了1 << 23,没有用1 <<21、1 << 22,不然就重了。
ast_clear_flag(&flags[0],SIP_REINVITE);
ast_set_flag(&flags[0],SIP_DIRECT_MEDIA | SIP_DIRECT_MEDIA_NAT);
ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA_NAT)