问题描述:Freeswitch配置外呼网关,主叫外呼,存在被叫单通,主叫听不到被叫声音的现象。
估计大部分同学都是参照下面的步骤添加的外部网关,然后上面的这个现象估计就跑不掉了。
1、配置外部网关,在FreeSwitch目录在conf\sip_profiles\external 目录下,创建一个my_gate.xml, 内容如下:
[root@lyz-VirtualBox external]# ls my_gate.xml example.xml [root@lyz-VirtualBox external]# cat my_gate.xml <include> <gateway name="my_gate">//gateway 网关定义,name 是网关配置名称,在拨号时用到 <param name="proxy" value="192.168.23.71:5060"/> <param name="register" value="false"/>//表示不注册// <param name="caller-id-in-from" value="true"/> <!--Most gateways seem to want this--> <param name="username" value="freeswitch_123"/> <param name="password" value="1234"/> </gateway>
2、配置拨号规则:所有0开头的号码都转给上级网关。(注明,这个拨号规则太简单了,fs默认走了代理模式,会出现单通现象。)
<include> <extension name="mycall"> <condition field="destination_number" expression="^0(\d+)$"> <action application="bridge" data="sofia/gateway/my_gate/$1"/> </condition> </extension> </include>
3、问题现象:主叫外呼到上级网关,通过主叫端和Freeswitch端抓包分析:
抓主叫端dump,发现主叫端只有发出包,没有收到包;
抓服务器日志,有收到对端网关转发过来的包,但没有给主叫端转包;
打开fs的rtp debug日志开关,发现fs收到对端网关的rtp包之后,因为主叫端的media_flow 为4,
代码:
SWITCH_DECLARE(switch_status_t) switch_core_media_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id, switch_media_type_t type) { switch_status_t status = SWITCH_STATUS_SUCCESS; int bytes = 0, samples = 0, frames = 0; switch_rtp_engine_t *engine; switch_media_handle_t *smh; switch_assert(session); if (!(smh = session->media_handle)) { return SWITCH_STATUS_FALSE; } if (!smh->media_flags[SCMF_RUNNING]) { return SWITCH_STATUS_FALSE; } engine = &smh->engines[type]; if (type == SWITCH_MEDIA_TYPE_VIDEO) { if (engine->thread_write_lock && engine->thread_write_lock != switch_thread_self()) { return SWITCH_STATUS_SUCCESS; } } if (type == SWITCH_MEDIA_TYPE_AUDIO) { switch_media_flow_t audio_flow = switch_core_session_media_flow(session, SWITCH_MEDIA_TYPE_AUDIO); if (audio_flow != SWITCH_MEDIA_FLOW_SENDRECV && audio_flow != SWITCH_MEDIA_FLOW_SENDONLY) { //从这里退出了 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, " switch_core_session_ media_flow audio_flow %d.\n", audio_flow); return SWITCH_STATUS_SUCCESS; } }
通过增加日志发现,只给被叫端添加了media_flow的读写模式,默认则是4:SWITCH_MEDIA_FLOW_DISABLED
2024-04-07 10:38:08.490172 99.77% [DEBUG] switch_core_media.c:4719 sofia/external/8009 switch_core_media_set_smode type:0 smode:0, old_smode:4. 2024-04-07 10:38:08.490172 99.77% [DEBUG] switch_core_media.c:4719 sofia/external/8009 switch_core_media_set_smode type:1 smode:0, old_smode:4.
代码
SWITCH_DECLARE(void) switch_core_media_set_smode(switch_core_session_t *session, switch_media_type_t type, switch_media_flow_t smode, switch_sdp_type_t sdp_type) { switch_media_handle_t *smh; switch_rtp_engine_t *engine; const char *varname = NULL, *smode_str = NULL; switch_media_flow_t old_smode, opp_smode = smode; switch_core_session_t *other_session; int pass_codecs = 0; if (!(smh = session->media_handle)) { return; } engine = &smh->engines[type]; varname = media_flow_varname(type); media_flow_get_mode(smode, &smode_str, &opp_smode); old_smode = engine->smode; engine->smode = smode; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "engine:%08x, %s switch_core_media_set_smode smode:%d, old_smode:%d.\n", engine, switch_channel_get_name(session->channel), smode, old_smode);
那问题可能出在,被叫回200OK之后,没有走sdp协商流程,所以主叫端的smode一直都是disable。
怎么修改呢?只能继续分析,为什么通过外呼回来的session为什么没有走协商流程了。
通过分析日志,外呼时,freeswitch处于PROXY模式,代理模式下freeswitch只转包,不参与中间协商,不转码,协商由客户端自动完成,但是这个过程中freeswitch又没有把上级网关转发的包转给主叫端,这就是很奇怪了。
通过日志和调试确定,sofia_handle_sip_i_state 接到对方的200 OK后,由于是代理模式,并没有走sdp协商过程。
修改方法1:
switch_core_media_patch_sdp方法,增加判断主叫端的smode是否为DISABLE,如果是则修改为SENDRECV.
#if 1//代理模式下设置为sendrecv if (a_engine->smode == SWITCH_MEDIA_FLOW_DISABLED) { switch_core_media_set_smode(smh->session, SWITCH_MEDIA_TYPE_AUDIO, SWITCH_MEDIA_FLOW_SENDRECV, SDP_TYPE_RESPONSE); } if (v_engine->smode == SWITCH_MEDIA_FLOW_DISABLED) { switch_core_media_set_smode(smh->session, SWITCH_MEDIA_TYPE_VIDEO, SWITCH_MEDIA_FLOW_SENDRECV, SDP_TYPE_RESPONSE); } if (t_engine->smode == SWITCH_MEDIA_FLOW_DISABLED) { switch_core_media_set_smode(smh->session, SWITCH_MEDIA_TYPE_TEXT, SWITCH_MEDIA_FLOW_SENDRECV, SDP_TYPE_RESPONSE); } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "[proxy ]a_engine->smode:%d, mode2:%d, mode3:%d\n", a_engine->smode, v_engine->smode, t_engine->smode); #endif//add end.
方法2:
修改拨号规则
知乎上也有同学提到相同的问题:
-------------------广告线---------------
项目、合作,欢迎勾搭,邮箱:promall@qq.com
本文为呱牛笔记原创文章,转载无需和我联系,但请注明来自呱牛笔记 ,it3q.com