Android仿微信录音功能(录音后的raw文件转mp3文件)

现在很多时候需要用到录音,然后如果我们的App是ios和android两端的话,就要考虑录音的文件在两端都能使用,这个时候就需要适配,两端的录音文件都要是mp3文件,这样才能保证两边都能播放。

针对这个,封装了一个简单可用的录音控件。

使用方法:

1.在xml文件中添加

<ant.muxi.com.audiodemo.view.SoundTextView
 android:id="@+id/record_audio"
 android:text="按住开始录音"
 android:gravity="center"
 android:background="@drawable/bg_round_black"
 android:layout_marginLeft="20dp"
 android:layout_marginRight="20dp"
 android:layout_marginBottom="40px"
 android:padding="20px"
 android:layout_width="match_parent"
 android:layout_height="wrap_content">
 </ant.muxi.com.audiodemo.view.SoundTextView>

2.别忘了申请录音权限

AndPermission.with(MainActivity.this)
  .permission(Manifest.permission.RECORD_AUDIO,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE)
  .onGranted(permissions -> {
   showSelect();
  })
  .onDenied(permissions -> {
   Toast.makeText(MainActivity.this,"请同意录音权限",Toast.LENGTH_SHORT).show();
  })
  .start();
private void showSelect() {
 SoundTextView recordAudio = findViewById(R.id.record_audio);
 recordAudio.setOnRecordFinishedListener(new SoundTextView.OnRecordFinishedListener() {
  @Override
  public void newMessage(String path, int duration) {
  int index = path.lastIndexOf("/");
  String fileName = path.substring(index + 1);
  Log.e("录音文件", "path=: "+path );
  }
 });
 }

使用方法如上非常简单:

主要的类

package ant.muxi.com.audiodemo.view;
 import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.widget.AppCompatTextView;
import java.io.File;
import ant.muxi.com.audiodemo.R;
import ant.muxi.com.audiodemo.audio.ProgressTextUtils;
import ant.muxi.com.audiodemo.audio.RecordManager;
public class SoundTextView extends AppCompatTextView {
 private Context mContext;
 private Dialog recordIndicator;
 private TextView mVoiceTime;
 private File file;
 private String type = "1";//默认开始录音 type=2,录音完毕
 RecordManager recordManager;
 File fileto;
 int level;
 private long downT;
 String sountime;
 public SoundTextView(Context context) {
 super(context);
 init();
 }
 public SoundTextView(Context context, AttributeSet attrs, int defStyle) {
 super(context, attrs, defStyle);
 this.mContext = context;
 init();
 }
 public SoundTextView(Context context, AttributeSet attrs) {
 super(context, attrs);
 this.mContext = context;
 init();
 }
 private void init() {
 recordIndicator = new Dialog(getContext(), R.style.jmui_record_voice_dialog);
 recordIndicator.setContentView(R.layout.jmui_dialog_record_voice);
 mVoiceTime = (TextView) recordIndicator.findViewById(R.id.voice_time);
 file = new File(Environment.getExternalStorageDirectory() + "/recoder.amr");
 fileto = new File(Environment.getExternalStorageDirectory() + "/recoder.mp3");
 recordManager = new RecordManager(
  (Activity) mContext,
  String.valueOf(file),
  String.valueOf(fileto));
 recordManager.setOnAudioStatusUpdateListener(new RecordManager.OnAudioStatusUpdateListener() {
  @Override
  public void onUpdate(double db) {
  //得到分贝
  if (null != recordIndicator) {
   level = (int) db;
   handler.sendEmptyMessage(0x111);
  }
  }
 });
 }
 Handler handler = new Handler() {
 @Override
 public void handleMessage(Message msg) {
  super.handleMessage(msg);
  switch (msg.what) {
  case 0x111:
   sountime = ProgressTextUtils.getSecsProgress(System.currentTimeMillis() - downT);
   long time = System.currentTimeMillis() - downT;
   mVoiceTime.setText(ProgressTextUtils.getProgressText(time));
   //判断时间
   judetime(Integer.parseInt(sountime));
   break;
  }
 }
 };
 public void judetime(int time) {
 if (time > 14) {
  //结束录制
  Toast.makeText(mContext, "录音不能超过十五秒", Toast.LENGTH_SHORT).show();
  recordManager.stop_mp3();
  new Thread() {
  @Override
  public void run() {
   super.run();
   recordManager.saveData();
   finishRecord(fileto.getPath(), sountime);
  }
  }.start();
  recordIndicator.dismiss();
  type = "2";
 }
 }
 @Override
 public boolean onTouchEvent(MotionEvent event) {
 int action = event.getAction();
 switch (action) {
  case MotionEvent.ACTION_DOWN:
  if (type.equals("1")) {
   //开始发送时间
   downT = System.currentTimeMillis();
   recordManager.start_mp3();
   recordIndicator.show();
  } else {
   Log.e("-log-", "您已经录制完毕: ");
  }
  return true;
  case MotionEvent.ACTION_UP:
  if (type.equals("1")) {
   try {
   if (Integer.parseInt(sountime) > 2) {
    recordManager.stop_mp3();
    new Thread() {
    @Override
    public void run() {
     super.run();
     recordManager.saveData();
     finishRecord(fileto.getPath(), sountime);
    }
    }.start();
    if (recordIndicator.isShowing()) {
    recordIndicator.dismiss();
    }
    type = "2";
   } else {
    recordManager.stop_mp3();
    if (recordIndicator.isShowing()) {
    recordIndicator.dismiss();
    }
    sountime = null;
    Toast.makeText(mContext, "录音时间少于3秒,请重新录制", Toast.LENGTH_SHORT).show();
   }
   } catch (Exception e) {
   recordManager.stop_mp3();
   if (recordIndicator.isShowing()) {
    recordIndicator.dismiss();
   }
   sountime = null;
   Toast.makeText(mContext, "录音时间少于3秒,请重新录制", Toast.LENGTH_SHORT).show();
   }
  }
  break;
  case MotionEvent.ACTION_CANCEL:
  if (recordIndicator.isShowing()) {
   recordIndicator.dismiss();
  }
  break;
 }
 return super.onTouchEvent(event);
 }
 //录音完毕加载 ListView item
 private void finishRecord(String path, String time) {
 if (onRecordFinishedListener != null) {
  onRecordFinishedListener.newMessage(path, Integer.parseInt(time));
  type = "1";
 }
 //发送语音
 // Toasts.toast(getContext(),"您已经录完了一条语音"+myRecAudioFile);
 }
 private OnRecordFinishedListener onRecordFinishedListener;
 public void setOnRecordFinishedListener(OnRecordFinishedListener onRecordFinishedListener) {
 this.onRecordFinishedListener = onRecordFinishedListener;
 }
 public interface OnRecordFinishedListener {
 void newMessage(String path, int duration);
 }
}

主要的录音管理类

public class RecordManager {
 //录制成MP3格式..............................................
 /**构造时候需要的Activity,主要用于获取文件夹的路径*/
 private Activity activity;
 /**文件代号*/
 public static final int RAW = 0X00000001;
 public static final int MP3 = 0X00000002;
 /**文件路径*/
 private String rawPath = null;
 private String mp3Path = null;
 /**采样频率*/
 private static final int SAMPLE_RATE = 11025;
 /**录音需要的一些变量*/
 private short[] mBuffer;
 private AudioRecord mRecorder;
 /**录音状态*/
 private boolean isRecording = false;
 /**是否转换ok*/
 private boolean convertOk = false;
 public RecordManager(Activity activity, String rawPath, String mp3Path) {
 this.activity = activity;
 this.rawPath = rawPath;
 this.mp3Path = mp3Path;
 }
 /**开始录音*/
 public boolean start_mp3() {
 // 如果正在录音,则返回
 if (isRecording) {
  return isRecording;
 }
 // 初始化
 if (mRecorder == null) {
  initRecorder();
 }
 getFilePath();
 mRecorder.startRecording();
 startBufferedWrite(new File(rawPath));
 isRecording = true;
 return isRecording;
 }
 /**停止录音,并且转换文件,这很可能是个耗时操作,建议在后台中做*/
 public boolean stop_mp3() {
 if (!isRecording) {
  return isRecording;
 }
 // 停止
 mRecorder.stop();
 isRecording = false;
//TODO
 // 开始转换(转换代码就这两句)
// FLameUtils lameUtils = new FLameUtils(1, SAMPLE_RATE, 96);
// convertOk = lameUtils.raw2mp3(rawPath, mp3Path);
// return isRecording ^ convertOk;// convertOk==true,return true
 return isRecording;
 }
 public void saveData(){
 FLameUtils lameUtils = new FLameUtils(1, SAMPLE_RATE, 96);
 convertOk = lameUtils.raw2mp3(rawPath, mp3Path);
 }
 /**获取文件的路径*/
 public String getFilePath(int fileAlias) {
 if (fileAlias == RAW) {
  return rawPath;
 } else if (fileAlias == MP3) {
  return mp3Path;
 } else
  return null;
 }
 /**清理文件*/
 public void cleanFile(int cleanFlag) {
 File f = null;
 try {
  switch (cleanFlag) {
  case MP3:
   f = new File(mp3Path);
   if (f.exists())
   f.delete();
   break;
  case RAW:
   f = new File(rawPath);
   if (f.exists())
   f.delete();
   break;
  case RAW | MP3:
   f = new File(rawPath);
   if (f.exists())
   f.delete();
   f = new File(mp3Path);
   if (f.exists())
   f.delete();
   break;
  }
  f = null;
 } catch (Exception e) {
  e.printStackTrace();
 }
 }
 /**关闭,可以先调用cleanFile来清理文件*/
 public void close() {
 if (mRecorder != null)
  mRecorder.release();
 activity = null;
 }
 /**初始化*/
 private void initRecorder() {
 int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE,
  AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
 mBuffer = new short[bufferSize];
 mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE,
  AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
  bufferSize);
 }
 /**设置路径,第一个为raw文件,第二个为mp3文件*/
 private void getFilePath() {
 try {
  String folder = "audio_recorder_2_mp3";
  String fileName = String.valueOf(System.currentTimeMillis());
  if (rawPath == null) {
  File raw = new File(activity.getDir(folder,
   activity.MODE_PRIVATE), fileName + ".raw");
  raw.createNewFile();
  rawPath = raw.getAbsolutePath();
  raw = null;
  }
  if (mp3Path == null) {
  File mp3 = new File(activity.getDir(folder,
   activity.MODE_PRIVATE), fileName + ".mp3");
  mp3.createNewFile();
  mp3Path = mp3.getAbsolutePath();
  mp3 = null;
  }
  Log.d("rawPath", rawPath);
  Log.d("mp3Path", mp3Path);
 } catch (Exception e) {
  e.printStackTrace();
 }
 }
 /**执行cmd命令,并等待结果*/
 private boolean runCommand(String command) {
 boolean ret = false;
 Process process = null;
 try {
  process = Runtime.getRuntime().exec(command);
  process.waitFor();
  ret = true;
 } catch (Exception e) {
  e.printStackTrace();
 } finally {
  try {
  process.destroy();
  } catch (Exception e) {
  e.printStackTrace();
  }
 }
 return ret;
 }
 /**写入到raw文件*/
 private void startBufferedWrite(final File file) {
 Object mLock = new Object();
 new Thread(new Runnable() {
  @Override
  public void run() {
  DataOutputStream output = null;
  try {
   output = new DataOutputStream(new BufferedOutputStream(
    new FileOutputStream(file)));
   while (isRecording) {//开始录制
   int readSize = mRecorder.read(mBuffer, 0,
    mBuffer.length);//是实际读取的数据长度
   for (int i = 0; i < readSize; i++) {
    output.writeShort(mBuffer[i]);
   }
   long v = 0;
   // 将 buffer 内容取出,进行平方和运算
   for (int i = 0; i < mBuffer.length; i++) {
    v += mBuffer[i] * mBuffer[i];
   }
   // 平方和除以数据总长度,得到音量大小。
   double mean = v / (double) readSize;
   double volume = 10 * Math.log10(mean);
   synchronized (mLock) {
    try {
    if(null != audioStatusUpdateListener) {
     audioStatusUpdateListener.onUpdate(volume);
    }
    mLock.wait(100);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
   }
   }
  } catch (IOException e) {
   e.printStackTrace();
  } finally {
   if (output != null) {
   try {
    output.flush();
   } catch (IOException e) {
    e.printStackTrace();
   } finally {
    try {
    output.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
   }
   }
  }
  }
 }).start();
 }
 public RecordManager.OnAudioStatusUpdateListener audioStatusUpdateListener;
 public void setOnAudioStatusUpdateListener(RecordManager.OnAudioStatusUpdateListener audioStatusUpdateListener) {
 this.audioStatusUpdateListener = audioStatusUpdateListener;
 }
 public interface OnAudioStatusUpdateListener {
 public void onUpdate(double db);
 }
}

完整代码:http://xiazai.jb51.net/201911/yuanma/AudioDemo_jb51.rar

总结

以上所述是小编给大家介绍的Android仿微信录音功能(录音后的raw文件转mp3文件,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • Android仿微信语音对讲录音功能

    自微信出现以来取得了很好的成绩,语音对讲的实现更加方便了人与人之间的交流.今天来实践一下微信的语音对讲的录音实现,这个也比较容易实现.在此,我将该按钮封装成为一个控件,并通过策略模式的方式实现录音和界面的解耦合,以方便我们在实际情况中对录音方法的不同需求(例如想要实现wav格式的编码时我们也就不能再使用MediaRecorder,而只能使用AudioRecord进行处理). 效果图: 实现思路: 1.在微信中我们可以看到实现语音对讲的是通过点按按钮来完成的,因此在这里我选择重新自己的控件使其继承

  • Android实现录音方法(仿微信语音、麦克风录音、发送语音、解决5.0以上BUG)

    先给大家展示下效果图,如果大家感觉不错,请参考使用方法, 效果图如下所示: 使用方法: 录音工具类:AudioRecoderUtils.java,代码如下: public class AudioRecoderUtils { //文件路径 private String filePath; //文件夹路径 private String FolderPath; private MediaRecorder mMediaRecorder; private final String TAG = "fan&q

  • Android仿微信录音功能

    提要:需求是开发类似微信发语音的功能,没有语音转文字.网上看了一些代码,不能拿来直接用,部分代码逻辑有问题,所以想把自己的代码贴出来,仅供参考. 功能: a.设置最大录音时长和录音倒计时(为了方便测试,最大时长设置为15秒,开始倒计时设置为7秒) b.在录音之前检查录音和存储权限 源码: 1.录音对话框管理类DialogManager: /** * 功能:录音对话框管理类 */ public class DialogManager { private AlertDialog.Builder bu

  • Android仿微信录音功能(录音后的raw文件转mp3文件)

    现在很多时候需要用到录音,然后如果我们的App是ios和android两端的话,就要考虑录音的文件在两端都能使用,这个时候就需要适配,两端的录音文件都要是mp3文件,这样才能保证两边都能播放. 针对这个,封装了一个简单可用的录音控件. 使用方法: 1.在xml文件中添加 <ant.muxi.com.audiodemo.view.SoundTextView android:id="@+id/record_audio" android:text="按住开始录音"

  • Android仿微信语音聊天功能

    本文实例讲述了Android仿微信语音聊天功能代码.分享给大家供大家参考.具体如下: 项目效果如下: 具体代码如下: AudioManager.java package com.xuliugen.weichat; import java.io.File; import java.io.IOException; import java.util.UUID; import android.media.MediaRecorder; public class AudioManager { private

  • Android仿微信图片点击全屏效果

    废话不多说,先看下效果: 先是微信的 再是模仿的 先说下实现原理,再一步步分析 这里总共有2个Activity一个就是主页,一个就是显示我们图片效果的页面,参数通过Intent传送,素材内容均来自网络,(感谢聪明的蘑菇) 图片都是Glide异步下的,下的,下的重要的事情说三次,然后就是用动画做放大操作然后显示出来了(并没有做下载原图的实现,反正也是一样 下载下来Set上去而且动画都不需要更简便). OK,我们来看分析下 obj,目录下分别创建了2个对象,一个用来使用来处理显示页面的图片尺寸信息以

  • Android仿微信发送语音消息的功能及示例代码

    微信的发送语音是有一个向上取消的,我们使用onTouchListener来监听手势,然后做出相应的操作就行了. 直接上代码: //语音操作对象 private MediaPlayer mPlayer = null; private MediaRecorder mRecorder = null; //语音文件保存路径 private String FileName = null; FileName = Environment.getExternalStorageDirectory().getAbs

  • Android仿微信语音消息的录制和播放功能

    一.简述 效果: 实现功能: 长按Button时改变Button显示文字,弹出Dialog(动态更新音量),动态生成录音文件,开始录音: 监听手指动作,规定区域.录音状态下手指划出规定区域取消录音,删除生成的录音文件: 监听手指动作.当手指抬起时,判断是否开始录音,录音时长是否过短,符合条件则提示录音时长过短:正常结束时通过回调返回该次录音的文件路径和时长. 4.点击录音列表的item时,播放动画,播放对应的音频文件. 主要用到4个核心类: 自定义录音按钮(AudioRecordButton):

  • Android仿微信录制语音功能

    本文实例为大家分享了Android仿微信录制语音的具体代码,供大家参考,具体内容如下 前言 我把录音分成了两部分 1.UI界面,弹窗读秒 2.一个类(包含开始.停止.创建文件名功能) 第一部分 由于6.0权限问题,点击按钮申请权限通过则弹窗,如何申请权限 弹窗布局popw_record.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http:

  • Android仿微信滑动弹出编辑、删除菜单效果、增加下拉刷新功能

    如何为不同的list item呈现不同的菜单,本文实例就为大家介绍了Android仿微信或QQ滑动弹出编辑.删除菜单效果.增加下拉刷新等功能的实现,分享给大家供大家参考,具体内容如下 效果图: 1. 下载开源项目,并将其中的liberary导入到自己的项目中: 2. 使用SwipeMenuListView代替ListView,在页面中布局: <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeRefresh

  • Android实现简单底部导航栏 Android仿微信滑动切换效果

    Android仿微信滑动切换最终实现效果: 大体思路: 1. 主要使用两个自定义View配合实现; 底部图标加文字为一个自定义view,底部导航栏为一个载体,根据需要来添加底部图标; 2. 底部导航栏的设置方法类似于TabLayout的关联,View需要创建关联方法,用来关联VIewPager; 3. 通过关联方法获取ViewPager实例后,根据ViewPager页面数创建底部导航栏的图标按钮; 代码实现: 1. 新建第一个自定义View, 图标 + 文字 的底部按钮; /** * 自定义控件

随机推荐