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. 事件回調中,要考慮用戶按錯鍵的情況,比如提示用戶按數字鍵,然后用戶輸入了字母或星號之類的,遇到這種要把之前的輸入結果清掉。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM