通过Asterisk管理界面(AMI)从Java应用程序与Asterisk服务器进行交互
如果您只是刚刚开始在这方面进行研究,那么与该服务器的交互在您看来可能会有些混乱,就像我曾经觉得的那样。
为了不以回答问题的方式在论坛上寻找必要的信息,我附上了一个小教程,内容涉及从Java与Asterisk服务器进行交互。
重要提示:我假设一旦您达到编写代码的阶段,那么您已经拥有可以使用的工作Asterisk服务器。1)选择什么使工作更方便?绝对-星号管理界面(AMI):此界面具有全方位的功能,可让您拨打电话,从服务器实时监听事件,接收呼叫状态并在必要时中断它。
2)要连接什么库?这个:
<dependency> <groupId>org.asteriskjava</groupId> <artifactId>asterisk-java</artifactId> <version>2.0.4</version> </dependency>
3)需要在服务器上查看哪些配置?extensions.conf-描述diaplan的配置。 您将不断与他联系。 如果使用一种更易理解的语言,则它将包含服务器收到特定号码的呼叫时将执行的操作的脚本。 首先,在diaplan中搜索特定的上下文-将其写在方括号中,然后在要联系的该上下文的标签下搜索一个数字。
manager.conf-使用您的Asterisk服务器的用户名和密码进行配置
此配置的内容应大致如下:
[user_name] secret = password read = all write = all deny=0.0.0.0/0.0.0.0 permit=0.0.0.0/255.255.255.0
- user_name-用户名
- 秘密-密码
- deny-该用户拒绝访问的IP地址
- 允许-允许访问。 请务必在许可中指定要与之联系的IP,因为翠菊可以拒绝您的请求。
sip.conf-所有中继都在这里注册。 中继线是电话,我们将通过该电话呼叫客户。
4)从哪里开始编写代码?有两个选项:您需要在Asterisk服务器上执行某些操作,或者侦听服务器上的事件。 我们的序列包括两者。
我们描述行动计划:
- 打开与服务器的连接;
- 我们描述了工作场景;
- 我们听事件;
- 关闭连接。
因此,将在创建DefaultAsteriskServer对象的过程中初始化连接:
import org.asteriskjava.live.AsteriskServer; import org.asteriskjava.live.DefaultAsteriskServer;
AsteriskServer asteriskServer = new DefaultAsteriskServer(HOSTNAME, USERNAME, PASSWORD); asteriskServer.initialize();
打开连接后,我们需要致电用户。 我们将其称为行动方案。 该场景的描述将在一个单独的类中:
public class ScenarioCall extends OriginateAction { private final Logger log = LoggerFactory.getLogger(ScenarioCall.class); private String TRUNK; private final String PHONE_FOR_RINGING; private final String EXTEN_FOR_APP; private final String CONTEXT_FOR_APP; public ScenarioCall(String trunk, String phoneForRinging, String extension, String context) { this.TRUNK = trunk; this.PHONE_FOR_RINGING = phoneForRinging; this.EXTEN_FOR_APP = extension; this.CONTEXT_FOR_APP = context; this.init(); } private void init() {
在这种情况下,我们需要了解什么? 首先,创建中继连接。 中继线是您用来呼叫订户的号码。 此后,将在中继线和订户之间创建一个连接,然后在订户和您需要的其他人之间建立连接。
就是按照这个顺序。
this.setContext(CONTEXT_FOR_APP)
传输的值:在上下文中,我们将在其中查找要与订户关联的电话号码(来自extensions.conf)。
this.setExten(EXTEN_FOR_APP)
传输的值:联系订户后(从extensions.conf中)将执行的脚本。
this.setCallerId(callId)
传输的值:我们的订户号码
this.setChannel(channelAsterisk)
发送值:已建立的通信通道,通常如下所示:trunk_name / phone_user。
在哪里寻找trunk_name? 星号服务器上有一个sip.conf配置-所有干线都在那里注册。
建立通话:
if (asteriskServer .getManagerConnection().getState().equals(ManagerConnectionState.CONNECTED) || asteriskServer .getManagerConnection().getState().equals(ManagerConnectionState.CONNECTING) || asteriskServer .getManagerConnection().getState().equals(ManagerConnectionState.INITIAL)) { try { ScenarioCall scenarioCall = new ScenarioCall(trank, phone, extension, context); CallBack callBackForScenarioCall = new CallBack(); asteriskServer.originateAsync(scenarioCall, callBackForScenarioCall); } catch (ManagerCommunicationException e) {
我们创建了一个呼叫,但是如何动态跟踪呢?
为此,要完成两件事:在OriginAsync方法中传递CallBack类的实例。
并且侦听器挂在服务器上,它将合并发生在我们身上的所有内容。
需要一个侦听器,因为当用户已经通话时,CallBack类不会通知您呼叫结束,也不会通知您用户仍然可以转移到其他地方。
public class CallBack implements OriginateCallback { private ChannelState resultCall = ChannelState.PRERING; @Override public void onDialing(AsteriskChannel asteriskChannel) {
如何将听众挂在星号上?为此,请创建一个实现类AsteriskServerListener,PropertyChangeListener。
对于创建的连接,通过AsteriskConnection类的实例,我们实现:
this.asteriskConnection.addAsteriskServerListener(this.callBackEventListener);
this.callBackEventListener-我们的侦听器类的实例,其源于:
** * Asterisk * PropertyChangeListener , . * AsteriskServerListener , AsteriskConnection. */ public class CallBackEventListener implements AsteriskServerListener, PropertyChangeListener { public void onNewAsteriskChannel(AsteriskChannel channel) { channel.addPropertyChangeListener(this); } public void onNewMeetMeUser(MeetMeUser user) { user.addPropertyChangeListener(this); } public void onNewQueueEntry(AsteriskQueueEntry user) { user.addPropertyChangeListener(this); } public void onNewAgent(AsteriskAgent asteriskAgent) { asteriskAgent.addPropertyChangeListener(this); } public void propertyChange(PropertyChangeEvent propertyChangeEvent) { findEventEndCall(propertyChangeEvent); } private void findEventEndCall(PropertyChangeEvent event) { if (event.getSource() instanceof AsteriskChannel) { AsteriskChannel callBackChannel = (AsteriskChannel) event.getSource(); String callId = getStringWithOnlyDigits(callBackChannel.getCallerId().toString()); callId = ValidValues.getValidCallId(callId); if (callBackChannel.getState().toString().equals("HUNGUP") && event.getOldValue().toString().contains("RINGING")) {
我建议您在一开始时就承诺,关于propertyChange的内容并查看PropertyChangeEvent,这将是服务器上发生的所有事情的堆。 它根本不过滤信息。 因此,得出的结论是:尽可能少地挂起听众。 并非针对每个调用,因为据我发现,即使在OriginateCallback类中也可以完成。 这没用。 查看出现哪些PropertyChangeEvent对象,查看那里的字段类型以及所需的字段。 下一步-欢迎来到信息处理领域。
关于数据验证的一些知识。
在OriginateAction.setChannel中-传递trunk_name / phone_user
phone_user-如果是俄语,则国际数字为加号,则应以8开头。
在OriginateAction.setCallerId中-传输客户端的电话号码,
然后在CallBackEventListener中,它将出现在callBackChannel.getCallerId()中。
将像这样:
String callId = getStringWithOnlyDigits(callBackChannel.getCallerId().toString());
最后,不要忘记:
asteriskServer.shutdown();
如果需要中断任何呼叫,则在CallBackEventListener类中
在现有的通讯渠道上,我们执行:
callBackChannel.hangup();
原来如此简单的教程。 乍一看,当然很简单,但是请相信我,查找信息,推迟使用所有方法并停止工作需要大量时间和精力。
祝您使用Asterisk服务器好运!
进一步阅读:
1)
Asterisk-Java教程2)
星号管理界面(AMI)