如何使用Asterisk-Java进行IP电话拨打

如何使用A​s​t​e​r​i​s​k​-​J​a​v​a进行IP电话拨打

 

环境: Linux

参考API: http://www.asterisk-java.org/latest/apidocs/index.html

 

网上关于这个的文章已经不少,这里主要是把一些注意事项整理一下,然后是保留部分代码以备以后使用.

 

这里我们要做的是:用户点击页面的'打电话'按键,系统将通过Java完成目标IP电话和当前用户电话的自动连接功能.

 

首先是常规的代码:

package org.jerval.test.pbx;

import java.io.IOException;
import java.util.Map;

import org.asteriskjava.manager.AuthenticationFailedException;
import org.asteriskjava.manager.ManagerConnection;
import org.asteriskjava.manager.ManagerConnectionFactory;
import org.asteriskjava.manager.TimeoutException;
import org.asteriskjava.manager.action.OriginateAction;
import org.asteriskjava.manager.response.ManagerResponse;

public class HelloManager {
    private ManagerConnection managerConnection;

    public HelloManager() throws IOException {
        ManagerConnectionFactory factory = new ManagerConnectionFactory("10.17.64.10", 5038, "admin", "xxxx");
        this.managerConnection = factory.createManagerConnection();
    }

    public void run() throws IOException, AuthenticationFailedException, TimeoutException {
        System.out.println("Login start...");
        managerConnection.login();
        System.out.println("Login sucessfully...");

        OriginateAction originateAction;
        ManagerResponse originateResponse;

        managerConnection.addEventListener(new HelloEvents());
        originateAction = new OriginateAction();
        originateAction.setChannel("SIP/791582");
        originateAction.setContext("default");
        originateAction.setExten("791650");
        originateAction.setPriority(new Integer(1));
        originateAction.setTimeout(30000L);
        originateAction.setCallerId("US Reception <XXX Company>");
        // send the originate action and wait for a maximum of 30 seconds for Asterisk to send a reply
        originateResponse = managerConnection.sendAction(originateAction);
        Map<String,Object> map = originateResponse.getAttributes();
        System.out.println(map);

        // print out whether the originate succeeded or not
        System.out.println(originateResponse.getMessage());
        System.out.println("Enter Response=" + originateResponse.getResponse());
        // Originate successfully queued

        // and finally log off and disconnect
        System.out.println("Log off start...");
        managerConnection.logoff();
        System.out.println("Log off sucessfully...");
    }

    public static void main(String[] args) throws Exception {
        HelloManager helloManager = new HelloManager();
        helloManager.run();
    }
}

>>如果电话成功连接将出现如下消息:

{response=Success, message=Originate successfully queued, actionid=26399554_6#}
Originate successfully queued
Enter Response=Success

 

 

>>如果电话不可达:

{response=Error, message=Originate failed, actionid=25358555_6#}
Originate failed
Enter Response=Error

 

 

>>如果在规定时间内无应答:

Exception in thread "main" org.asteriskjava.manager.TimeoutException: Timeout waiting for response to Originate
	at org.asteriskjava.manager.internal.ManagerConnectionImpl.sendAction(ManagerConnectionImpl.java:825)
	at org.asteriskjava.manager.internal.ManagerConnectionImpl.sendAction(ManagerConnectionImpl.java:781)
	at org.asteriskjava.manager.DefaultManagerConnection.sendAction(DefaultManagerConnection.java:311)
	at org.jerval.test.pbx.HelloManager.run(HelloManager.java:38)
	at org.jerval.test.pbx.HelloManager.main(HelloManager.java:55)

 

 

这里需要注意的两点是:

1,如何获取正确的管理帐号:

在Linux下/etc/asterisk/manager.conf文件中会有如下信息:

[admin]
secret = admin 
deny=0.0.0.0/0.0.0.0 
permit=127.0.0.1/255.255.255.0 
read = system,call,log,verbose,command,agent,user 
write = system,call,log,verbose,command,agent,user

2,如果出现下面错误如何解决:

>>问题1:

0    [main] INFO  org.asteriskjava.manager.internal.ManagerConnectionImpl  - Connecting to 10.17.64.10:5038
Exception in thread "main" java.net.ConnectException: Connection refused: connect
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
	at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
	at java.net.Socket.connect(Socket.java:529)
	at org.asteriskjava.util.internal.SocketConnectionFacadeImpl.<init>(SocketConnectionFacadeImpl.java:77)
	at org.asteriskjava.manager.internal.ManagerConnectionImpl.createSocket(ManagerConnectionImpl.java:729)
	at org.asteriskjava.manager.internal.ManagerConnectionImpl.connect(ManagerConnectionImpl.java:708)
	at org.asteriskjava.manager.internal.ManagerConnectionImpl.doLogin(ManagerConnectionImpl.java:490)
	at org.asteriskjava.manager.internal.ManagerConnectionImpl.login(ManagerConnectionImpl.java:438)
	at org.asteriskjava.manager.internal.ManagerConnectionImpl.login(ManagerConnectionImpl.java:423)
	at org.asteriskjava.manager.DefaultManagerConnection.login(DefaultManagerConnection.java:294)
	at org.jerval.test.pbx.HelloManager.run(HelloManager.java:23)
	at org.jerval.test.pbx.HelloManager.main(HelloManager.java:55)

这种错误通常是端口不正确,此时在Linux下/etc/asterisk/manager.conf文件中会有如下信息:

[general]
enabled = yes
port = 5538
bindaddr =  0.0.0.0

由此可见端口应该是5538 . 但通常都会使用默认端口5038的.

 

>>问题2:

Login start...
0    [main] INFO  org.asteriskjava.manager.internal.ManagerConnectionImpl  - Connecting to 10.17.64.10:5038
115  [Asterisk-Java ManagerConnection-0-Reader-0] INFO  org.asteriskjava.manager.internal.ManagerConnectionImpl  - Connected via Asterisk Call Manager/1.3
115  [Asterisk-Java ManagerConnection-0-Reader-0] WARN  org.asteriskjava.manager.internal.ManagerConnectionImpl  - Unsupported protocol version 'Asterisk Call Manager/1.3'. Use at your own risk.
Exception in thread "main" org.asteriskjava.manager.AuthenticationFailedException: Authentication failed
	at org.asteriskjava.manager.internal.ManagerConnectionImpl.doLogin(ManagerConnectionImpl.java:578)
	at org.asteriskjava.manager.internal.ManagerConnectionImpl.login(ManagerConnectionImpl.java:438)
	at org.asteriskjava.manager.internal.ManagerConnectionImpl.login(ManagerConnectionImpl.java:423)
	at org.asteriskjava.manager.DefaultManagerConnection.login(DefaultManagerConnection.java:294)
	at org.jerval.test.pbx.HelloManager.run(HelloManager.java:23)
	at org.jerval.test.pbx.HelloManager.main(HelloManager.java:55)
1142 [main] INFO  org.asteriskjava.manager.internal.ManagerConnectionImpl  - Closing socket.
1142 [Asterisk-Java ManagerConnection-0-Reader-0] INFO  org.asteriskjava.manager.internal.ManagerReaderImpl  - Terminating reader thread: No more lines available: null

这种情况下,首先得确保帐号没有问题(参考:1,如何获取正确的管理帐号). 如果确定了帐号没有问题时,问题可能是没有将你机器的IP放到管理所允许的IP列表里.

打开/etc/asterisk/manager.conf:

[admin]
secret = admin 
deny=0.0.0.0/0.0.0.0 
permit=192.168.87.222/255.255.255.0 
read = system,call,log,verbose,command,agent,user 
write = system,call,log,verbose,command,agent,user

加入自己机器的IP:192.168.87.222

 

Live API

相比于manager包下面的API,live API更加容易使用或者说更加人性化.比如上面的HelloManager可以使用如下代码代替:

package org.jerval.test.pbx.live;

import org.asteriskjava.live.AsteriskServer;
import org.asteriskjava.live.DefaultAsteriskServer;
import org.asteriskjava.live.ManagerCommunicationException;
import org.asteriskjava.manager.action.OriginateAction;

public class HelloLive {
    private AsteriskServer asteriskServer;

    public HelloLive() {
        asteriskServer = new DefaultAsteriskServer("10.17.64.10", 5038, "admin", "xxxx");
    }

    public void run() throws ManagerCommunicationException {
        OriginateAction originateAction = new OriginateAction();
        originateAction.setChannel("SIP/791582");
        originateAction.setContext("default");
        originateAction.setExten("791650");
        originateAction.setPriority(new Integer(1));
        originateAction.setTimeout(30000L);
        originateAction.setCallerId("US Reception <XXXX>");
        asteriskServer.originate(originateAction);
    }

    public static void main(String[] args) throws Exception {
        HelloLive helloLive = new HelloLive();
        helloLive.run();
    }
}

是不是看起来更加简单?

当然你也可以进行事件的监听,举个简单的例子:

package org.jerval.test.pbx.live;

import org.asteriskjava.live.AsteriskServer;
import org.asteriskjava.live.DefaultAsteriskServer;
import org.asteriskjava.live.ManagerCommunicationException;
import org.asteriskjava.manager.action.OriginateAction;

public class HelloLive {
    private AsteriskServer asteriskServer;

    public HelloLive() {
        asteriskServer = new DefaultAsteriskServer("10.17.64.10", 5038, "admin", "xxxx");
    }

    public void run() throws ManagerCommunicationException {
        OriginateAction originateAction = new OriginateAction();
        originateAction.setChannel("SIP/791582");
        originateAction.setContext("default");
        originateAction.setExten("791650");
        originateAction.setPriority(new Integer(1));
        originateAction.setTimeout(30000L);
        originateAction.setCallerId("US Reception <XXXX>");
        asteriskServer.addAsteriskServerListener(new HelloListener());
        asteriskServer.originate(originateAction);
    }

    public static void main(String[] args) throws Exception {
        HelloLive helloLive = new HelloLive();
        helloLive.run();
    }
}

这里通过代码:asteriskServer.addAsteriskServerListener(new HelloListener());添加事件监听器.

事件监听器代码:

package org.jerval.test.pbx.live;

import org.asteriskjava.live.AsteriskChannel;
import org.asteriskjava.live.AsteriskQueueEntry;
import org.asteriskjava.live.AsteriskServerListener;
import org.asteriskjava.live.MeetMeUser;
import org.asteriskjava.live.internal.AsteriskAgentImpl;

public class HelloListener implements AsteriskServerListener {

    @Override
    public void onNewAsteriskChannel(AsteriskChannel channel) {
        System.out.println("------onNewAsteriskChannel---------------------" + channel);
    }

    @Override
    public void onNewMeetMeUser(MeetMeUser user) {
        System.out.println("------onNewMeetMeUser---------------------" + user);
    }

    @Override
    public void onNewAgent(AsteriskAgentImpl agent) {
        System.out.println("------onNewAgent---------------------" + agent);
    }

    @Override
    public void onNewQueueEntry(AsteriskQueueEntry entry) {
        System.out.println("------onNewQueueEntry---------------------" + entry);
    }
}

 

通常在正式的应用中,当我们拨打用户电话时,通常需要在页面中提示用户目标电话的状态,此时可以使用如下代码完成:

package org.jerval.test.pbx.live;

import org.asteriskjava.live.AsteriskChannel;
import org.asteriskjava.live.AsteriskServer;
import org.asteriskjava.live.DefaultAsteriskServer;
import org.asteriskjava.live.LiveException;
import org.asteriskjava.live.ManagerCommunicationException;
import org.asteriskjava.live.OriginateCallback;
import org.asteriskjava.manager.action.OriginateAction;

public class HelloLive2 {
    private AsteriskServer asteriskServer;

    public HelloLive2() {
        asteriskServer = new DefaultAsteriskServer("10.17.64.10", 5038, "admin", "xxxx");
    }

    public void run() throws ManagerCommunicationException {
        OriginateAction originateAction = new OriginateAction();
        originateAction.setChannel("SIP/791582");// 791582 791703
        originateAction.setContext("default");
        originateAction.setExten("791650");
        originateAction.setPriority(new Integer(1));
        originateAction.setTimeout(10000L);
        originateAction.setCallerId("US Reception <XXX>");
        OriginateCallback callback = new OriginateCallback() {

            @Override
            public void onDialing(AsteriskChannel channel) {
                System.out.println("------onDialing---------------------");
            }

            @Override
            public void onSuccess(AsteriskChannel channel) {
                System.out.println("------onSuccess---------------------");
            }

            @Override
            public void onNoAnswer(AsteriskChannel channel) {
                System.out.println("------onNoAnswer---------------------");
            }

            @Override
            public void onBusy(AsteriskChannel channel) {
                System.out.println("------onBusy---------------------");
            }

            @Override
            public void onFailure(LiveException cause) {
                System.out.println("------onFailure---------------------");
            }
        };
         asteriskServer.originateAsync(originateAction, callback);
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
        }
    }

    public static void main(String[] args) throws Exception {
        HelloLive2 helloLive = new HelloLive2();
        helloLive.run();
    }
}

这里的OriginateCallback里的实现方法可以由需求来改写,比如将消息实时反馈到页面上.

 

对于代码Thread.sleep(20000);,主要是为了让主线程保持,以便于最后主线程能输出负责监听的子线程所打印的状态,这里的时间通常要大于上面的timeOut时间. 因此,如果你不写线程睡眠或者等待的这句代码的话,回调方法打印的结果将不会出现在控制台中. 我开始也这此弄了很久.呵呵. 

 

例子:

 当然实际开发中,我们可能会有这样的场景. 当用户拨打电话后,如果是收到onFailure的状态,则立即将结果返回结用户,否则在等待一些时间后,收到onNoAnswer,onBusy,onSuccess时才将结果状态返回给用户. 因此这里将会用到线程的wait和notify方法.代码如下:

package org.jerval.test.pbx.live;

import org.asteriskjava.live.AsteriskServer;
import org.asteriskjava.live.DefaultAsteriskServer;
import org.asteriskjava.live.ManagerCommunicationException;
import org.asteriskjava.manager.action.OriginateAction;

public class HelloLive3 {
    private AsteriskServer asteriskServer;

    public HelloLive3() {
        asteriskServer = new DefaultAsteriskServer("10.17.64.10", 5038, "admin", "amp111");
    }

    public String run() throws ManagerCommunicationException {
        OriginateAction originateAction = new OriginateAction();
        originateAction.setChannel("SIP/791703");// 791582 791703
        originateAction.setContext("default");
        originateAction.setExten("791650");
        originateAction.setPriority(new Integer(1));
        originateAction.setTimeout(10000L);
        originateAction.setCallerId("US Reception <XXX>");
        
        StringBuilder msg = new StringBuilder();
        Thread thread = Thread.currentThread();
        MyOriginateCallback callback = new MyOriginateCallback(msg, thread);
        asteriskServer.originateAsync(originateAction, callback);
        // Wait one minute to get monitor msg.
        synchronized (thread) {
            try {
                thread.wait(60 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        return msg.toString();
    }

    public static void main(String[] args) throws Exception {
        HelloLive3 helloLive = new HelloLive3();
        System.out.println(helloLive.run());
    }
}

 

package org.jerval.test.pbx.live;

import org.asteriskjava.live.AsteriskChannel;
import org.asteriskjava.live.LiveException;
import org.asteriskjava.live.OriginateCallback;

public class MyOriginateCallback implements OriginateCallback {

    private StringBuilder msg;
    private Thread thread;

    public MyOriginateCallback(StringBuilder msg, Thread thread) {
        this.msg = msg;
        this.thread = thread;
    }

    private void notifyMainThread(){
        synchronized (thread) {
            thread.notifyAll();
        }
    }
    
    @Override
    public void onDialing(AsteriskChannel channel) {
        System.out.println("------onDialing---------------------");
    }

    @Override
    public void onSuccess(AsteriskChannel channel) {
        System.out.println("------onSuccess---------------------");
        msg.append("[onSuccess]");
        notifyMainThread();
    }

    @Override
    public void onNoAnswer(AsteriskChannel channel) {
        System.out.println("------onNoAnswer---------------------");
        msg.append("[onNoAnswer]");
        notifyMainThread();
    }

    @Override
    public void onBusy(AsteriskChannel channel) {
        System.out.println("------onBusy---------------------");
        msg.append("[onBusy]");
        notifyMainThread();
    }

    @Override
    public void onFailure(LiveException cause) {
        System.out.println("------onFailure---------------------");
        msg.append("[onFailure]");
        notifyMainThread();
    }
}

 

 

 

猜你喜欢

转载自jerval.iteye.com/blog/2087287
今日推荐