服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android仿微信录音功能(录音后的raw文件转mp3文件)

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

2022-11-08 14:30WheatHusks Android

这篇文章主要介绍了Android中仿微信录音功能录音后的raw文件转mp3文件,本文通过实例代码给大家讲解的非常详细,需要的朋友可以参考下

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

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

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

使用方法:

1.在xml文件中添加

?
1
2
3
4
5
6
7
8
9
10
11
12
<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.别忘了申请录音权限

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 );
  }
 });
 }

使用方法如上非常简单:

主要的类

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
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);
 }
}

主要的录音管理类

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
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);
 }
}

完整代码:AudioDemo.rar

总结

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

原文链接:https://blog.csdn.net/shihuiyun/article/details/103095719

延伸 · 阅读

精彩推荐
  • AndroidAndroid下修改SeekBar样式的解决办法

    Android下修改SeekBar样式的解决办法

    本篇文章是对在Android下修改SeekBar样式的解决办法进行了详细的分析介绍,需要的朋友参考下...

    Android开发网8042021-01-28
  • AndroidAndroid开发之menu菜单

    Android开发之menu菜单

    Android系统里面有四种类型的菜单:options menu(选项菜单),context menu(上下文菜单),sub menu(子菜单),Popup menu(弹出菜单),本文给大家详解android开发之...

    q6100983088482021-04-09
  • AndroidAndroid编程绘制圆形图片的方法

    Android编程绘制圆形图片的方法

    这篇文章主要介绍了Android编程绘制圆形图片的方法,结合实例形式较为详细的分析了Android通过自定义控件实现图形绘制的相关技巧,需要的朋友可以参考下...

    xurong4882021-05-31
  • AndroidAndroid编程中黑名单的实现方法

    Android编程中黑名单的实现方法

    这篇文章主要介绍了Android编程中黑名单的实现方法,结合实例形式详细分析了Android通过对比通信录及自动挂断电话等技巧实现黑名单功能的功能,需要的朋友...

    lg8783985097392021-06-07
  • AndroidObjectAnimator属性动画源码分析篇

    ObjectAnimator属性动画源码分析篇

    今天小编就为大家分享一篇关于ObjectAnimator属性动画源码分析篇,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小...

    Zy_JiBai10212022-09-15
  • Android解决Android模拟器端口被占用问题的办法

    解决Android模拟器端口被占用问题的办法

    这篇文章主要为大家分享了Android模拟器端口被占用问题的解决办法,遇到Android模拟器端口被占用的时候,真的很头疼,如何才能解决端口被占用的问题,...

    孤傲苍狼7822021-04-16
  • Androidandroid实现简单左滑删除控件

    android实现简单左滑删除控件

    这篇文章主要为大家详细介绍了android实现一个简单左滑删除控件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    qq_2035271311812022-10-28
  • AndroidAndroid实现多参数文件和数据上传

    Android实现多参数文件和数据上传

    这篇文章主要为大家详细介绍了Android实现多参数文件和数据上传,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    静下心来静下心来9222022-09-08