Android仿微信錄音功能(錄音后的raw文件轉(zhuǎn)mp3文件)
現(xiàn)在很多時(shí)候需要用到錄音,然后如果我們的App是ios和android兩端的話,就要考慮錄音的文件在兩端都能使用,這個(gè)時(shí)候就需要適配,兩端的錄音文件都要是mp3文件,這樣才能保證兩邊都能播放。
針對(duì)這個(gè),封裝了一個(gè)簡(jiǎn)單可用的錄音控件。
使用方法:
1.在xml文件中添加
<ant.muxi.com.audiodemo.view.SoundTextView android:id="@+id/record_audio" android:text="按住開(kāi)始錄音" 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.別忘了申請(qǐng)錄音權(quán)限
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,"請(qǐng)同意錄音權(quán)限",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 );
}
});
}
使用方法如上非常簡(jiǎn)單:
主要的類(lèi)
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";//默認(rèn)開(kāi)始錄音 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));
//判斷時(shí)間
judetime(Integer.parseInt(sountime));
break;
}
}
};
public void judetime(int time) {
if (time > 14) {
//結(jié)束錄制
Toast.makeText(mContext, "錄音不能超過(guò)十五秒", 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")) {
//開(kāi)始發(fā)送時(shí)間
downT = System.currentTimeMillis();
recordManager.start_mp3();
recordIndicator.show();
} else {
Log.e("-log-", "您已經(jīng)錄制完畢: ");
}
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, "錄音時(shí)間少于3秒,請(qǐng)重新錄制", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
recordManager.stop_mp3();
if (recordIndicator.isShowing()) {
recordIndicator.dismiss();
}
sountime = null;
Toast.makeText(mContext, "錄音時(shí)間少于3秒,請(qǐng)重新錄制", 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";
}
//發(fā)送語(yǔ)音
// Toasts.toast(getContext(),"您已經(jīng)錄完了一條語(yǔ)音"+myRecAudioFile);
}
private OnRecordFinishedListener onRecordFinishedListener;
public void setOnRecordFinishedListener(OnRecordFinishedListener onRecordFinishedListener) {
this.onRecordFinishedListener = onRecordFinishedListener;
}
public interface OnRecordFinishedListener {
void newMessage(String path, int duration);
}
}
主要的錄音管理類(lèi)
public class RecordManager {
//錄制成MP3格式..............................................
/**構(gòu)造時(shí)候需要的Activity,主要用于獲取文件夾的路徑*/
private Activity activity;
/**文件代號(hào)*/
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;
/**錄音狀態(tài)*/
private boolean isRecording = false;
/**是否轉(zhuǎn)換ok*/
private boolean convertOk = false;
public RecordManager(Activity activity, String rawPath, String mp3Path) {
this.activity = activity;
this.rawPath = rawPath;
this.mp3Path = mp3Path;
}
/**開(kāi)始錄音*/
public boolean start_mp3() {
// 如果正在錄音,則返回
if (isRecording) {
return isRecording;
}
// 初始化
if (mRecorder == null) {
initRecorder();
}
getFilePath();
mRecorder.startRecording();
startBufferedWrite(new File(rawPath));
isRecording = true;
return isRecording;
}
/**停止錄音,并且轉(zhuǎn)換文件,這很可能是個(gè)耗時(shí)操作,建議在后臺(tái)中做*/
public boolean stop_mp3() {
if (!isRecording) {
return isRecording;
}
// 停止
mRecorder.stop();
isRecording = false;
//TODO
// 開(kāi)始轉(zhuǎn)換(轉(zhuǎn)換代碼就這兩句)
// 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();
}
}
/**關(guān)閉,可以先調(diào)用cleanFile來(lái)清理文件*/
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);
}
/**設(shè)置路徑,第一個(gè)為raw文件,第二個(gè)為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();
}
}
/**執(zhí)行cmd命令,并等待結(jié)果*/
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;
}
/**寫(xiě)入到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) {//開(kāi)始錄制
int readSize = mRecorder.read(mBuffer, 0,
mBuffer.length);//是實(shí)際讀取的數(shù)據(jù)長(zhǎng)度
for (int i = 0; i < readSize; i++) {
output.writeShort(mBuffer[i]);
}
long v = 0;
// 將 buffer 內(nèi)容取出,進(jìn)行平方和運(yùn)算
for (int i = 0; i < mBuffer.length; i++) {
v += mBuffer[i] * mBuffer[i];
}
// 平方和除以數(shù)據(jù)總長(zhǎng)度,得到音量大小。
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
總結(jié)
以上所述是小編給大家介紹的Android仿微信錄音功能(錄音后的raw文件轉(zhuǎn)mp3文件,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)我們網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
上一篇:Android自定義View實(shí)現(xiàn)微信語(yǔ)音界面
欄 目:Android
下一篇:Android RadioGroup多行顯示效果 解決單選問(wèn)題
本文標(biāo)題:Android仿微信錄音功能(錄音后的raw文件轉(zhuǎn)mp3文件)
本文地址:http://www.jygsgssxh.com/a1/Android/9084.html
您可能感興趣的文章
- 01-10Android自定義View之繪制圓形頭像功能
- 01-10Android實(shí)現(xiàn)雙擊返回鍵退出應(yīng)用實(shí)現(xiàn)方法詳解
- 01-10android實(shí)現(xiàn)記住用戶(hù)名和密碼以及自動(dòng)登錄
- 01-10android實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能
- 01-10Android 友盟第三方登錄與分享的實(shí)現(xiàn)代碼
- 01-10android實(shí)現(xiàn)指紋識(shí)別功能
- 01-10Emoji表情在Android JNI中的兼容性問(wèn)題詳解
- 01-10Android實(shí)現(xiàn)圓形漸變加載進(jìn)度條
- 01-10android開(kāi)發(fā)環(huán)境中SDK文件夾下的所需內(nèi)容詳解
- 01-10android異步消息機(jī)制 源碼層面徹底解析(1)


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10Android自定義View之繪制圓形頭像功能
- 01-10Android實(shí)現(xiàn)雙擊返回鍵退出應(yīng)用實(shí)現(xiàn)方
- 01-10android實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能
- 01-10android實(shí)現(xiàn)記住用戶(hù)名和密碼以及自動(dòng)
- 01-10C++自定義API函數(shù)實(shí)現(xiàn)大數(shù)相乘算法
- 01-10Android 友盟第三方登錄與分享的實(shí)現(xiàn)代
- 01-10android實(shí)現(xiàn)指紋識(shí)別功能
- 01-10如何給Flutter界面切換實(shí)現(xiàn)點(diǎn)特效
- 01-10Android實(shí)現(xiàn)圓形漸變加載進(jìn)度條
- 01-10Emoji表情在Android JNI中的兼容性問(wèn)題詳
隨機(jī)閱讀
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置


