如何实现对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程序的入口。几个重要类之间实例化过程,如下图:
图一(实例化过程)
上图红色部份是我们重点要了解的,打开NewPhoneFrame.java文件,这里一个继续JFrame的GUI表单类。用户通过它同Softphone的其它部份交互。
NewPhoneFrame的公共控件变量、公共成员函数,都是为了被NewGuiManager调用。而当用户的操作,激发NewPhoneFrame的某部份代码时,它的“执行流”,则会先流到NewGuiManager。
如果,你只是想为Softphone换一个人机界面,那就从NewPhoneFrame入手吧!参考NewPhoneFrame为自己写一个MyPhoneFrame,替换NewGuiManager.java中出现的字符串NewPhoneFrame为MyPhoneFrame。我这里替换了两次。再次运行SipCommunicator,你会发现Softphone的界面已经换成了你的NewPhoneFrame。
更进一步
对Softphone,进行API封装。
现在我们建立一个新类CSoftphone,用它来封装Softphone的应用程序接口。
图二(Softphone类图)
第一步,我们来构造CSoftphone
构造函数代码段如下:
private SipCommunicator sipCommunicator=null; //原Softphone的全局对象,行28
private NewGuiManager gm=null; //GUI管理器,行29
/**
* @param args 控制台过来的,参数列表
* @throws Exception 构造失败,简单抛出异常
*/
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 。
下面是拨号,代码
/**
* 拨打电话;它是异步的,你应该从回调函数中,获取,Dial是否成功的结果。请参考setRecall方法。
* 注意:已经在Dial的状态下,再dial会导致Softphone抛出异常
* @param strID PhoneNumber 例如:[email protected] c=cc
其中IP地址,是你bridge所在的地址,c=cc,表示,加入cc会议。
* @return
*/
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);
}
}
/**
* 实例化这个类的对象后,应该调用下面的成员函数
* 释放Softphone
*/
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
图三(ISoftphone接口)
/**
* 设置状态通知
* @param objRecall Softphone会把当前工作情况通知给objRecall对象
*/
public void setRecall(ISoftphone objRecall)
{
gm.listenNGM=objRecall;
}
假设inst是你的应用对象,那么inst对象,所属的类必须继承ISoftphone。因为,只有这样,Softphone才能将消息,通知给你的应用对象。
同时,我们还必须稍微修改下NewGuiManager::update函数体,在update函数体的后部份,加入下面的代码:
/* public ISoftphone listenNGM=null; 这段代码是加在NewGuiManager,成员变量说明中的。
*/
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;
/**
* 实例化CSoftphone,并为CSoftphone的args数组中,添加”-nogui”,屏蔽掉Softphone自己的图形化人机界面。这里的代码略。
*/
//启动你的GUI 这里你的应用对象是inst
NewJFrame inst = new NewJFrame();
//设置回调,使softphone的状态更新能够通知到inst
softphone.setRecall(inst);
//把softphone扔给inst,使在应用对象里可以调用它
inst.m_softphone = softphone;
/**
* 启动(Launch) inst应用对象,详细的代码略。
*/
后言
正文对如何实现Softphone的封装做了下简单的介绍,有些实现细节没有谈到,具体请参考CSoftphone.java文件中的内容,它可以给你更进一步的信息。希望此文可以带领你步入Softphone两次开发的大门。
参考资源
[1]JVoicebridge官网 jvoicebridge.dev.java.net
附CSoftphone.java源代码
- packagecom.cwebs.softphone;
-
- importjava.io.IOException;
- importjava.text.ParseException;
-
- importcom.sun.mc.softphone.SipCommunicator;
- importcom.sun.mc.softphone.common.Utils;
- importcom.sun.mc.softphone.gui.InterlocutorUI;
- importcom.sun.mc.softphone.gui.NewGuiManager;
- importcom.sun.mc.softphone.gui.event.UserActionListener;
- importcom.sun.mc.softphone.gui.event.UserCallControlEvent;
- importcom.sun.mc.softphone.gui.event.UserCallInitiationEvent;
- importcom.sun.mc.softphone.media.CallDoneListener;
- importcom.sun.mc.softphone.media.MediaManager;
- importcom.sun.mc.softphone.media.MediaManagerFactory;
-
- publicclassCSoftphone{
- privateSipCommunicatorsipCommunicator=null;
- privateNewGuiManagergm=null;
-
- publicCSoftphone(String[]args)throwsException
- {
- try{
- sipCommunicator=newSipCommunicator(args);
- }catch(ParseExceptione){
- SipCommunicator.usage();
- System.exit(1);
- thrownewException("Initializationfailed!");
- }
- gm=(NewGuiManager)sipCommunicator.guiManager;
- }
-
- publicvoidsetRecall(ISoftphoneobjRecall)
- {
- gm.listenNGM=objRecall;
- }
-
- publicvoiddial(StringstrID)
- {
-
- gm.alertManager.stopAllAlerts();
- Stringcallee=gm.format(strID);
-
- UserCallInitiationEventcommEvt=newUserCallInitiationEvent(callee);
- for(inti=gm.listeners.size()-1;i>=0;i--){
- ((UserActionListener)gm.listeners.get(i)).handleDialRequest(commEvt);
- }
- }
-
- publicvoidexit()
- {
- for(inti=gm.listeners.size()-1;i>=0;i--){
- ((UserActionListener)gm.listeners.get(i)).handleExitRequest();
- }
- }
-
- publicvoidsetPreference(StringstrKey,StringstrValue)
- {
-
- if(strKey.equalsIgnoreCase("CHANNELS"))
- {
-
- Utils.setPreference("com.sun.mc.softphone.media.CHANNELS",strValue);
- Utils.setPreference("com.sun.mc.softphone.media.TRANSMIT_CHANNELS",strValue);
- }
- if(strKey.equalsIgnoreCase("SAMPLE_RATE"))
- {
-
- Utils.setPreference("com.sun.mc.softphone.media.SAMPLE_RATE",strValue);
- Utils.setPreference("com.sun.mc.softphone.media.TRANSMIT_SAMPLE_RATE",strValue);
- }
- if(strKey.equalsIgnoreCase("MICROPHONE_BUFFER_SIZE"))
- {
-
- Utils.setPreference("com.sun.mc.softphone.media.MICROPHONE_BUFFER_SIZE",strValue);
- }
-
- if(strKey.equalsIgnoreCase("REGISTRAR_ADDRESS"))
- {
-
- Utils.setPreference("com.sun.mc.softphone.sip.REGISTRAR_ADDRESS",strValue);
- }
- if(strKey.equalsIgnoreCase("USER_NAME"))
- {
-
- Utils.setPreference("com.sun.mc.softphone.sip.AUTHENTICATION_USER_NAME",strValue);
- Utils.setPreference("com.sun.mc.softphone.sip.USER_NAME",strValue);
- }
- if(strKey.equalsIgnoreCase("OUTBOUND_PROXY_ADDRESS"))
- {
-
- Utils.setPreference("javax.sip.OUTBOUND_PROXY_ADDRESS",strValue);
- }
-
- if(strKey.equalsIgnoreCase("LAST_FILE_PLAYED"))
- {
-
- Utils.setPreference("com.sun.mc.softphone.gui.LAST_FILE_PLAYED",strValue);
- }
- if(strKey.equalsIgnoreCase("LAST_FILE_RECORDED"))
- {
-
- Utils.setPreference("com.sun.mc.softphone.gui.LAST_FILE_RECORDED",strValue);
- }
- }
-
- publicStringgetPreferece(StringstrKey)
- {
-
- if(strKey.equalsIgnoreCase("CHANNELS"))
- {
-
- returnUtils.getPreference("com.sun.mc.softphone.media.CHANNELS");
-
- }
- if(strKey.equalsIgnoreCase("SAMPLE_RATE"))
- {
-
- returnUtils.getPreference("com.sun.mc.softphone.media.SAMPLE_RATE");
-
- }
- if(strKey.equalsIgnoreCase("MICROPHONE_BUFFER_SIZE"))
- {
-
- returnUtils.getPreference("com.sun.mc.softphone.media.MICROPHONE_BUFFER_SIZE");
- }
-
- if(strKey.equalsIgnoreCase("REGISTRAR_ADDRESS"))
- {
-
- returnUtils.getPreference("com.sun.mc.softphone.sip.REGISTRAR_ADDRESS");
- }
- if(strKey.equalsIgnoreCase("USER_NAME"))
- {
-
- returnUtils.getPreference("com.sun.mc.softphone.sip.AUTHENTICATION_USER_NAME");
-
- }
- if(strKey.equalsIgnoreCase("OUTBOUND_PROXY_ADDRESS"))
- {
-
- returnUtils.getPreference("javax.sip.OUTBOUND_PROXY_ADDRESS");
- }
-
- if(strKey.equalsIgnoreCase("LAST_FILE_PLAYED"))
- {
-
- returnUtils.getPreference("com.sun.mc.softphone.gui.LAST_FILE_PLAYED");
- }
- if(strKey.equalsIgnoreCase("LAST_FILE_RECORDED"))
- {
-
- returnUtils.getPreference("com.sun.mc.softphone.gui.LAST_FILE_RECORDED");
- }
- returnnull;
- }
-
- publicvoidstartRecording(StringstrPath,booleanrecordingMic,CallDoneListenerobjListener)throwsIOException
- {
-
- if(strPath==null||strPath.length()<1)
- {
- return;
- }
-
- MediaManagermediaManager;
- mediaManager=MediaManagerFactory.getInstance();
- if(mediaManager!=null)
- {
- mediaManager.startRecording(strPath,newString("au"),recordingMic,objListener);
- }
- }
-
- publicvoidstopRecording(booleanrecordingMic)
- {
-
- MediaManagermediaManager;
- mediaManager=MediaManagerFactory.getInstance();
- if(mediaManager!=null)
- {
- mediaManager.stopRecording(recordingMic);
- }
- }
-
- publicvoidhangup()
- {
- InterlocutorUIinter=gm.interlocutors.getInterlocutorAt(0);
- if(inter!=null){
- UserCallControlEventcommEvt=newUserCallControlEvent(inter);
- for(inti=gm.listeners.size()-1;i>=0;i--){
- ((UserActionListener)gm.listeners.get(i)).handleHangupRequest(
- commEvt);
- }
- }
- }
-
- publicvoidanswer()
- {
- InterlocutorUIinter=gm.interlocutors.getInterlocutorAt(0);
- if(inter!=null){
- UserCallControlEventcommEvt=newUserCallControlEvent(inter);
- for(inti=gm.listeners.size()-1;i>=0;i--){
- ((UserActionListener)gm.listeners.get(i)).handleAnswerRequest(
- commEvt);
- }
- }
- }
-
- publicvoidmute()
- {
- InterlocutorUIinter=gm.interlocutors.getInterlocutorAt(0);
- if(inter!=null){
- UserCallControlEventcommEvt=newUserCallControlEvent(inter);
- for(inti=gm.listeners.size()-1;i>=0;i--){
- ((UserActionListener)gm.listeners.get(i)).handleMuteRequest(
- commEvt);
- }
- }
- }
- }