freeswitch笔记(9)-esl outbound中如何放音采集按键?
关于这个功能,esl-client 上给出的源码示例极具误导性,根本跑不起来,见: https://github.com/esl-client/esl-client/blob/master/src/test/java/OutboundTest.java
正确姿势:必须在事件订阅的回调里,才能拿到用户按键值
示例代码:
package org.freeswitch.esl.client; import org.freeswitch.esl.client.dptools.Execute;
import org.freeswitch.esl.client.dptools.ExecuteException;
import org.freeswitch.esl.client.internal.Context;
import org.freeswitch.esl.client.outbound.IClientHandler;
import org.freeswitch.esl.client.outbound.IClientHandlerFactory;
import org.freeswitch.esl.client.outbound.SocketClient;
import org.freeswitch.esl.client.transport.event.EslEvent;
import org.freeswitch.esl.client.transport.message.EslHeaders.Name;
import org.freeswitch.esl.client.transport.message.EslMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.net.InetSocketAddress;
import java.util.regex.Pattern; import static com.google.common.base.Throwables.throwIfUnchecked; public class OutboundDTMFTest {
private static Logger logger = LoggerFactory.getLogger(OutboundDTMFTest.class);
private static String sb = "/usr/local/freeswitch/sounds/en/us/callie/ivr/8000/";
String prompt = sb + "ivr-please_enter_extension_followed_by_pound.wav";
String failed = sb + "ivr-that_was_an_invalid_entry.wav"; public static void main(String[] args) {
new OutboundDTMFTest();
} public OutboundDTMFTest() {
try {
//outbound test
final SocketClient outboundServer = new SocketClient(
new InetSocketAddress("localhost", 8086),
new OutboundHandlerFactory());
outboundServer.startAsync();
} catch (Throwable t) {
throwIfUnchecked(t);
}
} public class OutboundHandlerFactory implements IClientHandlerFactory { @Override
public IClientHandler createClientHandler() {
//just for sample , recommend use singleton pattern, to avoid new too many instance
return new OutboundHandler();
}
} public class OutboundHandler implements IClientHandler { StringBuffer buffer = new StringBuffer(10);
String pattern1 = "^\\d+";
String pattern2 = "^\\d+#$"; @Override
public void onConnect(Context context, EslEvent eslEvent) {
try {
Execute exe = new Execute(context, ""); //订阅DTMF事件
EslMessage eslMessage = context.sendCommand("event plain DTMF");
if (eslMessage.getHeaderValue(Name.REPLY_TEXT).startsWith("+OK")) {
logger.info("subscribe event success!");
} exe.answer(); int timeOutSeconds = 30; //放音采集
exe.playAndGetDigits(1,
1, 10, timeOutSeconds * 1000, "#", prompt,
failed, pattern1, timeOutSeconds * 1000); //等待用户输入按键
long start = System.currentTimeMillis();
while (true) {
if (System.currentTimeMillis() - start > timeOutSeconds * 1000) {
break;
} if (buffer.length() > 0 && Pattern.matches(pattern2, buffer.toString())) {
break;
} Thread.sleep(50);
} System.out.println("you pressed:" + buffer.toString()); } catch (ExecuteException | InterruptedException e) {
logger.error("Could not prompt for digits", e);
} finally {
context.closeChannel();
} } @Override
public void onEslEvent(Context ctx, EslEvent event) {
// System.out.println(event.getEventName());
if (event.getEventName().equalsIgnoreCase("DTMF")) {
String key = event.getEventHeaders().get("DTMF-Digit");
if ("#".equalsIgnoreCase(key)) {
//检查是否输入正确(如果错误,请将之前输入的清空掉)
if (!Pattern.matches(pattern1, buffer.toString())) {
buffer.setLength(0);
return;
}
}
buffer.append(key);
}
}
}
}
解释一下:
1. 首先要订阅DTMF事件,只有在事件回调里,才能拿到用户按键信息
2. playAndGetDigits 在outbound async full异步模式下,这个方法的返回值,其实没啥用,永远都是__undef__,所以要在后面循环检测结果,还要考虑用户一直不按键的情况,要有超时保底
3. 事件回调onEslEvent与用户进线onConnect是在2个不同的方法中,但是都是在同一个线程里的,所以为方便起见,用了一个线程安全的StringBuffer用来保存按键信息
4. 事件回调中,要考虑用户按错键的情况,比如提示用户按数字键,然后用户输入了字母或星号之类的,遇到这种要把之前的输入结果清掉。
freeswitch笔记(9)-esl outbound中如何放音采集按键?的更多相关文章
- shell 中函数放回字符串问题
shell 中函数放回字符串问题 shell 中不可以直接 return 字符串 ,可以return 数字.如果要return 字符串 改为 echo "hello world" ...
- python笔记之提取网页中的超链接
python笔记之提取网页中的超链接 对于提取网页中的超链接,先把网页内容读取出来,然后用beautifulsoup来解析是比较方便的.但是我发现一个问题,如果直接提取a标签的href,就会包含jav ...
- 阅读OReilly.Web.Scraping.with.Python.2015.6笔记---找出网页中所有的href
阅读OReilly.Web.Scraping.with.Python.2015.6笔记---找出网页中所有的href 1.查找以<a>开头的所有文本,然后判断href是否在<a> ...
- [译]我们应该在HTML文档中何处放script标签
本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...
- 从加载DLL的中获取放置于Resources文件夹中资源字典的几种方法
原文:从加载DLL的中获取放置于Resources文件夹中资源字典的几种方法 主程序 为 Main_Test.exe 被加载的DLL 为 Load_Test.dll 此DLL 中 有一个 文件夹Re ...
- [RN] React Native 使用 图片预览和放大 插件 react-native-image-zoom-viewer 过程中,放大报错问题
React Native 使用 图片预览和放大 插件 react-native-image-zoom-viewer 过程中,放大报错问题 报错如下: Cannot record touch end w ...
- Django笔记八之model中Meta参数的使用
前面介绍了 model 的字段属性,字段类型,这篇笔记介绍一下 model 的 Meta 选项. 这个选项提供了一些参数,比如排序(ordering),表名(db_table)等. 但这都不是必需的, ...
- H5之audio标签放音兼容所有浏览器方法
前端交流群,群文件提供大量文档.书籍和资料.期待你的加入!群号:127768464 由于项目需要,最近刚做了一个网页放音的功能,使用到了H5新标签<audio></audio> ...
- c#录音和放音,超简单!不用DirectX
最近在做android与C#录音并互相通信的小东西.但是卡在C#录音这儿了.找了好久,说的都是DirectX,可是我总是安装不上,这才找到了这个简单的录音方法.当然,如果你想要录得好并且处理音频,那还 ...
- alsamixer + alsactl 控制放音通道
1 使用alsamixer的gui界面配置放音(控制OUT1,OUT2的音量); 2 退出alsamixer,使用alsactl store生成配置文件,文件位于/etc/asound.state; ...
随机推荐
- 第二章 Spring Boot 整合 Kafka消息队列 生产者
系列文章目录 第一章 Kafka 配置部署及SASL_PLAINTEXT安全认证 第二章 Spring Boot 整合 Kafka消息队列 生产者 第三章 Spring Boot 整合 Kaf ...
- 【BUG】Hexo|GET _MG_0001.JPG 404 (Not Found),hexo博客搭建过程图片路径正确却找不到图片
我的问题 我查了好多资料,结果原因是图片名称开头是_则该文件会被忽略...我注意到网上并没有提到这个问题,遂补了一下这篇博客并且汇总了我找到的所有解决办法. 具体检查方式: hexo生成一下静态资源: ...
- 【ROS】6.1 中间人攻击移动过程
原视频 中间人攻击 实验目的 ARP欺骗可以作为中间人攻击的一个起手式.前一个实验我们完成了ARP欺骗,在本章实验中,我们将会在上一个实验的基础上,针对键盘控制过程的报文进行修改,使键盘控制异常. 本 ...
- Rust 在 Linux 下的安装
Rust 在 Linux 下的安装 我感觉, Rust 这个语言, 集 C, C++, Java, Scala, JavaScript, TypeScript, Python ... 等语言的优势于一 ...
- 区块链共识算法--PoW
PoW算法为一种概率算法,其共识结果是临时的,随着时间推移或某种强化,共识结果被推翻的概率越来越小,最终称为事实上结果 1 研究 工作量证明(Proof Of Work,简称POW),简单理解就是一份 ...
- ComfyUI+通义万相 Wan2.1系列生成视频教程
一.Wan2.1系列 Wan2.1 系列是阿里巴巴通义实验室推出的开源视频生成模型套件,共有 4 个模型,包括文生视频的 Wan2.1-T2V-1.3B 和 Wan2.1-T2V-14B,以及图生视频 ...
- 【教程】Ubuntu 16.04 配置 CLion 开发 ROS Melodic
[教程]Ubuntu 16.04 配置 CLion 开发 ROS Melodic 目录 [教程]Ubuntu 16.04 配置 CLion 开发 ROS Melodic 笔者环境 步骤 下载安装 CL ...
- Spring Boot2.5 集成数据库连接池 HikariCP
目录 §工程环境 §数据库连接池介绍 数据库连接池工作原理剖析 §Java常见数据库连接池性能比较 §数据库连接池选型 Druid vs HikariCP性能对比 §HikariCP为什么这么快 §数 ...
- 「Log」2023.8.28 小记
序幕 七点多到校,整理博客,开了一篇新做题记录. 整理一下学过知识点,准备阶段复习. 八点整开始打模拟赛,接下来算游记. T1 是个静态区间第 \(k\) 小板子,纯主席树被空间卡掉了,打了 \(60 ...
- java的StackOverflowError异常
之前明明能查到,现在突然报错StackOverflowError,并一直在控制台返回空对象 多次遇到这种情况 发现是东西存入缓存中,缓存内存不够导致栈溢出,刷新kill缓存即可