Android仿微信錄音功能(錄音後的raw檔案轉mp3檔案)
阿新 • • 發佈:2020-01-07
現在很多時候需要用到錄音,然後如果我們的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,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,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,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,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,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檔案,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回覆大家的。在此也非常感謝大家對我們網站的支援!
如果你覺得本文對你有幫助,歡迎轉載,煩請註明出處,謝謝!