Android - Sipdroid 简单记录

5 篇文章 0 订阅

        记录一下 Sipdroid 适配过程中的几个小修改。

情况1:wifi 情况下正常,4G或者以太网情况下无法播放提示音

 4G 情况下偶然一次呼叫时,在刚开始通话中发送了一次 dtmf,发现提示音直接播放,怀疑和流发送的相关逻辑有关,查看发送代码如下:

sipUA/src/main/java/org/sipdroid/media/RtpStreamSender.java

	/** Runs it in a new Thread. */
	@TargetApi(23)
	public void run() {
		long lastsent = 0;

		if (rtp_socket == null)
			return;
		int seqn = 0;
		long time = 0;
		double p = 0;
		boolean improve = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getBoolean(Settings.PREF_IMPROVE, Settings.DEFAULT_IMPROVE);
		int micgain = 0;
		long last_tx_time = 0;
		long next_tx_delay;
		long now;
		running = true;
		m = 1;
		int dtframesize = 4;
		
    	if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
    		if (Receiver.mContext.checkSelfPermission(Manifest.permission.RECORD_AUDIO)
    		        != PackageManager.PERMISSION_GRANTED) {
    		        return;
    		}
    	
		android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
		mu = p_type.codec.samp_rate()/8000;
		int min = AudioRecord.getMinBufferSize(p_type.codec.samp_rate(), 
				AudioFormat.CHANNEL_CONFIGURATION_MONO, 
				AudioFormat.ENCODING_PCM_16BIT);
		if (min == 640) {
			if (frame_size == 960) frame_size = 320;
			if (frame_size == 1024) frame_size = 160;
			min = 4096*3/2;
		} else if (min < 4096) {
			if (min <= 2048 && frame_size == 1024) frame_size /= 2;
			min = 4096*3/2;
		} else if (min == 4096) {
			min *= 3/2;
			if (frame_size == 960) frame_size = 320;
		} else {
			if (frame_size == 960) frame_size = 320;
			if (frame_size == 1024) frame_size = 160; // frame_size *= 2;
		}
		frame_rate = p_type.codec.samp_rate()/frame_size;
		long frame_period = 1000 / frame_rate;
		frame_rate *= 1.5;
		byte[] buffer = new byte[frame_size + 12];
		RtpPacket rtp_packet = new RtpPacket(buffer, 0);
		rtp_packet.setPayloadType(p_type.number);
		if (DEBUG)
			println("Reading blocks of " + buffer.length + " bytes");
		
		println("Sample rate  = " + p_type.codec.samp_rate());
		println("Buffer size = " + min);

		AudioRecord record = null;
		
		short[] lin = new short[frame_size*(frame_rate+2)];
		int num,ring = 0,pos;
		random = new Random();
		InputStream alerting = null;
		try {
			alerting = Receiver.mContext.getAssets().open("alerting");
		} catch (IOException e2) {
			if (!Sipdroid.release) e2.printStackTrace();
		}
		p_type.codec.init();
		while (running) {
			 if (changed || record == null) {
				if (record != null) {
					record.stop();
					record.release();
					if (RtpStreamReceiver.samsung) {
						AudioManager am = (AudioManager) Receiver.mContext.getSystemService(Context.AUDIO_SERVICE);
						am.setMode(AudioManager.MODE_IN_CALL);
						am.setMode(AudioManager.MODE_NORMAL);
					}
				}
				changed = false;
				record = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, p_type.codec.samp_rate(), AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, 
							min);
				if (record.getState() != AudioRecord.STATE_INITIALIZED) {
					record = null;
					continue;
				}
				if (Build.VERSION.SDK_INT >= 16) {
					RtpStreamSenderNew_SDK16.aec(record);
				}
				record.startRecording();
				micgain = (int)(Settings.getMicGain()*10);
			 }
			 if (muted || Receiver.call_state == UserAgent.UA_STATE_HOLD) {
				if (Receiver.call_state == UserAgent.UA_STATE_HOLD)
					RtpStreamReceiver.restoreMode();
				record.stop();
				while (running && (muted || Receiver.call_state == UserAgent.UA_STATE_HOLD)) {
					try {
						sleep(1000);
					} catch (InterruptedException e1) {
					}
				}
				record.startRecording();
			 }
			 //DTMF change start
			 if (dtmf.length() != 0) {
	 			 byte[] dtmfbuf = new byte[dtframesize + 12];
				 RtpPacket dt_packet = new RtpPacket(dtmfbuf, 0);
				 dt_packet.setPayloadType(dtmf_payload_type);
 				 dt_packet.setPayloadLength(dtframesize);
				 dt_packet.setSscr(rtp_packet.getSscr());
				 long dttime = time;
				 int duration;
				 
	 			 for (int i = 0; i < 6; i++) { 
 	 				 time += 160;
 	 				 duration = (int)(time - dttime);
	 				 dt_packet.setSequenceNumber(seqn++);
	 				 dt_packet.setTimestamp(dttime);
	 				 dtmfbuf[12] = rtpEventMap.get(dtmf.charAt(0));
	 				 dtmfbuf[13] = (byte)0x0a;
	 				 dtmfbuf[14] = (byte)(duration >> 8);
	 				 dtmfbuf[15] = (byte)duration;
	 				 try {
						rtp_socket.send(dt_packet);
						sleep(20);
	 				 } catch (Exception e1) {
	 				 }
	 			 }
	 			 for (int i = 0; i < 3; i++) {
	 				 duration = (int)(time - dttime);
	 				 dt_packet.setSequenceNumber(seqn);
	 				 dt_packet.setTimestamp(dttime);
	 				 dtmfbuf[12] = rtpEventMap.get(dtmf.charAt(0));
	 				 dtmfbuf[13] = (byte)0x8a;
	 				 dtmfbuf[14] = (byte)(duration >> 8);
	 				 dtmfbuf[15] = (byte)duration;
	 				 try {
						rtp_socket.send(dt_packet);
	 				 } catch (Exception e1) {
	 				 }	 			 
	 			 }
	 			 time += 160; seqn++;
				dtmf=dtmf.substring(1);
			 }
			 //DTMF change end

			 if (frame_size < 480) {
				 now = System.currentTimeMillis();
				 next_tx_delay = frame_period - (now - last_tx_time);
				 last_tx_time = now;
				 if (next_tx_delay > 0) {
					 try {
						 sleep(next_tx_delay);
					 } catch (InterruptedException e1) {
					 }
					 last_tx_time += next_tx_delay-sync_adj;
				 }
			 }
			 pos = Integer.parseInt(Build.VERSION.SDK) == 21?0:((ring+delay*frame_rate*frame_size/2)%(frame_size*(frame_rate+1)));
			 num = record.read(lin,pos,frame_size);
			 if (num <= 0)
				 continue;
			 if (!p_type.codec.isValid())
				 continue;
			 
			 // Call recording: Save the frame to the CallRecorder.
			 if (call_recorder != null)
			 	call_recorder.writeOutgoing(lin, pos, num);

			 if (RtpStreamReceiver.speakermode == AudioManager.MODE_NORMAL) {
 				 calc(lin,pos,num);
 	 			 if (RtpStreamReceiver.nearend != 0 && RtpStreamReceiver.down_time == 0)
	 				 noise(lin,pos,num,p/2);
	 			 else if (nearend == 0)
	 				 p = 0.9*p + 0.1*s;
 			 } else switch (micgain) {
 			 case 1:
 				 calc1(lin,pos,num);
 				 break;
 			 case 2:
 				 calc2(lin,pos,num);
 				 break;
 			 case 10:
 				 calc10(lin,pos,num);
 				 break;
 			 }
			 if (Receiver.call_state != UserAgent.UA_STATE_INCALL &&
					 Receiver.call_state != UserAgent.UA_STATE_OUTGOING_CALL && alerting != null) {
				 try {
					if (alerting.available() < num/mu)
						alerting.reset();
					alerting.read(buffer,12,num/mu);
				 } catch (IOException e) {
					if (!Sipdroid.release) e.printStackTrace();
				 }
				 if (p_type.codec.number() != 8) {
					 G711.alaw2linear(buffer, lin, num, mu);
					 num = p_type.codec.encode(lin, 0, buffer, num);
				 }
			 } else {
				 num = p_type.codec.encode(lin, Integer.parseInt(Build.VERSION.SDK) == 21?0:(ring%(frame_size*(frame_rate+1))), buffer, num);
			 }
			 
 			 ring += frame_size;
 			 rtp_packet.setSequenceNumber(seqn++);
 			 rtp_packet.setTimestamp(time);
 			 rtp_packet.setPayloadLength(num);
 			 now = SystemClock.elapsedRealtime();
 			 if (RtpStreamReceiver.timeout == 0 || Receiver.on_wlan || now-lastsent > 500)
	 			 try {
	 				 lastsent = now;
	 				 rtp_socket.send(rtp_packet);
	 				 if (m > 1 && (RtpStreamReceiver.timeout == 0 || Receiver.on_wlan))
	 					 for (int i = 1; i < m; i++)
	 						 rtp_socket.send(rtp_packet);
	 			 } catch (Exception e) {
	 				if (new_socket == null) {
		 				rtp_socket.getDatagramSocket().close();
		 				try {
							if (running)
								rtp_socket = new RtpSocket(new_socket = new SipdroidSocket(local_port), InetAddress
									.getByName(dest_addr), dest_port);
						} catch (Exception e1) {
						}
	 				}
	 			 }
 			 if (p_type.codec.number() == 9)
 				 time += frame_size/2;
 			 else
 				 time += frame_size;
 			 if (RtpStreamReceiver.good != 0 &&
 					 RtpStreamReceiver.loss2/RtpStreamReceiver.good > 0.01) {
 				 if (improve && delay == 0 &&
 						 (p_type.codec.number() == 0 || p_type.codec.number() == 8 || p_type.codec.number() == 9))        	
 					 m = 2;
 				 else
 					 
 					 m = 1;
 			 } else
 				 m = 1;
		}
		if (Integer.parseInt(Build.VERSION.SDK) < 5)
			while (RtpStreamReceiver.getMode() == AudioManager.MODE_IN_CALL)
				try {
					sleep(1000);
				} catch (InterruptedException e) {
				}
		if (record != null) {
			record.stop();
			record.release();
		}
		m = 0;
		
		p_type.codec.close();
		rtp_socket.getDatagramSocket().close();
		rtp_socket = null;
		
		// Call recorder: stop recording outgoing.
		if (call_recorder != null)
		{
			call_recorder.stopOutgoing();
			call_recorder = null;
		}

		if (DEBUG)
			println("rtp sender terminated");
	}

        发现在线程启动时,“RtpStreamReceiver.timeout == 0 || Receiver.on_wlan || now-lastsent > 500” 条件下会发送一个 rtp 包,此处感觉和发送 dtmf 很像,而且和 wifi 网络下提示音播放正常也对应上了,于是查看 Receiver.on_wlan 这个参数在哪里定义。

sipUA/src/main/java/org/sipdroid/sipua/ui/Receiver.java

    public static boolean on_wlan = true;

   
    public static boolean isFast(int i) {
        WifiManager wm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
        WifiInfo wi = wm.getConnectionInfo();

        if (PreferenceManager.getDefaultSharedPreferences(mContext).getString(org.sipdroid.sipua.ui.Settings.PREF_USERNAME + (i != 0 ? i : ""), "").equals("") ||
                PreferenceManager.getDefaultSharedPreferences(mContext).getString(org.sipdroid.sipua.ui.Settings.PREF_SERVER + (i != 0 ? i : ""), "").equals(""))
            return false;
        if (wi != null) {
            if (!Sipdroid.release)
                Log.i("SipUA:", "isFastWifi() " + WifiInfo.getDetailedStateOf(wi.getSupplicantState())
                        + " " + wi.getIpAddress());
            if (wi.getIpAddress() != 0 && (WifiInfo.getDetailedStateOf(wi.getSupplicantState()) == DetailedState.OBTAINING_IPADDR
                    || WifiInfo.getDetailedStateOf(wi.getSupplicantState()) == DetailedState.CONNECTED)
                    || WifiInfo.getDetailedStateOf(wi.getSupplicantState()) == DetailedState.CONNECTING) {
                on_wlan = true;
                if (!on_vpn())
                    return PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean(org.sipdroid.sipua.ui.Settings.PREF_WLAN + (i != 0 ? i : ""), org.sipdroid.sipua.ui.Settings.DEFAULT_WLAN);
                else
                    return PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean(org.sipdroid.sipua.ui.Settings.PREF_VPN + (i != 0 ? i : ""), org.sipdroid.sipua.ui.Settings.DEFAULT_VPN);
            }
        }
//        on_wlan = false;
        return isFastGSM(i);
    }

        将其默认值修改为 true,注释置为 false 的语句,再次运行,提示音播放成功。感觉像是在通话建立成功后,需要发送消息通知给服务器通话开始。如有其他见解烦请指导我下。

情况2:编码类型为 G722,通话无法成功。

        直接去掉不可用的编码类型,只保留了 PCMA 和 PCMU。

sipUA/src/main/java/org/sipdroid/codecs/Codecs.java

public class Codecs {
    	private static final Vector<Codec> codecs = new Vector<Codec>() {{
//			add(new G722());
//			add(new SILK24());		save space (until a common library for all bitrates gets available?)
//			add(new SILK16());
//			add(new SILK8());
			add(new alaw());
			add(new ulaw());
//			add(new Speex());
//			add(new GSM());
//			add(new BV16());
		}};
...

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Sipdroid APK是一款用于Android系统的一款允许用户进行VoIP(Voice over Internet Protocol)通话的应用程序。VoIP是一种通过互联网而不是传统的电话线进行语音通信的技术。Sipdroid APK允许用户通过Wi-Fi或数据网络连接到其他使用相同协议的用户进行语音通话。 Sipdroid APK具有许多功能和优点。首先,它可以帮助用户节省通信费用,特别是在国际长途通话方面。通过使用互联网连接,用户可以享受更低廉的通话费用,并避免传统电话公司的高额长途费用。 此外,Sipdroid APK提供了高质量的语音通话。它使用了先进的音频编解码技术,确保用户可以在通话过程中享受清晰、无杂音的声音质量。这对于商务通话或重要的电话会议非常关键。 Sipdroid APK还具有很好的灵活性和可扩展性。它兼容许多不同的VoIP服务提供商和协议,例如Asterisk、FreePBX、Google Voice等。这意味着用户可以根据自己的喜好和需求选择适合自己的服务。 此外,Sipdroid APK还具有用户友好的界面和简单的设置过程。用户只需下载并安装该应用程序,然后按照指示进行简单的设置即可开始使用。这使得它非常适合普通用户和那些对技术要求不高的人。 总的来说,Sipdroid APK是一款功能强大、灵活易用的VoIP通话应用程序。它可以帮助用户节省通信费用,并提供高质量的语音通话体验。无论是个人用户还是商务用户,Sipdroid APK都是一款优秀的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值