天天看点

如何实现对JVoicebridge的二次开发如何实现对JVoicebridge的二次开发

如何实现对JVoicebridge的二次开发

作者:kagula

时间:2008-10-23

内容简介

JVoicebridge是个开源的音频会议软件。

本文主要介绍把JVoicebridge提供的功能,集成到自己程序中的手段。

JVoicebridge的使用可以参考《JVoiceBridge使用简介》

阅读前提

[1]Java开发经验

[2]Eclipse使用经验

[3]svn插件使用经验

[4]如何使用JVoicebridge

正文

我这里使用的环境是: JDK 1.6.x,MyEclipse5.1.x  svn1.2.x

进入官网首页,点击项目工具中的subversion项,根据里面的svn地址,把源码download下来。利用源码包中的softphone,新建一个softphone项目。

展开softphone源码,com.sun.mc.softphone包中的SipCommunicator类就是Softphone程序的入口。几个重要类之间实例化过程,如下图:

如何实现对JVoicebridge的二次开发如何实现对JVoicebridge的二次开发

图一(实例化过程)

  上图红色部份是我们重点要了解的,打开NewPhoneFrame.java文件,这里一个继续JFrame的GUI表单类。用户通过它同Softphone的其它部份交互。

NewPhoneFrame的公共控件变量、公共成员函数,都是为了被NewGuiManager调用。而当用户的操作,激发NewPhoneFrame的某部份代码时,它的“执行流”,则会先流到NewGuiManager。

如果,你只是想为Softphone换一个人机界面,那就从NewPhoneFrame入手吧!参考NewPhoneFrame为自己写一个MyPhoneFrame,替换NewGuiManager.java中出现的字符串NewPhoneFrame为MyPhoneFrame。我这里替换了两次。再次运行SipCommunicator,你会发现Softphone的界面已经换成了你的NewPhoneFrame。

更进一步

对Softphone,进行API封装。

现在我们建立一个新类CSoftphone,用它来封装Softphone的应用程序接口。

如何实现对JVoicebridge的二次开发如何实现对JVoicebridge的二次开发

图二(Softphone类图)

第一步,我们来构造CSoftphone

   构造函数代码段如下:

     private SipCommunicator sipCommunicator=null;  //原Softphone的全局对象,行28

     private NewGuiManager gm=null;  //GUI管理器,行29

     public CSoftphone(String[] args) throws Exception

     {

              try {

            sipCommunicator = new SipCommunicator(args);  //行38

              } catch (ParseException e) {

                  SipCommunicator.usage();

                  System.exit(1);

                  throw new Exception("Initialization failed!");

              }

              gm = (NewGuiManager)sipCommunicator.guiManager;   //行44

     }

上面的代码片段中,红色部份,是值得注意的。

行38:代码类同SipCommunicator::main()函数体部份。不要忘记,传给它的参数列表中包含”-nogui”,因为,我们不需要SipCommunicator提供给我们的缺省窗口。

行44:的代码是为了方便我们以后封装Softphone的API。

第二步,建立接口

  接口代码如面。这里要注意的是,导入CSoftphone接口,你会发现很多来自Softphone的方法或类,不能被找到,请找到这些源码的位置,把它们的存取属性改为public 。

  下面是拨号,代码

     public void dial(String strID)

     {

              //正文     

              gm.alertManager.stopAllAlerts();

              String callee=gm.format(strID);

        UserCallInitiationEvent commEvt = new UserCallInitiationEvent(callee);

        for (int i = gm.listeners.size() - 1; i >= 0; i--) {

            ( (UserActionListener) gm.listeners.get(i)).handleDialRequest(commEvt);

        }

     }

     public void exit()

     {

        for (int i = gm.listeners.size() - 1; i >= 0; i--) {

            ( (UserActionListener) gm.listeners.get(i)).handleExitRequest();

        }

     }

注意:exit函数,没有及时调用,可能会造成,你的程序退出了,但是Softphone还没有退出。

接口中封装的代码,都是来自Softphone包的NewGuiManager类,你只要如上,稍微修改,就能直接使用了。

第三步,如何回调

    上面的Dial从某种角度上来说是异步的,怎么才能知道,你已经加入了通话状态, 这就需要一个接口。这里我定义了ISoftphone

如何实现对JVoicebridge的二次开发如何实现对JVoicebridge的二次开发

图三(ISoftphone接口)

     public void setRecall(ISoftphone objRecall)

     {

              gm.listenNGM=objRecall;

     }

假设inst是你的应用对象,那么inst对象,所属的类必须继承ISoftphone。因为,只有这样,Softphone才能将消息,通知给你的应用对象。

  同时,我们还必须稍微修改下NewGuiManager::update函数体,在update函数体的后部份,加入下面的代码:

        if(listenNGM!=null)

        {

             listenNGM.updataStatus(state);  //行 352

        }

行352:的代码,是为了当NewGuiManager::update被激发时,实现ISoftphone接口的listenNGM::updataStatus也能被激发,这样才能把Softphone的状态,通知到你的应用对象。

  第四步,如何使用接口

我们的接口,现在全部封装在CSoftphone类中[1]我们先要实例化CSoftphone [2]然后把CSoftphone的实例,告诉你的应用对象。[3]最后在CSoftphone实例中设置你的回调对象。

源码片段如下:

Public static void main(String[] args) {

                   //启动Softphone

                   CSoftphone  softphone=null;

                   //启动你的GUI 这里你的应用对象是inst

                   NewJFrame inst = new NewJFrame();

//设置回调,使softphone的状态更新能够通知到inst

                   softphone.setRecall(inst);

//把softphone扔给inst,使在应用对象里可以调用它

                   inst.m_softphone = softphone;

后言

    正文对如何实现Softphone的封装做了下简单的介绍,有些实现细节没有谈到,具体请参考CSoftphone.java文件中的内容,它可以给你更进一步的信息。希望此文可以带领你步入Softphone两次开发的大门。

参考资源

[1]JVoicebridge官网  jvoicebridge.dev.java.net

附CSoftphone.java源代码

  1. package com.cwebs.softphone;
  2. import java.io.IOException;
  3. import java.text.ParseException;
  4. import com.sun.mc.softphone.SipCommunicator;
  5. import com.sun.mc.softphone.common.Utils;
  6. import com.sun.mc.softphone.gui.InterlocutorUI;
  7. import com.sun.mc.softphone.gui.NewGuiManager;
  8. import com.sun.mc.softphone.gui.event.UserActionListener;
  9. import com.sun.mc.softphone.gui.event.UserCallControlEvent;
  10. import com.sun.mc.softphone.gui.event.UserCallInitiationEvent;
  11. import com.sun.mc.softphone.media.CallDoneListener;
  12. import com.sun.mc.softphone.media.MediaManager;
  13. import com.sun.mc.softphone.media.MediaManagerFactory;
  14. public class CSoftphone {
  15.     private SipCommunicator sipCommunicator=null;  //原Softphone的全局对象
  16.     private NewGuiManager gm=null;  //GUI管理器
  17.     public CSoftphone(String[] args) throws Exception
  18.     {
  19.         try {
  20.             sipCommunicator = new SipCommunicator(args);
  21.         } catch (ParseException e) {
  22.             SipCommunicator.usage();
  23.             System.exit(1);
  24.             throw new Exception("Initialization failed!");
  25.         }
  26.         gm = (NewGuiManager)sipCommunicator.guiManager;
  27.     }
  28.     public void setRecall(ISoftphone objRecall)
  29.     {
  30.         gm.listenNGM=objRecall;
  31.     }
  32.     public void dial(String strID)
  33.     {
  34.         //正文    
  35.         gm.alertManager.stopAllAlerts();
  36.         String callee=gm.format(strID);
  37.         UserCallInitiationEvent commEvt = new UserCallInitiationEvent(callee);
  38.         for (int i = gm.listeners.size() - 1; i >= 0; i--) {
  39.             ( (UserActionListener) gm.listeners.get(i)).handleDialRequest(commEvt);
  40.         }
  41.     }
  42.     public void exit()
  43.     {
  44.         for (int i = gm.listeners.size() - 1; i >= 0; i--) {
  45.             ( (UserActionListener) gm.listeners.get(i)).handleExitRequest();
  46.         }
  47.     }
  48.     public void setPreference(String strKey,String strValue)
  49.     {       
  50.         //media系列设置
  51.         if(strKey.equalsIgnoreCase("CHANNELS"))
  52.         {
  53.             //设置声道,取值范围  1,2
  54.             Utils.setPreference("com.sun.mc.softphone.media.CHANNELS",strValue);
  55.             Utils.setPreference("com.sun.mc.softphone.media.TRANSMIT_CHANNELS",strValue);           
  56.         }
  57.         if(strKey.equalsIgnoreCase("SAMPLE_RATE"))
  58.         {
  59.             //设置采样率,建议8000,取值范围8000,16000
  60.             Utils.setPreference("com.sun.mc.softphone.media.SAMPLE_RATE",strValue);
  61.             Utils.setPreference("com.sun.mc.softphone.media.TRANSMIT_SAMPLE_RATE",strValue);
  62.         }
  63.         if(strKey.equalsIgnoreCase("MICROPHONE_BUFFER_SIZE"))
  64.         {
  65.             //设置Microphone缓存,建议60,取值范围0,大于等于60的正整数
  66.             Utils.setPreference("com.sun.mc.softphone.media.MICROPHONE_BUFFER_SIZE",strValue);
  67.         }
  68.         //sip系列设置
  69.         if(strKey.equalsIgnoreCase("REGISTRAR_ADDRESS"))
  70.         {
  71.             //设置bridge服务器地址,例如:192.168.0.112
  72.             Utils.setPreference("com.sun.mc.softphone.sip.REGISTRAR_ADDRESS",strValue);
  73.         }   
  74.         if(strKey.equalsIgnoreCase("USER_NAME"))
  75.         {
  76.             //设置登录到bridge去的,登录名,例如:Administrator
  77.             Utils.setPreference("com.sun.mc.softphone.sip.AUTHENTICATION_USER_NAME",strValue);
  78.             Utils.setPreference("com.sun.mc.softphone.sip.USER_NAME",strValue);
  79.         }       
  80.         if(strKey.equalsIgnoreCase("OUTBOUND_PROXY_ADDRESS"))
  81.         {
  82.             //设置代理服务器地址及端口,缺省值为129.148.75.104:5060//udp
  83.             Utils.setPreference("javax.sip.OUTBOUND_PROXY_ADDRESS",strValue);
  84.         }
  85.         //gui系列设置
  86.         if(strKey.equalsIgnoreCase("LAST_FILE_PLAYED"))
  87.         {
  88.             //设置最近播放的文件名,遵循文件名命名规范,中文文件名未做测试。
  89.             Utils.setPreference("com.sun.mc.softphone.gui.LAST_FILE_PLAYED",strValue);
  90.         }
  91.         if(strKey.equalsIgnoreCase("LAST_FILE_RECORDED"))
  92.         {
  93.             //设置最近录音的文件名,遵循文件名命名规范,中文文件名未做测试。
  94.             Utils.setPreference("com.sun.mc.softphone.gui.LAST_FILE_RECORDED",strValue);
  95.         }
  96.     }
  97.     public String getPreferece(String strKey)
  98.     {
  99.         //media系列设置
  100.         if(strKey.equalsIgnoreCase("CHANNELS"))
  101.         {
  102.             //设置声道,取值范围  1,2
  103.             return Utils.getPreference("com.sun.mc.softphone.media.CHANNELS");
  104.             //Utils.setPreference("com.sun.mc.softphone.media.TRANSMIT_CHANNELS",strValue);         
  105.         }
  106.         if(strKey.equalsIgnoreCase("SAMPLE_RATE"))
  107.         {
  108.             //设置采样率,建议8000,取值范围8000,16000
  109.             return Utils.getPreference("com.sun.mc.softphone.media.SAMPLE_RATE");
  110.             //Utils.setPreference("com.sun.mc.softphone.media.TRANSMIT_SAMPLE_RATE",strValue);
  111.         }
  112.         if(strKey.equalsIgnoreCase("MICROPHONE_BUFFER_SIZE"))
  113.         {
  114.             //设置Microphone缓存,建议60,取值范围0,大于等于60的正整数
  115.             return Utils.getPreference("com.sun.mc.softphone.media.MICROPHONE_BUFFER_SIZE");
  116.         }
  117.         //sip系列设置
  118.         if(strKey.equalsIgnoreCase("REGISTRAR_ADDRESS"))
  119.         {
  120.             //设置bridge服务器地址,例如:192.168.0.112
  121.             return Utils.getPreference("com.sun.mc.softphone.sip.REGISTRAR_ADDRESS");
  122.         }   
  123.         if(strKey.equalsIgnoreCase("USER_NAME"))
  124.         {
  125.             //设置登录到bridge去的,登录名,例如:Administrator
  126.             return Utils.getPreference("com.sun.mc.softphone.sip.AUTHENTICATION_USER_NAME");
  127.             //Utils.setPreference("com.sun.mc.softphone.sip.USER_NAME",strValue);
  128.         }       
  129.         if(strKey.equalsIgnoreCase("OUTBOUND_PROXY_ADDRESS"))
  130.         {
  131.             //设置代理服务器地址及端口,缺省值为129.148.75.104:5060//udp
  132.             return Utils.getPreference("javax.sip.OUTBOUND_PROXY_ADDRESS");
  133.         }
  134.         //gui系列设置
  135.         if(strKey.equalsIgnoreCase("LAST_FILE_PLAYED"))
  136.         {
  137.             //设置最近播放的文件名,遵循文件名命名规范,中文文件名未做测试。
  138.             return Utils.getPreference("com.sun.mc.softphone.gui.LAST_FILE_PLAYED");
  139.         }
  140.         if(strKey.equalsIgnoreCase("LAST_FILE_RECORDED"))
  141.         {
  142.             //设置最近录音的文件名,遵循文件名命名规范,中文文件名未做测试。
  143.             return Utils.getPreference("com.sun.mc.softphone.gui.LAST_FILE_RECORDED");
  144.         }
  145.         return null;
  146.     }
  147.     public void startRecording(String strPath,boolean recordingMic,CallDoneListener objListener) throws IOException
  148.     {
  149.         //入口参数检查
  150.         if(strPath==null||strPath.length()<1)
  151.         {
  152.             return;
  153.         }
  154.         //正文
  155.         MediaManager mediaManager;
  156.         mediaManager=MediaManagerFactory.getInstance();
  157.         if(mediaManager!=null)
  158.         {
  159.             mediaManager.startRecording(strPath, new String("au"), recordingMic, objListener);          
  160.         }
  161.     }
  162.     public void stopRecording(boolean recordingMic)
  163.     {
  164.         //正文
  165.         MediaManager mediaManager;
  166.         mediaManager=MediaManagerFactory.getInstance();
  167.         if(mediaManager!=null)
  168.         {
  169.             mediaManager.stopRecording(recordingMic);           
  170.         }
  171.     }
  172.     public void hangup()
  173.     {
  174.         InterlocutorUI inter = gm.interlocutors.getInterlocutorAt(0);
  175.         if(inter!=null) {
  176.             UserCallControlEvent commEvt = new UserCallControlEvent(inter);
  177.             for (int i = gm.listeners.size() - 1; i >= 0; i--) {
  178.                 ( (UserActionListener) gm.listeners.get(i)).handleHangupRequest(
  179.                     commEvt);
  180.             }
  181.         }
  182.     }
  183.     public void answer()
  184.     {
  185.         InterlocutorUI inter = gm.interlocutors.getInterlocutorAt(0);
  186.         if(inter!=null) {
  187.             UserCallControlEvent commEvt = new UserCallControlEvent(inter);
  188.             for (int i = gm.listeners.size() - 1; i >= 0; i--) {
  189.                 ( (UserActionListener) gm.listeners.get(i)).handleAnswerRequest(
  190.                     commEvt);
  191.             }
  192.         }       
  193.     }
  194.     public void mute()
  195.     {
  196.         InterlocutorUI inter = gm.interlocutors.getInterlocutorAt(0);
  197.         if(inter!=null) {
  198.             UserCallControlEvent commEvt = new UserCallControlEvent(inter);
  199.             for (int i = gm.listeners.size() - 1; i >= 0; i--) {
  200.                 ( (UserActionListener) gm.listeners.get(i)).handleMuteRequest(
  201.                     commEvt);
  202.             }
  203.         }
  204.     }
  205. }

继续阅读