• 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. 事件回调中,要考虑用户按错键的情况,比如提示用户按数字键,然后用户输入了字母或星号之类的,遇到这种要把之前的输入结果清掉。

  • 相关阅读:
    oracle新建用户赋权限
    Linux配置tomcat自动启动
    java白皮书关键术语
    sql中exists和not exists的用法
    db2用户、权限相关命令
    面试问题
    能ping通,但是打不开网页
    kali linux的错误
    virtualbox display size
    Jetson tk1 安装 CUDA,ROS,OpenCV和kinect2以及刷机以及ssh远程控制
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/13415269.html
Copyright © 2020-2023  润新知