FreeSWITCH Java ESL Client Demo

1简介

在开启Java ESL Client编程之前,请先阅读《FreeSWITCH权威指南》学习什么是FreeSWITCH Event Socket。

Java连接FreeSWITCH的ESL可以采用两种模式:inbound和outbound。

  1. Inbound模式:Java应用作为客户端主动连接到FreeSWITCH的内置TCP服务器上,默认监听8021端口。连接成功后,Java应用可以订阅FreeSWITCH的各种事件通知,并对特定事件进行处理,也可以向FreeSWITCH发送命令。例如,通过Java应用可以获取来电事件,并且可以控制呼叫流程,如发送异步API命令发起呼叫 。

  2. Outbound模式:Java应用作为服务器端,FreeSWITCH作为客户端连接到Java应用。这种模式下,需要在FreeSWITCH配置中指定Java应用的IP和端口。当有来电时,FreeSWITCH会连接到Java应用,Java应用可以根据业务需求对通话进行处理,如播放音乐或转接呼叫 。

选择哪种模式取决于具体的业务需求。如果需要监控所有来电情况或实现自助语音服务,inbound模式可能更合适。而如果需要对来电进行人工客服分配,outbound模式可能更简单 。另外,Java ESL客户端库支持这两种模式,并且提供了丰富的API来处理ESL连接和事件 。

在实际开发中,开发者可以根据需要选择适合的连接模式,并利用Java ESL客户端提供的接口来实现与FreeSWITCH的交互。

Java ESL客户端通过与FreeSWITCH的Event Socket Library(ESL)交互,能够实现以下操作:

  1. 连接管理:建立与FreeSWITCH的连接,并处理连接的生命周期,包括断开和重连。

  2. 事件订阅:订阅FreeSWITCH产生的各种事件,如呼叫开始、结束、通道变更等。

  3. 事件处理:接收并处理来自FreeSWITCH的事件通知,允许应用根据事件执行业务逻辑。

  4. 发送API命令:向FreeSWITCH发送同步或异步API命令来控制呼叫流程,例如发起呼叫、挂断、转接等。

  5. 执行异步命令:发送异步命令并接收结果,如查询呼叫状态、执行数据库操作等。

  6. 同步命令执行:发送同步命令并等待其执行结果,适用于需要即时反馈的操作。

  7. 设置呼叫变量:在呼叫过程中设置或修改呼叫变量,以控制FreeSWITCH的行为。

  8. 用户和设备管理:通过API命令管理SIP用户、分机、IVR流程等。

  9. 呼叫录音:控制呼叫录音的开始和停止。

  10. 呼叫监听和监视:监听特定呼叫的音频流或监视呼叫状态。

  11. 发送DTMF:向正在通话的通道发送DTMF信号。

  12. 应用执行:在呼叫中执行特定的FreeSWITCH应用,如播放音乐、发送短信等。

  13. 错误处理:处理与FreeSWITCH连接或命令执行过程中可能出现的错误。

  14. 日志记录:记录与FreeSWITCH交互的日志信息,方便问题排查。

  15. 自定义协议支持:实现自定义的ESL协议命令,以支持FreeSWITCH的高级特性。

  16. 多线程和并发处理:支持多线程环境下的并发调用和事件处理。

  17. 资源管理:管理与FreeSWITCH的连接资源,优化连接使用效率。

Java ESL客户端作为一个强大的工具,允许开发者通过编程方式与FreeSWITCH进行交互,实现复杂的呼叫处理和通信应用(fs_cli)。

2实现

2.1maven依赖

<dependency>
<groupId>org.freeswitch.esl.client</groupId>
<artifactId>org.freeswitch.esl.client</artifactId>
<version>0.9.2</version>
</dependency>

2.2代码

package org.example;

import org.freeswitch.esl.client.IEslEventListener;
import org.freeswitch.esl.client.inbound.Client;
import org.freeswitch.esl.client.transport.event.EslEvent;

/**
 * @author yrz
 * @create 2024/08/20
 */
public class ESLClient {
    private static final String HOST = "10.192.33.34";
    private static final int PORT = 8021;
    private static final String PASSWORD = "ClueCon";
    private static String job_UUID = null;

    public static void main(String[] args) {
        InBound();
    }

    private static void InBound() {
        final Client client = new Client();
        try {
            client.connect(HOST, PORT, PASSWORD, 20);
            System.out.println("连接成功");
        } catch (Exception e) {
            System.out.println("连接失败");
        }

        client.addEventListener(new IEslEventListener() {
            @Override
            public void eventReceived(EslEvent event) {
                if (event.getEventName().equals("CHANNEL_ANSWER")) {
                    System.out.println("通道应答");
                } else if (event.getEventName().equals("HEARTBEAT")) {
                    System.out.println("收到心跳 --> " + event.getEventBodyLines());
                    job_UUID = client.sendAsyncApiCommand("status", null);
                    System.out.println("Job_UUID --> " + job_UUID);
                } else if (event.getEventName().equals("CHANNEL_DESTROY")) {
                    System.out.println("通道销毁");
                } else if (event.getEventName().equals("CHANNEL_HANGUP_COMPLETE")) {
                    //挂断
                    System.out.println("通道挂断完成");
                } else if (event.getEventName().equals("CHANNEL_CREATE")) {
                    System.out.println("通道创建");
                }
            }
            @Override
            public void backgroundJobResultReceived(EslEvent event) {
                String uuid = event.getEventHeaders().get("Job-UUID");
                if (job_UUID.equals(uuid)) {
                    for (String s : event.getEventBodyLines()) {
                        System.out.println(s);
                    }
                }
            }
        });
        client.setEventSubscriptions("plain", "all");
    }
}
/*
播打电话
String originate = client.sendAsyncApiCommand("originate", CallEnum.CALL_BRIDGE);
类型
//相当于1001给1002打电话   {origination_caller_id_number=1001}可以设置1001方显示名字(默认是0000000)
public static final String CALL_BRIDGE = "{origination_caller_id_number=1002}user/1001 &bridge(user/1002)";
// 给1001打电话,channel启动echo app(类似汤姆猫)   并修改名字和号码
public static final String CALL_CHANNEL_CHANGE_NAME = "{origination_caller_id_name='Zhang San',origination_caller_id_number=1234}user/1001 &echo";
//等价于 user/1001 &echo
public static final String CALL_DIALPLAN_XML = "user/1001 echo inline";
// 给1001通话,channel启动playback app(播放录音)
public static final String CALL_PLAYBACK = "{origination_caller_id_name='Zhang San',origination_caller_id_number=1234}user/1001 &playback(/播放文件路径)";
// 顺振 第一个呼叫失败,呼叫第二个,以此类推
public static final String CALL_PARAMAGNETIC_RESONANCE = "user/1001|user/1002 &echo";
// 同振 同时呼叫   谁先接听谁通话,另一个挂断
public static final String CALL_WITH_VIBRATION = "user/1001,user/1002 &echo";
// 服务器先给1001打,1001接听后进入dialplan,找到1002这个exten,最后执行&echo
public static final String CALL_EXTEN = "user/1001 1002";
// 在1001接听后进入public dialplan查找路由
public static final String CALL_DIALPLAN_CONTEXT = "user/1001 1002 XML public";
// 在呼叫时,在SDP里面向对方提供G729 PCMU编码,但在执行是会缺少PCMU编码   需要转义字符\或者^^:   {absolute_codec_string=G729\,PCMU}user/1001 &echo 或者下面的
public static final String CALL_ESCAPE_CODEC = "{absolute_codec_string=G729^^:PCMU}user/1001 &echo";
*/

3问题处理

3.1mod_event_socket.c:2674 IP ::ffff Rejected by acl “loopback.auto”

event socket默认监听地址为127.0.0.1。

在event_socket.conf.xml配置文件中,取消该行注释:

<param name="apply-inbound-acl" value="loopback.auto"/>

在acl.conf.xml中增加:

<list name="loopback.auto" default="allow">  
	<node type="allow" cidr="0.0.0.0"/>  
</list>
/***********************************************/
<list name="loopback.auto" default="allow">  
    <node type="allow" cidr="0.0.0.0/0"/>  
</list>

reloadxml

reloadacl

4参考文档

https://developer.signalwire.com/freeswitch/FreeSWITCH-Explained/Client-and-Developer-Interfaces/Java-ESL/Java-ESL-Client_7144076/

https://github.com/esl-client/esl-client

https://sunxiaodou.com/2017/08/02/java-esl-freeswitch/

https://blog.csdn.net/qq_40170041/article/details/127015890

Certainly! Here's a basic example of a FreeSWITCH Java demo application that can make a phone call: ```java import org.freeswitch.esl.client.OutboundClient; import org.freeswitch.esl.client.transport.event.EslEvent; import org.freeswitch.esl.client.transport.message.EslMessage; public class FreeSwitchJavaDemo { public static void main(String[] args) { String host = "localhost"; int port = 8021; String password = "ClueCon"; try (OutboundClient client = new OutboundClient()) { client.connect(host, port, password); String destinationNumber = "1000"; String callerIdNumber = "1234"; EslMessage response = client.sendSyncApiCommand( String.format("originate {origination_caller_id_number=%s}sofia/gateway/mygateway/%s &echo", callerIdNumber, destinationNumber) ); if (response.getHeaderValue("Reply-Text").startsWith("+OK")) { System.out.println("Call successfully placed!"); } else { System.out.println("Failed to place the call!"); } // Listen for events client.addEventListener((EslEvent event) -> { // Handle and process events here }); // Wait for some time to receive events Thread.sleep(5000); } catch (Exception ex) { ex.printStackTrace(); } } } ``` In this example, we use the FreeSWITCH ESL (Event Socket Library) Java API to establish a connection with the FreeSWITCH server. We then use the `sendSyncApiCommand` method to send an originate command, which initiates a call from `callerIdNumber` to `destinationNumber`. We also add the `&echo` parameter to have an echo application handle the call. After sending the command, we check the response to see if the call was successfully placed. Additionally, we can add an event listener to handle and process events received from FreeSWITCH. Remember to replace `localhost`, `8021`, `ClueCon`, `1000`, and `1234` with your own FreeSWITCH server details, gateway, and desired phone numbers. This is just a basic example to get you started. You can explore the FreeSWITCH Java API documentation and sample applications for more advanced functionality and customization options.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倔强的初学者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值