呼叫中心——ESL接入

ESL作为java客户端通信组件,底层主要通过socket跟freeSwitch建立通信。具体使用步骤是:

1.spring项目中引入pom依赖:

        <dependency>
            <groupId>thirdparty.org.freeswitch.esl.client</groupId>
            <artifactId>esl-client</artifactId>
            <version>1.0</version>
        </dependency>        

2.ESL的client应用有两种模式:inbound和outbound。本项目采用前者。

a.Client 的声明:

Client eslClient = new Client();

b.初始化连接信息:

public static void connection(Client eslClient) throws InboundConnectionFailure {
        String host = HippoUtil.getValue(HippoUtil.FS_INSIDE_HOST);
        Integer port = Integer.parseInt(HippoUtil.getValue(HippoUtil.FS_INSIDE_PORT));
        String password = HippoUtil.getValue(HippoUtil.FS_INSIDE_PASSWORD);
        Integer timeoutSeconds = Integer.parseInt(HippoUtil.getValue(HippoUtil.FS_INSIDE_TIMEOUTSECONDS));
        eslClient.connect(new InetSocketAddress(host, port), password, timeoutSeconds);
        eslClient.cancelEventSubscriptions();
        eslClient.setEventSubscriptions(IModEslApi.EventFormat.PLAIN, CommonContants.PLAIN);
}

c.为client加入监听

import org.freeswitch.esl.client.inbound.IEslEventListener;
import org.freeswitch.esl.client.internal.Context;
import org.freeswitch.esl.client.transport.event.EslEvent;
import org.freeswitch.esl.client.transport.message.EslHeaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Objects;


/**
 * 创建esl监听
 */
@Component
public class EslEventListener implements IEslEventListener {

    private final Logger log = LoggerFactory.getLogger(this.getClass());
    
    @Autowired
    EslEventHandler eslEventHandler;

    /***
     * 事件监听
     * @param event
     */
    @Override
    public void onEslEvent(Context ctx, EslEvent event) {
        if (InjectServiceUtil.getInstance().getEslEventHandler() == null){
            return;
        }
        Map<String, String> headers = event.getEventHeaders();
        //过滤器***

        //初始信息cache化 比如redis存储fs的IP信息等
        String callUuid = headers.get(CommonContants.EventHeader.callUUID);
        String ip = headers.get(CommonContants.EventHeader.IPv4);
        //调用具体的event handler
        eslEventHandler.execute(event);
    }
}

在此注意:由于部署时候会存在多个java客户端,而生产上FS服务器也会部署多个,因为我们需要对每个应用(client)和具体的FS进行映射处理(可以持久化到db)。且同一时刻,一个会话只会在一个esl的连接里处理,因此在一通电话里,client和FS保持的会话是不可间断。且我们需要进行心跳机制保持Client和FS的连接不能被中断。这里需要对client的status进行监控。

另外,listener 里可以加入具体的业务逻辑 ,比如session落库、status记录(callUUID之类的)。而handler可以根据不同的通话命令引导到不同的handler***处理。

其中event header里主要的key如下:

public class EventHeader {
        public final static String direction = "variable_call_direction";
        public final static String callState = "Channel-Call-State";
        public final static String hangupCause = "Hangup-Cause";
        public final static String sipFromUser = "variable_sip_from_user";
        public final static String sipToUser = "variable_sip_to_user";
        public final static String uuid = "variable_uuid";
        public final static String callUUID = "Channel-Call-UUID";
        public final static String fileName = "fileName";
        public final static String callerIdNumber = "Caller-Caller-ID-Number";
        public final static String calleeIdNumber = "Caller-Callee-ID-Number";
        public final static String createdTime = "Caller-Channel-Created-Time";
        public final static String answeredTime = "Caller-Channel-Answered-Time";
        public final static String hangupTime = "Caller-Channel-Hangup-Time";
        public final static String executeOnAnswer = "variable_execute_on_answer";
        public final static String dtmfDigit = "DTMF-Digit";
        public final static String application = "Application";
        public final static String exeAppName = "execute-app-name";
        public final static String dtmfArgs = "variable_dtmf_args";
        public final static String readResult = "variable_read_result";
        public final static String exeRead = "read";
        public final static String speak = "speak";
        public final static String bridge = "bridge";
        public final static String success = "success";
        public final static String failure = "failure";

        public final static String asrResult = "variable_detect_speech_result";
        public final static String currentApplication = "variable_current_application";
        public final static String applicationResponse = "Application-Response";
        public final static String fileUrl = "variable_current_application_data";
        public final static String dialedUser = "variable_dialed_user";
        public final static String disposition = "variable_bridge_disposition";

        public final static String customCallType = "variable_custom_call_type";

        public final static String IPv4 = "FreeSWITCH-IPv4";

        public final static String billmsec = "variable_billmsec";

        public final static String mduration = "variable_mduration";


        // 筛号变量
        public final static String selectTelDa2Tone = "da2_tone";
        public final static String selectTelDa2SampleUniqueid = "da2_sample_uniqueid";

        public final static String selectTelDa2SampleBrief = "da2_sample_brief";
        //号码样本分类
        public final static String selectTelDa2SampleCategory = "da2_sample_category";
        public final static String selectTelDa2SampleName = "da2_sample_name";
    }

ESLEventHandler的核心实现如下:

@Service("eslEventHandler")
public class EslEventHandler {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AnswerHandler answerHandler;

    @Autowired
    private BridgeHandler bridgeHandler;

    @Autowired
    private DestroyHandler destroyHandler;

    @Autowired
    private HangComHandler hangupCompHandler;

    @Autowired
    private HangupHandler hangupHandler;

    @Autowired
    private HeartbeatHandler heartbeatHandler;

    @Autowired
    private PlaybackStopHandler playbackStopHandler;

    @Autowired
    private RobotPlaybackStopHandler robotPlaybackStopHandler;

    @Autowired
    private ExecuteComHandler executeComHandler;

    @Autowired
    private RobotExecuteComHandler robotExecuteComHandler;

    @Autowired
    private RobotBridgeHandler robotBridgeHandler;

    @Autowired
    private ParkHandler parkHandler;

    @Autowired
    private StateHandler stateHandler;

    @Autowired
    ExceptionHandler exceptionHandler;

    @Autowired
    private SelectTelHandler selectTelHandler;

    /**
     * 统一事件处理方法
     * @param event
     */
    public void eventHandler(EslEvent event){
        //业务侧自定义的当前会话任务DTO
        CurrentTaskDto currentTaskDto = null;
        Map<String, String> headers = event.getEventHeaders();
        String uuid = headers.get(CommonContants.EventHeader.callUUID);
        //根据不同类型调用具体的handler 比如通过switch 语法。。
    }
}

可以看到,上述代码块,有不同类型的handler,其实这里可以根据策略模式进行适配,或者责任链的模式,将不同handler串联在一起应用。当然,初期为了快速落地,我们也可以使用简单的if/else即可。

另外,每个Session都会有一个初始事件,而为了进行拥塞控制或者限流,我们可以考虑将不同session在发起时利用生产者-消费者的方式进行事件分发和消费和隔离。比如在EventListener里只引入一个eventStorage或eventProducer。然后通过多线程方式不断进行consume,消费者主要逻辑就是调用唯一的hander入口。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要将Java应用程序与FreeSWITCH集成,您可以使用FreeSWITCH提供的ESL(Event Socket Library)库。ESL是一种通过TCP/IP套接字与FreeSWITCH交互的库,它使您能够发送命令和接收事件。您可以使用Java Socket编程API与ESL进行通信。 以下是一个简单的Java代码示例,演示如何连接到FreeSWITCH ESLeventsocket,并发送一个命令: ```java import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; public class FreeSwitchIntegration { public static void main(String[] args) throws UnknownHostException, IOException { // 创建一个Socket连接 Socket socket = new Socket("localhost", 8021); // 发送authenticate命令进行鉴权 String authString = "auth ClueCon\n\n"; socket.getOutputStream().write(authString.getBytes()); // 读取响应 byte[] response = new byte[1024]; socket.getInputStream().read(response); // 发送一个show命令 String commandString = "api show channels\n\n"; socket.getOutputStream().write(commandString.getBytes()); // 读取响应 response = new byte[1024]; socket.getInputStream().read(response); System.out.println(new String(response)); // 关闭Socket连接 socket.close(); } } ``` 在这个例子中,我们首先创建一个Socket连接到FreeSWITCH的ESL端口(默认为8021)。然后我们发送一个authenticate命令进行鉴权。在获得响应后,我们发送一个show命令并读取响应。最后,我们关闭Socket连接。 您可以使用类似的方法与FreeSWITCH进行交互,发送命令并处理事件。请注意,此代码示例仅用于演示目的,实际情况下您需要进行更多的错误处理和异常处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值