Android實(shí)現(xiàn)錄音功能實(shí)現(xiàn)實(shí)例(MediaRecorder)
本文介紹了Android實(shí)現(xiàn)錄音的實(shí)例代碼(MediaRecorder),分享給大家,具體如下:
Android提供了兩個API用于錄音的實(shí)現(xiàn):MediaRecorder 和 AudioRecord,各有優(yōu)劣。
1、MediaRecorder
已經(jīng)集成了錄音、編碼、壓縮等,支持少量的錄音音頻格式,大概有.aac(API = 16) .amr .3gp
優(yōu)點(diǎn):大部分已經(jīng)集成,直接調(diào)用相關(guān)接口即可,代碼量小
缺點(diǎn):無法實(shí)時處理音頻;輸出的音頻格式不是很多,例如沒有輸出mp3格式文件
2、AudioRecord
主要是實(shí)現(xiàn)邊錄邊播(AudioRecord+AudioTrack)以及對音頻的實(shí)時處理(如會說話的湯姆貓、語音)
優(yōu)點(diǎn):語音的實(shí)時處理,可以用代碼實(shí)現(xiàn)各種音頻的封裝
缺點(diǎn):輸出是PCM語音數(shù)據(jù),如果保存成音頻文件,是不能夠被播放器播放的,所以必須先寫代碼實(shí)現(xiàn)數(shù)據(jù)編碼以及壓縮
先說 MediaRecorder : MediaRecorder因?yàn)榇蟛糠止δ芤呀?jīng)集成,所以使用起來相對比較簡單。
下面是個小demo:
① 界面
界面比較簡單,由于MediaRecorder 并不能實(shí)現(xiàn)暫停、繼續(xù)錄音的功能
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="開始" />
<Button
android:id="@+id/btn_stop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
android:text="停止" />
<TextView
android:id="@+id/text_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="00:00:00"
android:padding="5dp"
android:layout_marginTop="10dp"/>
</LinearLayout>
② 相關(guān)錄音功能
開始錄音
public void startRecord() {
// 開始錄音
/* ①Initial:實(shí)例化MediaRecorder對象 */
if (mMediaRecorder == null)
mMediaRecorder = new MediaRecorder();
try {
/* ②setAudioSource/setVedioSource */
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 設(shè)置麥克風(fēng)
/*
* ②設(shè)置輸出文件的格式:THREE_GPP/MPEG-4/RAW_AMR/Default THREE_GPP(3gp格式
* ,H263視頻/ARM音頻編碼)、MPEG-4、RAW_AMR(只支持音頻且音頻編碼要求為AMR_NB)
*/
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
/* ②設(shè)置音頻文件的編碼:AAC/AMR_NB/AMR_MB/Default 聲音的(波形)的采樣 */
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
fileName = DateFormat.format("yyyyMMdd_HHmmss", Calendar.getInstance(Locale.CHINA)) + ".m4a";
if (!FileUtils.isFolderExist(FileUtils.getFolderName(audioSaveDir))) {
FileUtils.makeFolders(audioSaveDir);
}
filePath = audioSaveDir + fileName;
/* ③準(zhǔn)備 */
mMediaRecorder.setOutputFile(filePath);
mMediaRecorder.prepare();
/* ④開始 */
mMediaRecorder.start();
} catch (IllegalStateException e) {
LogUtil.i("call startAmr(File mRecAudioFile) failed!" + e.getMessage());
} catch (IOException e) {
LogUtil.i("call startAmr(File mRecAudioFile) failed!" + e.getMessage());
}
}
音頻編碼可以根據(jù)自己實(shí)際需要自己設(shè)定,文件名防止重復(fù),使用了日期_時分秒的結(jié)構(gòu),audioSaveDir 是文件存儲目錄,可自行設(shè)定。
停止錄音
public void stopRecord() {
try {
mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder = null;
filePath = "";
} catch (RuntimeException e) {
LogUtil.e(e.toString());
mMediaRecorder.reset();
mMediaRecorder.release();
mMediaRecorder = null;
File file = new File(filePath);
if (file.exists())
file.delete();
filePath = "";
}
}
時長記錄
// 記錄錄音時長
private void countTime() {
while (isRecording) {
LogUtil.d("正在錄音");
timeCount++;
Message msg = Message.obtain();
msg.what = TIME_COUNT;
msg.obj = timeCount;
myHandler.sendMessage(msg);
try {
timeThread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
LogUtil.d("結(jié)束錄音");
timeCount = 0;
Message msg = Message.obtain();
msg.what = TIME_COUNT;
msg.obj = timeCount;
myHandler.sendMessage(msg);
}
將錄音時長格式化
// 格式化 錄音時長為 時:分:秒
public static String FormatMiss(int miss) {
String hh = miss / 3600 > 9 ? miss / 3600 + "" : "0" + miss / 3600;
String mm = (miss % 3600) / 60 > 9 ? (miss % 3600) / 60 + "" : "0" + (miss % 3600) / 60;
String ss = (miss % 3600) % 60 > 9 ? (miss % 3600) % 60 + "" : "0" + (miss % 3600) % 60;
return hh + ":" + mm + ":" + ss;
}
Activity全部代碼
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.zzx.hellokotlin.R;
import com.zzx.hellokotlin.utils.FileUtils;
import com.zzx.hellokotlin.utils.LogUtil;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.Locale;
public class Record2Activity extends AppCompatActivity {
// 錄音界面相關(guān)
Button btnStart;
Button btnStop;
TextView textTime;
// 錄音功能相關(guān)
MediaRecorder mMediaRecorder; // MediaRecorder 實(shí)例
boolean isRecording; // 錄音狀態(tài)
String fileName; // 錄音文件的名稱
String filePath; // 錄音文件存儲路徑
Thread timeThread; // 記錄錄音時長的線程
int timeCount; // 錄音時長 計數(shù)
final int TIME_COUNT = 0x101;
// 錄音文件存放目錄
final String audioSaveDir = Environment.getExternalStorageDirectory().getAbsolutePath()+"/audiodemo/";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_record2);
btnStart = (Button) findViewById(R.id.btn_start);
btnStop = (Button) findViewById(R.id.btn_stop);
textTime = (TextView) findViewById(R.id.text_time);
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 開始錄音
btnStart.setEnabled(false);
btnStop.setEnabled(true);
startRecord();
isRecording = true;
// 初始化錄音時長記錄
timeThread = new Thread(new Runnable() {
@Override
public void run() {
countTime();
}
});
timeThread.start();
}
});
btnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 停止錄音
btnStart.setEnabled(true);
btnStop.setEnabled(false);
stopRecord();
isRecording = false;
}
});
}
// 記錄錄音時長
private void countTime() {
while (isRecording) {
LogUtil.d("正在錄音");
timeCount++;
Message msg = Message.obtain();
msg.what = TIME_COUNT;
msg.obj = timeCount;
myHandler.sendMessage(msg);
try {
timeThread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
LogUtil.d("結(jié)束錄音");
timeCount = 0;
Message msg = Message.obtain();
msg.what = TIME_COUNT;
msg.obj = timeCount;
myHandler.sendMessage(msg);
}
/**
* 開始錄音 使用amr格式
* 錄音文件
* @return
*/
public void startRecord() {
// 開始錄音
/* ①Initial:實(shí)例化MediaRecorder對象 */
if (mMediaRecorder == null)
mMediaRecorder = new MediaRecorder();
try {
/* ②setAudioSource/setVedioSource */
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 設(shè)置麥克風(fēng)
/*
* ②設(shè)置輸出文件的格式:THREE_GPP/MPEG-4/RAW_AMR/Default THREE_GPP(3gp格式
* ,H263視頻/ARM音頻編碼)、MPEG-4、RAW_AMR(只支持音頻且音頻編碼要求為AMR_NB)
*/
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
/* ②設(shè)置音頻文件的編碼:AAC/AMR_NB/AMR_MB/Default 聲音的(波形)的采樣 */
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
fileName = DateFormat.format("yyyyMMdd_HHmmss", Calendar.getInstance(Locale.CHINA)) + ".m4a";
if (!FileUtils.isFolderExist(FileUtils.getFolderName(audioSaveDir))) {
FileUtils.makeFolders(audioSaveDir);
}
filePath = audioSaveDir + fileName;
/* ③準(zhǔn)備 */
mMediaRecorder.setOutputFile(filePath);
mMediaRecorder.prepare();
/* ④開始 */
mMediaRecorder.start();
} catch (IllegalStateException e) {
LogUtil.i("call startAmr(File mRecAudioFile) failed!" + e.getMessage());
} catch (IOException e) {
LogUtil.i("call startAmr(File mRecAudioFile) failed!" + e.getMessage());
}
}
/**
* 停止錄音
*/
public void stopRecord() {
//有一些網(wǎng)友反應(yīng)在5.0以上在調(diào)用stop的時候會報錯,翻閱了一下谷歌文檔發(fā)現(xiàn)上面確實(shí)寫的有可能會報錯的情況,捕獲異常清理一下就行了,感謝大家反饋!
try {
mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder = null;
filePath = "";
} catch (RuntimeException e) {
LogUtil.e(e.toString());
mMediaRecorder.reset();
mMediaRecorder.release();
mMediaRecorder = null;
File file = new File(filePath);
if (file.exists())
file.delete();
filePath = "";
}
}
// 格式化 錄音時長為 時:分:秒
public static String FormatMiss(int miss) {
String hh = miss / 3600 > 9 ? miss / 3600 + "" : "0" + miss / 3600;
String mm = (miss % 3600) / 60 > 9 ? (miss % 3600) / 60 + "" : "0" + (miss % 3600) / 60;
String ss = (miss % 3600) % 60 > 9 ? (miss % 3600) % 60 + "" : "0" + (miss % 3600) % 60;
return hh + ":" + mm + ":" + ss;
}
Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case TIME_COUNT:
int count = (int) msg.obj;
LogUtil.d("count == " + count);
textTime.setText(FormatMiss(count));
break;
}
}
};
}
總結(jié):MediaRecorder 實(shí)現(xiàn)錄音還是比較簡單的,只是不能暫停。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android給通知channel靜音的方法實(shí)例
- Android實(shí)現(xiàn)靜音檢測功能
- Android 判斷網(wǎng)絡(luò)狀態(tài)對音頻靜音的實(shí)現(xiàn)方法
- Android實(shí)現(xiàn)定時自動靜音小助手
- Android EasyPlayer聲音自動停止、恢復(fù),一鍵靜音等功能
- android實(shí)現(xiàn)來電靜音示例(監(jiān)聽來電)
- android系統(tǒng)在靜音模式下關(guān)閉camera拍照聲音的方法
- Android音頻錄制MediaRecorder之簡易的錄音軟件實(shí)現(xiàn)代碼
- Android簡單的利用MediaRecorder進(jìn)行錄音的實(shí)例代碼
- Android實(shí)現(xiàn)錄音靜音降噪
相關(guān)文章
探究Android客戶端網(wǎng)絡(luò)預(yù)連接優(yōu)化機(jī)制
一般情況下,我們都是用一些封裝好的網(wǎng)絡(luò)框架去請求網(wǎng)絡(luò),對底層實(shí)現(xiàn)不甚關(guān)注,而大部分情況下也不需要特別關(guān)注處理。了解底層的一些實(shí)現(xiàn),有益于我們對網(wǎng)絡(luò)加載進(jìn)行優(yōu)化。本文就是關(guān)于根據(jù)http的連接復(fù)用機(jī)制來優(yōu)化網(wǎng)絡(luò)加載速度的原理與細(xì)節(jié)2021-06-06
基于Flutter實(shí)現(xiàn)愛心三連動畫效果
Animation是一個抽象類,它并不參與屏幕的繪制,而是在設(shè)定的時間范圍內(nèi)對一段區(qū)間值進(jìn)行插值。本文將利用Animation制作一個愛心三連動畫效果,感興趣的可以學(xué)習(xí)一下2022-03-03
Android中PopupWindow響應(yīng)返回鍵并關(guān)閉的2種方法
這篇文章主要介紹了Android中PopupWindow響應(yīng)返回鍵并關(guān)閉的2種方法,本文講解了最簡單的方法、最通用的方法,需要的朋友可以參考下2015-04-04
Android類加載ClassLoader雙親委托機(jī)制詳解
這篇文章主要為大家介紹了Android類加載ClassLoader雙親委托機(jī)制詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07

