雖然freeswitch已經內置了一些標識的事件,比如:CHANNEL_CREATE(發起呼叫時觸發),CHANNEL_HANGUP_COMPLETE(電話掛斷時觸發)...,但是有時候我們想根據業務需求,新增一些自定義的事件,比如:客人進線后,如果分配到了一個空閑的客服,希望觸發一個特定的事件。
可參考以下代碼(注:以下所有代碼依賴的esl-client,來自於github上的最新代碼)
@Override
public void onConnect(Context context, EslEvent eslEvent) {
try {
Execute exe = new Execute(context, null);
StringBuilder sbEvent = new StringBuilder();
sbEvent.append("Event-Name=").append("CUSTOM").append(",");
sbEvent.append("Event-Subclass=").append("callcenter::info").append(",");
//自定義事件中的變量(根據業務需求,可自行添加,注:系統變量並不能覆蓋,比如下面的Caller-ANI)
sbEvent.append("Caller-ANI=").append("999999").append(",");
//只有業務新增的變量,賦值才有意義
sbEvent.append("MY-VAR-1=").append("abcdefg").append(",");
//觸發自定義事件
exe.event(sbEvent.toString());
//其它處理(這里只是示例調用了echo)
exe.echo();
} catch (ExecuteException e) {
e.printStackTrace();
} finally {
context.closeChannel();
}
}
ESL outbound外聯模式下,onConnect方法中的上述代碼,相當於每次進線,都觸發一個自定義事件,然后調用echo,讓主叫方聽到自己的聲音。
測試一下,可以在inbound中監控該事件,主要代碼如下:
//inbound test
final Client inboundClient = new Client();
inboundClient.connect(new InetSocketAddress("localhost", 8021), "ClueCon", 10);
inboundClient.setEventSubscriptions(IModEslApi.EventFormat.PLAIN, "ALL");
inboundClient.addEventListener((ctx, event) ->
{
String eventName = event.getEventName();
if (eventName.equalsIgnoreCase("CUSTOM") || eventName.contains("HANGUP_COMPLETE")) {
String ani = event.getEventHeaders().get("Caller-ANI");
String myvar = event.getEventHeaders().get("MY-VAR-1");
System.out.println("INBOUND=> eventName: " + event.getEventName() + ", ani = " + ani + ", myvar = " + myvar);
}
}
執行結果 :
這里有幾個要注意的地方:
1. 系統自帶的默認通道變量,比如Caller-ANI,在自定義事件中並不能通過賦值的方式篡改。比如上面的示例中,我們把Caller-ANI想改成999999,但是沒未生效。
2. 每一次自定義事件的觸發,設置的業務變量(比如:上面的MY-VAR-1),只在本次事件中有效,並不象freeswitch自帶的變量,可以一直傳遞到后面的事件中。
3. 如果需要添加自定義變量,且一直能向下傳遞到所有事件中,可以用export導出變量
exe.export("MY-VAR-2", "something", true);
而且用export導出的變量,在取值時,要加上variable_前綴,即:
event.getEventHeaders().get("variable_MY-VAR-2");
另外還有一個大坑,可能是esl-client代碼的問題,在inbound訂閱事件時,可以指定訂閱指定事件,上面的示例中,我們用的是ALL,即訂閱所有事件。
inboundClient.setEventSubscriptions(IModEslApi.EventFormat.PLAIN, "ALL");
根據setEventSubscriptions源碼的注釋說明,可以用類似 “A B C”的方式,指定訂閱事件A, B ,C
/**
* Set the current event subscription for this connection to the server. Examples of the events
* argument are:
* <pre>
* ALL
* CHANNEL_CREATE CHANNEL_DESTROY HEARTBEAT
* CUSTOM conference::maintenance
* CHANNEL_CREATE CHANNEL_DESTROY CUSTOM conference::maintenance sofia::register sofia::expire
* </pre>
* Subsequent calls to this method replaces any previous subscriptions that were set.
* </p>
* Note: current implementation can only process 'plain' events.
*
* @param format can be { plain | xml }
* @param events { all | space separated list of events }
* @return a {@link CommandResponse} with the server's response.
*/
@Override
public CommandResponse setEventSubscriptions(EventFormat format, String events) {
checkConnected();
return clientContext.get().setEventSubscriptions(format, events);
}
但現實是殘酷的,當我們換成后
inboundClient.setEventSubscriptions(IModEslApi.EventFormat.PLAIN, "CHANNEL_CREATE CHANNEL_HANGUP CHANNEL_HANGUP_COMPLETE CHANNEL_DESTROY CUSTOM");
居然發現inbound模式下的CUSTOM事件無法訂閱成功(注:解決方法,見評價區1樓ctgu_czy的回復,感謝ctgu_czy)


