FreeSWITCH Java ESL Client Demo
1简介
在开启Java ESL Client编程之前,请先阅读《FreeSWITCH权威指南》学习什么是FreeSWITCH Event Socket。
Java连接FreeSWITCH的ESL可以采用两种模式:inbound和outbound。
-
Inbound模式:Java应用作为客户端主动连接到FreeSWITCH的内置TCP服务器上,默认监听8021端口。连接成功后,Java应用可以订阅FreeSWITCH的各种事件通知,并对特定事件进行处理,也可以向FreeSWITCH发送命令。例如,通过Java应用可以获取来电事件,并且可以控制呼叫流程,如发送异步API命令发起呼叫 。
-
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)交互,能够实现以下操作:
-
连接管理:建立与FreeSWITCH的连接,并处理连接的生命周期,包括断开和重连。
-
事件订阅:订阅FreeSWITCH产生的各种事件,如呼叫开始、结束、通道变更等。
-
事件处理:接收并处理来自FreeSWITCH的事件通知,允许应用根据事件执行业务逻辑。
-
发送API命令:向FreeSWITCH发送同步或异步API命令来控制呼叫流程,例如发起呼叫、挂断、转接等。
-
执行异步命令:发送异步命令并接收结果,如查询呼叫状态、执行数据库操作等。
-
同步命令执行:发送同步命令并等待其执行结果,适用于需要即时反馈的操作。
-
设置呼叫变量:在呼叫过程中设置或修改呼叫变量,以控制FreeSWITCH的行为。
-
用户和设备管理:通过API命令管理SIP用户、分机、IVR流程等。
-
呼叫录音:控制呼叫录音的开始和停止。
-
呼叫监听和监视:监听特定呼叫的音频流或监视呼叫状态。
-
发送DTMF:向正在通话的通道发送DTMF信号。
-
应用执行:在呼叫中执行特定的FreeSWITCH应用,如播放音乐、发送短信等。
-
错误处理:处理与FreeSWITCH连接或命令执行过程中可能出现的错误。
-
日志记录:记录与FreeSWITCH交互的日志信息,方便问题排查。
-
自定义协议支持:实现自定义的ESL协议命令,以支持FreeSWITCH的高级特性。
-
多线程和并发处理:支持多线程环境下的并发调用和事件处理。
-
资源管理:管理与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() {@Overridepublic 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("通道创建");}}@Overridepublic 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
相关文章:
FreeSWITCH Java ESL Client Demo
1简介 在开启Java ESL Client编程之前,请先阅读《FreeSWITCH权威指南》学习什么是FreeSWITCH Event Socket。 Java连接FreeSWITCH的ESL可以采用两种模式:inbound和outbound。 Inbound模式:Java应用作为客户端主动连接到FreeSWITCH的内置TCP…...
手摸手系列之Linux下根据自己的jdk包构建docker镜像
项目在本地导出PDF文件正常,部署到Linux服务器docker容器中导出就报错,百撕不得姐,经查,docker依赖的openjdk版本是8u112版本,而我本地是8u421版本,那就升级jdk的小版本试试。 在docker的中央仓库[点我直达…...
tomcat相关
一、部署安装tomcat 在10和20上安装tomcat [root10 ~]# dnf install java-1.8.0-openjdk.x86_64 -y #安装java环境 [root10 ~]# tar zxf apache-tomcat-9.0.93.tar.gz -C /usr/local/ #安装并启动tomcat [root10 ~]# ln -s /usr/local/apache-tomcat-9.0.93/ /usr/local/tomcat…...
20240821给飞凌OK3588-C的核心板刷Rockchip原厂的Buildroot并启动
20240821给飞凌OK3588-C的核心板刷Rockchip原厂的Buildroot并启动 2024/8/21 15:22 viewproviewpro-ThinkBook-16-G5-IRH:~/repo_RK3588_Buildroot20240508$ viewproviewpro-ThinkBook-16-G5-IRH:~/repo_RK3588_Buildroot20240508$ ./build.sh lunch 3. rockchip_rk3588_evb7_…...
服务优雅上下线优雅停机
一、目的 服务发生线程锁住,需要下线服务时,保证请求中的接口不受影响,执行完后,再下线服务 二、步骤 *kill -15时执行改钩子函数 优雅停机 1.当线程锁住 2.运维那边监控到,然后进行kill -15 进程ID 3.代码这边监…...
什么是生信分析?深入探讨生物信息学的技术、方法与广泛应用
介绍 生物信息学分析,简称生信分析,是一个结合了生物学、计算机科学、信息学和统计学的多学科领域,旨在处理、分析和解释海量的生物数据。随着现代生物技术的发展,尤其是高通量测序(Next-Generation Sequencing, NGS&…...
JavaScript判断数组是否包含某个值
目录: 1.for循环/while循环2.数组的some方法3.数组的filter方法4.array.indexOf5.array.findIndex6.array.includes7.array.find8.set中的has方法 1.for循环/while循环 for循环: function contains(arr, val) {for (var i 0; i < arr.length; i) {if (arr[i] …...
C# - 如何在Windows系统中通过C#添加新的PATH条目至系统和用户环境变量
编写系统环境变量-->系统变量-->path-->添加新的列 01:直接写 using Microsoft.Win32; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace updatesystempath01 {class Program{stati…...
Unity | Shader基础知识(第二十二集:两次渲染)
目录 一、前言 二、“渲染两次” 三、本次成品介绍 四、第一次渲染代码 五、第二次渲染代码 六、截止目前的所有代码 七、调整代码 八、总结 一、前言 之前一直讲的shader文件中,都只写了一次CG代码。 为了大家对这部分的整体理解,我们这次渲…...
鸿蒙Harmony实战开发:Arkts构造函数
构造函数 类声明可以包含用于初始化对象状态的构造函数。 构造函数定义如下: constructor ([parameters]) {// ... } typescript 如果未定义构造函数,则会自动创建具有空参数列表的默认构造函数,例如: class Point {x: numbe…...
@vueuse/core使用useColorMode实现主题颜色切换
useColorMode 是一个在前端开发中常用的自定义钩子(Hook),尤其在需要支持深色模式和浅色模式切换的场景下。这个钩子可以根据用户的选择或系统设置动态调整页面样式。 一、安装和引入 npm install vueuse/core # 或者 yarn add vueuse/…...
生信分析入门:从基础知识到实践操作的全方位指南
随着生物学研究的数字化转型,生物信息学(简称生信)分析已经成为现代生命科学研究中的关键工具。对于刚开始接触生信分析的初学者来说,这个领域可能看起来复杂而陌生。然而,通过系统的学习和实践,生信分析可…...
【STM32 FreeRTOS】内存管理
除了FreeRTOS提供的动态内存管理方法,标准的C库也提供了函数malloc()和函数free()来实现动态的申请和释放内存。 为啥不用标准的C库自带的内存管理算法?因为标准C库的动态管理方法有如下缺点: 占用大量的代码空间,不适合用在资源…...
vue3+vite+cesium配置参考
在vite项目中使用Cesium的配置 关键: 资源目录的复制;CESIUM_BASE_URL的正确配置 //vite.config.js // ... // 安装打包复制资源插件,手动复制不需要 // npm i vite-plugin-static-copy import { viteStaticCopy } from vite-plugin-static-c…...
WEB应用服务器TOMCAT
知识点 一 、WEB技术 1、前端三大核心技术 1.1 HTML HTML ( HyperText Markup Language )超文本标记语言,它不同于一般的编程语言。超文本 即超出纯文本的范畴,例如:描述文本颜色、大小、字体等信息,或使…...
maven打包jar后运行提示“没有主清单属性”问题的几种解决方案
常用的几种maven项目打包后,jar运行提示“没有主清单属性”问题的解决方案,大部分都是要修改pom.xml文件,同时有几种自己常用的配置文件,主要供自用,勿喷。 第一种: <build><plugins><plug…...
计算机毕业设计选题推荐-民宿可视化分析-Python爬虫-随机森林算法
✨作者主页:IT毕设梦工厂✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…...
WKWebView加载项目中网页的资源图片路径异常
问题原因,将含有html的文件通过如下方式引入到工程中: 这种处理方式,当应用程序变以后,引入的文件会被全部放在Resources目录下,而忽略你原本的文件路径信息。因此导致出问题。 解决方案: 采用如下方式引…...
算法全面剖析
算法 查找算法: 顺序查找: 基本思想: 顺序查找也称为线形查找,属于无序查找算法。从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功&am…...
tp5php7.4配置sqlserver问题汇总
先修改database.php文件 查看php版本选择sqlserver扩展 通过百度网盘分享的文件:sqlserver 链接:https://pan.baidu.com/s/1zrIV8VWQZM9miLpyH01Aww?pwdxdgx 提取码:xdgx 通过我的分享链接复制自己需要的dll到php的ext下 在php.ini里添加扩…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
