Android MediaRecorder实现暂停断点录音功能
基本原理如下:MediaRecorder通过MIC录音,系统没有自带的pause功能,每次暂停录音,都会结束本次的录音。现在本人的设计思路是:MediaRecorder录音暂停时,保存这段所录下的音频A,继续录音后,再次暂停,保留录音音频B;以此类推直到最终的录音结束时,依次读取之前保存的A、B……的录音文件,并将其合并在一起。涉及的技术:文件的保存读取、音频的合并等
音频的合并:设置MediaRecorder的音频输出格式mMediaRecorder01.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
mMediaRecorder01 .setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
输出的是amr格式。amr的音频文件的文件头,相对来说是固定的6个字节的固定字符,A.amr文件和B.amr文件的合并,只需将B以字节流读取,去
掉前6个字节,和A的字节流合并后保存,就实现了音频合并,不涉及复杂的音频编码问题。(MediaRecorder的音频输出格式比较多,有jpgg、MP3等之类的格式,合成的原理大同小异,只需要注意他们的音频文件头的格式就可以了。)
public class EX07 extends Activity {
private ImageButton myButton1;
private ImageButton myButton2;
private ImageButton myButton3;
private ImageButton myButton4;
private Button myButton;
private ListView myListView1;
private String strTempFile = "YYT_";
private File myRecAudioFile;
/**录音保存路径**/
private File myRecAudioDir;
private File myPlayFile;
private MediaRecorder mMediaRecorder01;
private int mMinute;
private boolean xx=true;
/**存放音频文件列表**/
private ArrayList<String> recordFiles;
private ArrayAdapter<String> adapter;
private TextView myTextView1;
/**文件存在**/
private boolean sdcardExit;
/**是否停止录音**/
private boolean isStopRecord;
/**按钮背景图片的标志位**/
private boolean sigle = false;
private String length1 = null; private final String SUFFIX=".amr"; /**暂停按钮**/
Button buttonpause; /**记录需要合成的几段amr语音文件**/
private ArrayList<String> list; int second=; int minute=; /**计时器**/
Timer timer; /**是否暂停标志位**/
private boolean isPause; /**在暂停状态中**/
private boolean inThePause; /** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.main); //暂停标志位 为false
isPause=false;
//暂停状态标志位
inThePause=false; //初始化list
list=new ArrayList<String>(); //四个按钮
myButton1 = (ImageButton) findViewById(R.id.ImageButton01);
myButton2 = (ImageButton) findViewById(R.id.ImageButton02);
myButton3 = (ImageButton) findViewById(R.id.ImageButton03);
myButton4 = (ImageButton) findViewById(R.id.ImageButton04);
myButton = (Button) findViewById(R.id.myButton);
buttonpause=(Button)findViewById(R.id.mypuase);
myListView1 = (ListView) findViewById(R.id.ListView01);
myTextView1 = (TextView) findViewById(R.id.TextView01);
myButton2.setEnabled(false);
myButton3.setEnabled(false);
myButton4.setEnabled(false); myPlayFile=null; // 判断sd Card是否插入
sdcardExit = Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED);
// 取得sd card路径作为录音文件的位置
if (sdcardExit){
String pathStr = Environment.getExternalStorageDirectory().getPath()+"/YYT";
myRecAudioDir= new File(pathStr);
if(!myRecAudioDir.exists()){
myRecAudioDir.mkdirs();
Log.v("录音", "创建录音文件!" + myRecAudioDir.exists());
}
// Environment.getExternalStorageDirectory().getPath() + "/" + PREFIX + "/";
}
// 取得sd card 目录里的.arm文件
getRecordFiles(); adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, recordFiles);
// 将ArrayAdater添加ListView对象中
myListView1.setAdapter(adapter);
// 录音 myButton1.setOnClickListener(new ImageButton.OnClickListener() { @Override
public void onClick(View v) {
second=;
minute=; list.clear();
// Calendar c=Calendar.getInstance();
// int mMinute1=c.get(Calendar.MINUTE); sigle = true;
// TODO Auto-generated method stub start(); if (sigle = false) {
myButton1.setBackgroundResource(R.drawable.record_hover1);
} else {
myButton1.setBackgroundResource(R.drawable.record_dis1);
myButton2.setBackgroundResource(R.drawable.stop_hover2);
myButton3.setBackgroundResource(R.drawable.play_hover1);
myButton4.setBackgroundResource(R.drawable.delete_hover);
} } });
// 停止
myButton2.setOnClickListener(new ImageButton.OnClickListener() { @Override
public void onClick(View v) { xx=false;
sigle = true;
timer.cancel();
// TODO Auto-generated method stub //这里写暂停处理的 文件!加上list里面 语音合成起来
if(isPause){ //在暂停状态按下结束键,处理list就可以了
if(inThePause){
getInputCollection(list, false);
}
//在正在录音时,处理list里面的和正在录音的语音
else{
list.add(myRecAudioFile.getPath());
recodeStop();
getInputCollection(list, true);
} //还原标志位
isPause=false;
inThePause=false;
buttonpause.setText("暂停录音"); // adapter.add(myRecAudioFile.getName()); } //若录音没有经过任何暂停
else{ if (myRecAudioFile != null) {
// 停止录音
mMediaRecorder01.stop();
mMediaRecorder01.release();
mMediaRecorder01 = null;
// 将录音频文件给Adapter
adapter.add(myRecAudioFile.getName());
DecimalFormat df = new DecimalFormat("#.000");
if (myRecAudioFile.length() <= *) {
//length1 = (myRecAudioFile.length() / 1024.0)+""; length1=df.format(myRecAudioFile.length() / 1024.0)+"K";
} else {
//length1 = (myRecAudioFile.length() / 1024.0 / 1024)+"";
//DecimalFormat df = new DecimalFormat("#.000");
length1=df.format(myRecAudioFile.length() / 1024.0 / )+"M";
}
System.out.println(length1); myTextView1.setText("停 止" + myRecAudioFile.getName()
+ "文件大小为:" + length1);
myButton2.setEnabled(false); } } if (sigle = false) {
myButton2.setBackgroundResource(R.drawable.stop_hover2);
} else {
myButton1.setBackgroundResource(R.drawable.record_hover1);
myButton2.setBackgroundResource(R.drawable.stop1);
myButton3.setBackgroundResource(R.drawable.play_hover1);
myButton4.setBackgroundResource(R.drawable.delete_hover);
} //停止录音了
isStopRecord = true;
} }); // 播放
myButton3.setOnClickListener(new ImageButton.OnClickListener() { @Override
public void onClick(View v) {
sigle = true;
// TODO Auto-generated method stub
if (myPlayFile != null && myPlayFile.exists()) {
// 打开播放程序
openFile(myPlayFile);
} else {
Toast.makeText(EX07.this, "你选的是一个空文件", Toast.LENGTH_LONG)
.show();
Log.d("没有选择文件","没有选择文件");
}
if (sigle = false) {
myButton3.setBackgroundResource(R.drawable.play_hover1);
} else {
myButton1.setBackgroundResource(R.drawable.record_hover1);
myButton2.setBackgroundResource(R.drawable.stop_hover2);
myButton3.setBackgroundResource(R.drawable.play1);
myButton4.setBackgroundResource(R.drawable.delete_hover);
}
} }); // 删除
myButton4.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
sigle = true;
// TODO Auto-generated method stub if (myPlayFile != null) {
// 先将Adapter删除文件名
adapter.remove(myPlayFile.getName());
// 删除文件
if (myPlayFile.exists())
myPlayFile.delete();
myTextView1.setText("完成删除!"); }
if (sigle = false) {
myButton4.setBackgroundResource(R.drawable.delete_hover);
} else {
myButton1.setBackgroundResource(R.drawable.record_hover1);
myButton2.setBackgroundResource(R.drawable.stop_hover2);
myButton3.setBackgroundResource(R.drawable.play_hover1);
myButton4.setBackgroundResource(R.drawable.delete_dis);
}
}
}); /**
* 暂停按钮,记录之前保存的语音文件
*/
buttonpause.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
// TODO Auto-generated method stub isPause=true; //已经暂停过了,再次点击按钮 开始录音,录音状态在录音中
if(inThePause){
buttonpause.setText("暂停录音");
start();
inThePause=false; }
//正在录音,点击暂停,现在录音状态为暂停
else{ //当前正在录音的文件名,全程
list.add(myRecAudioFile.getPath());
inThePause=true;
recodeStop();
//start();
buttonpause.setText("继续录音"); //计时停止
timer.cancel();
}
}
}); myListView1
.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg, View arg1,
int arg2, long arg3) {
// TODO Auto-generated method stub
// 当有单点击文件名时将删除按钮及播放按钮Enable
myButton3.setEnabled(true);
myButton4.setEnabled(true);
myPlayFile = new File(myRecAudioDir.getAbsolutePath()
+ File.separator
+ ((TextView) arg1).getText().toString()); DecimalFormat df = new DecimalFormat("#.000");
if (myPlayFile.length() <= *) {
length1=df.format(myPlayFile.length() / 1024.0)+"K";
} else {
length1=df.format(myPlayFile.length() / 1024.0/)+"M";
}
myTextView1.setText("你选的是"
+ ((TextView) arg1).getText().toString()
+ "文件大小为:" + length1);
Toast.makeText(EX07.this,"你选的是" + (((TextView) arg1).getText())+ "文件大小为:" + length1,
Toast.LENGTH_LONG).show(); } }); myButton.setOnClickListener(new Button.OnClickListener() { @Override
public void onClick(View v) {
// TODO Auto-generated method stub
showSize show = new showSize();
String text = show.showsize();
Toast.makeText(EX07.this, text, Toast.LENGTH_LONG).show();
}
});
} protected void recodeStop() {
if (mMediaRecorder01 != null && !isStopRecord) {
// 停止录音
mMediaRecorder01.stop();
mMediaRecorder01.release();
mMediaRecorder01 = null;
} timer.cancel();
} /**
* activity的生命周期,stop时关闭录音资源
*/
@Override
protected void onStop() {
// TODO Auto-generated method stub
if (mMediaRecorder01 != null && !isStopRecord) {
// 停止录音
mMediaRecorder01.stop();
mMediaRecorder01.release();
mMediaRecorder01 = null;
}
super.onStop();
} /**
* 获取目录下的所有音频文件
*/
private void getRecordFiles() {
// TODO Auto-generated method stub
recordFiles = new ArrayList<String>();
if (sdcardExit) {
File files[] = myRecAudioDir.listFiles();
if (files != null) {
for (int i = ; i < files.length; i++) {
if (files[i].getName().indexOf(".") >= ) { // 只取.amr 文件
String fileS = files[i].getName().substring(
files[i].getName().indexOf("."));
if (fileS.toLowerCase().equals(".mp3")
|| fileS.toLowerCase().equals(".amr")
|| fileS.toLowerCase().equals(".mp4"))
recordFiles.add(files[i].getName()); }
}
}
} } // 打开录音播放程序
private void openFile(File f) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(android.content.Intent.ACTION_VIEW);
String type = getMIMEType(f);
intent.setDataAndType(Uri.fromFile(f), type);
startActivity(intent);
// Uri uri=Uri.fromFile(f);
// MediaPlayer mediaPlayer=MediaPlayer.create(this, uri);
// try {
// mediaPlayer.prepare();
// } catch (IllegalStateException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// mediaPlayer.start();
} private String getMIMEType(File f) { String end = f.getName().substring(f.getName().lastIndexOf(".") + ,
f.getName().length()).toLowerCase();
String type = "";
if (end.equals("mp3") || end.equals("aac") || end.equals("amr")
|| end.equals("mpeg") || end.equals("mp4")) {
type = "audio";
} else if (end.equals("jpg") || end.equals("gif") || end.equals("png")
|| end.equals("jpeg")) {
type = "image";
} else {
type = "*";
}
type += "/";
return type;
} private void start(){ TimerTask timerTask=new TimerTask() { @Override
public void run() {
// TODO Auto-generated method stub
second++;
if(second>=){
second=;
minute++;
}
handler.sendEmptyMessage();
}
};
timer=new Timer();
timer.schedule(timerTask, ,); try {
if (!sdcardExit) {
Toast.makeText(EX07.this, "请插入SD card",
Toast.LENGTH_LONG).show();
return;
}
String mMinute1=getTime();
Toast.makeText(EX07.this, "当前时间是:"+mMinute1,Toast.LENGTH_LONG).show();
// 创建音频文件
// myRecAudioFile = File.createTempFile(mMinute1, ".amr",
// myRecAudioDir); myRecAudioFile=new File(myRecAudioDir,mMinute1+SUFFIX);
mMediaRecorder01 = new MediaRecorder();
// 设置录音为麦克风
mMediaRecorder01
.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder01
.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
mMediaRecorder01
.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); //录音文件保存这里
mMediaRecorder01.setOutputFile(myRecAudioFile
.getAbsolutePath());
mMediaRecorder01.prepare();
mMediaRecorder01.start(); // mMediaRecorder01.getMaxAmplitude();
// mMediaRecorder01.getAudioSourceMax();
mMediaRecorder01.setOnInfoListener(new OnInfoListener() { @Override
public void onInfo(MediaRecorder mr, int what, int extra) {
// TODO Auto-generated method stub
int a=mr.getMaxAmplitude();
Toast.makeText(EX07.this, a, ).show();
}
}); myTextView1.setText("录音中......");
myButton2.setEnabled(true);
myButton3.setEnabled(false);
myButton4.setEnabled(false);
isStopRecord = false;
} catch (IOException e) {
e.printStackTrace(); } }
private String getTime(){
SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年MM月dd日HH:mm:ss");
Date curDate=new Date(System.currentTimeMillis());//获取当前时间
String time = formatter.format(curDate);
System.out.println("当前时间");
return time;
} Handler handler=new Handler(){ @Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg); myTextView1.setText("录音时间:"+minute+":"+second);
} }; /**
* @param isAddLastRecord 是否需要添加list之外的最新录音,一起合并
* @return 将合并的流用字符保存
*/
public void getInputCollection(List list,boolean isAddLastRecord){ String mMinute1=getTime();
Toast.makeText(EX07.this, "当前时间是:"+mMinute1,Toast.LENGTH_LONG).show(); // 创建音频文件,合并的文件放这里
File file1=new File(myRecAudioDir,mMinute1+SUFFIX);
FileOutputStream fileOutputStream = null; if(!file1.exists()){
try {
file1.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
fileOutputStream=new FileOutputStream(file1); } catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//list里面为暂停录音 所产生的 几段录音文件的名字,中间几段文件的减去前面的6个字节头文件 for(int i=;i<list.size();i++){
File file=new File((String) list.get(i));
Log.d("list的长度", list.size()+"");
try {
FileInputStream fileInputStream=new FileInputStream(file);
byte []myByte=new byte[fileInputStream.available()];
//文件长度
int length = myByte.length; //头文件
if(i==){
while(fileInputStream.read(myByte)!=-){
fileOutputStream.write(myByte, ,length);
}
} //之后的文件,去掉头文件就可以了
else{
while(fileInputStream.read(myByte)!=-){ fileOutputStream.write(myByte, , length-);
}
} fileOutputStream.flush();
fileInputStream.close();
System.out.println("合成文件长度:"+file1.length()); } catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
//结束后关闭流
try {
fileOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //加上当前正在录音的这一段
// if(isAddLastRecord){
//
//
// //刚刚录音的
// try {
// FileInputStream fileInputStream=new FileInputStream(myRecAudioFile);
// byte []myByte=new byte[fileInputStream.available()];
// System.out.println(fileInputStream.available()+"");
// while(fileInputStream.read(myByte)!=-1){
// //outputStream.
// fileOutputStream.write(myByte, 6, (fileInputStream.available()-6));
// }
//
// fileOutputStream.flush();
// fileInputStream.close();
// fileOutputStream.close();
// System.out.println("合成文件长度:"+file1.length());
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//
// } //合成一个文件后,删除之前暂停录音所保存的零碎合成文件
deleteListRecord(isAddLastRecord);
//
adapter.add(file1.getName()); } private void deleteListRecord(boolean isAddLastRecord){
for(int i=;i<list.size();i++){
File file=new File((String) list.get(i));
if(file.exists()){
file.delete();
}
}
//正在暂停后,继续录音的这一段音频文件
if(isAddLastRecord){
myRecAudioFile.delete();
}
}
}
Android MediaRecorder实现暂停断点录音功能的更多相关文章
- Android 能够暂停的录音功能
Android ApI提供了MediaRecorder和AudioRecord两个类给开发者来很方便地实现音视频的录制(前者可以实现音频和视频的录制,后者只能实 现音频的录制).这两个类都提供了sta ...
- Android MediaRecorder解析
源码路径:frameworks/base/media/java/android/media/MediaRecorder.javaframeworks/base/media/jni/android_me ...
- android 脱壳 之 dvmDexFileOpenPartial断点脱壳原理分析
android 脱壳 之 dvmDexFileOpenPartial断点脱壳原理分析 导语: 笔者主要研究方向是网络通信协议的加密解密, 对应用程序加固脱壳技术很少研究, 脱壳壳经历更是经历少之甚少. ...
- Android MediaRecorder自定义分辨率
Android MediaRecorder自定义分辨率 工作这么久了,确实积累了不少东西,但都是以文档的形式存在U盘里的,为什么不写博客呢?因为懒啊!!!总感觉博客太难写了(大概是上学时候写作文恐惧症 ...
- Android MediaRecorder录制播放音频
1.请求录制音频权限 <user-permission android:name="android.permission.RECORD_AUDIO"/> RECORD_ ...
- android studio学习----调试---断点调试
Android Studio调试其实也非常方便,一般问题直接通过AS的DDMS的Logcat就可以搞定.AS支持类似Eclipse的DDMS的所有功能.这里要说的是疑难问题的调试方式,即断点调试. 首 ...
- Android MediaRecorder录制音频
今天介绍一下在Android中怎么录制音频,在Android中使用MediaRecorder来录制音频,步骤: 1.创建MediaRecorder对象. 2.调用MediaRecorder对象的set ...
- VS2015 使用 Visual Studio Emulator For Android 调试无法命中断点的解决办法?
源解决方案是英文版的,地址:https://dzone.com/articles/fix-for-could-not-connect-to-the-debugger-while-de 问题现象: 1. ...
- Android -- 多线程下载, 断点下载
1. 原理图 2. 示例代码 需要权限 <uses-permission android:name="android.permission.INTERNET"/> &l ...
随机推荐
- 自定义View实现钟摆效果进度条PendulumView
转载请注明出处:http://blog.csdn.net/fightlei/article/details/52556755 在网上看到了一个IOS组件PendulumView,实现了钟摆的动画效果. ...
- 获取LAMP与LNMP的编译参数
1.查看nginx的编译参数[root@LNMP ~]# /application/nginx/sbin/nginx -Vnginx version: nginx/1.6.3built by gcc ...
- MySQL授权命令grant的详细使用方法
2019-01-07 转自 https://www.cnblogs.com/crxis/p/7044582.html 本文实例,运行于 MySQL 5.0 及以上版本. MySQL 赋予用户权限命令的 ...
- C语言实现全排列和回溯法总结
一.递归实现全排列 #include"cstdio" ]; void print_permutation(int n,int *A,int cur){ if(cur==n){ ;i ...
- Zookeeper---系统学习
1.概述 1.1 Zookeeper解决了什么问题? 分布式环境中 协调和管理服务 是一个复杂的过程: Zookeeper通过 其简单的架构和API 解决了这个问题,Zookeeper ...
- 使用java配置来构建spring项目
java配置是Spring4.x推荐的配置方式,可以完全代替xml配置,java配置是通过@Configuration和@Bean来实现的.@Configuration声明当前类是一个配置类,相当于S ...
- dfs.replication、dfs.replication.min/max及dfs.safemode.threshold.pct
一.参数含义 dfs.replication:设置数据块应该被复制的份数: dfs.replication.min:所规定的数据块副本的最小份数: dfs.replication.max:所规定的数据 ...
- 开发常用的 JavaScript 知识点总结
No1.语法和类型 1.声明定义 变量类型:var,定义变量:let,定义块域(scope)本地变量:const,定义只读常量.变量格式:以字母.下划线“_”或者$符号开头,大小写敏感.变量赋值:声明 ...
- 简单的js定时器
var flag = 0; var time = 0; var stoptime = setInterval(function(){ if (flag<9999999) { //执行定时器 } ...
- Oracle PL/SQL Developer 上传下载Excel
接到需求,Oracle数据库对Excel数据进行上传和下载,百度后没有很全的方案,整理搜到的资料,以备不时之需. 一.下载Oracle数据到Excel中. 下载数据到Excel在MSSql中很简单,直 ...