安卓编程实现wifi聊天,视频和音频通话
安卓编程实现wifi聊天,传文件,视频和音频通话
在移动开发的过程中,即时通讯是许多app必须要用到的功能,许多app都没有自主开发自己的聊天系统,反而引用了第三方的即时通讯sdk,贵还不说,有时候想自己增加功能也是麻烦,本文通过安卓编程为例,使用wifi作为服务器,实现了安卓即时通讯和视频音频的通话功能。
安卓开启热点服务
安卓系统自带的热点服务,本次编程将热点开启作为局域网的聊天服务器,一台手机作为主服务器搭建聊天服务。
热点创建服务代码如下
public void createServer(){
try {
// System.out.println(“本机ip:”+getLocalIpAddress());
ServerSocket ss = new ServerSocket(30000);
while (true) {
String localip= getHostIP();
System.out.println("本机ip:"+localip);
Socket s = ss.accept();
System.out.println("已连接ip:"+s.getInetAddress().toString());
vibrators();
// showNot(“已连接ip:”+s.getInetAddress().toString());
simpleNotice(“已连接ip:”+s.getInetAddress().toString());
socketList.add(s);
new Thread(new ServerThead(s,handler)).start();
Intent intent = new Intent();
intent.setAction("www.ailiaw.com.mywifi");//设置意图
intent.putExtra("action", "newmsg");//设置所需发送的消息标签以及内容
// BroadCastActivity.this.sendBroadcast(intent);
SimpleServer.this.sendOrderedBroadcast(intent,null);//有序广播
}
} catch (IOException e) {
e.printStackTrace();
}
}
客户端也是由安卓手机来接受的,使用普通的Socket连接即可
public void createConnection() {
try {
socket = new Socket(ip, port);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
if (socket != null) {
try {
socket.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
if (socket != null) {
try {
socket.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
} finally {
}
}
Socket客户端发送文本消息方法
public void sendMessage(String sendMessage) {
try {
out = new DataOutputStream(socket.getOutputStream());
if (sendMessage.equals(“Windows”)) {
out.writeByte(0x1);
out.flush();
return;
}
if (sendMessage.equals(“Unix”)) {
out.writeByte(0x2);
out.flush();
return;
}
if (sendMessage.equals(“Linux”)) {
out.writeByte(0x3);
out.flush();
} else {
out.writeUTF(sendMessage);
out.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
if (out != null) {
try {
out.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
视频聊天原理:安卓编程获取SurfaceView的视频流转成图片流发送,另一端则接收实时展示图片,形成了动画视频
//获取摄像头流并开启线程通过socket发送
private void initCamera() {
if (!isPreview) {
if (null == camera) {
// 打开前置摄像头
int cameraCount = 0;
@SuppressWarnings("unused")
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
cameraCount = Camera.getNumberOfCameras(); // get cameras number
for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
Camera.getCameraInfo(camIdx, cameraInfo); // get camerainfo
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
//代表摄像头的方位,目前有定义值两个分别为CAMERA_FACING_FRONT前置和CAMERA_FACING_BACK后置
try {
camera = Camera.open(camIdx);
} catch (RuntimeException e) {
e.printStackTrace();
break;
}
}
}
}
//前置摄像头为空则切换后摄像头
if (null == camera) {
// 打开前后置摄像头
int cameraCount = 0;
@SuppressWarnings("unused")
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
cameraCount = Camera.getNumberOfCameras(); // get cameras number
for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
Camera.getCameraInfo(camIdx, cameraInfo); // get camerainfo
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
//代表摄像头的方位,目前有定义值两个分别为CAMERA_FACING_FRONT前置和CAMERA_FACING_BACK后置
try {
camera = Camera.open(camIdx);
} catch (RuntimeException e) {
e.printStackTrace();
break;
}
}
}
}
// camera = Camera.open();
ClientThread.size = camera.getParameters().getPreviewSize();
}
if (camera != null && !isPreview) {
try {
camera.setPreviewDisplay(sfh); // 通过SurfaceView显示取景画面
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(screenWidth, screenHeight / 4 * 3);
/* 每秒从摄像头捕获5帧画面, */
parameters.setPreviewFrameRate(5);
parameters.setPictureFormat(ImageFormat.NV21); // 设置图片格式
parameters.setPictureSize(screenWidth, screenHeight / 4 * 3); // 设置照片的大小
camera.setDisplayOrientation(90);
camera.setPreviewCallback(new PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera c) {
// TODO Auto-generated method stub
Size size = camera.getParameters().getPreviewSize();
try {
//调用image.compressToJpeg()将YUV格式图像数据data转为jpg格式
YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
if (image != null) {
Message msg = clientThread.revHandler.obtainMessage();
msg.what = 0x111;
msg.obj = image;
clientThread.revHandler.sendMessage(msg);
/*outstream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, outstream);
outstream.flush();
new Thread(clientThread).start();*/
}
} catch (Exception ex) {
Log.e("Sys", "Error:" + ex.getMessage());
}
}
});
camera.startPreview(); // 开始预览
camera.autoFocus(null); // 自动对焦
} catch (Exception e) {
e.printStackTrace();
}
isPreview = true;
}
}
//接收视频流转为图片展示
byte [] buffer = new byte[1024];
int len = 0;
try {
ss = new ServerSocket(40000);
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
return;
}
InputStream ins = null;
while(true){
try {
s = ss.accept();
Log.e("strat","ljq");
ins = s.getInputStream();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
while( (len=ins.read(buffer)) != -1){
outStream.write(buffer, 0, len);
}
ins.close();
byte data[] = outStream.toByteArray();
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
Message msg =handler.obtainMessage();
msg.what = COMPLETED;
msg.obj = bitmap;
handler.sendMessage(msg);
outStream.flush();
outStream.close();
if(!s.isClosed()){
s.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
//Bitmap bitmap = BitmapFactory.decodeStream(ins);
}
安卓语音聊天则是通过AudioRecord获取音频流,通过Socket发送,另一端则接收音频流,再通过AudioTrack实时播放出来
.//采集声音并发送
class RecordPlayThread extends Thread{
@SuppressLint(“WrongConstant”)
public void run(){
try{
//byte 文件来存储声音
byte[] buffer = new byte[recBufSize];
//开始采集声音
audioRecord.startRecording();
//播放声音
// audioTrack.play();
int frame_size = 320;//g726_32 : 4:1的压缩比
short [] encodeData = new short[frame_size/2];
while(isRecording){
/* int bufferReadResult = audioRecord.read(encodeData, 0, 160);
// calc1(encodeData,0,160);
test_Noise(encodeData,160);
int wirteNum = audioTrack.write(encodeData, 0, bufferReadResult);*/
//从MIC存储到缓存区
int bufferReadResult = audioRecord.read(buffer,0, recBufSize);
byte[] tmpBuf = new byte[bufferReadResult];
System.arraycopy(buffer, 0, tmpBuf, 0, bufferReadResult);
Message msg = clientThread.revHandler.obtainMessage();
msg.what = 0x111;
msg.obj = tmpBuf;
clientThread.revHandler.sendMessage(msg);
//播放缓存区的数据
// audioTrack.write(tmpBuf, 0, tmpBuf.length);
}
1
// audioTrack.stop();
// audioRecord.stop();
audioRecord.stop();
audioRecord.release();
audioRecord = null;
// audioTrack.stop();
// audioTrack.release();
// audioTrack = null;
}catch(Throwable t){
Toast.makeText(RecordActivity.this, t.getMessage(),1000);
}
}
};
}
//接收音频声音播放
byte [] buffer = new byte[1024];
int len = 0;
try {
ss = new ServerSocket(40050);
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
return;
}
InputStream ins = null;
while(true){
try {
s = ss.accept();
Log.e("strat","ljq");
ins = s.getInputStream();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
while( (len=ins.read(buffer)) != -1){
outStream.write(buffer, 0, len);
}
ins.close();
byte[] data = outStream.toByteArray();
Message msg =handler.obtainMessage();
msg.what = COMPLETED;
msg.obj = data;
handler.sendMessage(msg);
outStream.flush();
outStream.close();
if(!s.isClosed()){
s.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
}
class RMyHandler extends Handler {
@Override
public void handleMessage(Message msg){
if (msg.what == COMPLETED) {
try{
byte[] tmpBuf = (byte[])msg.obj;
if(!isplay)
{
audioTrack.play();
isplay=true;
}
//播放缓存区的数据
audioTrack.write(tmpBuf, 0, tmpBuf.length);
if(!isplay)
{
audioTrack.stop();
audioTrack.release();
}
// audioTrack = null;
super.handleMessage(msg);
}catch (Exception e)
{
Toast.makeText(RecordActivity.this,"语音播放失败", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
}
}
视频聊天可以演化成直播室形式,只不过只有一个人发送视频流和音频流,其他人则只是接收
第一次写技术博客,希望对大家有用,要完整源码也可以私聊小编
项目地址
https://download.csdn.net/download/zhongzhizhuo/12570465
http://m.ailiaw.top/#/
http://news.ailiaw.top/
————————————————
版权声明:本文为CSDN博主「zhongzhizhuo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zhongzhizhuo/article/details/107081393