音頻錄制(一)

MediaRecorder.AudioSource音頻參數(shù)說明

MediaRecorder.AudioSource.MIC參數(shù)說明

其中第一個參數(shù)就是選擇錄音源的靶累,其可選參數(shù)如下:

MediaRecorder.AudioSource.CAMCORDER? ?//?設定錄音來源于同方向的相機麥克風相同松捉,若相機無內置相機或無法識別幻件,則使用預設的麥克風 MediaRecorder.AudioSource.DEFAULT? // 默認音頻源
MediaRecorder.AudioSource.MIC? // 設定錄音來源為主麥克風。
MediaRecorder.AudioSource.VOICE_CALL? // 設定錄音來源為語音撥出的語音與對方說話的聲音MediaRecorder.AudioSource.VOICE_COMMUNICATION? // 攝像頭旁邊的麥克風
MediaRecorder.AudioSource.VOICE_DOWNLINK? // 下行聲音
MediaRecorder.AudioSource.VOICE_RECOGNITION? // 語音識別
MediaRecorder.AudioSource.VOICE_UPLINK? //?上行聲音

音頻的兩種錄制方式-AudioRecord,MediaRecorder的使用及播放

AudioRecord和MediaRecorder兩種都可以錄制音頻名船,MediaRecorder已實現(xiàn)大量的封裝浙垫,操作起來更加簡單,而AudioRecord使用起來更加靈活努释,能實現(xiàn)更多的功能。

1.AudioRecord(基于字節(jié)流錄音)?

優(yōu)點:可以實現(xiàn)語音的實時處理咬摇,進行邊錄邊播伐蒂,對音頻的實時處理。?

缺點:輸出的是PCM的語音數(shù)據(jù)肛鹏,如果保存成音頻文件是不能被播放器播放的逸邦。要用到AudioTrack這個去進行處理。

2.MediaRecorder(基于文件錄音)?

已集成了錄音在扰,編碼昭雌,壓縮等,支持少量的音頻格式文件健田。?

優(yōu)點:封裝度很高烛卧,操作簡單?

缺點:無法實現(xiàn)實時處理音頻,輸出的音頻格式少妓局。

功能實現(xiàn):MediaRecorder(這里需要注意总放,無論錄制還是播放都是一個耗時操作,需要在非主線程中去操作)

//實現(xiàn)觸摸錄音好爬,松開錄音結束tv_press_send.setOnTouchListener(new View.OnTouchListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public boolean onTouch(View v, MotionEvent event) {
? ? ? ? ? ? ? ? switch (event.getAction()) {
? ? ? ? ? ? ? ? ? ? case MotionEvent.ACTION_DOWN:
? ? ? ? ? ? ? ? ? ? ? ? startRecorder();
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? case MotionEvent.ACTION_UP:
? ? ? ? ? ? ? ? ? ? ? ? stopRecorder();
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? case MotionEvent.ACTION_CANCEL:
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? });

開啟一個單線程去實現(xiàn)錄音功能局雄,及失敗操作:

/**
? ? ?* 開啟錄音
? ? ?*/
? ? private void startRecorder() {
? ? ? ? tv_press_send.setText("正在說話...");
? ? ? ? //提交后臺任務,開始錄音? ? ? ? mExecutorService.submit(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? //釋放上一次的錄音
? ? ? ? ? ? ? ? releaseRecorder();
? ? ? ? ? ? ? ? //開始錄音
? ? ? ? ? ? ? ? if (!doStart()) {
? ? ? ? ? ? ? ? ? ? recorderFial();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? });
? ? }

啟動錄音存炮,及MediaRecorder的配置:

/**
?* 啟動錄音
?* * @return
*/
?private boolean doStart() {
? ? ? ? try {
? ? ? ? ? ? //創(chuàng)建MediaRecorder
? ? ? ? ? ? mMediaRecorder = new MediaRecorder();
? ? ? ? ? ? //創(chuàng)建錄音文件
? ? ? ? ? ? mRecorderFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
? ? ? ? ? ? ? ? ? ? + "/recorderdemo/" + System.currentTimeMillis() + ".m4a");

? ? ? ? ? ? if (!mRecorderFile.getParentFile().exists()) mRecorderFile.getParentFile().mkdirs();
? ? ? ? ? ? mRecorderFile.createNewFile();
? ? ? ? ? ? //配置MediaRecorder
? ? ? ? ? ? //從麥克風采集
? ? ? ? ? ? mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
? ? ? ? ? ? //保存文件為MP4格式
? ? ? ? ? ? mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
? ? ? ? ? ? //所有android系統(tǒng)都支持的適中采樣的頻率
? ? ? ? ? ? mMediaRecorder.setAudioSamplingRate(44100);
? ? ? ? ? ? //通用的AAC編碼格式
? ? ? ? ? ? mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
? ? ? ? ? ? //設置音質頻率
? ? ? ? ? ? mMediaRecorder.setAudioEncodingBitRate(96000);
? ? ? ? ? ? //設置文件錄音的位置
? ? ? ? ? ? mMediaRecorder.setOutputFile(mRecorderFile.getAbsolutePath());
? ? ? ? ? ? //開始錄音
? ? ? ? ? ? mMediaRecorder.prepare();
? ? ? ? ? ? mMediaRecorder.start();
? ? ? ? ? ? startRecorderTime = System.currentTimeMillis();
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? Toast.makeText(FileActivity.this, "錄音失敗炬搭,請重試", Toast.LENGTH_SHORT).show();
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? //記錄開始錄音時間,用于統(tǒng)計時長穆桂,小于3秒中宫盔,錄音不發(fā)送? ? ? ? return true;
? ? }

停止錄音操作:

/**
?* 關閉錄音 *
?* @return*/
?private boolean doStop() {
? ? ? ? try {
? ? ? ? ? ? mMediaRecorder.stop();
? ? ? ? ? ? stopRecorderTime = System.currentTimeMillis();
? ? ? ? ? ? final int second = (int) (stopRecorderTime - startRecorderTime) / 1000;
? ? ? ? ? ? //按住時間小于3秒鐘,算作錄取失敗享完,不進行發(fā)送
? ? ? ? ? ? if (second < 3) return false;
? ? ? ? ? ? mHander.post(new Runnable() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? tv_sendmsg.setText("錄制成功:" + second + "秒");
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? ? ? return true;
? ? }

釋放MediaRecorder:

/**
? * 釋放上一次的錄音
? */
? ? private void releaseRecorder() {
? ? ? ? if (mMediaRecorder != null) {
? ? ? ? ? ? mMediaRecorder.release();
? ? ? ? ? ? mMediaRecorder = null;
? ? ? ? }
? ? }

錄音的播放:使用MediaPlayer

開啟一個單線程灼芭,去播放:

/**
?* 播放錄音 *
?* @paramview
?*/
?public void playrecorder(View view) {
? ? ? ? if (!mIsPlaying) {
? ? ? ? ? ? mExecutorService.submit(new Runnable() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? doPlay(mRecorderFile);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? } else {
? ? ? ? ? ? Toast.makeText(FileActivity.this, "正在播放", Toast.LENGTH_SHORT).show();
? ? ? ? }
? ? }

具體播放代碼:

private void doPlay(File audioFile) {
? ? ? ? try {
? ? ? ? ? ? //配置播放器 MediaPlayer
? ? ? ? ? ? mediaPlayer = new MediaPlayer();
? ? ? ? ? ? //設置聲音文件
? ? ? ? ? ? mediaPlayer.setDataSource(audioFile.getAbsolutePath());
? ? ? ? ? ? //配置音量,中等音量
? ? ? ? ? ? mediaPlayer.setVolume(1,1);
? ? ? ? ? ? //播放是否循環(huán)
? ? ? ? ? ? mediaPlayer.setLooping(false);
? ? ? ? ? ? //設置監(jiān)聽回調 播放完畢
? ? ? ? ? ? mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void onCompletion(MediaPlayer mp) {
? ? ? ? ? ? ? ? ? ? stopPlayer();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? ? ? mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public boolean onError(MediaPlayer mp, int what, int extra) {
? ? ? ? ? ? ? ? ? ? stopPlayer();
? ? ? ? ? ? ? ? ? ? Toast.makeText(FileActivity.this,"播放失敗",Toast.LENGTH_SHORT).show();
? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? ? ? //設置播放
? ? ? ? ? ? mediaPlayer.prepare();
? ? ? ? ? ? mediaPlayer.start();
? ? ? ? ? ? //異常處理,防止閃退
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? stopPlayer();
? ? ? ? }
? ? }

activity銷毀后的onDestory的處理:

@Override
?protected void onDestroy() {
? ? ? ? super.onDestroy();
? ? ? ? //當activity關閉時般又,停止這個線程彼绷,防止內存泄漏
? ? ? ? mExecutorService.shutdownNow();
? ? ? ? releaseRecorder();
? ? }

MediaRecord完整功能實現(xiàn)代碼:

package com.example.amelon.myapplication;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public classFileActivityextendsAppCompatActivity{

? ? private TextView tv_sendmsg, tv_press_send;
? ? private ExecutorService mExecutorService;
? ? private MediaRecorder mMediaRecorder;
? ? private MediaPlayer mediaPlayer;
? ? private File mRecorderFile;
? ? private long startRecorderTime, stopRecorderTime;
? ? private Handler mHander = new Handler(Looper.getMainLooper());
? ? private boolean mIsPlaying = false;

? ? @Override
? ? protected void onCreate(Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? setContentView(R.layout.activity_first);
? ? ? ? setTitle("文件錄音");
? ? ? ? initView();
? ? ? ? //錄音JNI函數(shù)不具有線程安全性巍佑,因此用單線程? ? ? ? mExecutorService = Executors.newSingleThreadExecutor();
? ? }

? ? private void initView() {
? ? ? ? tv_sendmsg = (TextView) findViewById(R.id.tv_sendmsg);
? ? ? ? tv_press_send = (TextView) findViewById(R.id.tv_press_send);
? ? ? ? tv_press_send.setOnTouchListener(new View.OnTouchListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public boolean onTouch(View v, MotionEvent event) {
? ? ? ? ? ? ? ? switch (event.getAction()) {
? ? ? ? ? ? ? ? ? ? case MotionEvent.ACTION_DOWN:
? ? ? ? ? ? ? ? ? ? ? ? startRecorder();
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? case MotionEvent.ACTION_UP:
? ? ? ? ? ? ? ? ? ? ? ? stopRecorder();
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? case MotionEvent.ACTION_CANCEL:
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? });
? ? }

? ? /**
? ? ?* 開啟錄音
? ? ?*/
? ? private void startRecorder() {
? ? ? ? tv_press_send.setText("正在說話...");
? ? ? ? //提交后臺任務,開始錄音
? ? ? ? mExecutorService.submit(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? //釋放上一次的錄音
? ? ? ? ? ? ? ? releaseRecorder();
? ? ? ? ? ? ? ? //開始錄音
? ? ? ? ? ? ? ? if (!doStart()) {
? ? ? ? ? ? ? ? ? ? recorderFial();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? });
? ? }

? ? /**
? ? ?* 釋放上一次的錄音
? ? ?*/
? ? private void releaseRecorder() {
? ? ? ? if (mMediaRecorder != null) {
? ? ? ? ? ? mMediaRecorder.release();
? ? ? ? ? ? mMediaRecorder = null;
? ? ? ? }
? ? }

? ? /**
? ? ?* 啟動錄音? ? *
? ? ?* @return
? ? ?*/
? ? private boolean doStart() {
? ? ? ? try {
? ? ? ? ? ? //創(chuàng)建MediaRecorder
? ? ? ? ? ? mMediaRecorder = new MediaRecorder();
? ? ? ? ? ? //創(chuàng)建錄音文件
? ? ? ? ? ? mRecorderFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
? ? ? ? ? ? ? ? ? ? + "/recorderdemo/" + System.currentTimeMillis() + ".m4a");

? ? ? ? ? ? if (!mRecorderFile.getParentFile().exists()) mRecorderFile.getParentFile().mkdirs();
? ? ? ? ? ? mRecorderFile.createNewFile();
? ? ? ? ? ? //配置MediaRecorder
? ? ? ? ? ? //從麥克風采集
? ? ? ? ? ? mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
? ? ? ? ? ? //保存文件為MP4格式
? ? ? ? ? ? mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
? ? ? ? ? ? //所有android系統(tǒng)都支持的適中采樣的頻率
? ? ? ? ? ? mMediaRecorder.setAudioSamplingRate(44100);
? ? ? ? ? ? //通用的AAC編碼格式
? ? ? ? ? ? mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
? ? ? ? ? ? //設置音質頻率
? ? ? ? ? ? mMediaRecorder.setAudioEncodingBitRate(96000);
? ? ? ? ? ? //設置文件錄音的位置
? ? ? ? ? ? mMediaRecorder.setOutputFile(mRecorderFile.getAbsolutePath());
? ? ? ? ? ? //開始錄音
? ? ? ? ? ? mMediaRecorder.prepare();
? ? ? ? ? ? mMediaRecorder.start();
? ? ? ? ? ? startRecorderTime = System.currentTimeMillis();
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? Toast.makeText(FileActivity.this, "錄音失敗寄悯,請重試", Toast.LENGTH_SHORT).show();
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? //記錄開始錄音時間萤衰,用于統(tǒng)計時長,小于3秒中猜旬,錄音不發(fā)送? ? ? ? return true;
? ? }

? ? /**
? ? ?* 關閉錄音? ? *
? ? ?* @return*/
? ? private boolean doStop() {
? ? ? ? try {
? ? ? ? ? ? mMediaRecorder.stop();
? ? ? ? ? ? stopRecorderTime = System.currentTimeMillis();
? ? ? ? ? ? final int second = (int) (stopRecorderTime - startRecorderTime) / 1000;
? ? ? ? ? ? //按住時間小于3秒鐘腻菇,算作錄取失敗,不進行發(fā)送? ? ? ? ? ? if (second < 3) return false;
? ? ? ? ? ? mHander.post(new Runnable() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? tv_sendmsg.setText("錄制成功:" + second + "秒");
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? ? ? return true;
? ? }

? ? /**
? ? ?* 錄音失敗邏輯
? ? ?*/
? ? private void recorderFial() {
? ? ? ? mRecorderFile = null;
? ? ? ? mHander.post(new Runnable() {
? ? ? ? ? ? @Override? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? tv_press_send.setText("錄音失敗請重新錄音");
? ? ? ? ? ? }
? ? ? ? });
? ? }

? ? /**
? ? ?* 停止錄音
? ? ?*/
? ? private void stopRecorder() {
? ? ? ? tv_press_send.setText("開始錄音");
? ? ? ? //提交后臺任務昔馋,停止錄音
? ? ? ? mExecutorService.submit(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? if (!doStop()) {
? ? ? ? ? ? ? ? ? ? recorderFial();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? releaseRecorder();
? ? ? ? ? ? }
? ? ? ? });
? ? }

? ? /**
? ? ?* 播放錄音? ? *?
? ? * @paramview
? ? ?*/?
? ?public void playrecorder(View view) {
? ? ? ? if (!mIsPlaying) {
? ? ? ? ? ? mExecutorService.submit(new Runnable() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? doPlay(mRecorderFile);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? } else {
? ? ? ? ? ? Toast.makeText(FileActivity.this, "正在播放", Toast.LENGTH_SHORT).show();
? ? ? ? }
? ? }
? ? private void doPlay(File audioFile) {
? ? ? ? try {
? ? ? ? ? ? //配置播放器 MediaPlayer
? ? ? ? ? ? mediaPlayer = new MediaPlayer();
? ? ? ? ? ? //設置聲音文件
? ? ? ? ? ? mediaPlayer.setDataSource(audioFile.getAbsolutePath());
? ? ? ? ? ? //配置音量,中等音量
? ? ? ? ? ? mediaPlayer.setVolume(1,1);
? ? ? ? ? ? //播放是否循環(huán)
? ? ? ? ? ? mediaPlayer.setLooping(false);
? ? ? ? ? ? //設置監(jiān)聽回調 播放完畢
? ? ? ? ? ? mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void onCompletion(MediaPlayer mp) {
? ? ? ? ? ? ? ? ? ? stopPlayer();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });

? ? ? ? ? ? mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public boolean onError(MediaPlayer mp, int what, int extra) {
? ? ? ? ? ? ? ? ? ? stopPlayer();
? ? ? ? ? ? ? ? ? ? Toast.makeText(FileActivity.this,"播放失敗",Toast.LENGTH_SHORT).show();
? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });

? ? ? ? ? ? //設置播放
? ? ? ? ? ? mediaPlayer.prepare();
? ? ? ? ? ? mediaPlayer.start();
? ? ? ? ? ? //異常處理,防止閃退
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? stopPlayer();
? ? ? ? }
? ? }

? ? private void stopPlayer(){
? ? ? ? mIsPlaying=false;
? ? ? ? mediaPlayer.release();
? ? ? ? mediaPlayer=null;
? ? }

? ? @Override
? ? protected void onDestroy() {
? ? ? ? super.onDestroy();
? ? ? ? //當activity關閉時糖耸,停止這個線程秘遏,防止內存泄漏
? ? ? ? mExecutorService.shutdownNow();
? ? ? ? releaseRecorder();
? ? }
}

xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
?xmlns:tools="http://schemas.android.com/tools"
?android:id="@+id/activity_first"
?android:layout_width="match_parent"
?android:layout_height="match_parent"
?android:orientation="vertical"
?android:padding="2dp"
?tools:context="com.example.amelon.myapplication.FileActivity">


<Button
?android:onClick="playrecorder"
?android:layout_width="wrap_content"
?android:layout_height="wrap_content"
?android:text="播放"
?android:paddingLeft="3dp"
?android:paddingRight="3dp" />

<TextView
?android:id="@+id/tv_sendmsg"
?android:layout_weight="8"
?android:layout_width="wrap_content"
?android:layout_height="0dp"
?android:layout_marginTop="30dp"
?android:onClick="filerecord"
?android:text="文件錄音:" />

< TextView
?android:id="@+id/tv_press_send"
?android:layout_width="match_parent"
?android:layout_weight="1"
?android:background="@android:color/darker_gray"
?android:gravity="center"
?android:layout_height="0dp"
?android:textSize="24sp"
?android:textColor="#70ffffff"
?android:paddingLeft="10dp"
?android:paddingRight="10dp"
?android:text="按下說話" />

< /LinearLayout>


AudioRecord的功能實現(xiàn):?

實現(xiàn)一個點擊button進行錄音,再次點擊停止錄音功能

開啟錄音和停止錄音:

public void recorderaudio(View view) {
? ? ? ? if (mIsRecording) {
? ? ? ? ? ? bt_stream_recorder.setText("開始錄音");
? ? ? ? ? ? //在開始錄音中如果這個值沒有變false嘉竟,則一直進行邦危,當再次點擊變false時,錄音才停止
? ? ? ? ? ? mIsRecording = false;
? ? ? ? ? ? //執(zhí)行停止錄音邏輯舍扰,這塊不用下面代碼倦蚪,只需上面變換mIsRecording這個狀態(tài)就可以了,下面一直走while
? ? ? ? ? /*? mExecutorService.submit(new Runnable() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? stopRecorder();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });*/?
? ? ? ?} else {
? ? ? ? ? ? bt_stream_recorder.setText("停止錄音");
? ? ? ? ? ? //提交后臺任務边苹,執(zhí)行錄音邏輯
? ? ? ? ? ? mIsRecording = true;
? ? ? ? ? ? //提交后臺任務陵且,執(zhí)行錄音邏輯
? ? ? ? ? ? mExecutorService.submit(new Runnable() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? startRecorder();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
? ? }

開啟錄音:

/**
? ? ?* 開始錄音
? ? ?*/
? ? private void startRecorder() {
? ? ? ? // realeseRecorder();
? ? ? ? if (!dostart()) recorderFail();
? ? }

AudioRecord的配置及功能實現(xiàn)具體代碼:

private boolean dostart() {
? ? ? ? try {
? ? ? ? ? ? //記錄開始錄音時間
? ? ? ? ? ? startRecorderTime = System.currentTimeMillis();
? ? ? ? ? ? //創(chuàng)建錄音文件
? ? ? ? ? ? mAudioRecordFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
? ? ? ? ? ? ? ? ? ? "/recorderdemo/" + System.currentTimeMillis() + ".pcm");
? ? ? ? ? ? if (!mAudioRecordFile.getParentFile().exists())
? ? ? ? ? ? ? ? mAudioRecordFile.getParentFile().mkdirs();
? ? ? ? ? ? mAudioRecordFile.createNewFile();
? ? ? ? ? ? //創(chuàng)建文件輸出流
? ? ? ? ? ? mFileOutputStream = new FileOutputStream(mAudioRecordFile);
? ? ? ? ? ? //配置AudioRecord
? ? ? ? ? ? int audioSource = MediaRecorder.AudioSource.MIC;
? ? ? ? ? ? //所有android系統(tǒng)都支持
? ? ? ? ? ? int sampleRate = 44100;
? ? ? ? ? ? //單聲道輸入
? ? ? ? ? ? int channelConfig = AudioFormat.CHANNEL_IN_MONO;
? ? ? ? ? ? //PCM_16是所有android系統(tǒng)都支持的
? ? ? ? ? ? int autioFormat = AudioFormat.ENCODING_PCM_16BIT;
? ? ? ? ? ? //計算AudioRecord內部buffer最小
? ? ? ? ? ? int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, autioFormat);
? ? ? ? ? ? //buffer不能小于最低要求,也不能小于我們每次我們讀取的大小个束。
? ? ? ? ? ? mAudioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, autioFormat, Math.max(minBufferSize, BUFFER_SIZE));
? ? ? ? ? ? //開始錄音
? ? ? ? ? ? mAudioRecord.startRecording();
? ? ? ? ? ? //循環(huán)讀取數(shù)據(jù)慕购,寫入輸出流中
? ? ? ? ? ? while (mIsRecording) {
? ? ? ? ? ? ? ? //只要還在錄音就一直讀取
? ? ? ? ? ? ? ? int read = mAudioRecord.read(mBuffer, 0, BUFFER_SIZE);
? ? ? ? ? ? ? ? if(read<=0){
? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? }else {
? ? ? ? ? ? ? ? ? ? mFileOutputStream.write(mBuffer, 0, read);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? //退出循環(huán),停止錄音茬底,釋放資源
? ? ? ? ? ? stopRecorder();
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? return false;
? ? ? ? } finally {
? ? ? ? ? ? if (mAudioRecord != null) {
? ? ? ? ? ? ? ? mAudioRecord.release();
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return true;
? ? }

再次點擊停止錄音操作代碼:

private boolean doStop() {
? ? ? ? //停止錄音沪悲,關閉文件輸出流
? ? ? ? mAudioRecord.stop();
? ? ? ? mAudioRecord.release();
? ? ? ? mAudioRecord = null;
? ? ? ? //記錄結束時間,統(tǒng)計錄音時長
? ? ? ? stopRecorderTime = System.currentTimeMillis();
? ? ? ? //大于3秒算成功阱表,在主線程更新UI
? ? ? ? final int send = (int) (stopRecorderTime - startRecorderTime) / 1000;
? ? ? ? if (send > 3) {
? ? ? ? ? ? mHandler.post(new Runnable() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? tv_stream_msg.setText("錄音成功:" + send + "秒");
? ? ? ? ? ? ? ? ? ? bt_stream_recorder.setText("開始錄音");
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? } else {
? ? ? ? ? ? recorderFail();
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? return true;
? ? }

錄取失敗殿如,更新UI操作:

private boolean recorderFail() {
? ? ? ? mHandler.post(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? bt_stream_recorder.setText("開始錄音");
? ? ? ? ? ? ? ? tv_stream_msg.setText("錄取失敗,請重新錄入");
? ? ? ? ? ? ? ? mIsRecording=false;
? ? ? ? ? ? ? ? Log.i("Tag8", "go here111111111");
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? return false;
? ? }

播放錄音代碼:

/** * 播放聲音
?* @paramview
?*/
?public void player(View view){
? ? ? ? mExecutorService.submit(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? if(!mIsPlaying){
? ? ? ? ? ? ? ? ? ? Log.i("Tag8","go here");
? ? ? ? ? ? ? ? ? ? mIsPlaying=true;
? ? ? ? ? ? ? ? ? ? doPlay(mAudioRecordFile);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? });
? ? }

播放錄音具體實現(xiàn)最爬,AudioTrack的使用:

private void doPlay(File audioFile) {
? ? ? ? if(audioFile !=null){
? ? ? ? ? ? Log.i("Tag8","go there");
? ? ? ? ? ? //配置播放器
? ? ? ? ? ? //音樂類型涉馁,揚聲器播放
? ? ? ? ? ? int streamType= AudioManager.STREAM_MUSIC;
? ? ? ? ? ? //錄音時采用的采樣頻率,所以播放時同樣的采樣頻率
? ? ? ? ? ? int sampleRate=44100;
? ? ? ? ? ? //單聲道爱致,和錄音時設置的一樣
? ? ? ? ? ? int channelConfig=AudioFormat.CHANNEL_OUT_MONO;
? ? ? ? ? ? //錄音時使用16bit谨胞,所以播放時同樣采用該方式
? ? ? ? ? ? int audioFormat=AudioFormat.ENCODING_PCM_16BIT;
? ? ? ? ? ? //流模式
? ? ? ? ? ? int mode= AudioTrack.MODE_STREAM;
? ? ? ? ? ? //計算最小buffer大小
? ? ? ? ? ? int minBufferSize=AudioTrack.getMinBufferSize(sampleRate,channelConfig,audioFormat);
? ? ? ? ? ? //構造AudioTrack? 不能小于AudioTrack的最低要求,也不能小于我們每次讀的大小
? ? ? ? ? ? AudioTrack audioTrack=new AudioTrack(streamType,sampleRate,channelConfig,audioFormat,
? ? ? ? ? ? ? ? ? ? Math.max(minBufferSize,BUFFER_SIZE),mode);
? ? ? ? ? ? //從文件流讀數(shù)據(jù)
? ? ? ? ? ? FileInputStream inputStream=null;
? ? ? ? ? ? try{
? ? ? ? ? ? ? ? //循環(huán)讀數(shù)據(jù)蒜鸡,寫到播放器去播放
? ? ? ? ? ? ? ? inputStream=new FileInputStream(audioFile);
? ? ? ? ? ? ? ? //循環(huán)讀數(shù)據(jù)胯努,寫到播放器去播放
? ? ? ? ? ? ? ? int read;
? ? ? ? ? ? ? ? //只要沒讀完牢裳,循環(huán)播放
? ? ? ? ? ? ? ? while ((read=inputStream.read(mBuffer))>0){
? ? ? ? ? ? ? ? ? ? Log.i("Tag8","read:"+read);
? ? ? ? ? ? ? ? ? ? int ret=audioTrack.write(mBuffer,0,read);
? ? ? ? ? ? ? ? ? ? //檢查write的返回值,處理錯誤
? ? ? ? ? ? ? ? ? ? switch (ret){
? ? ? ? ? ? ? ? ? ? ? ? case AudioTrack.ERROR_INVALID_OPERATION:
? ? ? ? ? ? ? ? ? ? ? ? case AudioTrack.ERROR_BAD_VALUE:
? ? ? ? ? ? ? ? ? ? ? ? case AudioManager.ERROR_DEAD_OBJECT:
? ? ? ? ? ? ? ? ? ? ? ? ? ? playFail();
? ? ? ? ? ? ? ? ? ? ? ? ? ? return;
? ? ? ? ? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }catch (Exception e){
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? //讀取失敗
? ? ? ? ? ? ? ? playFail();
? ? ? ? ? ? }finally {
? ? ? ? ? ? ? ? mIsPlaying=false;
? ? ? ? ? ? ? ? //關閉文件輸入流?
? ? ? ? ? ? ? ?if(inputStream !=null){
? ? ? ? ? ? ? ? ? ? closeStream(inputStream);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? //播放器釋放
? ? ? ? ? ? ? ? resetQuietly(audioTrack);
? ? ? ? ? ? }
? ? ? ? }
? ? }

播放失斠杜妗:更新UI操作

/**
? ? ?* 播放失敗
? ? ?*/
? ? private void playFail() {
? ? ? ? mHandler.post(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? tv_stream_msg.setText("播放失敗");
? ? ? ? ? ? }
? ? ? ? });
? ? }

activity銷毀處理代碼:

//防止內存泄漏
@Override protected void onDestroy() {
? ? ? ? super.onDestroy();
? ? ? ? if (mExecutorService != null) {
? ? ? ? ? ? mExecutorService.shutdownNow();
? ? ? ? }
? ? ? ? if (mAudioRecord != null) {
? ? ? ? ? ? mAudioRecord.stop();
? ? ? ? ? ? mAudioRecord.release();
? ? ? ? ? ? mAudioRecord = null;
? ? ? ? }
? ? }

AudioRecord的功能實現(xiàn)完整代碼:

package com.example.amelon.myapplication;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public classStreamActivityextendsAppCompatActivity{ private Button bt_stream_recorder;
? ? private TextView tv_stream_msg;
? ? private ExecutorService mExecutorService;
? ? private long startRecorderTime, stopRecorderTime;
? ? private volatile boolean mIsRecording = false;
? ? private AudioRecord mAudioRecord;
? ? private FileOutputStream mFileOutputStream;
? ? private File mAudioRecordFile;
? ? private byte[] mBuffer;
? ? //buffer值不能太大蒲讯,避免OOM
? ? private static final int BUFFER_SIZE = 2048;
? ? private boolean mIsPlaying=false;
? ? private Handler mHandler = new Handler(Looper.getMainLooper());
? ? @Override
? ? protected void onCreate(Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? setContentView(R.layout.activity_stream);
? ? ? ? setTitle("字節(jié)流錄音");
? ? ? ? initView();
? ? ? ? mExecutorService = Executors.newSingleThreadExecutor();
? ? ? ? mBuffer = new byte[BUFFER_SIZE];
? ? }

? ? private void initView() {
? ? ? ? bt_stream_recorder = (Button) findViewById(R.id.bt_stream_recorder);
? ? ? ? tv_stream_msg = (TextView) findViewById(R.id.tv_stream_msg);
? ? }

? ? public void recorderaudio(View view) {
? ? ? ? if (mIsRecording) {
? ? ? ? ? ? bt_stream_recorder.setText("開始錄音");
? ? ? ? ? ? //在開始錄音中如果這個值沒有變false,則一直進行灰署,當再次點擊變false時判帮,錄音才停止
? ? ? ? ? ? mIsRecording = false;
? ? ? ? ? ? //執(zhí)行停止錄音邏輯,這塊不用下面代碼溉箕,只需上面變換mIsRecording這個狀態(tài)就可以了晦墙,下面一直走while
? ? ? ? ? /*? mExecutorService.submit(new Runnable() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? stopRecorder();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });*/
? ? ? ? } else {
? ? ? ? ? ? bt_stream_recorder.setText("停止錄音");
? ? ? ? ? ? //提交后臺任務,執(zhí)行錄音邏輯
? ? ? ? ? ? mIsRecording = true;
? ? ? ? ? ? //提交后臺任務肴茄,執(zhí)行錄音邏輯
? ? ? ? ? ? mExecutorService.submit(new Runnable() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? startRecorder();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
? ? }

? ? /**
? ? ?* 開始錄音
? ? ?*/
? ? private void startRecorder() {
? ? ? ? // realeseRecorder();
? ? ? ? if (!dostart()) recorderFail();
? ? }

? ? /**
? ? ?* 停止錄音
? ? ?*/
? ? private void stopRecorder() {
? ? ? ? mIsRecording=false;
? ? ? ? if (!doStop()) recorderFail();
? ? }
? ? private boolean dostart() {
? ? ? ? try {
? ? ? ? ? ? //記錄開始錄音時間
? ? ? ? ? ? startRecorderTime = System.currentTimeMillis();
? ? ? ? ? ? //創(chuàng)建錄音文件
? ? ? ? ? ? mAudioRecordFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
? ? ? ? ? ? ? ? ? ? "/recorderdemo/" + System.currentTimeMillis() + ".pcm");
? ? ? ? ? ? if (!mAudioRecordFile.getParentFile().exists())
? ? ? ? ? ? ? ? mAudioRecordFile.getParentFile().mkdirs();
? ? ? ? ? ? mAudioRecordFile.createNewFile();
? ? ? ? ? ? //創(chuàng)建文件輸出流
? ? ? ? ? ? mFileOutputStream = new FileOutputStream(mAudioRecordFile);
? ? ? ? ? ? //配置AudioRecord
? ? ? ? ? ? int audioSource = MediaRecorder.AudioSource.MIC;
? ? ? ? ? ? //所有android系統(tǒng)都支持
? ? ? ? ? ? int sampleRate = 44100;
? ? ? ? ? ? //單聲道輸入
? ? ? ? ? ? int channelConfig = AudioFormat.CHANNEL_IN_MONO;
? ? ? ? ? ? //PCM_16是所有android系統(tǒng)都支持的
? ? ? ? ? ? int autioFormat = AudioFormat.ENCODING_PCM_16BIT;
? ? ? ? ? ? //計算AudioRecord內部buffer最小
? ? ? ? ? ? int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, autioFormat);
? ? ? ? ? ? //buffer不能小于最低要求晌畅,也不能小于我們每次我們讀取的大小。
? ? ? ? ? ? mAudioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, autioFormat, Math.max(minBufferSize, BUFFER_SIZE));
? ? ? ? ? ? //開始錄音? ? ? ? ? ? mAudioRecord.startRecording();
? ? ? ? ? ? //循環(huán)讀取數(shù)據(jù),寫入輸出流中
? ? ? ? ? ? while (mIsRecording) {
? ? ? ? ? ? ? ? //只要還在錄音就一直讀取
? ? ? ? ? ? ? ? int read = mAudioRecord.read(mBuffer, 0, BUFFER_SIZE);
? ? ? ? ? ? ? ? if(read<=0){
? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? }else {
? ? ? ? ? ? ? ? ? ? mFileOutputStream.write(mBuffer, 0, read);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? //退出循環(huán),停止錄音梅忌,釋放資源
? ? ? ? ? ? stopRecorder();
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? return false;
? ? ? ? } finally {
? ? ? ? ? ? if (mAudioRecord != null) {
? ? ? ? ? ? ? ? mAudioRecord.release();
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return true;
? ? }

? ? private boolean recorderFail() {
? ? ? ? mHandler.post(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? bt_stream_recorder.setText("開始錄音");
? ? ? ? ? ? ? ? tv_stream_msg.setText("錄取失敗泽裳,請重新錄入");
? ? ? ? ? ? ? ? mIsRecording=false;
? ? ? ? ? ? ? ? Log.i("Tag8", "go here111111111");
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? return false;
? ? }

? ? private void realeseRecorder() {
? ? ? ? mAudioRecord.release();
? ? }

? ? private boolean doStop() {
? ? ? ? //停止錄音,關閉文件輸出流? ? ? ? mAudioRecord.stop();
? ? ? ? mAudioRecord.release();
? ? ? ? mAudioRecord = null;
? ? ? ? Log.i("Tag8", "go here");
? ? ? ? //記錄結束時間,統(tǒng)計錄音時長
? ? ? ? stopRecorderTime = System.currentTimeMillis();
? ? ? ? //大于3秒算成功,在主線程更新UI
? ? ? ? final int send = (int) (stopRecorderTime - startRecorderTime) / 1000;
? ? ? ? if (send > 3) {
? ? ? ? ? ? mHandler.post(new Runnable() {
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? tv_stream_msg.setText("錄音成功:" + send + "秒");
? ? ? ? ? ? ? ? ? ? bt_stream_recorder.setText("開始錄音");
? ? ? ? ? ? ? ? ? ? Log.i("Tag8", "go there");
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? } else {
? ? ? ? ? ? recorderFail();
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? return true;
? ? }

? ? /**
? ? ?* 播放聲音
? ? ?* @paramview
? ? ?*/
? ? public void player(View view){
? ? ? ? mExecutorService.submit(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? if(!mIsPlaying){
? ? ? ? ? ? ? ? ? ? Log.i("Tag8","go here");
? ? ? ? ? ? ? ? ? ? mIsPlaying=true;
? ? ? ? ? ? ? ? ? ? doPlay(mAudioRecordFile);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? });
? ? }

? ? private void doPlay(File audioFile) {
? ? ? ? if(audioFile !=null){
? ? ? ? ? ? Log.i("Tag8","go there");
? ? ? ? ? ? //配置播放器
? ? ? ? ? ? //音樂類型,揚聲器播放
? ? ? ? ? ? int streamType= AudioManager.STREAM_MUSIC;
? ? ? ? ? ? //錄音時采用的采樣頻率入热,所以播放時同樣的采樣頻率
? ? ? ? ? ? int sampleRate=44100;
? ? ? ? ? ? //單聲道,和錄音時設置的一樣
? ? ? ? ? ? int channelConfig=AudioFormat.CHANNEL_OUT_MONO;
? ? ? ? ? ? //錄音時使用16bit晓铆,所以播放時同樣采用該方式
? ? ? ? ? ? int audioFormat=AudioFormat.ENCODING_PCM_16BIT;
? ? ? ? ? ? //流模式
? ? ? ? ? ? int mode= AudioTrack.MODE_STREAM;
? ? ? ? ? ? //計算最小buffer大小
? ? ? ? ? ? int minBufferSize=AudioTrack.getMinBufferSize(sampleRate,channelConfig,audioFormat);
? ? ? ? ? ? //構造AudioTrack? 不能小于AudioTrack的最低要求才顿,也不能小于我們每次讀的大小
? ? ? ? ? ? AudioTrack audioTrack=new AudioTrack(streamType,sampleRate,channelConfig,audioFormat,
? ? ? ? ? ? ? ? ? ? Math.max(minBufferSize,BUFFER_SIZE),mode);
? ? ? ? ? ? //從文件流讀數(shù)據(jù)? ? ? ? ? ? FileInputStream inputStream=null;
? ? ? ? ? ? try{
? ? ? ? ? ? ? ? //循環(huán)讀數(shù)據(jù),寫到播放器去播放
? ? ? ? ? ? ? ? inputStream=new FileInputStream(audioFile);
? ? ? ? ? ? ? ? //循環(huán)讀數(shù)據(jù)尤蒿,寫到播放器去播放
? ? ? ? ? ? ? ? int read;
? ? ? ? ? ? ? ? //只要沒讀完郑气,循環(huán)播放
? ? ? ? ? ? ? ? while ((read=inputStream.read(mBuffer))>0){
? ? ? ? ? ? ? ? ? ? Log.i("Tag8","read:"+read);
? ? ? ? ? ? ? ? ? ? int ret=audioTrack.write(mBuffer,0,read);
? ? ? ? ? ? ? ? ? ? //檢查write的返回值,處理錯誤
? ? ? ? ? ? ? ? ? ? switch (ret){
? ? ? ? ? ? ? ? ? ? ? ? case AudioTrack.ERROR_INVALID_OPERATION:
? ? ? ? ? ? ? ? ? ? ? ? case AudioTrack.ERROR_BAD_VALUE:
? ? ? ? ? ? ? ? ? ? ? ? case AudioManager.ERROR_DEAD_OBJECT:
? ? ? ? ? ? ? ? ? ? ? ? ? ? playFail();
? ? ? ? ? ? ? ? ? ? ? ? ? ? return;
? ? ? ? ? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }catch (Exception e){
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? //讀取失敗
? ? ? ? ? ? ? ? playFail();
? ? ? ? ? ? }finally {
? ? ? ? ? ? ? ? mIsPlaying=false;
? ? ? ? ? ? ? ? //關閉文件輸入流
? ? ? ? ? ? ? ? if(inputStream !=null){
? ? ? ? ? ? ? ? ? ? closeStream(inputStream);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? //播放器釋放
? ? ? ? ? ? ? ? resetQuietly(audioTrack);
? ? ? ? ? ? }
? ? ? ? ? ? //循環(huán)讀數(shù)據(jù)腰池,寫到播放器去播放
? ? ? ? ? ? //錯誤處理尾组,防止閃退? ? ? ? }
? ? }
? ? /**
? ? ?* 關閉輸入流
? ? ?* @paraminputStream
? ? ?*/
? ? private void closeStream(FileInputStream inputStream){
? ? ? ? try {
? ? ? ? ? ? inputStream.close();
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }

? ? private void resetQuietly(AudioTrack audioTrack){
? ? ? ? try{
? ? ? ? ? ? audioTrack.stop();
? ? ? ? ? ? audioTrack.release();
? ? ? ? }catch (Exception e){
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }

? ? /**
? ? ?* 播放失敗
? ? ?*/
? ? private void playFail() {
? ? ? ? mHandler.post(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? tv_stream_msg.setText("播放失敗");
? ? ? ? ? ? }
? ? ? ? });
? ? }

? ? @Override
? ? protected void onDestroy() {
? ? ? ? super.onDestroy();
? ? ? ? if (mExecutorService != null) {
? ? ? ? ? ? mExecutorService.shutdownNow();
? ? ? ? }
? ? ? ? if (mAudioRecord != null) {
? ? ? ? ? ? mAudioRecord.stop();
? ? ? ? ? ? mAudioRecord.release();
? ? ? ? ? ? mAudioRecord = null;
? ? ? ? }
? ? }
}

xml布局文件:

<?xml version="1.0" encoding="utf-8"?>

< LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
?xmlns:tools="http://schemas.android.com/tools"
?android:id="@+id/activity_stream"
?android:layout_width="match_parent"
?android:layout_height="match_parent"
?android:padding="2dp"
?android:orientation="vertical"
?tools:context="com.example.amelon.myapplication.StreamActivity">

< LinearLayout
?android:layout_width="match_parent"
?android:layout_height="0dp"
?android:layout_weight="3"
?android:orientation="vertical" >

< Button
?android:onClick="recorderaudio"
?android:id="@+id/bt_stream_recorder"
?android:layout_width="wrap_content"
?android:layout_height="wrap_content"
?android:background="#50000000"
?android:layout_margin="10dp"
?android:textSize="24sp"
?android:textColor="#fff"
?android:padding="10dp"
?android:text="開始錄音" />

< Button
?android:onClick="player"
?android:layout_width="wrap_content"
?android:layout_height="wrap_content"
?android:background="#50000000"
?android:layout_margin="10dp"
?android:textSize="24sp"
?android:textColor="#fff"
?android:padding="10dp"
?android:text="播 放" />

< /LinearLayout>

< TextView
?android:id="@+id/tv_stream_msg"
?android:layout_weight="7"
?android:layout_width="match_parent"
?android:layout_height="wrap_content"
?android:textSize="24sp"
?android:padding="10dp"
?android:text="錄音結果" />

< /LinearLayout>

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市示弓,隨后出現(xiàn)的幾起案子讳侨,更是在濱河造成了極大的恐慌,老刑警劉巖奏属,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跨跨,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機勇婴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門忱嘹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人耕渴,你說我怎么就攤上這事拘悦。” “怎么了橱脸?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵础米,是天一觀的道長。 經(jīng)常有香客問我添诉,道長屁桑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任栏赴,我火速辦了婚禮蘑斧,結果婚禮上,老公的妹妹穿的比我還像新娘艾帐。我一直安慰自己,他們只是感情好盆偿,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布柒爸。 她就那樣靜靜地躺著,像睡著了一般事扭。 火紅的嫁衣襯著肌膚如雪捎稚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天求橄,我揣著相機與錄音今野,去河邊找鬼。 笑死罐农,一個胖子當著我的面吹牛条霜,可吹牛的內容都是我干的。 我是一名探鬼主播涵亏,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼宰睡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了气筋?” 一聲冷哼從身側響起拆内,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宠默,沒想到半個月后麸恍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡搀矫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年抹沪,在試婚紗的時候發(fā)現(xiàn)自己被綠了刻肄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡采够,死狀恐怖肄方,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情蹬癌,我是刑警寧澤权她,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站逝薪,受9級特大地震影響隅要,放射性物質發(fā)生泄漏。R本人自食惡果不足惜董济,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一步清、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧虏肾,春花似錦廓啊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吹埠,卻和暖如春第步,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缘琅。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工粘都, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人刷袍。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓翩隧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親呻纹。 傳聞我的和親對象是個殘疾皇子鸽心,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn)居暖,斷路器顽频,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,510評論 25 707
  • ¥開啟¥ 【iAPP實現(xiàn)進入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,358評論 0 17
  • This is the jar of love 我承認之前的情感都是輕率而不夠真誠的太闺。真正的感情應該是我聯(lián)系你糯景,你...
    韋雄閱讀 1,406評論 3 0
  • 無意中翻了翻微信通訊錄里很久不聯(lián)系的朋友,打開她們的朋友圈,卻意外的發(fā)現(xiàn)沒有任何東西蟀淮,我的第一反應就是她們是不是把...
    司夕閱讀 380評論 0 0