现在很多时候需要用到录音,然后如果我们的App是ios和android两端的话,就要考虑录音的文件在两端都能使用,这个时候就需要适配,两端的录音文件都要是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