仿微信音频录入和播放
lib中导入so文件和lib库
libs文件下载地址
链接: https://pan.baidu.com/s/1D1q2PV1IQArK79zAt1cfOw 提取码: f7jg 复制这段内容后打开百度网盘手机App,操作更方便哦
页面主类
package com.example.test_voaacencoder;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.Toast;
import com.example.test_voaacencoder.util.HttpOperateUtil;
import com.sinaapp.bashell.VoAACEncoder;
public class MainActivity extends Activity {
private AudioRecord recordInstance;
private boolean isStartRecord;
private FileOutputStream fos;
private int SAMPLERATE = 8000;
private ImageButton imageButton = null;
private Button mStartPlayBtn;
private Button mStopPlayBtn;
private MediaPlayer mMediaPlayer;
private String mRecordFileName;
String URL_UPLOAD_FILE = "http://192.168.1.147/receive_file.php";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// initView
imageButton = (ImageButton) findViewById(R.id.imageButtonDial);
imageButton.setBackgroundResource(R.drawable.btn_speak_normal);
imageButton.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Log.i("keanbin", "onLongClick()");
setTalkBtnBackground(true);
// 停止播放声音
stopPlay();
// 开始录音
startRecord();
return true;
}
});
imageButton.setOnTouchListener(new MyClickListener());
mStartPlayBtn = (Button) findViewById(R.id.btn_mian_startPlay);
mStartPlayBtn.setOnClickListener(mOnClickListener);
mStopPlayBtn = (Button) findViewById(R.id.btn_mian_stopPlay);
mStopPlayBtn.setOnClickListener(mOnClickListener);
}
private OnClickListener mOnClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_mian_startPlay:
if (isStartRecord) {
stopRecord();
}
startPlay();
break;
case R.id.btn_mian_stopPlay:
stopPlay();
break;
default:
break;
}
}
};
public void startRecord() {
if (!Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED)) {
Toast.makeText(MainActivity.this, "请插入SD卡!", Toast.LENGTH_SHORT)
.show();
return;
}
try {
// mRecordFileName = Environment.getExternalStorageDirectory()
// .toString()
// + "/testAAC"
// + System.currentTimeMillis()
// + ".aac";
mRecordFileName = Environment.getExternalStorageDirectory()
.toString() + "/testAAC.aac";
fos = new FileOutputStream(mRecordFileName);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
System.out.println("fos = " + fos);
new Thread(new Runnable() {
@Override
public void run() {
VoAACEncoder vo = new VoAACEncoder();
vo.Init(SAMPLERATE, 16000, (short) 1, (short) 1);// 采样率:16000,bitRate:32k,声道数:1,编码:0.raw
// 1.ADTS
int min = AudioRecord.getMinBufferSize(SAMPLERATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
if (min < 2048) {
min = 2048;
}
byte[] tempBuffer = new byte[2048];
recordInstance = new AudioRecord(MediaRecorder.AudioSource.MIC,
SAMPLERATE, AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, min);
recordInstance.startRecording();
isStartRecord = true;
while (isStartRecord) {
int bufferRead = recordInstance.read(tempBuffer, 0, 2048);
byte[] ret = vo.Enc(tempBuffer);
if (bufferRead > 0) {
System.out.println("ret:" + ret.length);
try {
fos.write(ret);
} catch (IOException e) {
e.printStackTrace();
}
}
}
recordInstance.stop();
recordInstance.release();
recordInstance = null;
vo.Uninit();
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
public void stopRecord() {
isStartRecord = false;
}
public void startPlay() {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
// TODO Auto-generated method stub
String fileUrl = "http://192.168.1.147/upload/testAAC.aac";
String fileName = HttpOperateUtil.downLoadFile(fileUrl,
fileUrl.substring(fileUrl.lastIndexOf("/") + 1));
Log.i("keanbin", "fileName = " + fileName);
File file = new File(fileName);
if (!file.exists()) {
Toast.makeText(MainActivity.this, "没有音乐文件!", Toast.LENGTH_SHORT)
.show();
return;
}
mMediaPlayer = MediaPlayer.create(MainActivity.this,
Uri.parse(fileName));
mMediaPlayer.setLooping(false);
mMediaPlayer.start();
Looper.loop();
}
}).start();
}
public void stopPlay() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
}
}
@Override
protected void onDestroy() {
stopPlay();
stopRecord();
super.onDestroy();
}
class MyClickListener implements OnTouchListener {
public boolean onTouch(View v, MotionEvent event) {
Log.i("keanbin", "event.getAction() = " + event.getAction());
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
setTalkBtnBackground(false);
// TODO 正常放开,接下来一般做以下事情:发送录音文件到服务器
if (isStartRecord) {
// 停止录音
stopRecord();
Toast.makeText(MainActivity.this, "开始上传文件!",
Toast.LENGTH_SHORT).show();
// 上传文件
HttpOperateUtil
.uploadFile(URL_UPLOAD_FILE, mRecordFileName);
Toast.makeText(MainActivity.this, "上传完文件!",
Toast.LENGTH_SHORT).show();
}
break;
case MotionEvent.ACTION_CANCEL:
setTalkBtnBackground(false);
// TODO 异常放开,接下来一般做以下事情:删除录音文件
// 停止录音
stopRecord();
break;
default:
break;
}
return false;
}
}
public void setTalkBtnBackground(boolean isTalk) {
if (isTalk) {
imageButton.setBackgroundResource(R.drawable.btn_speak_pressed);
} else {
imageButton.setBackgroundResource(R.drawable.btn_speak_normal);
}
}
}
Utli类 上传音频文件和下载音频文件
package com.example.test_voaacencoder.util;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import android.os.Environment;
import android.util.Log;
public class HttpOperateUtil {
public static boolean uploadFile(String uploadUrl, String srcPath) {
String end = "\r\n";
String twoHyphens = "--";
String boundary = "******";
try {
URL url = new URL(uploadUrl);
HttpURLConnection httpURLConnection = (HttpURLConnection) url
.openConnection();
// 设置每次传输的流大小,可以有效防止手机因为内存不足崩溃
// 此方法用于在预先不知道内容长度时启用,没有进行内部缓冲的 HTTP 请求正文的流。
httpURLConnection.setChunkedStreamingMode(128 * 1024);// 128K
// 允许输入输出流
httpURLConnection.setDoInput(true);
httpURLConnection.setDoOutput(true);
httpURLConnection.setUseCaches(false);
// 使用POST方法
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
httpURLConnection.setRequestProperty("Charset", "UTF-8");
httpURLConnection.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + boundary);
DataOutputStream dos = new DataOutputStream(
httpURLConnection.getOutputStream());
dos.writeBytes(twoHyphens + boundary + end);
dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\"; filename=\""
+ srcPath.substring(srcPath.lastIndexOf("/") + 1)
+ "\""
+ end);
dos.writeBytes(end);
// 上传文件内容
FileInputStream fis = new FileInputStream(srcPath);
byte[] buffer = new byte[8192]; // 8k
int count = 0;
// 读取文件
while ((count = fis.read(buffer)) != -1) {
dos.write(buffer, 0, count);
}
fis.close();
dos.writeBytes(end);
dos.writeBytes(twoHyphens + boundary + twoHyphens + end);
dos.flush();
// 服务器返回结果
InputStream is = httpURLConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "utf-8");
BufferedReader br = new BufferedReader(isr);
String result = br.readLine();
// Toast.makeText(this, result, Toast.LENGTH_LONG).show();
Log.i("uploadFile", "uploadFile result = " + result);
try {
dos.close();
} catch (Exception e) {
e.printStackTrace();
// setTitle(e.getMessage());
}
is.close();
return true;
} catch (Exception e) {
e.printStackTrace();
// setTitle(e.getMessage());
}
return false;
}
public static String downLoadFile(String fileUrl, String fileName) {
String fileDir = "";
try {
// 判断SD卡是否存在,并且是否具有读写权限
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
// 获得存储卡的路径
String sdpath = Environment.getExternalStorageDirectory() + "/";
String savePath = sdpath + "download";
URL url = new URL(fileUrl);
// 创建连接
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.connect();
// 获取文件大小
int contentLength = conn.getContentLength();
// 创建输入流
InputStream is = conn.getInputStream();
File file = new File(savePath);
// 判断文件目录是否存在
if (!file.exists()) {
file.mkdir();
}
File apkFile = new File(savePath, fileName);
FileOutputStream fos = new FileOutputStream(apkFile);
int count = 0;
// 缓存
byte buf[] = new byte[1024];
// 写入到文件中
do {
int numread = is.read(buf);
// count += numread;
// // 计算进度条位置
// mPercent = (int) (((float) count / contentLength) * 100);
// // 更新进度
// mHandler.sendEmptyMessage(DOWNLOAD_PERCENT);
if (numread <= 0) {
// 下载完成
fileDir = savePath + "/" + fileName;
// if (checkUpdateResult(apkFile)) {
// // 下载成功
//
// } else {
// // 下载失败
// fos.close();
// is.close();
// // throw new RuntimeException("下载文件出错");
// }
break;
}
// 写入文件
fos.write(buf, 0, numread);
} while (true);// !mCancelUpdate);// 点击取消就停止下载.
fos.close();
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
return fileDir;
}
}
main.xml 文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="仿照米聊和微信中语音通话时按住按钮是一个状态和松开手是一个状态的效果,加入防止用户手jian狂按按钮导致的异常" />
<Button
android:id="@+id/btn_mian_startPlay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="播放录音" />
<Button
android:id="@+id/btn_mian_stopPlay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="停止播放" />
<ImageButton
android:id="@+id/imageButtonDial"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="20dip"
android:layout_marginTop="20dip" />
</LinearLayout>
录音按钮图片
在这里插入图片描述