微信公众号:Android疯子
Android基于UDP语音对讲系列(三)
之前研究了基于UDP的文字传输点击打开链接,以及Android端的语音录制点击打开链接,这篇文章就记录一下Android端局域网内的语音传输,简单的实现语音对讲,当然里面还存在着很多问题,包括语音不清晰啊、杂音多啊,不管了,先听见声音就行了。测试的时候两部手机。
程序写了两个线程,一个用于录制AudioRecordThread,一个用于播放AudioTrackThread.
(一)录制与发送
1 @Override
2 public void run() {
3 if (mSocket == null) return;
4 try {
5 mStartTime = System.currentTimeMillis();
6 audioRec.startRecording();
7 while (flag) {
8 try {
9 byte[] bytes_pkg = buffer.clone();
10 if (mRecordQueue.size() >= 2) {
11 int length = audioRec.read(buffer, 0, minBufferSize);
12 //获取音量大小
13 mVolume = getAudioColum(buffer);
14 System.out.println(TAG + "= " + mVolume);
15 Message message = mHandler.obtainMessage();
16 message.arg1 = (int) mVolume;
17 mHandler.sendMessage(message);
18
19 DatagramPacket writePacket;
20 InetAddress inet = InetAddress.getByName(inetAddressName);
21 writePacket = new DatagramPacket(buffer, length, inet, PORT);
22 writePacket.setLength(length);
23 System.out.println("AudioRTwritePacket = " + writePacket.getData().toString());
24
25 mSocket.send(writePacket);
26 }
27 mRecordQueue.add(bytes_pkg);
28 } catch (Exception e) { // TODO Auto-generated catch block
29 e.printStackTrace();
30 }
31 }
32 audioRec.stop();
33 } catch (Exception e) {
34 e.printStackTrace();
35 }
36 }
里面包含了获取音量大小,便于在页面上面展示,方法参考了[点击打开链接]
1private double getAudioColum(byte[] buffer) {
2 double sumVolume = 0.0;
3
4 double avgVolume = 0.0;
5
6 double volume = 0.0;
7
8 for (int i = 0; i < buffer.length; i += 2) {
9 int v1 = buffer[i] & 0xFF;
10
11 int v2 = buffer[i + 1] & 0xFF;
12
13 int temp = v1 + (v2 << 8);// 小端
14
15 if (temp >= 0x8000) {
16 temp = 0xffff - temp;
17
18 }
19 sumVolume += Math.abs(temp);
20
21 }
22 avgVolume = sumVolume / buffer.length / 2;
23
24 volume = Math.log10(1 + avgVolume) * 10;
25
26 return volume;
27}
(二)接收与播放
1@Override
2public void run() {
3 if (mSocket == null) return;
4 //从文件流读数据
5 audioTrk.play();
6 while (flag) {
7 DatagramPacket recevPacket;
8 try {
9 recevPacket = new DatagramPacket(buffer, 0, buffer.length);
10 mSocket.receive(recevPacket);
11 audioTrk.write(recevPacket.getData(), 0, recevPacket.getLength());
12 } catch (IOException e) {
13 // TODO Auto-generated catch block
14 e.printStackTrace();
15 }
16 }
17 audioTrk.stop();
18}
(三)主页面 接收按钮事件
1@OnClick({R.id.btn_receive})
2public void onViewClicked(View view) {
3 switch (view.getId()) {
4 case R.id.btn_receive:
5 if (btnReceive.getText().toString().equals("开始接收")) {
6 btnReceive.setText("停止接收");
7 try {
8 if (audioTrackThread == null) {
9 audioTrackThread = new AudioTrackThread();
10 }
11 new Thread(audioTrackThread).start();
12
13 } catch (SocketException e) {
14 e.printStackTrace();
15 }
16 } else { btnReceive.setText("开始接收");
17 audioTrackThread.setFlag(false);
18 }
19 break;
20 } }
(四)发送按钮事件
1ivSpeak.setOnTouchListener(new View.OnTouchListener() { @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) @Override
2 public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) {
3 case MotionEvent.ACTION_DOWN: //按下按钮开始录制
4 ivSpeak.setText("正在说话");
5 //显示录音提示
6 relativeLayout.setVisibility(View.VISIBLE);
7 try { if (audioRecordThread == null) { audioRecordThread = new AudioRecordThread(handler);
8 } audioRecordThread.setInetAddressName(tvReceiveIp.getText().toString());
9 audioRecordThread.setFlag(true);
10 new Thread(audioRecordThread).start();
11 } catch (SocketException e) { e.printStackTrace();
12 }
13 break;
14 case MotionEvent.ACTION_UP:
15 case MotionEvent.ACTION_CANCEL: //松开按钮结束录制
16 ivSpeak.setText("按住说话");
17 relativeLayout.setVisibility(View.GONE);
18 audioRecordThread.setFlag(false);
19 mStopTime = audioRecordThread.getmStopTime();
20 mStartTime = audioRecordThread.getmStartTime();
21 creatMessageBean((mStopTime - mStartTime) / 1000, true);
22 break;
23 }
24 return true;
25 } });