天天看點

如何實作對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. }

繼續閱讀