Android局域网内文字及语音发送,仿微信聊天 基于UDP/TCP传输

最近做了一个简单的仿微信聊天功能。目的是为了熟悉一下UDP/TCP的使用。

转载请说明出处:https://mp.csdn.net/console/editor/html/105584620

源码已上传,地址:https://download.csdn.net/download/checkchen99/12334651

首先上个图

这个就是简单的聊天界面,可发送文字,语音。

接下来上重点的代码。

 init();
 initAudioRecord();
 initAudioTracker();
 startReceiveThread();

init主要初始化UI,设置IP,绑定事件listener。 

之后是初始化AudioRecord和AuidoTracker参数

private void initAudioRecord(){
    //播放的采样频率 和录制的采样频率一样
    int sampleRate = 44100;
    //和录制的一样的
    int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    //录音用输入单声道  播放用输出单声道
    int channelConfig=AudioFormat.CHANNEL_IN_MONO;

    minBufferSize=AudioRecord.getMinBufferSize(
            sampleRate,
            channelConfig,AudioFormat.ENCODING_PCM_16BIT);
    System.out.println("****RecordMinBufferSize = "+minBufferSize);
    audioRec=new AudioRecord(MediaRecorder.AudioSource.MIC,
            sampleRate,channelConfig, audioFormat,minBufferSize);
    buffer=new byte[minBufferSize];
    if(audioRec==null){
        Log.d("chenshulin","audiRec = null");
        return;
    }
    //声学回声消除器 AcousticEchoCanceler 消除了从远程捕捉到音频信号上的信号的作用
    // if(AcousticEchoCanceler.isAvailable()){
    // aec=AcousticEchoCanceler.create(audioRec.getAudioSessionId());
    //  if(aec!=null){
    //     aec.setEnabled(true);
    //   }
    //    }

    //自动增益控制 AutomaticGainControl 自动恢复正常捕获的信号输出
    if(AutomaticGainControl.isAvailable()){
        agc=AutomaticGainControl.create(audioRec.getAudioSessionId());
        if(agc!=null){
            agc.setEnabled(true);
        }
    }

    //噪声抑制器 NoiseSuppressor 可以消除被捕获信号的背景噪音
    if(NoiseSuppressor.isAvailable()){
        nc=NoiseSuppressor.create(audioRec.getAudioSessionId());
        if(nc!=null){
            nc.setEnabled(true);
        }
    }
    mRecordQueue=new LinkedList<byte[]>();

}
private void initAudioTracker() {
    //扬声器播放
    int streamType = AudioManager.STREAM_MUSIC;
    //播放的采样频率 和录制的采样频率一样
    int sampleRate = 44100;//和录制的一样的
    int audioFormat= AudioFormat.ENCODING_PCM_16BIT;
    //流模式
    int mode = AudioTrack.MODE_STREAM;
    //录音用输入单声道  播放用输出单声道
    int channelConfig = AudioFormat.CHANNEL_OUT_MONO;
    int recBufSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);
    System.out.println("****playRecBufSize = "+recBufSize);
    audioTrk = new AudioTrack(streamType, sampleRate, channelConfig, audioFormat, recBufSize,mode);
    audioTrk.setStereoVolume(AudioTrack.getMaxVolume(),
            AudioTrack.getMaxVolume());
    bufferRece=new byte[recBufSize];
    return;

}

初始完后开始启动接收线程

void startReceiveThread(){
    new Thread(new Runnable() {
        @Override
        public void run() {
            receiveMsg();
        }
    }).start();
   new Thread(new Runnable() {
        @Override
        public void run() {
            ReceiveVoiceMsg();
                       }
    }).start();

}

 

这里启动了2个线程,一个用来接收文字,一个接收语音。先来看发送的代码,可以用TCP,也可以用使用UDP。作为实时发送用UDP会多一些。效率高一些。这里先将TCP。上代码:

 

void TcpSendMsg() throws UnknownHostException {

    InetAddress inetAddress = InetAddress.getByName(ClientIp);//得到IP地址,注意这个是接收端的ip。

    try {
        Socket tcpSocket = new Socket(inetAddress, 8850);//新建socket,绑定接收端的ip和端口
        OutputStream outputData = tcpSocket.getOutputStream();//创建输出流
        outputData.write(tvServiceMsg.getText().toString().getBytes());//将消息装入输出流
        outputData.close();
        tcpSocket.close();
        Log.d("csl","发送完成");
    }catch (Exception e) {
        e.getMessage();
        Log.d("csl","发送异常");
        Log.d("csl","e.getMessage()="+e.getMessage());
    }

}

看看TCP的接收端,也叫客户端。

String tcpRecSting ="";
   public void TcpReceiveMsg() {

       try {
           if (server == null)
               server = new ServerSocket(8850);//创建socket,绑定端口,这个端口跟发送端是同一个端口号。

       } catch (Exception e) {
           e.printStackTrace();
           Log.d("csl", "ServerSocket error" + e.getMessage());
       }
       while (true) {
           try {
               Log.d("chenshulin", "开始接收");
               final byte[] buffer = new byte[1024];//创建接收缓冲区
               Socket data = server.accept();
               InputStream dataStream = data.getInputStream();
               final int len = dataStream.read(buffer);//读取数据
               tcpRecSting = new String(buffer,0,len);//转化成String
               mHandler.sendEmptyMessage(TCP_MSG);

           } catch (Exception e) {

               Log.d("csl", "接收错误=" + e.getMessage());

           }
       }
   }

 

接下来看看语音数据的发送:

首先还是先要录音

 

View.OnTouchListener touchListener  = new View.OnTouchListener(){
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (v.getId() == R.id.btn_voice_send ){

            switch (event.getAction()) {

                case MotionEvent.ACTION_DOWN:
                    btn_voice_send.setText("正在说话");
                    Log.d("csl","正在说话");
                    try {
                    if (voiceSendSocket == null) {
                        voiceSendSocket = new DatagramSocket(sendPort);
                    }
                    } catch (SocketException e) {
                        e.printStackTrace();
                    }

                    mStartRecorderTime = System.currentTimeMillis();
                    createRecordFileName(mStartRecorderTime+"");
                    if (audioRecordThread == null) {
                        audioRecordThread = new RecordThread();
                    }
                    audioRecordThread.setFlag(true);
                    new Thread(audioRecordThread).start();

                    break;

                case MotionEvent.ACTION_UP:
                    btn_voice_send.setText("按住说话");
                    audioRecordThread.setFlag(false);
                    voiceSendSocket.close();
                    voiceSendSocket= null;
                    try {
                        SaveRecordFile();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    mEndRecorderTime = System.currentTimeMillis();
                    long recTime = (mEndRecorderTime-mStartRecorderTime)/1000;
                    creatMessageBean(recTime+"s", true,mAudioFile.toString());

                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            sendVoiceMsg(mAudioFile.getPath());
                        }
                    }).start();

                break;
            }
        }
        return true;
    }

};
public void run() {
    super.run();
    if (voiceSendSocket == null)
        return;

    try{
        audioRec.startRecording();//开始录音
        while (flag) {
            try {
                byte[] bytes_pkg = buffer.clone();
                if (mRecordQueue.size() >= 2) {
                    int length = audioRec.read(buffer, 0, minBufferSize);
                     mFileOutputStream.write(buffer,0,length);

                }
                mRecordQueue.add(bytes_pkg);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

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

}
private void sendVoiceMsg(String path){
    try {
        Log.d("csl","sendVoiceMsg");
    InetAddress inetAddress = InetAddress.getByName(ClientIp);

    Socket data = new Socket(inetAddress, sendVoicePort);
    OutputStream outputData = data.getOutputStream();
    FileInputStream fileInput = new FileInputStream(path);//获取录制好的音频文件
    int size = -1;
    byte[] buffer = new byte[1024];
    while ((size = fileInput.read(buffer, 0, 1024)) != -1) {//发送音频
        outputData.write(buffer, 0, size);
    }
    outputData.close();
    fileInput.close();
    data.close();
    Log.d("csl","发送完成");
    } catch (Exception e) {
         e.getMessage();
        Log.d("csl","发送异常");
        Log.d("csl","e.getMessage()="+e.getMessage());
    }
}

接收音频文件: 

private ServerSocket server = null;
String savePath;
// 文件接收方法
public String ReceiveVoiceMsg() {
    Log.d("csl","开始接收");
    try {
        if(server == null)
        server = new ServerSocket(sendVoicePort);

    } catch (Exception e) {
        e.printStackTrace();
        Log.d("chenshulin","ServerSocket error" + e.getMessage());
    }
    if (server != null) {
        while (true) {
            try {
                // 接收文件名
                Socket name = server.accept();
                InputStream nameStream = name.getInputStream();
                InputStreamReader streamReader = new InputStreamReader(nameStream);
                BufferedReader br = new BufferedReader(streamReader);
                String fileName = br.readLine();
                br.close();
                streamReader.close();
                nameStream.close();
                name.close();

                // 接收文件数据
                Socket data = server.accept();
                InputStream dataStream = data.getInputStream();
               // File dir = new File("/sdcard/MyMusic"); // 创建文件的存储路径
                File dir =new   File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/UdpPtthDemo/"+System.currentTimeMillis()+".pcm");
              //  if (!dir.exists()) {
                    //dir.mkdirs();
               // }
                savePath = dir.getPath(); // 定义完整的存储路径
                FileOutputStream file = new FileOutputStream(savePath, false);
                byte[] buffer = new byte[1024*8];
                int size = -1;
                while ((size = dataStream.read(buffer)) != -1) {
                    Log.d("csl","received size = "+size);
                    file.write(buffer, 0, size);
                }
                file.close();
                dataStream.close();
                data.close();
                Log.d("chenshulin","接收完成");
             //   creatMessageBean("收到消息",false,savePath);
                mHandler.sendEmptyMessage(RECE_VOICE_MSG);
                return fileName + " 接收完成";
            } catch (Exception e) {

                Log.d("csl","接收错误="+e.getMessage());
                return "接收错误:\n" + e.getMessage();
            }
        }
    }
    return "接收完成" ;
}

 

播放语音消息。将收到的消息list每个item绑定录音文件名, 点击是播放音频。

void playRecordFile(File audioFile) throws IOException {
    FileInputStream inputStream=null;
    inputStream=new FileInputStream(audioFile);
    int read;
    audioTrk.play();
    byte[] mBuffer = new byte[2048];
    while((read=inputStream.read(mBuffer))>0){
        int ret=audioTrk.write(mBuffer,0,read);
        //检查write返回值,错误处理
        switch (ret){
            case AudioTrack.ERROR_INVALID_OPERATION:
            case AudioTrack.ERROR_BAD_VALUE:
            case AudioManager.ERROR_DEAD_OBJECT:
               // playFail();
                return;
            default:
                break;
        }
    }
}

 这里参考了别的同仁博客https://blog.csdn.net/stormxiaofeng/article/details/80513947。大家可以看看。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值