问题描述: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:
修改拨号规则
知乎上也有同学提到相同的问题:
本文为呱牛笔记原创文章,转载无需和我联系,但请注明来自呱牛笔记 ,it3q.com