Android Sipdroid 语音通话项目简单使用

Sipdroid 项目类、结构的介绍可以参考下面博客:
http://blog.csdn.net/harvey2008/article/details/8484970

具体的文档介绍百度百科有,可以查阅,这里不贴链接了。

使用:
sipdroid 账号设置,开启注册

在onCreate 中进行初始化

Receiver.mContext = this;
Sipdroid.on(this, true);
//账号信息设置,具体的账号信息自己修改
     PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).edit().
    putString(Settings.PREF_USERNAME, "用户名")
    .putString(Settings.PREF_PASSWORD, "密码")
    .putString(Settings.PREF_SERVER, "服务器地址")
    .putString(Settings.PREF_DOMAIN, "")
    .putString(Settings.PREF_PORT, "服务器端口")
    .putString(Settings.PREF_PROTOCOL, "UDP")
    .putBoolean(Settings.PREF_CALLBACK, true)
    .putString(Settings.PREF_POSURL, "")
    .putBoolean(Settings.PREF_ON,true)
    .putBoolean(Settings.PREF_3G, true)
    .putBoolean(Settings.PREF_WLAN,true)
    .putBoolean(Settings.PREF_EDGE,true)
    .putString(Settings.PREF_FROMUSER, "")
    .commit();

//注册账号
Receiver.engine(this).register();
Receiver.engine(this).halt();
Receiver.engine(this).StartEngine();

最后在onDestory 注销注册

Editor edit = PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean(Settings.PREF_ON, false);
edit.commit();
Sipdroid.on(MainView.this, false);
Receiver.pos(true);
eceiver.engine(MainView.this).halt();
Receiver.mSipdroidEngine = null;
Receiver.reRegister(0);
stopService(new Intent(MainView.this,RegisterService.class));

一般到这里就可以使用sipdroid自带的功能,当然,需要将sipdroid包中的配置文件相对路径全部替换为绝对路径
如:<activity android:name=".ui.Sipdroid" />
应改为

<activity android:name="org.sipdroid.sipua.ui.Sipdroid" />

库自带的通话界面相对简陋(call_card.xml 通话界面显示,incall.xml )
这里写图片描述
这里写图片描述
修改直接进入 InCallScreen 中onCreate 设置布局,部分组件在CallCard使用,故CallCard.calss 也需要修改,主要是界面数据更新。
最直接的一行代码是mCallCard.mElapsedTime = mElapsedTime; 更新通话的时间。

//初始化通话界面显示
public void initInCallScreen() {
//拨号盘
mInCallPanel =(ViewGroup)findViewById(R.id.inCallPanel);
//通话界面Layout
mMainFrame = (ViewGroup)findViewById(R.id.mainFrame);
//通话界面 CallCard
View callCardLayout = getLayoutInflater().inflate( R.layout.call_card_popup,mInCallPanel);
mCallCard = (CallCard)callCardLayout.findViewById(R.id.callCard);
mCallCard.reset();

//通话布局中的滑动控制
mSlidingCardManager = new SlidingCardManager();
mSlidingCardManager.init(ccPhone, this, mMainFrame);
SlidingCardManager.WindowAttachNotifierView wanv =new SlidingCardManager.WindowAttachNotifierView(this);
wanv.setSlidingCardManager(mSlidingCardManager);
wanv.setVisibility(View.GONE);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(0, 0);
mMainFrame.addView(wanv, lp);

mStats = (TextView) findViewById(R.id.stats);
mCodec = (TextView) findViewById(R.id.codec);
mDialerDrawer = (SlidingDrawer)findViewById(R.id.dialer_container);
mCallCard.displayOnHoldCallStatus(ccPhone,null);
mCallCard.displayOngoingCallStatus(ccPhone,null);
if (getResources().getConfiguration().orientation ==              Configuration.ORIENTATION_LANDSCAPE){
    mCallCard.updateForLandscapeMode();
    }

// Have the WindowManager filter out touch events that are "too fat".
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES);

        //拨号盘按键、声音
        mDigits = (EditText) findViewById(R.id.digits);
        mDisplayMap.put(R.id.one, '1');
        mDisplayMap.put(R.id.two, '2');
        mDisplayMap.put(R.id.three, '3');
        mDisplayMap.put(R.id.four, '4');
        mDisplayMap.put(R.id.five, '5');
        mDisplayMap.put(R.id.six, '6');
        mDisplayMap.put(R.id.seven, '7');
        mDisplayMap.put(R.id.eight, '8');
        mDisplayMap.put(R.id.nine, '9');
        mDisplayMap.put(R.id.zero, '0');
        mDisplayMap.put(R.id.pound, '#');
        mDisplayMap.put(R.id.star, '*');

        mToneMap.put('1', ToneGenerator.TONE_DTMF_1);
        mToneMap.put('2', ToneGenerator.TONE_DTMF_2);
        mToneMap.put('3', ToneGenerator.TONE_DTMF_3);
        mToneMap.put('4', ToneGenerator.TONE_DTMF_4);
        mToneMap.put('5', ToneGenerator.TONE_DTMF_5);
        mToneMap.put('6', ToneGenerator.TONE_DTMF_6);
        mToneMap.put('7', ToneGenerator.TONE_DTMF_7);
        mToneMap.put('8', ToneGenerator.TONE_DTMF_8);
        mToneMap.put('9', ToneGenerator.TONE_DTMF_9);
        mToneMap.put('0', ToneGenerator.TONE_DTMF_0);
        mToneMap.put('#', ToneGenerator.TONE_DTMF_P);
        mToneMap.put('*', ToneGenerator.TONE_DTMF_S);

        View button;
        for (int viewId : mDisplayMap.keySet()) {
            button = findViewById(viewId);
            button.setOnClickListener(this);
        }
    }

InCallScreen 和 CallCard 交互主要在 mCallCard.displayMainCallStatus(ccPhone, Receiver.ccCall); 这行代码

换句话说,如果要更换通话界面显示,可以直接在InCallScreen 里进行修改,删除initInCallScreen( ) 中的界面,替换为自己的界面,CallCard 里保留具体功能,将 ui 界面通话时间(mElapsedTime )和通话状态(upperTitle)和CallCard 关联进行数据更新,其他ui 控件可以和CallCard 分离,具体实现如挂断电话、静音、外放、录音等功能在InCallScreen中实现,而CallCard 保留通话状态更新。

CallCard
通话状态更新实现:
public void displayMainCallStatus(Phone phone, Call call)

InCallScreen 具体功能

主动结束通话:
public void reject() {
  if (Receiver.ccCall != null) {
      Receiver.stopRingtone();
      Receiver.ccCall.setState(Call.State.DISCONNECTED);
      mCallCard.displayMainCallStatus(ccPhone, Receiver.ccCall);
  }
  (new Thread() {
      public void run() {
          Receiver.engine(mContext).rejectcall();
      }
  }).start();
}

开启外放:
Receiver.engine(InCallScreen.this).speaker(RtpStreamReceiver.speakermode == AudioManager.MODE_NORMAL
                        ? AudioManager.MODE_IN_CALL : AudioManager.MODE_NORMAL);

静音:
获取音频管理器,设置麦克风静音
audioManager.setMicrophoneMute(true);

录音功能:
sipdroid 没有提供通话中语音录音功能,也许你想使用自带的麦克风收音,很遗憾,即使成功,也只有自己的声音,而对方的语音是不能被录到,而且麦克风是不能启动成功,为什么?因为通话中,麦克风已经被Sipdroid 占用,你是不能拿到控制权,所以,只能通过修改Sipdroid 中的语音数据传输代码来实现我们的目的。
事实上,Sipdroid有录音功能,但是必须在通话前确定是否录音,因此查看 org.sipdroid.media 包中可以找到我们想要的。

 org.sipdroid.media.JAudioLauncher 实现多媒体数据的控制器,其中有这么一段构造代码
 /** Costructs the audio launcher */
   public JAudioLauncher(int local_port, String remote_addr, int remote_port, int direction, String audiofile_in,String audiofile_out, int sample_rate, int sample_size, int frame_size, Log logger,Codecs.Map payload_type, int dtmf_pt){  
   jLauncher = this;
   log=logger;
   frame_rate=sample_rate/frame_size;
   useDTMF = (dtmf_pt != 0);
   try
   {
      CallRecorder call_recorder = null;
      **if (PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getBoolean(org.sipdroid.sipua.ui.Settings.PREF_CALLRECORD,
                    org.sipdroid.sipua.ui.Settings.DEFAULT_CALLRECORD))**
             **call_recorder** = new CallRecorder(null,payload_type.codec.samp_rate()); 
// Autogenerate filename from date. 
         socket=new SipdroidSocket(local_port);
         dir=direction;
         // sender
         if (dir>=0)
         {  printLog("new audio sender to "+remote_addr+":"+remote_port,LogLevel.MEDIUM);
            //audio_input=new AudioInput();
            sender=new RtpStreamSender(true,payload_type,frame_rate,frame_size,socket,remote_addr,remote_port,call_recorder);
            sender.setSyncAdj(2);
            sender.setDTMFpayloadType(dtmf_pt);
         }

         // receiver
         if (dir<=0)
         {  printLog("new audio receiver on "+local_port,LogLevel.MEDIUM);
            receiver=new RtpStreamReceiver(socket,payload_type,call_recorder);
         }
      }
      catch (Exception e) {  printException(e,LogLevel.HIGH);  }
   }

先判断录音有没有被勾选,有就new CallRecorder通话记录,没有的话,call_recorder 就是 null
那么,在数据发送器和数据接收器中必定有判断 CallRecorder 是否为空,不为空的时候再进行数据的保存,

org.sipdroid.media.RtpStreamReceiver 中:
run 方法里面有:

 // Call recording: Save incoming.
 // Data is in buffer lin, from 0 to len.
 if (call_recorder != null)
     call_recorder.writeIncoming(lin, 0, len);

org.sipdroid.media.RtpStreamSender 中
run 方法中有:

// Call recording: Save the frame to the CallRecorder. 
if (call_recorder != null)
    call_recorder.writeOutgoing(lin, pos, num);

所以在JAudioLauncher提供一个方法获取JAudioLauncher单例,再拿到RtpStreamReceiver和RtpStreamSender实例,在RtpStreamReceiver和RtpStreamSender类中增加方法能够对 call_recorder 进行赋值,就可以取得录音文件。

JAudioLauncher 中增加,如果处于非通话状态或者通话结束,发送器和接收器有可能为空,需在外面增加为空判断

    /** retrun JAudioLauncher if exit or null*/
   private static JAudioLauncher jLauncher = null;
   public static JAudioLauncher getInstance(){
       return jLauncher;
   }

   /** return RtpStreamReceiver instance or null*/
   public RtpStreamReceiver getRtpStreamReceiver(){
       return receiver;
   }

   /** return RtpStreamSender instance or null*/
   public RtpStreamSender getRtpStreamSender(){
       return sender;
   }

在 RtpStreamReceiver 和 RtpStreamSender 中增加:

     /** dynamic change CallRecorder */
    public void setCallRecorder(CallRecorder rec){
        this.call_recorder = rec;
    }

这样可以通过下面调用实现录音:

callRecorder = new CallRecorder(System.currentTimeMillis() + "", 8000);// sample_rate
 JAudioLauncher jal = JAudioLauncher.getInstance();
 if (jal != null) {
     jal.getRtpStreamReceiver().setCallRecorder(callRecorder);
      jal.getRtpStreamSender().setCallRecorder(callRecorder);
   }

取消录音:

if (callRecorder != null) {
    callRecorder.stopIncoming();
    callRecorder.stopOutgoing();
    callRecorder=null;
    }
 JAudioLauncher jal = JAudioLauncher.getInstance();
  if (jal != null) {
       jal.getRtpStreamReceiver().setCallRecorder(null);
       jal.getRtpStreamSender().setCallRecorder(null);
      }

录音文件默认存放在:/sdcard/Sipdroid_Recordings/
你也可以在 CallRecorder 中实现自己的路径存放

String path = "";//your file path
public CallRecorder(String filename,int sample_rate)
    {
        if (filename == null)
        {
            Time t = new Time();
            t.setToNow();
            filename = t.format2445(); // Create filename from current date.
        }

        // Make sure directory exists.
        File dir = new File(path);//"/sdcard/Sipdroid_Recordings/");
        dir.mkdirs();

        // If this fails, all of the other calls just silently return immediately.
        callWav = new WavWriter(
                //"/sdcard/Sipdroid_Recordings/" 
                path+ filename + ".wav",sample_rate);
}

语音界面修改到这里也就结束了,其他再说吧。

猜你喜欢

转载自blog.csdn.net/ganfanzhou/article/details/52122901
今日推荐