仿飞鸽传书的Android版本

1. 网络应用中基本上都是TCP(Transmission Control Protocol传输控制协议)和UDP

(User Datagram Protocol用户数据报协议),TCP是面向连接的通信协议,UDP是无连接的通信协议.
Socket连接套接字,Java分别为TCP和UDP提供了相应的类,TCP是java.net.ServerSocket(用于服务器端)
和java.net.Socket(用于客户端);UDP是java.net.DatagramSocket

2. 两台主机之间的点对点通信,称为“单播 Unicast”。当多台主机同时接受一个数据报时,
若采用单播通信,则源主机需要给每个接收主机发送一个相同的数据报;若采用组播通信,
则源主机只需要发送一个数据报即可到达每个接收主机,从而节省了网络带宽,降低了
发送主机的负荷。

3. 组播 Multicast是一种特殊的数据报传输方式,它将具有相同需求的主机加入到某一个组,向

组发送的信息,其所有成员均可接收到。

- 组是用组播地址(D类IP地址:224.0.0.0 - 239.255.255.255)和标准UDP端口号来标识的,

即待发送的数据报的目的地址为一个组播地址。主机可以申请加入某个组播地址所标识

的组,也可以从该组中退出。



程序源代码:

http://download.csdn.net/detail/thinkinwm/6524085


命令定义

1.命令定义     80        用户注册

2.命令定义     81        短消息

3.命令定义     82        文件传输


package com.android.flypigeon.util;

import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import com.android.flypigeon.R;

public class Constant {

	public static Map<String, Integer> exts = new HashMap<String, Integer>();
	static {
		exts.put("doc", R.drawable.doc);
		exts.put("docx", R.drawable.doc);
		exts.put("xls", R.drawable.xls);
		exts.put("xlsx", R.drawable.xls);
		exts.put("ppt", R.drawable.ppt);
		exts.put("pptx", R.drawable.ppt);
		exts.put("jpg", R.drawable.image);
		exts.put("jpeg", R.drawable.image);
		exts.put("gif", R.drawable.image);
		exts.put("png", R.drawable.image);
		exts.put("ico", R.drawable.image);
		exts.put("apk", R.drawable.apk);
		exts.put("jar", R.drawable.jar);
		exts.put("rar", R.drawable.rar);
		exts.put("zip", R.drawable.rar);
		exts.put("mp3", R.drawable.music);
		exts.put("wma", R.drawable.music);
		exts.put("aac", R.drawable.music);
		exts.put("ac3", R.drawable.music);
		exts.put("ogg", R.drawable.music);
		exts.put("flac", R.drawable.music);
		exts.put("midi", R.drawable.music);
		exts.put("pcm", R.drawable.music);
		exts.put("wav", R.drawable.music);
		exts.put("amr", R.drawable.music);
		exts.put("m4a", R.drawable.music);
		exts.put("ape", R.drawable.music);
		exts.put("mid", R.drawable.music);
		exts.put("mka", R.drawable.music);
		exts.put("svx", R.drawable.music);
		exts.put("snd", R.drawable.music);
		exts.put("vqf", R.drawable.music);
		exts.put("aif", R.drawable.music);
		exts.put("voc", R.drawable.music);
		exts.put("cda", R.drawable.music);
		exts.put("mpc", R.drawable.music);
		exts.put("mpeg", R.drawable.video);
		exts.put("mpg", R.drawable.video);
		exts.put("dat", R.drawable.video);
		exts.put("ra", R.drawable.video);
		exts.put("rm", R.drawable.video);
		exts.put("rmvb", R.drawable.video);
		exts.put("mp4", R.drawable.video);
		exts.put("flv", R.drawable.video);
		exts.put("mov", R.drawable.video);
		exts.put("qt", R.drawable.video);
		exts.put("asf", R.drawable.video);
		exts.put("wmv", R.drawable.video);
		exts.put("avi", R.drawable.video);
		exts.put("3gp", R.drawable.video);
		exts.put("mkv", R.drawable.video);
		exts.put("f4v", R.drawable.video);
		exts.put("m4v", R.drawable.video);
		exts.put("m4p", R.drawable.video);
		exts.put("m2v", R.drawable.video);
		exts.put("dat", R.drawable.video);
		exts.put("xvid", R.drawable.video);
		exts.put("divx", R.drawable.video);
		exts.put("vob", R.drawable.video);
		exts.put("mpv", R.drawable.video);
		exts.put("mpeg4", R.drawable.video);
		exts.put("mpe", R.drawable.video);
		exts.put("mlv", R.drawable.video);
		exts.put("ogm", R.drawable.video);
		exts.put("m2ts", R.drawable.video);
		exts.put("mts", R.drawable.video);
		exts.put("ask", R.drawable.video);
		exts.put("trp", R.drawable.video);
		exts.put("tp", R.drawable.video);
		exts.put("ts", R.drawable.video);
	}

	// 自定义Action
	public static final String updateMyInformationAction = "com.android.flypigeon.updateMyInformation";
	public static final String personHasChangedAction = "com.android.flypigeon.personHasChanged";
	public static final String hasMsgUpdatedAction = "com.android.flypigeon.hasMsgUpdated";
	public static final String receivedSendFileRequestAction = "com.android.flypigeon.receivedSendFileRequest";
	public static final String refuseReceiveFileAction = "com.android.flypigeon.refuseReceiveFile";
	public static final String remoteUserRefuseReceiveFileAction = "com.android.flypigeon.remoteUserRefuseReceiveFile";
	public static final String dataReceiveErrorAction = "com.android.flypigeon.dataReceiveError";
	public static final String dataSendErrorAction = "com.android.flypigeon.dataSendError";
	public static final String whoIsAliveAction = "com.android.flypigeon.whoIsAlive";// 询问当前那个Activity是激活状态
	public static final String imAliveNow = "com.android.flypigeon.imAliveNow";
	public static final String remoteUserUnAliveAction = "com.android.flypigeon.remoteUserUnAlive";
	public static final String fileSendStateUpdateAction = "com.android.flypigeon.fileSendStateUpdate";
	public static final String fileReceiveStateUpdateAction = "com.android.flypigeon.fileReceiveStateUpdate";
	public static final String receivedTalkRequestAction = "com.android.flypigeon.receivedTalkRequest";
	public static final String acceptTalkRequestAction = "com.android.flypigeon.acceptTalkRequest";
	public static final String remoteUserClosedTalkAction = "com.android.flypigeon.remoteUserClosedTalk";

	// 系统Action
	// System Action declare
	public static final String bootCompleted = "android.intent.action.BOOT_COMPLETED";
	public static final String WIFIACTION = "android.net.conn.CONNECTIVITY_CHANGE";
	public static final String ETHACTION = "android.intent.action.ETH_STATE";

	// 生成唯一ID码
	public static int getMyId() {
		int id = (int) (Math.random() * 1000000);
		return id;
	}

	// other 其它定义,另外消息长度为60个汉字,utf-8中定义一个汉字占3个字节,所以消息长度为180bytes
	// 文件长度为30个汉字,所以总长度为90个字节
	public static final int bufferSize = 256;
	public static final int msgLength = 180;
	public static final int fileNameLength = 90;
	public static final int readBufferSize = 4096;// 文件读写缓存
	public static final byte[] pkgHead = "AND".getBytes();
	public static final int CMD80 = 80;
	public static final int CMD81 = 81;
	public static final int CMD82 = 82;
	public static final int CMD83 = 83;
	public static final int CMD_TYPE1 = 1;
	public static final int CMD_TYPE2 = 2;
	public static final int CMD_TYPE3 = 3;
	public static final int OPR_CMD1 = 1;
	public static final int OPR_CMD2 = 2;
	public static final int OPR_CMD3 = 3;
	public static final int OPR_CMD4 = 4;
	public static final int OPR_CMD5 = 5;
	public static final int OPR_CMD6 = 6;
	public static final int OPR_CMD10 = 10;
	public static final String MULTICAST_IP = "239.9.9.1";
	public static final int PORT = 5760;
	public static final int AUDIO_PORT = 5761;

	// int to ip转换
	public static String intToIp(int i) {
		String ip = ((i >> 24) & 0xFF) + "." + ((i >> 16) & 0xFF) + "."
				+ ((i >> 8) & 0xFF) + "." + (i & 0xFF);

		return ip;
	}

	// 其它定义
	public static final int FILE_RESULT_CODE = 1;
	public static final int SELECT_FILES = 1;// 是否要在文件选择器中显示文件
	public static final int SELECT_FILE_PATH = 2;// 文件选择器只显示文件夹
	// 文件选择状态保存
	public static TreeMap<Integer, Boolean> fileSelectedState = new TreeMap<Integer, Boolean>();

	// 转换文件大小
	public static String formatFileSize(long fileS) {
		DecimalFormat df = new DecimalFormat("#.00");
		String fileSizeString = "";
		if (fileS < 1024) {
			fileSizeString = fileS + "B";
			// fileSizeString = df.format((double) fileS) + "B";
		} else if (fileS < 1048576) {
			fileSizeString = df.format((double) fileS / 1024) + "K";
		} else if (fileS < 1073741824) {
			fileSizeString = df.format((double) fileS / 1048576) + "M";
		} else {
			fileSizeString = df.format((double) fileS / 1073741824) + "G";
		}
		return fileSizeString;
	}

}


package com.android.flypigeon.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.android.flypigeon.R;
import com.android.flypigeon.util.ByteAndInt;
import com.android.flypigeon.util.Constant;
import com.android.flypigeon.util.FileName;
import com.android.flypigeon.util.FileState;
import com.android.flypigeon.util.Message;
import com.android.flypigeon.util.Person;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.IBinder;
import android.preference.PreferenceManager;

public class MainService extends Service {
	private ServiceBinder sBinder = new ServiceBinder();// 服务绑定器
	private static ArrayList<Map<Integer, Person>> children = new ArrayList<Map<Integer, Person>>();// 保存所有组中的用户,每个map对象保存一个组的全部用户
	private static Map<Integer, Person> childrenMap = new HashMap<Integer, Person>();// 当前在线用户
	private static ArrayList<Integer> personKeys = new ArrayList<Integer>();// 当前在线用户id
	private static Map<Integer, List<Message>> msgContainer = new HashMap<Integer, List<Message>>();// 所有用户信息容器
	private SharedPreferences pre = null;
	private SharedPreferences.Editor editor = null;
	private WifiManager wifiManager = null;
	private ServiceBroadcastReceiver receiver = null;
	private InetAddress localInetAddress = null;
	private String localIp = null;
	private byte[] localIpBytes = null;
	private byte[] regBuffer = new byte[Constant.bufferSize];// 本机网络注册交互指令
	private byte[] msgSendBuffer = new byte[Constant.bufferSize];// 信息发送交互
	private byte[] fileSendBuffer = new byte[Constant.bufferSize];// 文件发送交互指令
	private byte[] talkCmdBuffer = new byte[Constant.bufferSize];// 通话指令
	private static Person me = null;// 用来保存自身的相关信息
	private CommunicationBridge comBridge = null;// 通讯与协议解析模块

	@Override
	public IBinder onBind(Intent arg0) {
		return sBinder;
	}

	@Override
	public boolean onUnbind(Intent intent) {
		return false;
	}

	@Override
	public void onRebind(Intent intent) {

	}

	@Override
	public void onCreate() {

	}

	@Override
	public void onStart(Intent intent, int startId) {
		initCmdBuffer();// 初始化指令缓存
		wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
		new CheckNetConnectivity().start();// 侦测网络状态,获取IP地址

		comBridge = new CommunicationBridge();// 启动socket连接
		comBridge.start();

		pre = PreferenceManager.getDefaultSharedPreferences(this);
		editor = pre.edit();

		regBroadcastReceiver();// 注册广播接收器
		getMyInfomation();// 获得自身信息
		new UpdateMe().start();// 向网络发送心跳包,并注册
		new CheckUserOnline().start();// 检查用户列表是否有超时用户
		sendPersonHasChangedBroadcast();// 通知有新用户加入或退出
		System.out.println("Service started...");
	}

	// 服务绑定
	public class ServiceBinder extends Binder {
		public MainService getService() {
			return MainService.this;
		}
	}

	// 获得自已的相关信息
	private void getMyInfomation() {
		SharedPreferences pre = PreferenceManager
				.getDefaultSharedPreferences(this);
		int iconId = pre.getInt("headIconId", R.drawable.black_bird);
		String nickeName = pre.getString("nickeName", "Zhang San");
		int myId = pre.getInt("myId", Constant.getMyId());
		editor.putInt("myId", myId);
		editor.commit();

		if (null == me)
			me = new Person();
		me.personHeadIconId = iconId;
		me.personNickeName = nickeName;
		me.personId = myId;
		me.ipAddress = localIp;

		// 更新注册命令用户数据
		System.arraycopy(ByteAndInt.int2ByteArray(myId), 0, regBuffer, 6, 4);
		System.arraycopy(ByteAndInt.int2ByteArray(iconId), 0, regBuffer, 10, 4);
		for (int i = 14; i < 44; i++)
			regBuffer[i] = 0;// 把原来的昵称内容清空
		byte[] nickeNameBytes = nickeName.getBytes();
		System.arraycopy(nickeNameBytes, 0, regBuffer, 14,
				nickeNameBytes.length);

		// 更新通话命令用户数据
		System.arraycopy(ByteAndInt.int2ByteArray(myId), 0, talkCmdBuffer, 6, 4);
		System.arraycopy(ByteAndInt.int2ByteArray(iconId), 0, talkCmdBuffer,
				10, 4);
		for (int i = 14; i < 44; i++)
			talkCmdBuffer[i] = 0;// 把原来的昵称内容清空
		System.arraycopy(nickeNameBytes, 0, talkCmdBuffer, 14,
				nickeNameBytes.length);
	}

	private String getCurrentTime() {
		Date date = new Date();
		return date.toLocaleString();
	}

	// 检测网络连接状态,获得本机IP地址
	private class CheckNetConnectivity extends Thread {
		public void run() {
			try {
				if (!wifiManager.isWifiEnabled()) {
					wifiManager.setWifiEnabled(true);
				}

				for (Enumeration<NetworkInterface> en = NetworkInterface
						.getNetworkInterfaces(); en.hasMoreElements();) {
					NetworkInterface intf = en.nextElement();
					for (Enumeration<InetAddress> enumIpAddr = intf
							.getInetAddresses(); enumIpAddr.hasMoreElements();) {
						InetAddress inetAddress = enumIpAddr.nextElement();
						if (!inetAddress.isLoopbackAddress()) {
							if (inetAddress.isReachable(1000)) {
								localInetAddress = inetAddress;
								localIp = inetAddress.getHostAddress()
										.toString();
								localIpBytes = inetAddress.getAddress();
								System.arraycopy(localIpBytes, 0, regBuffer,
										44, 4);
							}
						}
					}
				}

			} catch (Exception ex) {
				ex.printStackTrace();
			}
		};
	};

	// 初始化指令缓存
	private void initCmdBuffer() {
		// 初始化用户注册指令缓存
		for (int i = 0; i < Constant.bufferSize; i++)
			regBuffer[i] = 0;
		System.arraycopy(Constant.pkgHead, 0, regBuffer, 0, 3);
		regBuffer[3] = Constant.CMD80;
		regBuffer[4] = Constant.CMD_TYPE1;
		regBuffer[5] = Constant.OPR_CMD1;

		// 初始化信息发送指令缓存
		for (int i = 0; i < Constant.bufferSize; i++)
			msgSendBuffer[i] = 0;
		System.arraycopy(Constant.pkgHead, 0, msgSendBuffer, 0, 3);
		msgSendBuffer[3] = Constant.CMD81;
		msgSendBuffer[4] = Constant.CMD_TYPE1;
		msgSendBuffer[5] = Constant.OPR_CMD1;

		// 初始化发送文件指令缓存
		for (int i = 0; i < Constant.bufferSize; i++)
			fileSendBuffer[i] = 0;
		System.arraycopy(Constant.pkgHead, 0, fileSendBuffer, 0, 3);
		fileSendBuffer[3] = Constant.CMD82;
		fileSendBuffer[4] = Constant.CMD_TYPE1;
		fileSendBuffer[5] = Constant.OPR_CMD1;

		// 初始化通话指令
		// 初始化发送文件指令缓存
		for (int i = 0; i < Constant.bufferSize; i++)
			talkCmdBuffer[i] = 0;
		System.arraycopy(Constant.pkgHead, 0, talkCmdBuffer, 0, 3);
		talkCmdBuffer[3] = Constant.CMD83;
		talkCmdBuffer[4] = Constant.CMD_TYPE1;
		talkCmdBuffer[5] = Constant.OPR_CMD1;
	}

	// 获得所有用户对象
	public ArrayList<Map<Integer, Person>> getChildren() {
		return children;
	}

	// 获得所有用户id
	public ArrayList<Integer> getPersonKeys() {
		return personKeys;
	}

	// 根据用户id获得该用户的消息
	public List<Message> getMessagesById(int personId) {
		return msgContainer.get(personId);
	}

	// 根据用户id获得该用户的消息数量
	public int getMessagesCountById(int personId) {
		List<Message> msgs = msgContainer.get(personId);
		if (null != msgs) {
			return msgs.size();
		} else {
			return 0;
		}
	}

	// 每隔10秒发送一个心跳包
	boolean isStopUpdateMe = false;

	private class UpdateMe extends Thread {
		@Override
		public void run() {
			while (!isStopUpdateMe) {
				try {
					comBridge.joinOrganization();
					sleep(10000);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	// 检测用户是否在线,如果超过15说明用户已离线,秒则从列表中清除该用户
	private class CheckUserOnline extends Thread {
		@Override
		public void run() {
			super.run();
			boolean hasChanged = false;
			while (!isStopUpdateMe) {
				if (childrenMap.size() > 0) {
					Set<Integer> keys = childrenMap.keySet();
					for (Integer key : keys) {
						if (System.currentTimeMillis()
								- childrenMap.get(key).timeStamp > 15000) {
							childrenMap.remove(key);
							personKeys.remove(Integer.valueOf(key));
							hasChanged = true;
						}
					}
				}
				if (hasChanged)
					sendPersonHasChangedBroadcast();
				try {
					sleep(5000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	// 发送用户更新广播
	private void sendPersonHasChangedBroadcast() {
		Intent intent = new Intent();
		intent.setAction(Constant.personHasChangedAction);
		sendBroadcast(intent);
	}

	// 注册广播接收器
	private void regBroadcastReceiver() {
		receiver = new ServiceBroadcastReceiver();
		IntentFilter filter = new IntentFilter();
		filter.addAction(Constant.WIFIACTION);
		filter.addAction(Constant.ETHACTION);
		filter.addAction(Constant.updateMyInformationAction);
		filter.addAction(Constant.refuseReceiveFileAction);
		filter.addAction(Constant.imAliveNow);
		registerReceiver(receiver, filter);
	}

	// 广播接收器处理类
	private class ServiceBroadcastReceiver extends BroadcastReceiver {
		@Override
		public void onReceive(Context context, Intent intent) {
			if (intent.getAction().equals(Constant.WIFIACTION)
					|| intent.getAction().equals(Constant.ETHACTION)) {
				new CheckNetConnectivity().start();
			} else if (intent.getAction().equals(
					Constant.updateMyInformationAction)) {
				getMyInfomation();
				comBridge.joinOrganization();
			} else if (intent.getAction().equals(
					Constant.refuseReceiveFileAction)) {
				comBridge.refuseReceiveFile();
			} else if (intent.getAction().equals(Constant.imAliveNow)) {

			}
		}
	}

	// 发送信息
	public void sendMsg(int personId, String msg) {
		comBridge.sendMsg(personId, msg);
	}

	// 发送文件
	public void sendFiles(int personId, ArrayList<FileName> files) {
		comBridge.sendFiles(personId, files);
	}

	// 接收文件
	public void receiveFiles(String fileSavePath) {
		comBridge.receiveFiles(fileSavePath);
	}

	// 获得欲接收的文件名
	public ArrayList<FileState> getReceivedFileNames() {
		return comBridge.getReceivedFileNames();
	}

	// 获得欲发送的文件名
	public ArrayList<FileState> getBeSendFileNames() {
		return comBridge.getBeSendFileNames();
	}

	// 开始语音呼叫
	public void startTalk(int personId) {
		comBridge.startTalk(personId);
	}

	// 结束语音呼叫
	public void stopTalk(int personId) {
		comBridge.stopTalk(personId);
	}

	// 接受远程语音呼叫
	public void acceptTalk(int personId) {
		comBridge.acceptTalk(personId);
	}

	@Override
	public void onDestroy() {
		comBridge.release();
		unregisterReceiver(receiver);
		isStopUpdateMe = true;
		System.out.println("Service on destory...");
	}

	// ========================协议分析与通讯模块=======================================================
	private class CommunicationBridge extends Thread {
		private MulticastSocket multicastSocket = null;
		private byte[] recvBuffer = new byte[Constant.bufferSize];
		private int fileSenderUid = 0;// 用来保存文件发送者的id号
		private boolean isBusyNow = false;// 现在是否正在收发文件,如果该状态为true则表示现在正在进行收发文件操作,这时需要向其它发送文件的用户发送忙指令
		private String fileSavePath = null;// 用来保存接收到的文件
		private boolean isStopTalk = false;// 通话结束标志
		private ArrayList<FileName> tempFiles = null;// 用来临时保存需要发送的文件名
		private int tempUid = 0;// 用来临时保存需要发送文件的用户id(接受文件方的用户id)
		private ArrayList<FileState> receivedFileNames = new ArrayList<FileState>();
		private ArrayList<FileState> beSendFileNames = new ArrayList<FileState>();

		private FileHandler fileHandler = null;// 文件处理线程,用来收发文件
		private AudioHandler audioHandler = null;// 音频处理模块,用来收发音频数据

		public CommunicationBridge() {
			fileHandler = new FileHandler();
			fileHandler.start();

			audioHandler = new AudioHandler();
			audioHandler.start();
		}

		// 打开组播端口,准备组播通讯
		@Override
		public void run() {
			super.run();
			try {
				multicastSocket = new MulticastSocket(Constant.PORT);
				multicastSocket.joinGroup(InetAddress
						.getByName(Constant.MULTICAST_IP));
				System.out.println("Socket started...");
				while (!multicastSocket.isClosed() && null != multicastSocket) {
					for (int i = 0; i < Constant.bufferSize; i++) {
						recvBuffer[i] = 0;
					}
					DatagramPacket rdp = new DatagramPacket(recvBuffer,
							recvBuffer.length);
					multicastSocket.receive(rdp);
					parsePackage(recvBuffer);
				}
			} catch (Exception e) {
				try {
					if (null != multicastSocket && !multicastSocket.isClosed()) {
						multicastSocket.leaveGroup(InetAddress
								.getByName(Constant.MULTICAST_IP));
						multicastSocket.close();
					}
				} catch (Exception e1) {
					e1.printStackTrace();
				}
				e.printStackTrace();
			}
		}

		// 解析接收到的数据包
		private void parsePackage(byte[] pkg) {
			int CMD = pkg[3];// 命令字
			int cmdType = pkg[4];// 命令类型
			int oprCmd = pkg[5];// 操作命令

			// 获得用户ID号
			byte[] uId = new byte[4];
			System.arraycopy(pkg, 6, uId, 0, 4);
			int userId = ByteAndInt.byteArray2Int(uId);

			switch (CMD) {
			case Constant.CMD80:
				switch (cmdType) {
				case Constant.CMD_TYPE1:
					// 如果该信息不是自己发出则给对方发送回应包,并把对方加入用户列表
					if (userId != me.personId) {
						updatePerson(userId, pkg);
						// 发送应答包
						byte[] ipBytes = new byte[4];// 获得请求方的ip地址
						System.arraycopy(pkg, 44, ipBytes, 0, 4);
						try {
							InetAddress targetIp = InetAddress
									.getByAddress(ipBytes);
							regBuffer[4] = Constant.CMD_TYPE2;// 把自己的注册信息修改成应答信息标志,把自己的信息发送给请求方
							DatagramPacket dp = new DatagramPacket(regBuffer,
									Constant.bufferSize, targetIp,
									Constant.PORT);
							multicastSocket.send(dp);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
					break;
				case Constant.CMD_TYPE2:
					updatePerson(userId, pkg);
					break;
				case Constant.CMD_TYPE3:
					childrenMap.remove(userId);
					personKeys.remove(Integer.valueOf(userId));
					sendPersonHasChangedBroadcast();
					break;
				}
				break;
			case Constant.CMD81:// 收到信息
				switch (cmdType) {
				case Constant.CMD_TYPE1:
					List<Message> messages = null;
					if (msgContainer.containsKey(userId)) {
						messages = msgContainer.get(userId);
					} else {
						messages = new ArrayList<Message>();
					}
					byte[] msgBytes = new byte[Constant.msgLength];
					System.arraycopy(pkg, 10, msgBytes, 0, Constant.msgLength);
					String msgStr = new String(msgBytes).trim();
					Message msg = new Message();
					msg.msg = msgStr;
					msg.receivedTime = getCurrentTime();
					messages.add(msg);
					msgContainer.put(userId, messages);

					Intent intent = new Intent();
					intent.setAction(Constant.hasMsgUpdatedAction);
					intent.putExtra("userId", userId);
					intent.putExtra("msgCount", messages.size());
					sendBroadcast(intent);
					break;
				case Constant.CMD_TYPE2:
					break;
				}
				break;
			case Constant.CMD82:
				switch (cmdType) {
				case Constant.CMD_TYPE1:// 收到文件传输请求
					switch (oprCmd) {
					case Constant.OPR_CMD1:
						// 发送广播,通知界面有文件需要传输
						if (!isBusyNow) {
							// isBusyNow = true;
							fileSenderUid = userId;// 保存文件发送者的id号,以便后面若接收者拒绝接收文件时可以通过该id找到发送者,并给发送者发送拒绝接收指令
							Person person = childrenMap.get(Integer
									.valueOf(userId));
							Intent intent = new Intent();
							intent.putExtra("person", person);
							intent.setAction(Constant.receivedSendFileRequestAction);
							sendBroadcast(intent);
						} else {// 如果当前正在收发文件则向对方发送忙指令
							Person person = childrenMap.get(Integer
									.valueOf(userId));
							fileSendBuffer[4] = Constant.CMD_TYPE2;
							fileSendBuffer[5] = Constant.OPR_CMD4;
							byte[] meIdBytes = ByteAndInt
									.int2ByteArray(me.personId);
							System.arraycopy(meIdBytes, 0, fileSendBuffer, 6, 4);
							try {
								DatagramPacket dp = new DatagramPacket(
										fileSendBuffer,
										Constant.bufferSize,
										InetAddress.getByName(person.ipAddress),
										Constant.PORT);
								multicastSocket.send(dp);
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
						break;
					case Constant.OPR_CMD5:// 接收对方传过来的文件名信息
						byte[] fileNameBytes = new byte[Constant.fileNameLength];
						byte[] fileSizeByte = new byte[8];
						System.arraycopy(pkg, 10, fileNameBytes, 0,
								Constant.fileNameLength);
						System.arraycopy(pkg, 100, fileSizeByte, 0, 8);
						FileState fs = new FileState();
						fs.fileName = new String(fileNameBytes).trim();
						fs.fileSize = Long.valueOf(ByteAndInt
								.byteArrayToLong(fileSizeByte));
						receivedFileNames.add(fs);
						break;
					}
					break;
				case Constant.CMD_TYPE2:
					switch (oprCmd) {
					case Constant.OPR_CMD2:// 对方同意接收文件
						fileHandler.startSendFile();
						System.out
								.println("Start send file to remote user ...");
						break;
					case Constant.OPR_CMD3:// 对方拒绝接收文件
						Intent intent = new Intent();
						intent.setAction(Constant.remoteUserRefuseReceiveFileAction);
						sendBroadcast(intent);
						System.out
								.println("Remote user refuse to receive file ...");
						break;
					case Constant.OPR_CMD4:// 对方现在忙
						System.out.println("Remote user is busy now ...");
						break;
					}
					break;
				}
				break;
			case Constant.CMD83:// 83命令,语音通讯相关
				switch (cmdType) {
				case Constant.CMD_TYPE1:
					switch (oprCmd) {
					case Constant.OPR_CMD1:// 接收到远程语音通话请求
						System.out.println("Received a talk request ... ");
						isStopTalk = false;
						Person person = childrenMap
								.get(Integer.valueOf(userId));
						Intent intent = new Intent();
						intent.putExtra("person", person);
						intent.setAction(Constant.receivedTalkRequestAction);
						sendBroadcast(intent);
						break;
					case Constant.OPR_CMD2:
						// 收到关闭指令,关闭语音通话
						System.out
								.println("Received remote user stop talk cmd ... ");
						isStopTalk = true;
						Intent i = new Intent();
						i.setAction(Constant.remoteUserClosedTalkAction);
						sendBroadcast(i);
						break;
					}
					break;
				case Constant.CMD_TYPE2:
					switch (oprCmd) {
					case Constant.OPR_CMD1:
						// 被叫应答,开始语音通话
						if (!isStopTalk) {
							System.out
									.println("Begin to talk with remote user ... ");
							Person person = childrenMap.get(Integer
									.valueOf(userId));
							audioHandler.audioSend(person);
						}
						break;
					}
					break;
				}
				break;
			}
		}

		// 更新或加用户信息到用户列表中
		private void updatePerson(int userId, byte[] pkg) {
			Person person = new Person();
			getPerson(pkg, person);
			childrenMap.put(userId, person);
			if (!personKeys.contains(Integer.valueOf(userId)))
				personKeys.add(Integer.valueOf(userId));
			if (!children.contains(childrenMap))
				children.add(childrenMap);
			sendPersonHasChangedBroadcast();
		}

		// 关闭Socket连接
		private void release() {
			try {
				regBuffer[4] = Constant.CMD_TYPE3;// 把命令类型修改成注消标志,并广播发送,从所有用户中退出
				DatagramPacket dp = new DatagramPacket(regBuffer,
						Constant.bufferSize,
						InetAddress.getByName(Constant.MULTICAST_IP),
						Constant.PORT);
				multicastSocket.send(dp);
				System.out.println("Send logout cmd ...");

				multicastSocket.leaveGroup(InetAddress
						.getByName(Constant.MULTICAST_IP));
				multicastSocket.close();

				System.out.println("Socket has closed ...");
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				fileHandler.release();
				audioHandler.release();
			}
		}

		// 分析数据包并获取一个用户信息
		private void getPerson(byte[] pkg, Person person) {

			byte[] personIdBytes = new byte[4];
			byte[] iconIdBytes = new byte[4];
			byte[] nickeNameBytes = new byte[30];
			byte[] personIpBytes = new byte[4];

			System.arraycopy(pkg, 6, personIdBytes, 0, 4);
			System.arraycopy(pkg, 10, iconIdBytes, 0, 4);
			System.arraycopy(pkg, 14, nickeNameBytes, 0, 30);
			System.arraycopy(pkg, 44, personIpBytes, 0, 4);

			person.personId = ByteAndInt.byteArray2Int(personIdBytes);
			person.personHeadIconId = ByteAndInt.byteArray2Int(iconIdBytes);
			person.personNickeName = (new String(nickeNameBytes)).trim();
			person.ipAddress = Constant.intToIp(ByteAndInt
					.byteArray2Int(personIpBytes));
			person.timeStamp = System.currentTimeMillis();
		}

		// 注册自己到网络中
		public void joinOrganization() {
			try {
				if (null != multicastSocket && !multicastSocket.isClosed()) {
					regBuffer[4] = Constant.CMD_TYPE1;// 恢复成注册请求标志,向网络中注册自己
					DatagramPacket dp = new DatagramPacket(regBuffer,
							Constant.bufferSize,
							InetAddress.getByName(Constant.MULTICAST_IP),
							Constant.PORT);
					multicastSocket.send(dp);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		// 发送信息
		public void sendMsg(int personId, String msg) {
			try {
				Person psn = childrenMap.get(personId);
				if (null != psn) {
					System.arraycopy(ByteAndInt.int2ByteArray(me.personId), 0,
							msgSendBuffer, 6, 4);
					int msgLength = Constant.msgLength + 10;
					for (int i = 10; i < msgLength; i++) {
						msgSendBuffer[i] = 0;
					}
					byte[] msgBytes = msg.getBytes();
					System.arraycopy(msgBytes, 0, msgSendBuffer, 10,
							msgBytes.length);
					DatagramPacket dp = new DatagramPacket(msgSendBuffer,
							Constant.bufferSize,
							InetAddress.getByName(psn.ipAddress), Constant.PORT);
					multicastSocket.send(dp);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		// 向对方发送请求接收文件指令
		public void sendFiles(int personId, ArrayList<FileName> files) {
			if (personId > 0 && null != files && files.size() > 0) {
				try {
					tempUid = personId;
					tempFiles = files;
					Person person = childrenMap.get(Integer.valueOf(tempUid));
					fileSendBuffer[4] = Constant.CMD_TYPE1;
					fileSendBuffer[5] = Constant.OPR_CMD5;
					byte[] meIdBytes = ByteAndInt.int2ByteArray(me.personId);
					System.arraycopy(meIdBytes, 0, fileSendBuffer, 6, 4);
					int fileNameLength = Constant.fileNameLength + 10;// 清除头文件包的文件名存储区域,以便写新的文件名
					// 把要传送的所有文件名传送给对方
					for (final FileName file : tempFiles) {
						// 收集生成要发送文件的文相关资料
						FileState fs = new FileState(file.fileSize, 0,
								file.getFileName());
						beSendFileNames.add(fs);

						byte[] fileNameBytes = file.getFileName().getBytes();
						for (int i = 10; i < fileNameLength; i++)
							fileSendBuffer[i] = 0;
						System.arraycopy(fileNameBytes, 0, fileSendBuffer, 10,
								fileNameBytes.length);// 把文件名放入头数据包
						System.arraycopy(
								ByteAndInt.longToByteArray(file.fileSize), 0,
								fileSendBuffer, 100, 8);
						DatagramPacket dp = new DatagramPacket(fileSendBuffer,
								Constant.bufferSize,
								InetAddress.getByName(person.ipAddress),
								Constant.PORT);
						multicastSocket.send(dp);
					}
					// 对方发送请求接收文件指令
					fileSendBuffer[5] = Constant.OPR_CMD1;
					DatagramPacket dp = new DatagramPacket(fileSendBuffer,
							Constant.bufferSize,
							InetAddress.getByName(person.ipAddress),
							Constant.PORT);
					multicastSocket.send(dp);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		// 向对方响应同意接收文件指令
		public void receiveFiles(String fileSavePath) {
			this.fileSavePath = fileSavePath;
			Person person = childrenMap.get(Integer.valueOf(fileSenderUid));
			fileSendBuffer[4] = Constant.CMD_TYPE2;
			fileSendBuffer[5] = Constant.OPR_CMD2;
			byte[] meIdBytes = ByteAndInt.int2ByteArray(me.personId);
			System.arraycopy(meIdBytes, 0, fileSendBuffer, 6, 4);
			try {
				DatagramPacket dp = new DatagramPacket(fileSendBuffer,
						Constant.bufferSize,
						InetAddress.getByName(person.ipAddress), Constant.PORT);
				multicastSocket.send(dp);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		// 向文件发送者发送拒绝接收文件指令
		public void refuseReceiveFile() {
			// isBusyNow = false;
			Person person = childrenMap.get(Integer.valueOf(fileSenderUid));
			fileSendBuffer[4] = Constant.CMD_TYPE2;
			fileSendBuffer[5] = Constant.OPR_CMD3;
			byte[] meIdBytes = ByteAndInt.int2ByteArray(me.personId);
			System.arraycopy(meIdBytes, 0, fileSendBuffer, 6, 4);
			try {
				DatagramPacket dp = new DatagramPacket(fileSendBuffer,
						Constant.bufferSize,
						InetAddress.getByName(person.ipAddress), Constant.PORT);
				multicastSocket.send(dp);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		// 获得欲接收文件的文件名
		public ArrayList<FileState> getReceivedFileNames() {
			return receivedFileNames;
		}

		// 获得欲发送文件的文件名
		public ArrayList<FileState> getBeSendFileNames() {
			return beSendFileNames;
		}

		// 开始语音呼叫,向远方发送语音呼叫请求
		public void startTalk(int personId) {
			try {
				isStopTalk = false;
				talkCmdBuffer[4] = Constant.CMD_TYPE1;
				talkCmdBuffer[5] = Constant.OPR_CMD1;
				System.arraycopy(InetAddress.getByName(me.ipAddress)
						.getAddress(), 0, talkCmdBuffer, 44, 4);
				Person person = childrenMap.get(Integer.valueOf(personId));
				DatagramPacket dp = new DatagramPacket(talkCmdBuffer,
						Constant.bufferSize,
						InetAddress.getByName(person.ipAddress), Constant.PORT);
				multicastSocket.send(dp);
			} catch (UnknownHostException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		// 结束语音呼叫
		public void stopTalk(int personId) {
			isStopTalk = true;
			talkCmdBuffer[4] = Constant.CMD_TYPE1;
			talkCmdBuffer[5] = Constant.OPR_CMD2;
			Person person = childrenMap.get(Integer.valueOf(personId));
			try {
				System.arraycopy(InetAddress.getByName(me.ipAddress)
						.getAddress(), 0, talkCmdBuffer, 44, 4);
				DatagramPacket dp = new DatagramPacket(talkCmdBuffer,
						Constant.bufferSize,
						InetAddress.getByName(person.ipAddress), Constant.PORT);
				multicastSocket.send(dp);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		// 接受远程语音呼叫请求,并向远程发送语音数据
		public void acceptTalk(int personId) {
			talkCmdBuffer[3] = Constant.CMD83;
			talkCmdBuffer[4] = Constant.CMD_TYPE2;
			talkCmdBuffer[5] = Constant.OPR_CMD1;
			try {
				// 发送接受语音指令
				System.arraycopy(InetAddress.getByName(me.ipAddress)
						.getAddress(), 0, talkCmdBuffer, 44, 4);
				Person person = childrenMap.get(Integer.valueOf(personId));
				DatagramPacket dp = new DatagramPacket(talkCmdBuffer,
						Constant.bufferSize,
						InetAddress.getByName(person.ipAddress), Constant.PORT);
				multicastSocket.send(dp);
				audioHandler.audioSend(person);// 同时向对方发送音频数据
			} catch (UnknownHostException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		// =========================TCP文件传输模块==================================================================
		// 基于Tcp传输的文件收发模块
		private class FileHandler extends Thread {
			private ServerSocket sSocket = null;

			public FileHandler() {
			}

			@Override
			public void run() {
				super.run();
				try {
					sSocket = new ServerSocket(Constant.PORT);
					System.out.println("File Handler socket started ...");
					while (!sSocket.isClosed() && null != sSocket) {
						Socket socket = sSocket.accept();
						socket.setSoTimeout(5000);
						new SaveFileToDisk(socket).start();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			// 保存接收到的数据
			private class SaveFileToDisk extends Thread {
				private Socket socket = null;

				public SaveFileToDisk(Socket socket) {
					this.socket = socket;
				}

				@Override
				public void run() {
					super.run();
					OutputStream output = null;
					InputStream input = null;
					try {
						byte[] recvFileCmd = new byte[Constant.bufferSize];// 接收对方第一次发过来的数据,该数据包中包含了要发送的文件名
						input = socket.getInputStream();
						input.read(recvFileCmd);// 读取对方发过来的数据
						int cmdType = recvFileCmd[4];// 按协议这位为命令类型
						int oprCmd = recvFileCmd[5];// 操作命令
						if (cmdType == Constant.CMD_TYPE1
								&& oprCmd == Constant.OPR_CMD6) {
							byte[] fileNameBytes = new byte[Constant.fileNameLength];// 从收到的数据包中提取文件名
							System.arraycopy(recvFileCmd, 10, fileNameBytes, 0,
									Constant.fileNameLength);
							StringBuffer sb = new StringBuffer();
							String fName = new String(fileNameBytes).trim();
							sb.append(fileSavePath).append(File.separator)
									.append(fName);// 组合成完整的文件名
							String fileName = sb.toString();
							File file = new File(fileName);// 根据获得的文件名创建文件
							// 定义数据接收缓冲区,准备接收对方传过来的文件内容
							byte[] readBuffer = new byte[Constant.readBufferSize];
							output = new FileOutputStream(file);// 打开文件输出流准备把接收到的内容写到文件中
							int readSize = 0;
							int length = 0;
							long count = 0;
							FileState fs = getFileStateByName(fName,
									receivedFileNames);

							while (-1 != (readSize = input.read(readBuffer))) {// 循环读取内容
								output.write(readBuffer, 0, readSize);// 把接收到的内容写到文件中
								output.flush();
								length += readSize;
								count++;
								if (count % 10 == 0) {
									fs.currentSize = length;
									fs.percent = ((int) ((Float.valueOf(length) / Float
											.valueOf(fs.fileSize)) * 100));
									Intent intent = new Intent();
									intent.setAction(Constant.fileReceiveStateUpdateAction);
									sendBroadcast(intent);
								}
							}
							fs.currentSize = length;
							fs.percent = ((int) ((Float.valueOf(length) / Float
									.valueOf(fs.fileSize)) * 100));
							Intent intent = new Intent();
							intent.setAction(Constant.fileReceiveStateUpdateAction);
							sendBroadcast(intent);
						} else {
							Intent intent = new Intent();
							intent.putExtra("msg",
									getString(R.string.data_receive_error));
							intent.setAction(Constant.dataReceiveErrorAction);
							sendBroadcast(intent);
						}
					} catch (Exception e) {
						Intent intent = new Intent();
						intent.putExtra("msg", e.getMessage());
						intent.setAction(Constant.dataReceiveErrorAction);
						sendBroadcast(intent);
						e.printStackTrace();
					} finally {
						try {
							if (null != input)
								input.close();
							if (null != output)
								output.close();
							if (!socket.isClosed())
								socket.close();
						} catch (Exception e1) {
							e1.printStackTrace();
						}
					}
				}
			}

			// 开始给对方发送文件
			public void startSendFile() {
				// 获得接收方信息
				Person person = childrenMap.get(Integer.valueOf(tempUid));
				final String userIp = person.ipAddress;
				// 组合头数据包,该数据包中包括要发送的文件名
				final byte[] sendFileCmd = new byte[Constant.bufferSize];
				for (int i = 0; i < Constant.bufferSize; i++)
					sendFileCmd[i] = 0;
				System.arraycopy(Constant.pkgHead, 0, sendFileCmd, 0, 3);
				sendFileCmd[3] = Constant.CMD82;
				sendFileCmd[4] = Constant.CMD_TYPE1;
				sendFileCmd[5] = Constant.OPR_CMD6;
				System.arraycopy(ByteAndInt.int2ByteArray(me.personId), 0,
						sendFileCmd, 6, 4);
				for (final FileName file : tempFiles) {// 采用多线程发送文件
					new Thread() {
						@Override
						public void run() {
							Socket socket = null;
							OutputStream output = null;
							InputStream input = null;
							try {
								socket = new Socket(userIp, Constant.PORT);
								byte[] fileNameBytes = file.getFileName()
										.getBytes();
								int fileNameLength = Constant.fileNameLength + 10;// 清除头文件包的文件名存储区域,以便写新的文件名
								for (int i = 10; i < fileNameLength; i++)
									sendFileCmd[i] = 0;
								System.arraycopy(fileNameBytes, 0, sendFileCmd,
										10, fileNameBytes.length);// 把文件名放入头数据包
								System.arraycopy(ByteAndInt
										.longToByteArray(file.fileSize), 0,
										sendFileCmd, 100, 8);
								output = socket.getOutputStream();// 构造一个输出流
								output.write(sendFileCmd);// 把头数据包发给对方
								output.flush();
								sleep(1000);// sleep 1秒钟,等待对方处理完
								// 定义数据发送缓冲区
								byte[] readBuffer = new byte[Constant.readBufferSize];// 文件读写缓存
								input = new FileInputStream(new File(
										file.fileName));// 打开一个文件输入流
								int readSize = 0;
								int length = 0;
								long count = 0;
								FileState fs = getFileStateByName(
										file.getFileName(), beSendFileNames);
								while (-1 != (readSize = input.read(readBuffer))) {// 循环把文件内容发送给对方
									output.write(readBuffer, 0, readSize);// 把内容写到输出流中发送给对方
									output.flush();
									length += readSize;

									count++;
									if (count % 10 == 0) {
										fs.currentSize = length;
										fs.percent = ((int) ((Float
												.valueOf(length) / Float
												.valueOf(fs.fileSize)) * 100));
										Intent intent = new Intent();
										intent.setAction(Constant.fileSendStateUpdateAction);
										sendBroadcast(intent);
									}
								}
								fs.currentSize = length;
								fs.percent = ((int) ((Float.valueOf(length) / Float
										.valueOf(fs.fileSize)) * 100));
								Intent intent = new Intent();
								intent.setAction(Constant.fileSendStateUpdateAction);
								sendBroadcast(intent);
							} catch (Exception e) {
								// 往界面层发送文件传输出错信息
								Intent intent = new Intent();
								intent.putExtra("msg", e.getMessage());
								intent.setAction(Constant.dataSendErrorAction);
								sendBroadcast(intent);
								e.printStackTrace();
							} finally {
								try {
									if (null != output)
										output.close();
									if (null != input)
										input.close();
									if (!socket.isClosed())
										socket.close();
								} catch (Exception e1) {
									e1.printStackTrace();
								}
							}
						}
					}.start();
				}
			}

			// 根据文件名从文件状态列表中获得该文件状态
			private FileState getFileStateByName(String fileName,
					ArrayList<FileState> fileStates) {
				for (FileState fileState : fileStates) {
					if (fileState.fileName.equals(fileName)) {
						return fileState;
					}
				}
				return null;
			}

			public void release() {
				try {
					System.out.println("File handler socket closed ...");
					if (null != sSocket)
						sSocket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		// =========================TCP文件传输模块结束==============================================================

		// =========================TCP语音传输模块==================================================================
		// 基于Tcp语音传输模块
		private class AudioHandler extends Thread {
			private ServerSocket sSocket = null;

			// private G711Codec codec;
			public AudioHandler() {
			}

			@Override
			public void run() {
				super.run();
				try {
					sSocket = new ServerSocket(Constant.AUDIO_PORT);// 监听音频端口
					System.out.println("Audio Handler socket started ...");
					while (!sSocket.isClosed() && null != sSocket) {
						Socket socket = sSocket.accept();
						socket.setSoTimeout(5000);
						audioPlay(socket);
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			// 用来启动音频播放子线程
			public void audioPlay(Socket socket) {
				new AudioPlay(socket).start();
			}

			// 用来启动音频发送子线程
			public void audioSend(Person person) {
				new AudioSend(person).start();
			}

			// 音频播线程
			public class AudioPlay extends Thread {
				Socket socket = null;

				public AudioPlay(Socket socket) {
					this.socket = socket;
					// android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
				}

				@Override
				public void run() {
					super.run();
					try {
						InputStream is = socket.getInputStream();
						// 获得音频缓冲区大小
						int bufferSize = android.media.AudioTrack
								.getMinBufferSize(8000,
										AudioFormat.CHANNEL_CONFIGURATION_MONO,
										AudioFormat.ENCODING_PCM_16BIT);

						// 获得音轨对象
						AudioTrack player = new AudioTrack(
								AudioManager.STREAM_MUSIC, 8000,
								AudioFormat.CHANNEL_CONFIGURATION_MONO,
								AudioFormat.ENCODING_PCM_16BIT, bufferSize,
								AudioTrack.MODE_STREAM);

						// 设置喇叭音量
						player.setStereoVolume(1.0f, 1.0f);
						// 开始播放声音
						player.play();
						byte[] audio = new byte[160];// 音频读取缓存
						int length = 0;

						while (!isStopTalk) {
							length = is.read(audio);// 从网络读取音频数据
							if (length > 0 && length % 2 == 0) {
								// for(int
								// i=0;i<length;i++)audio[i]=(byte)(audio[i]*2);//音频放大1倍
								player.write(audio, 0, length);// 播放音频数据
							}
						}
						player.stop();
						is.close();
						socket.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}

			// 音频发送线程
			public class AudioSend extends Thread {
				Person person = null;

				public AudioSend(Person person) {
					this.person = person;
					// android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
				}

				@Override
				public void run() {
					super.run();
					Socket socket = null;
					OutputStream os = null;
					AudioRecord recorder = null;
					try {
						socket = new Socket(person.ipAddress,
								Constant.AUDIO_PORT);
						socket.setSoTimeout(5000);
						os = socket.getOutputStream();
						// 获得录音缓冲区大小
						int bufferSize = AudioRecord.getMinBufferSize(8000,
								AudioFormat.CHANNEL_CONFIGURATION_MONO,
								AudioFormat.ENCODING_PCM_16BIT);

						// 获得录音机对象
						recorder = new AudioRecord(
								MediaRecorder.AudioSource.MIC, 8000,
								AudioFormat.CHANNEL_CONFIGURATION_MONO,
								AudioFormat.ENCODING_PCM_16BIT, bufferSize * 10);

						recorder.startRecording();// 开始录音
						byte[] readBuffer = new byte[640];// 录音缓冲区

						int length = 0;

						while (!isStopTalk) {
							length = recorder.read(readBuffer, 0, 640);// 从mic读取音频数据
							if (length > 0 && length % 2 == 0) {
								os.write(readBuffer, 0, length);// 写入到输出流,把音频数据通过网络发送给对方
							}
						}
						recorder.stop();
						os.close();
						socket.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}

			public void release() {
				try {
					System.out.println("Audio handler socket closed ...");
					if (null != sSocket)
						sSocket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		// =========================TCP语音传输模块结束==================================================================
	}
	// ========================协议分析与通讯模块结束=======================================================
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值