再谈SipDroid

研究了SipDroid2.7,自己对它的理解也渐渐的清晰了。

那它是怎样实现电话拨打以及电话监听的?它的音频接收以及发送是怎么实现的?它的视频又是怎么一回事?它在模拟器上的端口为什么总是变化的?它又是如何处理登陆超时以及通话出错的?

带着这些疑问进入它的代码思想境界!

使用yate搭配服务器,然后使用了一个yate与SipDroid客户端进行通话!~至于怎么搭配服务器以及SipDroid的配置设置,此处就不讨论了!~ 

登陆后的标识效果如图:


然后我使用了yate客户端程序拨打了SipDroid程序段上的帐号(banketree),如图:



接通后的效果图像如图:


好了,进入我们的主题了!~

它是怎样实现电话拨打以及电话监听的?

程序进入时会进行服务注册,如下:

  1. // 实例化一个引擎 注册模式    由登陆时进行……   
  2. /   Receiver.engine(this).registerMore();  
		// 实例化一个引擎 注册模式    由登陆时进行……
	//	Receiver.engine(this).registerMore();

我们知道Receiver.engine(this) 进行了SipUA引擎的实例化,并开启SipUA引擎,关键就SipUA引擎了!~

  1. // 构造引擎   
  2. public static synchronized SipdroidEngine engine(Context context)  
  3. {  
  4.     // 构造引擎的条件   
  5.     if (mContext == null  
  6.             || !context.getClass().getName()  
  7.                     .contains("ReceiverRestrictedContext"))  
  8.     {  
  9.         mContext = context;  
  10.     }  
  11.   
  12.     // 为空则构造   
  13.     if (mSipdroidEngine == null)  
  14.     {  
  15.         mSipdroidEngine = new SipdroidEngine();  
  16.   
  17.         // 开始    
  18.         mSipdroidEngine.StartEngine();  
  19.   
  20.         // 开启蓝牙服务   
  21.         if (Integer.parseInt(Build.VERSION.SDK) >= 8)  
  22.         {  
  23.             Bluetooth.init();  
  24.         }  
  25.     } else  
  26.     {  
  27.         // 引擎已经存在   
  28.         mSipdroidEngine.CheckEngine();  
  29.     }  
  30.   
  31.     // 开启服务   
  32.     context.startService(new Intent(context, RegisterService.class));  
  33.   
  34.     return mSipdroidEngine;  
  35. }  
	// 构造引擎
	public static synchronized SipdroidEngine engine(Context context)
	{
		// 构造引擎的条件
		if (mContext == null
				|| !context.getClass().getName()
						.contains("ReceiverRestrictedContext"))
		{
			mContext = context;
		}

		// 为空则构造
		if (mSipdroidEngine == null)
		{
			mSipdroidEngine = new SipdroidEngine();

			// 开始 
			mSipdroidEngine.StartEngine();

			// 开启蓝牙服务
			if (Integer.parseInt(Build.VERSION.SDK) >= 8)
			{
				Bluetooth.init();
			}
		} else
		{
			// 引擎已经存在
			mSipdroidEngine.CheckEngine();
		}

		// 开启服务
		context.startService(new Intent(context, RegisterService.class));

		return mSipdroidEngine;
	}

而StartEngine()里有开启监听!~

  1. //注册  在此向服务器发送请求。   
  2. register();  
  3.   
  4. //实例化一个ExtendedCall 循环监听指定端口    
  5. listen();  
		//注册  在此向服务器发送请求。
		register();
		
		//实例化一个ExtendedCall 循环监听指定端口 
		listen();

至于里面是怎么实现的,那就涉及到了SipUA封装的一些类以及消息了!~ 

消息以及协议的通信都是SipProvider类由完成的!~

  1. public void onReceivedMessage(Transport transport, Message msg)  
  2. {  
  3.     if (pm == null)  
  4.     {  
  5.         pm = (PowerManager) Receiver.mContext.getSystemService(Context.POWER_SERVICE);  
  6.         wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Sipdroid.SipProvider");  
  7.     }  
  8.     wl.acquire(); // modified   
  9.     //处理接收消息   当程序进行了监听,就会向此类添加一个监听事件标识    
  10.     //处理消息就是根据标识进行区分的,例如来电、接听、视频等等!~~~   
  11.     processReceivedMessage(msg);    
  12.     wl.release();  
  13. }  
	public void onReceivedMessage(Transport transport, Message msg)
	{
		if (pm == null)
		{
			pm = (PowerManager) Receiver.mContext.getSystemService(Context.POWER_SERVICE);
			wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Sipdroid.SipProvider");
		}
		wl.acquire(); // modified
		//处理接收消息   当程序进行了监听,就会向此类添加一个监听事件标识 
		//处理消息就是根据标识进行区分的,例如来电、接听、视频等等!~~~
		processReceivedMessage(msg);  
		wl.release();
	}

向服务器发送信息(发送协议进行登陆以及获取对方信息等等)也是由该类完成的!~如下:

  1. /** 
  2.      * Sends a Message, specifing the transport portocol, nexthop address and 
  3.      * port. 
  4.      * 发送一条消息,指定传输协议、地址、以及端口。 
  5.      */  
  6.     private ConnectionIdentifier sendMessage(Message msg, String proto, IpAddress dest_ipaddr, int dest_port, int ttl)  
  7.     {  
  8.         if(bDebug)  
  9.         {  
  10.             android.util.Log.i("SipProvider发送消息""msg:"+msg.toString());  
  11.         }  
  12.           
  13.         ConnectionIdentifier conn_id = new ConnectionIdentifier(proto, dest_ipaddr, dest_port);  
  14.         if (log_all_packets || msg.getLength() > MIN_MESSAGE_LENGTH)  
  15.             printLog("Sending message to " + conn_id, LogLevel.MEDIUM);  
  16.   
  17.         if (transport_udp && proto.equals(PROTO_UDP))  
  18.         {   
  19.             // UDP   
  20.             // printLog("using UDP",LogLevel.LOW);   
  21.             conn_id = null;  
  22.             try  
  23.             {   
  24.                 // if (ttl>0 && multicast_address) do something?   
  25.                 udp.sendMessage(msg, dest_ipaddr, dest_port);  
  26.             } catch (IOException e)  
  27.             {  
  28.                 printException(e, LogLevel.HIGH);  
  29.                 return null;  
  30.             }  
  31.         } else if (transport_tcp && proto.equals(PROTO_TCP))  
  32.         {   
  33.             // TCP   
  34.             // printLog("using TCP",LogLevel.LOW);   
  35.             if (connections == null || !connections.containsKey(conn_id))  
  36.             {   
  37.                 // modified   
  38.                 printLog("no active connection found matching " + conn_id, LogLevel.MEDIUM);  
  39.                 printLog("open " + proto + " connection to " + dest_ipaddr + ":" + dest_port, LogLevel.MEDIUM);  
  40.                 TcpTransport conn = null;  
  41.                 try  
  42.                 {  
  43.                     conn = new TcpTransport(dest_ipaddr, dest_port, this);  
  44.                 } catch (Exception e)  
  45.                 {  
  46.                     printLog("connection setup FAILED", LogLevel.HIGH);  
  47.                     return null;  
  48.                 }  
  49.                   
  50.                 printLog("connection " + conn + " opened", LogLevel.HIGH);  
  51.                 addConnection(conn);  
  52.                 if (!msg.isRegister())  
  53.                     Receiver.engine(Receiver.mContext).register(); // modified   
  54.             } else  
  55.             {  
  56.                 printLog("active connection found matching " + conn_id, LogLevel.MEDIUM);  
  57.             }  
  58.             ConnectedTransport conn = (ConnectedTransport) connections.get(conn_id);  
  59.             if (conn != null)  
  60.             {  
  61.                 printLog("sending data through conn " + conn, LogLevel.MEDIUM);  
  62.                 try  
  63.                 {  
  64.                     conn.sendMessage(msg);  
  65.                     conn_id = new ConnectionIdentifier(conn);  
  66.                 } catch (IOException e)  
  67.                 {  
  68.                     printException(e, LogLevel.HIGH);  
  69.                     return null;  
  70.                 }  
  71.             } else  
  72.             {   
  73.                 // this point has not to be reached这一点还没有达到   
  74.                 printLog("ERROR: conn " + conn_id + " not found: abort.", LogLevel.MEDIUM);  
  75.                 return null;  
  76.             }  
  77.         } else  
  78.         { // otherwise   
  79.             printWarning("Unsupported protocol (" + proto + "): Message discarded", LogLevel.HIGH);  
  80.             return null;  
  81.         }  
  82.         // logs   
  83.         String dest_addr = dest_ipaddr.toString();  
  84.         printMessageLog(proto, dest_addr, dest_port, msg.getLength(), msg, "sent");  
  85.         return conn_id;  
  86.     }  
/**
	 * Sends a Message, specifing the transport portocol, nexthop address and
	 * port.
	 * 发送一条消息,指定传输协议、地址、以及端口。
	 */
	private ConnectionIdentifier sendMessage(Message msg, String proto, IpAddress dest_ipaddr, int dest_port, int ttl)
	{
		if(bDebug)
		{
			android.util.Log.i("SipProvider发送消息", "msg:"+msg.toString());
		}
		
		ConnectionIdentifier conn_id = new ConnectionIdentifier(proto, dest_ipaddr, dest_port);
		if (log_all_packets || msg.getLength() > MIN_MESSAGE_LENGTH)
			printLog("Sending message to " + conn_id, LogLevel.MEDIUM);

		if (transport_udp && proto.equals(PROTO_UDP))
		{ 
			// UDP
			// printLog("using UDP",LogLevel.LOW);
			conn_id = null;
			try
			{ 
				// if (ttl>0 && multicast_address) do something?
				udp.sendMessage(msg, dest_ipaddr, dest_port);
			} catch (IOException e)
			{
				printException(e, LogLevel.HIGH);
				return null;
			}
		} else if (transport_tcp && proto.equals(PROTO_TCP))
		{ 
			// TCP
			// printLog("using TCP",LogLevel.LOW);
			if (connections == null || !connections.containsKey(conn_id))
			{ 
				// modified
				printLog("no active connection found matching " + conn_id, LogLevel.MEDIUM);
				printLog("open " + proto + " connection to " + dest_ipaddr + ":" + dest_port, LogLevel.MEDIUM);
				TcpTransport conn = null;
				try
				{
					conn = new TcpTransport(dest_ipaddr, dest_port, this);
				} catch (Exception e)
				{
					printLog("connection setup FAILED", LogLevel.HIGH);
					return null;
				}
				
				printLog("connection " + conn + " opened", LogLevel.HIGH);
				addConnection(conn);
				if (!msg.isRegister())
					Receiver.engine(Receiver.mContext).register(); // modified
			} else
			{
				printLog("active connection found matching " + conn_id, LogLevel.MEDIUM);
			}
			ConnectedTransport conn = (ConnectedTransport) connections.get(conn_id);
			if (conn != null)
			{
				printLog("sending data through conn " + conn, LogLevel.MEDIUM);
				try
				{
					conn.sendMessage(msg);
					conn_id = new ConnectionIdentifier(conn);
				} catch (IOException e)
				{
					printException(e, LogLevel.HIGH);
					return null;
				}
			} else
			{ 
				// this point has not to be reached这一点还没有达到
				printLog("ERROR: conn " + conn_id + " not found: abort.", LogLevel.MEDIUM);
				return null;
			}
		} else
		{ // otherwise
			printWarning("Unsupported protocol (" + proto + "): Message discarded", LogLevel.HIGH);
			return null;
		}
		// logs
		String dest_addr = dest_ipaddr.toString();
		printMessageLog(proto, dest_addr, dest_port, msg.getLength(), msg, "sent");
		return conn_id;
	}

消息的信息格式如下:


……

回到问题中来,监听电话已经明白了,那是如何实现拨打的?

当用户登陆后就会把自己的信息发送给服务端,服务端记录下来,等用户需要时就返回给他,比如我打banketree电话,我没有他的信息我怎么打呀,是吧!~

拨打电话的关键在UserAgent中,其它的都是封装好处理信息的类!~

  1. public boolean call(String target_url, boolean send_anonymous)  
  2. {  
  3.   
  4.     if (Receiver.call_state != UA_STATE_IDLE)  
  5.     {  
  6.         // We can initiate or terminate a call only when   
  7.         // we are in an idle state   
  8.         //只有当我们处于闲置状态,我们可以开始或结束通话   
  9.         printLog("Call attempted in state" + this.getSessionDescriptor()  
  10.                 + " : Failing Request", LogLevel.HIGH);  
  11.         return false;  
  12.     }  
  13.       
  14.     //挂断   
  15.     hangup(); // modified   
  16.       
  17.     //改变状态   
  18.     changeStatus(UA_STATE_OUTGOING_CALL, target_url);  
  19.   
  20.     String from_url;  
  21.   
  22.     if (!send_anonymous)  
  23.     {  
  24.         from_url = user_profile.from_url;  
  25.     } else  
  26.     {  
  27.         from_url = "sip:anonymous@anonymous.com";  
  28.     }  
  29.   
  30.     // change start multi codecs  更改启动多编解码器   
  31.     createOffer();  
  32.     // change end   
  33.       
  34.     call = new ExtendedCall(sip_provider, from_url,  
  35.             user_profile.contact_url, user_profile.username,  
  36.             user_profile.realm, user_profile.passwd, this);  
  37.   
  38.     // in case of incomplete url (e.g. only 'user' is present), try to   
  39.     // complete it   
  40.     //在不完整的URL(例如,“用户”是存在的话)的情况下,尽量去完成它   
  41.     if (target_url.indexOf("@") < 0)  
  42.     {  
  43.         if (user_profile.realm.equals(Settings.DEFAULT_SERVER))  
  44.             target_url = "&" + target_url;  
  45.           
  46.         target_url = target_url + "@" + realm; // modified   
  47.     }  
  48.   
  49.     // MMTel addition to define MMTel ICSI to be included in INVITE (added   
  50.     // by mandrajg)  要包含在INVITE MMTel除了定义MMTel ICSI   
  51.     String icsi = null;  
  52.     if (user_profile.mmtel == true)  
  53.     {  
  54.         icsi = "\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\"";  
  55.     }  
  56.   
  57.     //从服务器中获得对方的地址   
  58.     target_url = sip_provider.completeNameAddress(target_url).toString();  
  59.       
  60.     //真的拨打电话   
  61.     if (user_profile.no_offer)  
  62.     {  
  63.         call.call(target_url);  
  64.     } else  
  65.     {  
  66.         call.call(target_url, local_session, icsi); // modified by mandrajg   
  67.     }  
  68.   
  69.     return true;  
  70. }  
	public boolean call(String target_url, boolean send_anonymous)
	{

		if (Receiver.call_state != UA_STATE_IDLE)
		{
			// We can initiate or terminate a call only when
			// we are in an idle state
			//只有当我们处于闲置状态,我们可以开始或结束通话
			printLog("Call attempted in state" + this.getSessionDescriptor()
					+ " : Failing Request", LogLevel.HIGH);
			return false;
		}
		
		//挂断
		hangup(); // modified
		
		//改变状态
		changeStatus(UA_STATE_OUTGOING_CALL, target_url);

		String from_url;

		if (!send_anonymous)
		{
			from_url = user_profile.from_url;
		} else
		{
			from_url = "sip:anonymous@anonymous.com";
		}

		// change start multi codecs  更改启动多编解码器
		createOffer();
		// change end
		
		call = new ExtendedCall(sip_provider, from_url,
				user_profile.contact_url, user_profile.username,
				user_profile.realm, user_profile.passwd, this);

		// in case of incomplete url (e.g. only 'user' is present), try to
		// complete it
		//在不完整的URL(例如,“用户”是存在的话)的情况下,尽量去完成它
		if (target_url.indexOf("@") < 0)
		{
			if (user_profile.realm.equals(Settings.DEFAULT_SERVER))
				target_url = "&" + target_url;
			
			target_url = target_url + "@" + realm; // modified
		}

		// MMTel addition to define MMTel ICSI to be included in INVITE (added
		// by mandrajg)  要包含在INVITE MMTel除了定义MMTel ICSI
		String icsi = null;
		if (user_profile.mmtel == true)
		{
			icsi = "\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\"";
		}

		//从服务器中获得对方的地址
		target_url = sip_provider.completeNameAddress(target_url).toString();
		
		//真的拨打电话
		if (user_profile.no_offer)
		{
			call.call(target_url);
		} else
		{
			call.call(target_url, local_session, icsi); // modified by mandrajg
		}

		return true;
	}

那它的音频接收以及发送是怎么实现的?

管理音频有一个类,它是JAudioLauncher,当实例化它的时候,它会开启两个线程,一个是RtpStreamReceiver,另一个是RtpStreamReceiver!~

看标题就知道它们一个是发送的,一个是接收的!~

先来看下接收是怎么实现的!~

  1.     public void run()  
  2.     {  
  3.         boolean nodata = PreferenceManager.getDefaultSharedPreferences(  
  4.                 Receiver.mContext).getBoolean(  
  5.                 org.sipdroid.sipua.ui.Settings.PREF_NODATA,  
  6.                 org.sipdroid.sipua.ui.Settings.DEFAULT_NODATA);  
  7.         keepon = PreferenceManager.getDefaultSharedPreferences(  
  8.                 Receiver.mContext).getBoolean(  
  9.                 org.sipdroid.sipua.ui.Settings.PREF_KEEPON,  
  10.                 org.sipdroid.sipua.ui.Settings.DEFAULT_KEEPON);  
  11.   
  12.         if (rtp_socket == null)  
  13.         {  
  14.             if (DEBUG)  
  15.             {  
  16.                 println("ERROR: RTP socket is null(出错:rtp接受套接字出错!)");  
  17.             }  
  18.             return;  
  19.         }  
  20.   
  21.         //发送包 缓冲区   
  22.         byte[] buffer = new byte[BUFFER_SIZE + 12];  
  23.           
  24.         //构建包实例   
  25.         rtp_packet = new RtpPacket(buffer, 0);  
  26.   
  27.         if (DEBUG)  
  28.         {  
  29.             println("Reading blocks of max (读取快的最大值) = " + buffer.length + " bytes");  
  30.         }  
  31.   
  32.         running = true;  
  33.           
  34.         //开启蓝牙   
  35.         enableBluetooth(PreferenceManager.getDefaultSharedPreferences(  
  36.                 Receiver.mContext).getBoolean(  
  37.                 org.sipdroid.sipua.ui.Settings.PREF_BLUETOOTH,  
  38.                 org.sipdroid.sipua.ui.Settings.DEFAULT_BLUETOOTH));  
  39.           
  40.         restored = false;  
  41.   
  42.         //设置线程权限   
  43.         android.os.Process  
  44.                 .setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);  
  45.           
  46.         am = (AudioManager) Receiver.mContext  
  47.                 .getSystemService(Context.AUDIO_SERVICE);  
  48.         cr = Receiver.mContext.getContentResolver();  
  49.           
  50.         //保存设置   
  51.         saveSettings();  
  52.         Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY,  
  53.                 Settings.System.WIFI_SLEEP_POLICY_NEVER);  
  54.         am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,  
  55.                 AudioManager.VIBRATE_SETTING_OFF);  
  56.         am.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,  
  57.                 AudioManager.VIBRATE_SETTING_OFF);  
  58.         if (oldvol == -1)  
  59.         {  
  60.             oldvol = am.getStreamVolume(AudioManager.STREAM_MUSIC);  
  61.         }  
  62.   
  63.         //初始化模式   
  64.         initMode();  
  65.           
  66.         //设置音频编解码器   
  67.         setCodec();  
  68.   
  69.         //编辑音频  由发送包解码后放到此处 然后调整后放入到声音播放器中   
  70.         short lin[] = new short[BUFFER_SIZE];  
  71.         //它是负责清空lin的   
  72.         short lin2[] = new short[BUFFER_SIZE];  
  73.         int server, headroom, todo, len = 0, m = 1, expseq, getseq, vm = 1, gap, gseq;  
  74.           
  75.         ToneGenerator tg = new ToneGenerator(  
  76.                 AudioManager.STREAM_VOICE_CALL,  
  77.                 (int) (ToneGenerator.MAX_VOLUME * 2 * org.sipdroid.sipua.ui.Settings  
  78.                         .getEarGain()));  
  79.           
  80.         //播放   
  81.         track.play();  
  82.           
  83.         //指示虚拟机运行垃圾收集器,这将是一个好时机。   
  84.         //请注意,这仅是一个提示。有没有保证,垃圾收集器将实际运行。   
  85.         System.gc();  
  86.           
  87.         //清空   
  88.         empty();  
  89.           
  90.         lockFirst = true;  
  91.   
  92.         while (running)  
  93.         {  
  94.             lock(true);  
  95.               
  96.             if (Receiver.call_state == UserAgent.UA_STATE_HOLD)  
  97.             {  
  98.                 lock(false);  
  99.                   
  100.                 //停止   
  101.                 tg.stopTone();  
  102.                   
  103.                 //暂停   
  104.                 track.pause();  
  105.                   
  106.                 while (running  
  107.                         && Receiver.call_state == UserAgent.UA_STATE_HOLD)  
  108.                 {  
  109.                     try  
  110.                     {  
  111.                         sleep(1000);  
  112.                     } catch (InterruptedException e1)  
  113.                     {  
  114.                     }  
  115.                 }  
  116.   
  117.                 track.play();  
  118.                 System.gc();  
  119.                 timeout = 1;  
  120.                 luser = luser2 = -8000 * mu;  
  121.             }  
  122.               
  123.             try  
  124.             {  
  125.                 // 接受数据   
  126.                 rtp_socket.receive(rtp_packet);  
  127.   
  128.                 //超时   
  129.                 if (timeout != 0)  
  130.                 {  
  131.                     //停止音乐   
  132.                     tg.stopTone();  
  133.                       
  134.                     //暂停声音   
  135.                     track.pause();  
  136.                       
  137.                     //清空   
  138.                     for (int i = maxjitter * 2; i > 0; i -= BUFFER_SIZE)  
  139.                     {  
  140.                         write(lin2, 0, i > BUFFER_SIZE ? BUFFER_SIZE : i);  
  141.                     }  
  142.   
  143.                     cnt += maxjitter * 2;  
  144.                       
  145.                     //声音播放   
  146.                     track.play();  
  147.                     empty();  
  148.                 }  
  149.                 timeout = 0;  
  150.             } catch (IOException e)  
  151.             {  
  152.                 if (timeout == 0 && nodata)  
  153.                 {  
  154.                     tg.startTone(ToneGenerator.TONE_SUP_RINGTONE);  
  155.                 }  
  156.   
  157.                 //异常者 断开   
  158.                 rtp_socket.getDatagramSocket().disconnect();  
  159.                   
  160.                 if (++timeout > 60)  
  161.                 {  
  162.                     Receiver.engine(Receiver.mContext).rejectcall();  
  163.                     break;  
  164.                 }  
  165.             }  
  166.               
  167.             //在运行 且未超时   
  168.             if (running && timeout == 0)  
  169.             {  
  170.                 //得到数字字符   
  171.                 gseq = rtp_packet.getSequenceNumber();  
  172.                   
  173.                 //得到当前接受包的大小   
  174.                 if (seq == gseq)  
  175.                 {  
  176.                     m++;  
  177.                     continue;  
  178.                 }  
  179.                   
  180.                   
  181.                 gap = (gseq - seq) & 0xff;  
  182.                   
  183.                 if (gap > 240)  
  184.                 {  
  185.                     continue;  
  186.                 }  
  187.                   
  188.                 //返回帧中表示播放头位置。   
  189.                 server = track.getPlaybackHeadPosition();  
  190.                   
  191.                 //接受包的总大小 - 当前播放的位置   
  192.                 headroom = user - server;  
  193.   
  194.                 if (headroom > 2 * jitter)  
  195.                 {  
  196.                     cnt += len;  
  197.                 } else  
  198.                 {  
  199.                     cnt = 0;  
  200.                 }  
  201.   
  202.                 if (lserver == server)  
  203.                 {  
  204.                     cnt2++;  
  205.                 } else  
  206.                 {  
  207.                     cnt2 = 0;  
  208.                 }  
  209.   
  210.                 if (cnt <= 500 * mu || cnt2 >= 2 || headroom - jitter < len  
  211.                         || p_type.codec.number() != 8  
  212.                         || p_type.codec.number() != 0)  
  213.                 {  
  214.                     //有效负荷类型||改变类型   
  215.                     if (rtp_packet.getPayloadType() != p_type.number  
  216.                             && p_type.change(rtp_packet.getPayloadType()))  
  217.                     {  
  218.                         //保留声量   
  219.                         saveVolume();  
  220.                           
  221.                         //设置编解码器   
  222.                         setCodec();  
  223.                           
  224.                         //恢复声量   
  225.                         restoreVolume();  
  226.                           
  227.                         //头信息   
  228.                         codec = p_type.codec.getTitle();  
  229.                     }  
  230.                       
  231.                     //得到有效负荷长度   
  232.                     len = p_type.codec.decode(buffer, lin,  
  233.                             rtp_packet.getPayloadLength());  
  234.   
  235.                     // Call recording: Save incoming.Data is in buffer lin, from 0 to len.   
  236.                     //通话记录:保存传入。数据是在缓冲区林,从0到LEN。   
  237.                     if (call_recorder != null)  
  238.                     {  
  239.                         //写入   
  240.                         call_recorder.writeIncoming(lin, 0, len);  
  241.                     }  
  242.   
  243.                     //声音改变效果显示   
  244.                     if (speakermode == AudioManager.MODE_NORMAL)  
  245.                     {  
  246.                         calc(lin, 0, len);  
  247.                     } else if (gain > 1)  
  248.                     {  
  249.                         calc2(lin, 0, len);  
  250.                     }  
  251.                 }  
  252.   
  253.                 //   
  254.                 avgheadroom = avgheadroom * 0.99 + (double) headroom * 0.01;  
  255.                 if (avgcnt++ > 300)  
  256.                 {  
  257.                     devheadroom = devheadroom * 0.999  
  258.                             + Math.pow(Math.abs(headroom - avgheadroom), 2)  
  259.                             * 0.001;  
  260.                 }  
  261.                   
  262.                 //头大小   
  263.                 if (headroom < 250 * mu)  
  264.                 {  
  265.                     late++;  
  266.                     newjitter(true);  
  267. //                  System.out.println("RTP:underflow "   
  268. //                          + (int) Math.sqrt(devheadroom));   
  269.                     todo = jitter - headroom;  
  270.                     write(lin2, 0, todo > BUFFER_SIZE ? BUFFER_SIZE : todo);  
  271.                 }  
  272.   
  273.                 //   
  274.                 if (cnt > 500 * mu && cnt2 < 2)  
  275.                 {  
  276.                     todo = headroom - jitter;  
  277.                     if (todo < len)  
  278.                     {  
  279.                         write(lin, todo, len - todo);  
  280.                     }  
  281.                 } else  
  282.                 {  
  283.                     write(lin, 0, len);  
  284.                 }  
  285.   
  286.                 //丢失包统计   
  287.                 if (seq != 0)  
  288.                 {  
  289.                     getseq = gseq & 0xff;  
  290.                     expseq = ++seq & 0xff;  
  291.                     if (m == RtpStreamSender.m)  
  292.                     {  
  293.                         vm = m;  
  294.                     }  
  295.                       
  296.                     gap = (getseq - expseq) & 0xff;  
  297.                     if (gap > 0)  
  298.                     {  
  299.                     //  System.out.println("RTP:lost");   
  300.                         if (gap > 100)  
  301.                         {  
  302.                             gap = 1;  
  303.                         }  
  304.                         loss += gap;  
  305.                         lost += gap;  
  306.                         good += gap - 1;  
  307.                         loss2++;  
  308.                     } else  
  309.                     {  
  310.                         if (m < vm)  
  311.                         {  
  312.                             loss++;  
  313.                             loss2++;  
  314.                         }  
  315.                     }  
  316.                     good++;  
  317.                     if (good > 110)  
  318.                     {  
  319.                         good *= 0.99;  
  320.                         lost *= 0.99;  
  321.                         loss *= 0.99;  
  322.                         loss2 *= 0.99;  
  323.                         late *= 0.99;  
  324.                     }  
  325.                 }  
  326.                 m = 1;  
  327.                 seq = gseq;  
  328.   
  329.                 if (user >= luser + 8000 * mu  
  330.                         && (Receiver.call_state == UserAgent.UA_STATE_INCALL || Receiver.call_state == UserAgent.UA_STATE_OUTGOING_CALL))  
  331.                 {  
  332.                     if (luser == -8000 * mu || getMode() != speakermode)  
  333.                     {  
  334.                         //保留声量   
  335.                         saveVolume();  
  336.                           
  337.                         //设置模式   
  338.                         setMode(speakermode);  
  339.                           
  340.                         //恢复声量   
  341.                         restoreVolume();  
  342.                     }  
  343.                   
  344.                     luser = user;  
  345.                       
  346.                     if (user >= luser2 + 160000 * mu)  
  347.                     {  
  348.                         //抖动   
  349.                         newjitter(false);  
  350.                     }  
  351.                 }  
  352.                 lserver = server;  
  353.             }  
  354.         }  
	public void run()
	{
		boolean nodata = PreferenceManager.getDefaultSharedPreferences(
				Receiver.mContext).getBoolean(
				org.sipdroid.sipua.ui.Settings.PREF_NODATA,
				org.sipdroid.sipua.ui.Settings.DEFAULT_NODATA);
		keepon = PreferenceManager.getDefaultSharedPreferences(
				Receiver.mContext).getBoolean(
				org.sipdroid.sipua.ui.Settings.PREF_KEEPON,
				org.sipdroid.sipua.ui.Settings.DEFAULT_KEEPON);

		if (rtp_socket == null)
		{
			if (DEBUG)
			{
				println("ERROR: RTP socket is null(出错:rtp接受套接字出错!)");
			}
			return;
		}

		//发送包 缓冲区
		byte[] buffer = new byte[BUFFER_SIZE + 12];
		
		//构建包实例
		rtp_packet = new RtpPacket(buffer, 0);

		if (DEBUG)
		{
			println("Reading blocks of max (读取快的最大值) = " + buffer.length + " bytes");
		}

		running = true;
		
		//开启蓝牙
		enableBluetooth(PreferenceManager.getDefaultSharedPreferences(
				Receiver.mContext).getBoolean(
				org.sipdroid.sipua.ui.Settings.PREF_BLUETOOTH,
				org.sipdroid.sipua.ui.Settings.DEFAULT_BLUETOOTH));
		
		restored = false;

		//设置线程权限
		android.os.Process
				.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
		
		am = (AudioManager) Receiver.mContext
				.getSystemService(Context.AUDIO_SERVICE);
		cr = Receiver.mContext.getContentResolver();
		
		//保存设置
		saveSettings();
		Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY,
				Settings.System.WIFI_SLEEP_POLICY_NEVER);
		am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,
				AudioManager.VIBRATE_SETTING_OFF);
		am.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,
				AudioManager.VIBRATE_SETTING_OFF);
		if (oldvol == -1)
		{
			oldvol = am.getStreamVolume(AudioManager.STREAM_MUSIC);
		}

		//初始化模式
		initMode();
		
		//设置音频编解码器
		setCodec();

		//编辑音频  由发送包解码后放到此处 然后调整后放入到声音播放器中
		short lin[] = new short[BUFFER_SIZE];
		//它是负责清空lin的
		short lin2[] = new short[BUFFER_SIZE];
		int server, headroom, todo, len = 0, m = 1, expseq, getseq, vm = 1, gap, gseq;
		
		ToneGenerator tg = new ToneGenerator(
				AudioManager.STREAM_VOICE_CALL,
				(int) (ToneGenerator.MAX_VOLUME * 2 * org.sipdroid.sipua.ui.Settings
						.getEarGain()));
		
		//播放
		track.play();
		
		//指示虚拟机运行垃圾收集器,这将是一个好时机。
		//请注意,这仅是一个提示。有没有保证,垃圾收集器将实际运行。
		System.gc();
		
		//清空
		empty();
		
		lockFirst = true;

		while (running)
		{
			lock(true);
			
			if (Receiver.call_state == UserAgent.UA_STATE_HOLD)
			{
				lock(false);
				
				//停止
				tg.stopTone();
				
				//暂停
				track.pause();
				
				while (running
						&& Receiver.call_state == UserAgent.UA_STATE_HOLD)
				{
					try
					{
						sleep(1000);
					} catch (InterruptedException e1)
					{
					}
				}

				track.play();
				System.gc();
				timeout = 1;
				luser = luser2 = -8000 * mu;
			}
			
			try
			{
				// 接受数据
				rtp_socket.receive(rtp_packet);

				//超时
				if (timeout != 0)
				{
					//停止音乐
					tg.stopTone();
					
					//暂停声音
					track.pause();
					
					//清空
					for (int i = maxjitter * 2; i > 0; i -= BUFFER_SIZE)
					{
						write(lin2, 0, i > BUFFER_SIZE ? BUFFER_SIZE : i);
					}

					cnt += maxjitter * 2;
					
					//声音播放
					track.play();
					empty();
				}
				timeout = 0;
			} catch (IOException e)
			{
				if (timeout == 0 && nodata)
				{
					tg.startTone(ToneGenerator.TONE_SUP_RINGTONE);
				}

				//异常者 断开
				rtp_socket.getDatagramSocket().disconnect();
				
				if (++timeout > 60)
				{
					Receiver.engine(Receiver.mContext).rejectcall();
					break;
				}
			}
			
			//在运行 且未超时
			if (running && timeout == 0)
			{
				//得到数字字符
				gseq = rtp_packet.getSequenceNumber();
				
				//得到当前接受包的大小
				if (seq == gseq)
				{
					m++;
					continue;
				}
				
				
				gap = (gseq - seq) & 0xff;
				
				if (gap > 240)
				{
					continue;
				}
				
				//返回帧中表示播放头位置。
				server = track.getPlaybackHeadPosition();
				
				//接受包的总大小 - 当前播放的位置
				headroom = user - server;

				if (headroom > 2 * jitter)
				{
					cnt += len;
				} else
				{
					cnt = 0;
				}

				if (lserver == server)
				{
					cnt2++;
				} else
				{
					cnt2 = 0;
				}

				if (cnt <= 500 * mu || cnt2 >= 2 || headroom - jitter < len
						|| p_type.codec.number() != 8
						|| p_type.codec.number() != 0)
				{
					//有效负荷类型||改变类型
					if (rtp_packet.getPayloadType() != p_type.number
							&& p_type.change(rtp_packet.getPayloadType()))
					{
						//保留声量
						saveVolume();
						
						//设置编解码器
						setCodec();
						
						//恢复声量
						restoreVolume();
						
						//头信息
						codec = p_type.codec.getTitle();
					}
					
					//得到有效负荷长度
					len = p_type.codec.decode(buffer, lin,
							rtp_packet.getPayloadLength());

					// Call recording: Save incoming.Data is in buffer lin, from 0 to len.
					//通话记录:保存传入。数据是在缓冲区林,从0到LEN。
					if (call_recorder != null)
					{
						//写入
						call_recorder.writeIncoming(lin, 0, len);
					}

					//声音改变效果显示
					if (speakermode == AudioManager.MODE_NORMAL)
					{
						calc(lin, 0, len);
					} else if (gain > 1)
					{
						calc2(lin, 0, len);
					}
				}

				//
				avgheadroom = avgheadroom * 0.99 + (double) headroom * 0.01;
				if (avgcnt++ > 300)
				{
					devheadroom = devheadroom * 0.999
							+ Math.pow(Math.abs(headroom - avgheadroom), 2)
							* 0.001;
				}
				
				//头大小
				if (headroom < 250 * mu)
				{
					late++;
					newjitter(true);
//					System.out.println("RTP:underflow "
//							+ (int) Math.sqrt(devheadroom));
					todo = jitter - headroom;
					write(lin2, 0, todo > BUFFER_SIZE ? BUFFER_SIZE : todo);
				}

				//
				if (cnt > 500 * mu && cnt2 < 2)
				{
					todo = headroom - jitter;
					if (todo < len)
					{
						write(lin, todo, len - todo);
					}
				} else
				{
					write(lin, 0, len);
				}

				//丢失包统计
				if (seq != 0)
				{
					getseq = gseq & 0xff;
					expseq = ++seq & 0xff;
					if (m == RtpStreamSender.m)
					{
						vm = m;
					}
					
					gap = (getseq - expseq) & 0xff;
					if (gap > 0)
					{
					//	System.out.println("RTP:lost");
						if (gap > 100)
						{
							gap = 1;
						}
						loss += gap;
						lost += gap;
						good += gap - 1;
						loss2++;
					} else
					{
						if (m < vm)
						{
							loss++;
							loss2++;
						}
					}
					good++;
					if (good > 110)
					{
						good *= 0.99;
						lost *= 0.99;
						loss *= 0.99;
						loss2 *= 0.99;
						late *= 0.99;
					}
				}
				m = 1;
				seq = gseq;

				if (user >= luser + 8000 * mu
						&& (Receiver.call_state == UserAgent.UA_STATE_INCALL || Receiver.call_state == UserAgent.UA_STATE_OUTGOING_CALL))
				{
					if (luser == -8000 * mu || getMode() != speakermode)
					{
						//保留声量
						saveVolume();
						
						//设置模式
						setMode(speakermode);
						
						//恢复声量
						restoreVolume();
					}
				
					luser = user;
					
					if (user >= luser2 + 160000 * mu)
					{
						//抖动
						newjitter(false);
					}
				}
				lserver = server;
			}
		}

再看下发送包是怎么实现的,发送声音肯定是先录制,后读取,再发送!~如下:

  1.     public void run()  
  2.     {  
  3.         //测试音频数据   
  4. //      testVoiceFile mvoiceFile = new testVoiceFile("voice");   
  5. //      testVoiceFile mvoiceRtpFile = new testVoiceFile("rtpdate");   
  6.           
  7.         //wifi管理   
  8.         WifiManager wm = (WifiManager) Receiver.mContext  
  9.                 .getSystemService(Context.WIFI_SERVICE);  
  10.         long lastscan = 0, lastsent = 0;  
  11.   
  12.         if (rtp_socket == null)  
  13.             return;  
  14.         int seqn = 0;  
  15.         long time = 0;  
  16.         double p = 0;  
  17.           
  18.         //改善   
  19.         boolean improve = PreferenceManager.getDefaultSharedPreferences(  
  20.                 Receiver.mContext).getBoolean(Settings.PREF_IMPROVE,  
  21.                 Settings.DEFAULT_IMPROVE);  
  22.           
  23.         //选择wifi   
  24.         boolean selectWifi = PreferenceManager.getDefaultSharedPreferences(  
  25.                 Receiver.mContext).getBoolean(  
  26.                 org.sipdroid.sipua.ui.Settings.PREF_SELECTWIFI,  
  27.                 org.sipdroid.sipua.ui.Settings.DEFAULT_SELECTWIFI);  
  28.           
  29.         int micgain = 0;  
  30.         long last_tx_time = 0;  
  31.         long next_tx_delay;  
  32.         long now;  
  33.         running = true;  
  34.         m = 1;  
  35.         int dtframesize = 4;  
  36.   
  37.         //改变线程权限   
  38.         android.os.Process  
  39.                 .setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);  
  40.           
  41.         //解码速率   
  42.         mu = p_type.codec.samp_rate() / 8000;  
  43.         int min = AudioRecord.getMinBufferSize(p_type.codec.samp_rate(),  
  44.                 AudioFormat.CHANNEL_CONFIGURATION_MONO,  
  45.                 AudioFormat.ENCODING_PCM_16BIT);  //最小缓冲大小   
  46.           
  47.         if (min == 640)  
  48.         {  
  49.             if (frame_size == 960)  
  50.                 frame_size = 320;  
  51.             if (frame_size == 1024)  
  52.                 frame_size = 160;  
  53.             min = 4096 * 3 / 2;  
  54.         } else if (min < 4096)  
  55.         {  
  56.             if (min <= 2048 && frame_size == 1024)  
  57.                 frame_size /= 2;  
  58.             min = 4096 * 3 / 2;  
  59.         } else if (min == 4096)  
  60.         {  
  61.             min *= 3 / 2;  
  62.             if (frame_size == 960)  
  63.                 frame_size = 320;  
  64.         } else  
  65.         {  
  66.             if (frame_size == 960)  
  67.                 frame_size = 320;  
  68.             if (frame_size == 1024)  
  69.                 frame_size *= 2;  
  70.         }  
  71.           
  72.         //速率   
  73.         frame_rate = p_type.codec.samp_rate() / frame_size;  
  74.         long frame_period = 1000 / frame_rate;  
  75.         frame_rate *= 1.5;  
  76.           
  77.         //发送包缓冲区   
  78.         byte[] buffer = new byte[frame_size + 12];  //   
  79.           
  80.         //实例化包   
  81.         RtpPacket rtp_packet = new RtpPacket(buffer, 0);  
  82.           
  83.         //设置有效复合   
  84.         rtp_packet.setPayloadType(p_type.number);  
  85.           
  86.         //调式输出信息   
  87.         if (DEBUG)  
  88.             println("Reading blocks of (读取块大小)" + buffer.length + " bytes");  
  89.   
  90.         println("Sample rate (采样率) = " + p_type.codec.samp_rate());  
  91.         println("Buffer size(缓冲区大小) = " + min);  
  92.   
  93.         //录制   
  94.         AudioRecord record = null;  
  95.   
  96.         //获得声音内容变量   
  97.         short[] lin = new short[frame_size * (frame_rate + 1)];  
  98.         int num, ring = 0, pos;  
  99.           
  100.         //随机数   
  101.         random = new Random();  
  102.           
  103.         //输入流   
  104.         InputStream alerting = null;  
  105.         try  
  106.         {  
  107.             //接受   
  108.             alerting = Receiver.mContext.getAssets().open("alerting");  
  109.         } catch (IOException e2)  
  110.         {  
  111.             if (!Sipdroid.release)  
  112.                 e2.printStackTrace();  
  113.         }  
  114.           
  115.         //初始化音频编码   
  116.         p_type.codec.init();  
  117.           
  118.         if(Sipdroid.VoiceDebug)  
  119.         {  
  120.             Log.i("RtpStreamSender""音频发送开始啦");  
  121.         }  
  122.           
  123.         //循环发送  先录制 然后发送   
  124.         while (running)  
  125.         {  
  126.             //录制没有 或已经改变   
  127.             if (changed || record == null)  
  128.             {  
  129.                 if (record != null)  
  130.                 {  
  131.                     //释放操作   
  132.                     record.stop();  
  133.                     record.release();  
  134.                     if (RtpStreamReceiver.samsung)  
  135.                     {  
  136.                         AudioManager am = (AudioManager) Receiver.mContext  
  137.                                 .getSystemService(Context.AUDIO_SERVICE);  
  138.                         am.setMode(AudioManager.MODE_IN_CALL);  
  139.                         am.setMode(AudioManager.MODE_NORMAL);  
  140.                     }  
  141.                 }  
  142.                   
  143.                 //未改变   
  144.                 changed = false;  
  145.                   
  146.                 //实例化录制   
  147.                 record = new AudioRecord(MediaRecorder.AudioSource.MIC,  
  148.                         p_type.codec.samp_rate(),  
  149.                         AudioFormat.CHANNEL_CONFIGURATION_MONO,  
  150.                         AudioFormat.ENCODING_PCM_16BIT, min);  
  151.                   
  152.                 if(Sipdroid.VoiceDebug)  
  153.                 {  
  154.                     Log.i("RtpStreamSender""构造音频录制实例");  
  155.                 }  
  156.                   
  157.                 //得到录制类型   
  158.                 if (record.getState() != AudioRecord.STATE_INITIALIZED)  
  159.                 {  
  160.                     //拒接   
  161.                     Receiver.engine(Receiver.mContext).rejectcall();  
  162.                     record = null;  
  163.                     break;  
  164.                 }  
  165.                   
  166.                 //开始录制   
  167.                 record.startRecording();  
  168.                   
  169.                 //计算   
  170.                 micgain = (int) (Settings.getMicGain() * 10);  
  171.             }  
  172.               
  173.               
  174.             //静音或挂断 则停止   
  175.             if (muted || Receiver.call_state == UserAgent.UA_STATE_HOLD)  
  176.             {  
  177.                 //挂断   
  178.                 if (Receiver.call_state == UserAgent.UA_STATE_HOLD)  
  179.                 {  
  180.                     //恢复模式   
  181.                     RtpStreamReceiver.restoreMode();  
  182.                 }  
  183.                   
  184.                 if(Sipdroid.VoiceDebug)  
  185.                 {  
  186.                     Log.i("RtpStreamSender""挂断电话则停止录制");  
  187.                 }  
  188.                   
  189.                 //停止录音   
  190.                 record.stop();  
  191.               
  192.                 //延时   
  193.                 while (running  
  194.                         && (muted || Receiver.call_state == UserAgent.UA_STATE_HOLD))  
  195.                 {  
  196.                     try  
  197.                     {  
  198.                         sleep(1000);  
  199.                     } catch (InterruptedException e1)  
  200.                     {  
  201.                     }  
  202.                 }  
  203.                   
  204.                 //开始录制   
  205.                 record.startRecording();  
  206.             }  
  207.               
  208.             // DTMF change start   
  209.             if (dtmf.length() != 0)  
  210.             {  
  211.                 //构造包   
  212.                 byte[] dtmfbuf = new byte[dtframesize + 12];  
  213.                 RtpPacket dt_packet = new RtpPacket(dtmfbuf, 0);  
  214.                   
  215.                 //设置有效负荷   
  216.                 dt_packet.setPayloadType(dtmf_payload_type);  
  217.                   
  218.                 //设置大小   
  219.                 dt_packet.setPayloadLength(dtframesize);  
  220.                 dt_packet.setSscr(rtp_packet.getSscr());  
  221.                 long dttime = time;  
  222.                 int duration;  
  223.   
  224.                 for (int i = 0; i < 6; i++)  
  225.                 {  
  226.                     time += 160;  
  227.                     duration = (int) (time - dttime);  
  228.                     dt_packet.setSequenceNumber(seqn++);  
  229.                     dt_packet.setTimestamp(dttime);  
  230.                     dtmfbuf[12] = rtpEventMap.get(dtmf.charAt(0));  
  231.                     dtmfbuf[13] = (byte0x0a;  
  232.                     dtmfbuf[14] = (byte) (duration >> 8);  
  233.                     dtmfbuf[15] = (byte) duration;  
  234.                     try  
  235.                     {  
  236.                         //发送包 声音包   
  237.                         rtp_socket.send(dt_packet);  
  238.                           
  239.                         if (Sipdroid.VoiceDebug)  
  240.                         {  
  241.                             Log.i("RtpStreamSender",  
  242.                                     "第一次发送声音包  大小" + dt_packet.getLength()  
  243.                                             + " " + dt_packet.getPacket());  
  244.                         }  
  245.                           
  246.                         if(bShowVoiceDecodeData)  
  247.                         {  
  248. //                          mvoiceRtpFile.write(dt_packet.getPacket());   
  249.                         }  
  250.   
  251.                         sleep(20);  
  252.                     } catch (Exception e1)  
  253.                     {  
  254.                     }  
  255.                 }  
  256.                   
  257.                 //发送回音?   
  258.                 for (int i = 0; i < 3; i++)  
  259.                 {  
  260.                     duration = (int) (time - dttime);  
  261.                     dt_packet.setSequenceNumber(seqn);  
  262.                     dt_packet.setTimestamp(dttime);  
  263.                     dtmfbuf[12] = rtpEventMap.get(dtmf.charAt(0));  
  264.                     dtmfbuf[13] = (byte0x8a;  
  265.                     dtmfbuf[14] = (byte) (duration >> 8);  
  266.                     dtmfbuf[15] = (byte) duration;  
  267.                     try  
  268.                     {  
  269.                         //发送包   
  270.                         rtp_socket.send(dt_packet);  
  271.                           
  272.                         if (Sipdroid.VoiceDebug)  
  273.                         {  
  274.                             Log.i("RtpStreamSender",  
  275.                                     "第二次发送声音包  大小" + dt_packet.getLength()  
  276.                                             + " " + dt_packet.getPacket());  
  277.                         }  
  278.                           
  279.                         if(bShowVoiceDecodeData)  
  280.                         {  
  281. //                          mvoiceRtpFile.write(dt_packet.getPacket());   
  282.                         }  
  283.                     } catch (Exception e1)  
  284.                     {  
  285.                     }  
  286.                 }  
  287.                 time += 160;  
  288.                 seqn++;  
  289.                 dtmf = dtmf.substring(1);  
  290.             }  
  291.             // DTMF change end   
  292.   
  293.             if (frame_size < 480)  
  294.             {  
  295.                 now = System.currentTimeMillis();  
  296.                 next_tx_delay = frame_period - (now - last_tx_time);  
  297.                 last_tx_time = now;  
  298.                 if (next_tx_delay > 0)  
  299.                 {  
  300.                     try  
  301.                     {  
  302.                         sleep(next_tx_delay);  
  303.                     } catch (InterruptedException e1)  
  304.                     {  
  305.                     }  
  306.                     last_tx_time += next_tx_delay - sync_adj;  
  307.                 }  
  308.             }  
  309.               
  310.             //获得发送的位置   
  311.             pos = (ring + delay * frame_rate * frame_size)  
  312.                     % (frame_size * (frame_rate + 1));  
  313.               
  314.             //得到大小   
  315.             num = record.read(lin, pos, frame_size);  
  316.               
  317.             if (num <= 0)  
  318.                 continue;  
  319.               
  320.             //是否有效   
  321.             if (!p_type.codec.isValid())  
  322.                 continue;  
  323.   
  324.             // Call recording: Save the frame to the CallRecorder.   
  325.             //通话记录:框架保存的CallRecorder的。  新的录制    
  326.             if (call_recorder != null)  
  327.             {  
  328.                 //写入 输出   
  329.                 call_recorder.writeOutgoing(lin, pos, num);  
  330.             }  
  331.   
  332.             if (RtpStreamReceiver.speakermode == AudioManager.MODE_NORMAL)  
  333.             {  
  334.                 calc(lin, pos, num);  
  335.                 if (RtpStreamReceiver.nearend != 0  
  336.                         && RtpStreamReceiver.down_time == 0)  
  337.                 {  
  338.                     noise(lin, pos, num, p / 2);  
  339.                 }  
  340.                 else if (nearend == 0)  
  341.                 {  
  342.                     p = 0.9 * p + 0.1 * s;  
  343.                 }  
  344.             } else  
  345.             {  
  346.                 switch (micgain)  
  347.                 {  
  348.                 case 1:  
  349.                     calc1(lin, pos, num);  
  350.                     break;  
  351.                 case 2:  
  352.                     calc2(lin, pos, num);  
  353.                     break;  
  354.                 case 10:  
  355.                     calc10(lin, pos, num);  
  356.                     break;  
  357.                 }  
  358.             }  
  359.               
  360.             iCount++;  
  361.               
  362.             //通话中   
  363.             if (Receiver.call_state != UserAgent.UA_STATE_INCALL  
  364.                     && Receiver.call_state != UserAgent.UA_STATE_OUTGOING_CALL  
  365.                     && alerting != null)  
  366.             {  
  367.                 try  
  368.                 {  
  369.                     if (alerting.available() < num / mu)  
  370.                     {  
  371.                         alerting.reset();  
  372.                     }  
  373.                     alerting.read(buffer, 12, num / mu);  
  374.                 } catch (IOException e)  
  375.                 {  
  376.                     if (!Sipdroid.release)  
  377.                     {  
  378.                         e.printStackTrace();  
  379.                     }  
  380.                 }  
  381.                 if (p_type.codec.number() != 8)  
  382.                 {  
  383.                     G711.alaw2linear(buffer, lin, num, mu);  
  384.                     num = p_type.codec.encode(lin, 0, buffer, num);  
  385.                       
  386. //                  if(bShowVoiceDecodeData)   
  387. //                  {   
  388. //                      byte[] sdf = lin.toString().getBytes();   
  389. //                      mvoiceFile.write(sdf);   
  390. //                         
  391. //                      String string = "";   
  392. //                         
  393. //                      for(short i:buffer)   
  394. //                          string+=i;   
  395. //                                 
  396. //                      Log.i("p_type.codec.encode",iCount +"编码后的数据(buffer):"+string);   
  397. //                  }   
  398.                 }  
  399.             } else  
  400.             {  
  401.                 num = p_type.codec.encode(lin, ring  
  402.                         % (frame_size * (frame_rate + 1)), buffer, num); //进行了编码   
  403.                   
  404. //              if(bShowVoiceDecodeData)   
  405. //              {   
  406. //                  mvoiceFile.write(buffer);   
  407. //                     
  408. //                  String string = "";   
  409. //                     
  410. //                  for(short i:buffer)   
  411. //                      string+=i;   
  412. //                             
  413. //                  Log.i("p_type.codec.encode",iCount +"编码后的数据(buffer):"+string);   
  414. //              }   
  415.             }  
  416.               
  417.               
  418.   
  419.             //大小   
  420.             ring += frame_size;  
  421.             rtp_packet.setSequenceNumber(seqn++);  
  422.             rtp_packet.setTimestamp(time);  
  423.             rtp_packet.setPayloadLength(num);  
  424.               
  425.             //记录时间   
  426.             now = SystemClock.elapsedRealtime();              
  427.               
  428.             if (RtpStreamReceiver.timeout == 0 || Receiver.on_wlan  
  429.                     || now - lastsent > 500)  
  430.             {  
  431.                 try  
  432.                 {  
  433.                     lastsent = now;  
  434.                     rtp_socket.send(rtp_packet);  
  435.                   
  436.                     if (m > 1  
  437.                             && (RtpStreamReceiver.timeout == 0 || Receiver.on_wlan))  
  438.                     {  
  439.                         for (int i = 1; i < m; i++)  
  440.                             rtp_socket.send(rtp_packet);  
  441.                     }  
  442.                       
  443.                     if (Sipdroid.VoiceDebug)  
  444.                     {  
  445.                         Log.i("RtpStreamSender",  
  446.                                 "第三次发送声音包  大小" + rtp_packet.getLength()  
  447.                                         + " " + rtp_packet.getPacket());  
  448.                     }  
  449.                       
  450. //                  if(bShowVoiceDecodeData)   
  451. //                  {   
  452. //                      mvoiceRtpFile.write(rtp_packet.getPacket());   
  453. //                  }   
  454.                 } catch (Exception e)  
  455.                 {  
  456.                 }  
  457.             }  
  458.               
  459.             //编码数   
  460.             if (p_type.codec.number() == 9)  
  461.             {  
  462.                 time += frame_size / 2;  
  463.             }  
  464.             else  
  465.             {  
  466.                 time += frame_size;  
  467.             }  
  468.               
  469.             if (RtpStreamReceiver.good != 0  
  470.                     && RtpStreamReceiver.loss2 / RtpStreamReceiver.good > 0.01)  
  471.             {  
  472.                 if (selectWifi && Receiver.on_wlan && now - lastscan > 10000)  
  473.                 {  
  474.                     wm.startScan();  
  475.                     lastscan = now;  
  476.                 }  
  477.                 if (improve  
  478.                         && delay == 0  
  479.                         && (p_type.codec.number() == 0  
  480.                                 || p_type.codec.number() == 8 || p_type.codec  
  481.                                 .number() == 9))  
  482.                 {  
  483.                     m = 2;  
  484.                 }  
  485.                 else  
  486.                 {  
  487.                     m = 1;  
  488.                 }  
  489.             } else  
  490.             {  
  491.                 m = 1;  
  492.             }  
  493.         }  
	public void run()
	{
		//测试音频数据
//		testVoiceFile mvoiceFile = new testVoiceFile("voice");
//		testVoiceFile mvoiceRtpFile = new testVoiceFile("rtpdate");
		
		//wifi管理
		WifiManager wm = (WifiManager) Receiver.mContext
				.getSystemService(Context.WIFI_SERVICE);
		long lastscan = 0, 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);
		
		//选择wifi
		boolean selectWifi = PreferenceManager.getDefaultSharedPreferences(
				Receiver.mContext).getBoolean(
				org.sipdroid.sipua.ui.Settings.PREF_SELECTWIFI,
				org.sipdroid.sipua.ui.Settings.DEFAULT_SELECTWIFI);
		
		int micgain = 0;
		long last_tx_time = 0;
		long next_tx_delay;
		long now;
		running = true;
		m = 1;
		int dtframesize = 4;

		//改变线程权限
		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 *= 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 + 1)];
		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();
		
		if(Sipdroid.VoiceDebug)
		{
			Log.i("RtpStreamSender", "音频发送开始啦");
		}
		
		//循环发送  先录制 然后发送
		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.MIC,
						p_type.codec.samp_rate(),
						AudioFormat.CHANNEL_CONFIGURATION_MONO,
						AudioFormat.ENCODING_PCM_16BIT, min);
				
				if(Sipdroid.VoiceDebug)
				{
					Log.i("RtpStreamSender", "构造音频录制实例");
				}
				
				//得到录制类型
				if (record.getState() != AudioRecord.STATE_INITIALIZED)
				{
					//拒接
					Receiver.engine(Receiver.mContext).rejectcall();
					record = null;
					break;
				}
				
				//开始录制
				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();
				}
				
				if(Sipdroid.VoiceDebug)
				{
					Log.i("RtpStreamSender", "挂断电话则停止录制");
				}
				
				//停止录音
				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);
						
						if (Sipdroid.VoiceDebug)
						{
							Log.i("RtpStreamSender",
									"第一次发送声音包  大小" + dt_packet.getLength()
											+ " " + dt_packet.getPacket());
						}
						
						if(bShowVoiceDecodeData)
						{
//							mvoiceRtpFile.write(dt_packet.getPacket());
						}

						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);
						
						if (Sipdroid.VoiceDebug)
						{
							Log.i("RtpStreamSender",
									"第二次发送声音包  大小" + dt_packet.getLength()
											+ " " + dt_packet.getPacket());
						}
						
						if(bShowVoiceDecodeData)
						{
//							mvoiceRtpFile.write(dt_packet.getPacket());
						}
					} 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 = (ring + delay * frame_rate * frame_size)
					% (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.
			//通话记录:框架保存的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;
				}
			}
			
			iCount++;
			
			//通话中
			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);
					
//					if(bShowVoiceDecodeData)
//					{
//						byte[] sdf = lin.toString().getBytes();
//						mvoiceFile.write(sdf);
//						
//						String string = "";
//						
//						for(short i:buffer)
//							string+=i;
//								
//						Log.i("p_type.codec.encode",iCount +"编码后的数据(buffer):"+string);
//					}
				}
			} else
			{
				num = p_type.codec.encode(lin, ring
						% (frame_size * (frame_rate + 1)), buffer, num); //进行了编码
				
//				if(bShowVoiceDecodeData)
//				{
//					mvoiceFile.write(buffer);
//					
//					String string = "";
//					
//					for(short i:buffer)
//						string+=i;
//							
//					Log.i("p_type.codec.encode",iCount +"编码后的数据(buffer):"+string);
//				}
			}
			
			

			//大小
			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);
					}
					
					if (Sipdroid.VoiceDebug)
					{
						Log.i("RtpStreamSender",
								"第三次发送声音包  大小" + rtp_packet.getLength()
										+ " " + rtp_packet.getPacket());
					}
					
//					if(bShowVoiceDecodeData)
//					{
//						mvoiceRtpFile.write(rtp_packet.getPacket());
//					}
				} catch (Exception e)
				{
				}
			}
			
			//编码数
			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 (selectWifi && Receiver.on_wlan && now - lastscan > 10000)
				{
					wm.startScan();
					lastscan = now;
				}
				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;
			}
		}

好了,进入下一个问题,它的视频又是怎么一回事?此处不谈它的视频编码,直接介绍涉及它的流程!~

涉及视频的类有:VideoCamera、VideoCameraNew、VideoCameraNew2、VideoPreview!~ 而是否使用视频,关键在CallScreen类,CallScreen类是通话的界面!~

如下是否使用视频的代码,该代码在CallScreen中!~

  1. //是否开启视频流程关键地方     必须是在 电话中并且端口等设置正确    
  2. if (Receiver.call_state == UserAgent.UA_STATE_INCALL  
  3.         && socket == null  
  4.         && Receiver.engine(mContext).getLocalVideo() != 0  
  5.         && Receiver.engine(mContext).getRemoteVideo() != 0  
  6.         && PreferenceManager  
  7.                 .getDefaultSharedPreferences(this)  
  8.                 .getString(org.sipdroid.sipua.ui.Settings.PREF_SERVER,  
  9.                         org.sipdroid.sipua.ui.Settings.DEFAULT_SERVER)  
  10.                 .equals(org.sipdroid.sipua.ui.Settings.DEFAULT_SERVER))  
  11. {  
  12.     (new Thread()  
  13.     {  
  14.         public void run()  
  15.         {                     
  16.             // 视频包 在线包   
  17.             RtpPacket keepalive = new RtpPacket(new byte[12], 0);  
  18.             RtpPacket videopacket = new RtpPacket(new byte[1000], 0);  
  19.   
  20.             try  
  21.             {  
  22.                 if (intent == null || rtp_socket == null)  
  23.                 {  
  24.                     // 新建一个套接字   
  25.                     rtp_socket = new RtpSocket(  
  26.   
  27.                     // 初始化套接字   
  28.                             socket = new SipdroidSocket(Receiver  
  29.                                     .engine(mContext).getLocalVideo()),  
  30.   
  31.                             // 设置网络地址   
  32.                             InetAddress.getByName(Receiver.engine(  
  33.                                     mContext).getRemoteAddr()),  
  34.   
  35.                             // 接受远程视频   
  36.                             Receiver.engine(mContext).getRemoteVideo());  
  37.                     sleep(3000);  
  38.                 } else  
  39.                 {  
  40.                     // 接受数据   
  41.                     socket = rtp_socket.getDatagramSocket();  
  42.                 }  
  43.                 // 接受数据   
  44.                 rtp_socket.getDatagramSocket().setSoTimeout(15000);  
  45.             } catch (Exception e)  
  46.             {  
  47.                 if (!Sipdroid.release)  
  48.                 {  
  49.                     e.printStackTrace();  
  50.                 }  
  51.                 return;  
  52.             }  
  53.   
  54.             // 设置有效载荷类型   
  55.             keepalive.setPayloadType(126);  
  56.   
  57.             try  
  58.             {  
  59.                 // 发送数据   
  60.                 rtp_socket.send(keepalive);  
  61.             } catch (Exception e1)  
  62.             {  
  63.                 return;  
  64.             }  
  65.             for (;;)  
  66.             {  
  67.                 try  
  68.                 {  
  69.                     // 循环接收数据   
  70.                     rtp_socket.receive(videopacket);  
  71.                 } catch (IOException e)  
  72.                 {  
  73.                     // 异常则断开   
  74.                     rtp_socket.getDatagramSocket().disconnect();  
  75.                     try  
  76.                     {  
  77.                         // 发送在线包   
  78.                         rtp_socket.send(keepalive);  
  79.                     } catch (IOException e1)  
  80.                     {  
  81.                         return;  
  82.                     }  
  83.                 }  
  84.   
  85.                 // 得到有效负荷长度   
  86.                 if (videopacket.getPayloadLength() > 200)  
  87.                 {  
  88.                     if (intent != null)  
  89.                     {  
  90.                         // 发送数据   
  91.                         intent.putExtra("justplay"true);  
  92.                         mHandler.sendEmptyMessage(0);  
  93.                     } else  
  94.                     {  
  95.                         // 否则播放   
  96.                         Intent i = new Intent(mContext,  
  97.                                 org.sipdroid.sipua.ui.VideoCamera.class);  
  98.                         i.putExtra("justplay"true);  
  99.                         startActivity(i);  
  100.                     }  
  101.                     return;  
  102.                 }  
  103.             }  
  104.         }  
  105.     }).start();  
  106. }  
		//是否开启视频流程关键地方     必须是在 电话中并且端口等设置正确 
		if (Receiver.call_state == UserAgent.UA_STATE_INCALL
				&& socket == null
				&& Receiver.engine(mContext).getLocalVideo() != 0
				&& Receiver.engine(mContext).getRemoteVideo() != 0
				&& PreferenceManager
						.getDefaultSharedPreferences(this)
						.getString(org.sipdroid.sipua.ui.Settings.PREF_SERVER,
								org.sipdroid.sipua.ui.Settings.DEFAULT_SERVER)
						.equals(org.sipdroid.sipua.ui.Settings.DEFAULT_SERVER))
		{
			(new Thread()
			{
				public void run()
				{					
					// 视频包 在线包
					RtpPacket keepalive = new RtpPacket(new byte[12], 0);
					RtpPacket videopacket = new RtpPacket(new byte[1000], 0);

					try
					{
						if (intent == null || rtp_socket == null)
						{
							// 新建一个套接字
							rtp_socket = new RtpSocket(

							// 初始化套接字
									socket = new SipdroidSocket(Receiver
											.engine(mContext).getLocalVideo()),

									// 设置网络地址
									InetAddress.getByName(Receiver.engine(
											mContext).getRemoteAddr()),

									// 接受远程视频
									Receiver.engine(mContext).getRemoteVideo());
							sleep(3000);
						} else
						{
							// 接受数据
							socket = rtp_socket.getDatagramSocket();
						}
						// 接受数据
						rtp_socket.getDatagramSocket().setSoTimeout(15000);
					} catch (Exception e)
					{
						if (!Sipdroid.release)
						{
							e.printStackTrace();
						}
						return;
					}

					// 设置有效载荷类型
					keepalive.setPayloadType(126);

					try
					{
						// 发送数据
						rtp_socket.send(keepalive);
					} catch (Exception e1)
					{
						return;
					}
					for (;;)
					{
						try
						{
							// 循环接收数据
							rtp_socket.receive(videopacket);
						} catch (IOException e)
						{
							// 异常则断开
							rtp_socket.getDatagramSocket().disconnect();
							try
							{
								// 发送在线包
								rtp_socket.send(keepalive);
							} catch (IOException e1)
							{
								return;
							}
						}

						// 得到有效负荷长度
						if (videopacket.getPayloadLength() > 200)
						{
							if (intent != null)
							{
								// 发送数据
								intent.putExtra("justplay", true);
								mHandler.sendEmptyMessage(0);
							} else
							{
								// 否则播放
								Intent i = new Intent(mContext,
										org.sipdroid.sipua.ui.VideoCamera.class);
								i.putExtra("justplay", true);
								startActivity(i);
							}
							return;
						}
					}
				}
			}).start();
		}

之后就进入到涉及视频的类VideoCamera中了!~
它在模拟器上的端口为什么总是变化的?
抓包分析下,如图:



yate服务端第一次记录了我的rport为1849,从图中发现它是与服务器通信的端口!~服务器中也把它当做端口记录!~而SipUA客户端是使用了UDP套接字自定义了一个37850端口,这个端口一直到退出才改变,而yate服务端第一次记录了我的rport为2251,也就是说服务器记录的rport的端口是一直在发生改变的!~所以下次用户拨打对方,向服务器索取对方信息时出错,就有可能会直接挂掉!~

rport在Sip中的定义是rport方式主要是对sip信令中Via字头的扩展,不过同时也要求SIP Proxy支持该功能。NAT之后的sip client在发送请求的时候在via字头中添加rport字段,该消息经发出后路由到SIP Proxy,SIP Proxy通过检查消息的源地址和Via字段中的地址,得知该client处于NAT之后,并且基于已有的rport,将消息的真实地址即公网上的地址通过received和rport字段返回给client端,这样client就知道自己真实的公网地址,可以解决信令穿越的问题。
而有网友提出,使用Android模拟器通过路由器时端口会发生变化!~ 不知道这是不是真的!


它又是如何处理登陆超时以及通话出错的?
这就涉及到封装处理Sip协议的类了!~涉及的类不多,感兴趣的童鞋就自己研究了,我累了!~

有些问题需要讨论!~~欢迎高手指点!~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值