国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android使用AudioRecord實現(xiàn)暫停錄音功能實例代碼

2019-10-22 18:33:31
字體:
供稿:網(wǎng)友

題外話:發(fā)現(xiàn)好久都沒有上來寫博文了,畢業(yè)設(shè)計加上公司暫時沒有Android的項目做,只能去自學(xué)web上的知識,摸爬打滾到現(xiàn)在,花了一個多月時間根據(jù)公司的現(xiàn)有模板做了公司內(nèi)部一個任務(wù)管理系統(tǒng),感覺都是比較淺的知識,沒什么可以寫的。想到之前做的語音識別的項目,雖然現(xiàn)在沒什么下文了,但是誰懂~~~將來呢?

言歸正傳,項目長這樣子:

android,錄音暫停,android錄音暫停繼續(xù)

設(shè)計的思路:

由于自帶的AudioRecord沒有pauseRecord()方法,我把開始錄音-->(暫停/繼續(xù)錄音)...-->停止錄音叫做一次錄音,點擊一次暫停就會產(chǎn)生一個文件(.pcm),將一次錄音產(chǎn)生的所有文件名(.pcm)用一個list裝起來,點擊停止后將遍歷list取得所有文件路徑進(jìn)行拼接。

由于考慮到以后可能要進(jìn)行語音識別,所以對程序的靈活性和拓展性都做了相應(yīng)的處理,可以通過setListener()監(jiān)聽錄音的音頻流和監(jiān)聽錄音結(jié)束。

采用線程池對線程進(jìn)行管理,減少系統(tǒng)開銷。

對類的說明:

  1. AudioRecorder:封裝了錄音的方法:創(chuàng)建錄音對象、開始、暫停、停止、取消,使用靜態(tài)枚舉類Status來記錄錄音的狀態(tài)。
  2. FileUtils:文件工具類,用于文件路徑的獲取
  3. PcmToWav:封裝了將.pcm文件轉(zhuǎn)化.wav文件的方法
  4. WaveHeader: wav文件頭
  5. RecordStreamListener:監(jiān)聽錄音音頻流,用于拓展業(yè)務(wù)的處理

接下來是關(guān)鍵代碼部分:
1、AudioRecorder類:

package com.hxl.pauserecord.record;  import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.text.TextUtils; import android.util.Log;  import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;  /**  * Created by HXL on 16/8/11.  * 用于實現(xiàn)錄音 暫停錄音  */ public class AudioRecorder {  //音頻輸入-麥克風(fēng)  private final static int AUDIO_INPUT = MediaRecorder.AudioSource.MIC;  //采用頻率  //44100是目前的標(biāo)準(zhǔn),但是某些設(shè)備仍然支持22050,16000,11025  //采樣頻率一般共分為22.05KHz、44.1KHz、48KHz三個等級  private final static int AUDIO_SAMPLE_RATE = 16000;  //聲道 單聲道  private final static int AUDIO_CHANNEL = AudioFormat.CHANNEL_IN_MONO;  //編碼  private final static int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;  // 緩沖區(qū)字節(jié)大小  private int bufferSizeInBytes = 0;   //錄音對象  private AudioRecord audioRecord;   //錄音狀態(tài)  private Status status = Status.STATUS_NO_READY;   //文件名  private String fileName;   //錄音文件  private List<String> filesName = new ArrayList<>();   //線程池  private ExecutorService mExecutorService;   //錄音監(jiān)聽  private RecordStreamListener listener;    public AudioRecorder() {   mExecutorService = Executors.newCachedThreadPool();  }   /**   * 創(chuàng)建錄音對象   */  public void createAudio(String fileName, int audioSource, int sampleRateInHz, int channelConfig, int audioFormat) {   // 獲得緩沖區(qū)字節(jié)大小   bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,     channelConfig, channelConfig);   audioRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes);   this.fileName = fileName;  }   /**   * 創(chuàng)建默認(rèn)的錄音對象   *   * @param fileName 文件名   */  public void createDefaultAudio(String fileName) {   // 獲得緩沖區(qū)字節(jié)大小   bufferSizeInBytes = AudioRecord.getMinBufferSize(AUDIO_SAMPLE_RATE,     AUDIO_CHANNEL, AUDIO_ENCODING);   audioRecord = new AudioRecord(AUDIO_INPUT, AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING, bufferSizeInBytes);   this.fileName = fileName;   status = Status.STATUS_READY;  }    /**   * 開始錄音   *   */  public void startRecord() {    if (status == Status.STATUS_NO_READY||audioRecord==null) {    throw new IllegalStateException("錄音尚未初始化,請檢查是否禁止了錄音權(quán)限~");   }   if (status == Status.STATUS_START) {    throw new IllegalStateException("正在錄音");   }   Log.d("AudioRecorder", "===startRecord===" + audioRecord.getState());   audioRecord.startRecording();    String currentFileName = fileName;   if (status == Status.STATUS_PAUSE) {    //假如是暫停錄音 將文件名后面加個數(shù)字,防止重名文件內(nèi)容被覆蓋    currentFileName += filesName.size();    }   filesName.add(currentFileName);    final String finalFileName=currentFileName;   //將錄音狀態(tài)設(shè)置成正在錄音狀態(tài)   status = Status.STATUS_START;    //使用線程池管理線程   mExecutorService.execute(new Runnable() {    @Override    public void run() {     writeDataTOFile(finalFileName);    }   });  }   /**   * 暫停錄音   */  public void pauseRecord() {   Log.d("AudioRecorder", "===pauseRecord===");   if (status != Status.STATUS_START) {    throw new IllegalStateException("沒有在錄音");   } else {    audioRecord.stop();    status = Status.STATUS_PAUSE;   }  }   /**   * 停止錄音   */  public void stopRecord() {   Log.d("AudioRecorder", "===stopRecord===");   if (status == Status.STATUS_NO_READY || status == Status.STATUS_READY) {    throw new IllegalStateException("錄音尚未開始");   } else {    audioRecord.stop();    status = Status.STATUS_STOP;    release();   }  }   /**   * 釋放資源   */  public void release() {   Log.d("AudioRecorder", "===release===");   //假如有暫停錄音   try {    if (filesName.size() > 0) {     List<String> filePaths = new ArrayList<>();     for (String fileName : filesName) {      filePaths.add(FileUtils.getPcmFileAbsolutePath(fileName));     }     //清除     filesName.clear();     //將多個pcm文件轉(zhuǎn)化為wav文件     mergePCMFilesToWAVFile(filePaths);     } else {     //這里由于只要錄音過filesName.size都會大于0,沒錄音時fileName為null     //會報空指針 NullPointerException     // 將單個pcm文件轉(zhuǎn)化為wav文件     //Log.d("AudioRecorder", "=====makePCMFileToWAVFile======");     //makePCMFileToWAVFile();    }   } catch (IllegalStateException e) {    throw new IllegalStateException(e.getMessage());   }    if (audioRecord != null) {    audioRecord.release();    audioRecord = null;   }    status = Status.STATUS_NO_READY;  }   /**   * 取消錄音   */  public void canel() {   filesName.clear();   fileName = null;   if (audioRecord != null) {    audioRecord.release();    audioRecord = null;   }    status = Status.STATUS_NO_READY;  }    /**   * 將音頻信息寫入文件   *   */  private void writeDataTOFile(String currentFileName) {   // new一個byte數(shù)組用來存一些字節(jié)數(shù)據(jù),大小為緩沖區(qū)大小   byte[] audiodata = new byte[bufferSizeInBytes];    FileOutputStream fos = null;   int readsize = 0;   try {    File file = new File(FileUtils.getPcmFileAbsolutePath(currentFileName));    if (file.exists()) {     file.delete();    }    fos = new FileOutputStream(file);// 建立一個可存取字節(jié)的文件   } catch (IllegalStateException e) {    Log.e("AudioRecorder", e.getMessage());    throw new IllegalStateException(e.getMessage());   } catch (FileNotFoundException e) {    Log.e("AudioRecorder", e.getMessage());    }   while (status == Status.STATUS_START) {    readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);    if (AudioRecord.ERROR_INVALID_OPERATION != readsize && fos != null) {     try {      fos.write(audiodata);      if (listener != null) {       //用于拓展業(yè)務(wù)       listener.onRecording(audiodata, 0, audiodata.length);      }     } catch (IOException e) {      Log.e("AudioRecorder", e.getMessage());     }    }   }   if (listener != null) {    listener.finishRecord();   }   try {    if (fos != null) {     fos.close();// 關(guān)閉寫入流    }   } catch (IOException e) {    Log.e("AudioRecorder", e.getMessage());   }  }   /**   * 將pcm合并成wav   *   * @param filePaths   */  private void mergePCMFilesToWAVFile(final List<String> filePaths) {   mExecutorService.execute(new Runnable() {    @Override    public void run() {     if (PcmToWav.mergePCMFilesToWAVFile(filePaths, FileUtils.getWavFileAbsolutePath(fileName))) {      //操作成功     } else {      //操作失敗      Log.e("AudioRecorder", "mergePCMFilesToWAVFile fail");      throw new IllegalStateException("mergePCMFilesToWAVFile fail");     }    }   });  }   /**   * 將單個pcm文件轉(zhuǎn)化為wav文件   */  private void makePCMFileToWAVFile() {   mExecutorService.execute(new Runnable() {    @Override    public void run() {     if (PcmToWav.makePCMFileToWAVFile(FileUtils.getPcmFileAbsolutePath(fileName), FileUtils.getWavFileAbsolutePath(fileName), true)) {      //操作成功     } else {      //操作失敗      Log.e("AudioRecorder", "makePCMFileToWAVFile fail");      throw new IllegalStateException("makePCMFileToWAVFile fail");     }    }   });  }    /**   * 錄音對象的狀態(tài)   */  public enum Status {   //未開始   STATUS_NO_READY,   //預(yù)備   STATUS_READY,   //錄音   STATUS_START,   //暫停   STATUS_PAUSE,   //停止   STATUS_STOP  }   /**   * 獲取錄音對象的狀態(tài)   *   * @return   */  public Status getStatus() {   return status;  }   /**   * 獲取本次錄音文件的個數(shù)   *   * @return   */  public int getPcmFilesCount() {   return filesName.size();  }    public RecordStreamListener getListener() {   return listener;  }   public void setListener(RecordStreamListener listener) {   this.listener = listener;  }  } 

2:PcmToWav

package com.hxl.pauserecord.record;  import android.util.Log;  import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List;  /**  * Created by HXL on 16/8/11.  * 將pcm文件轉(zhuǎn)化為wav文件  */ public class PcmToWav {  /**   * 合并多個pcm文件為一個wav文件   *   * @param filePathList pcm文件路徑集合   * @param destinationPath 目標(biāo)wav文件路徑   * @return true|false   */  public static boolean mergePCMFilesToWAVFile(List<String> filePathList,              String destinationPath) {   File[] file = new File[filePathList.size()];   byte buffer[] = null;    int TOTAL_SIZE = 0;   int fileNum = filePathList.size();    for (int i = 0; i < fileNum; i++) {    file[i] = new File(filePathList.get(i));    TOTAL_SIZE += file[i].length();   }    // 填入?yún)?shù),比特率等等。這里用的是16位單聲道 8000 hz   WaveHeader header = new WaveHeader();   // 長度字段 = 內(nèi)容的大小(TOTAL_SIZE) +   // 頭部字段的大小(不包括前面4字節(jié)的標(biāo)識符RIFF以及fileLength本身的4字節(jié))   header.fileLength = TOTAL_SIZE + (44 - 8);   header.FmtHdrLeth = 16;   header.BitsPerSample = 16;   header.Channels = 2;   header.FormatTag = 0x0001;   header.SamplesPerSec = 8000;   header.BlockAlign = (short) (header.Channels * header.BitsPerSample / 8);   header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;   header.DataHdrLeth = TOTAL_SIZE;    byte[] h = null;   try {    h = header.getHeader();   } catch (IOException e1) {    Log.e("PcmToWav", e1.getMessage());    return false;   }    if (h.length != 44) // WAV標(biāo)準(zhǔn),頭部應(yīng)該是44字節(jié),如果不是44個字節(jié)則不進(jìn)行轉(zhuǎn)換文件    return false;    //先刪除目標(biāo)文件   File destfile = new File(destinationPath);   if (destfile.exists())    destfile.delete();    //合成所有的pcm文件的數(shù)據(jù),寫到目標(biāo)文件   try {    buffer = new byte[1024 * 4]; // Length of All Files, Total Size    InputStream inStream = null;    OutputStream ouStream = null;     ouStream = new BufferedOutputStream(new FileOutputStream(      destinationPath));    ouStream.write(h, 0, h.length);    for (int j = 0; j < fileNum; j++) {     inStream = new BufferedInputStream(new FileInputStream(file[j]));     int size = inStream.read(buffer);     while (size != -1) {      ouStream.write(buffer);      size = inStream.read(buffer);     }     inStream.close();    }    ouStream.close();   } catch (FileNotFoundException e) {    Log.e("PcmToWav", e.getMessage());    return false;   } catch (IOException ioe) {    Log.e("PcmToWav", ioe.getMessage());    return false;   }   clearFiles(filePathList);   Log.i("PcmToWav", "mergePCMFilesToWAVFile success!" + new SimpleDateFormat("yyyy-MM-dd hh:mm").format(new Date()));   return true;   }   /**   * 將一個pcm文件轉(zhuǎn)化為wav文件   *   * @param pcmPath   pcm文件路徑   * @param destinationPath 目標(biāo)文件路徑(wav)   * @param deletePcmFile 是否刪除源文件   * @return   */  public static boolean makePCMFileToWAVFile(String pcmPath, String destinationPath, boolean deletePcmFile) {   byte buffer[] = null;   int TOTAL_SIZE = 0;   File file = new File(pcmPath);   if (!file.exists()) {    return false;   }   TOTAL_SIZE = (int) file.length();   // 填入?yún)?shù),比特率等等。這里用的是16位單聲道 8000 hz   WaveHeader header = new WaveHeader();   // 長度字段 = 內(nèi)容的大?。═OTAL_SIZE) +   // 頭部字段的大小(不包括前面4字節(jié)的標(biāo)識符RIFF以及fileLength本身的4字節(jié))   header.fileLength = TOTAL_SIZE + (44 - 8);   header.FmtHdrLeth = 16;   header.BitsPerSample = 16;   header.Channels = 2;   header.FormatTag = 0x0001;   header.SamplesPerSec = 8000;   header.BlockAlign = (short) (header.Channels * header.BitsPerSample / 8);   header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;   header.DataHdrLeth = TOTAL_SIZE;    byte[] h = null;   try {    h = header.getHeader();   } catch (IOException e1) {    Log.e("PcmToWav", e1.getMessage());    return false;   }    if (h.length != 44) // WAV標(biāo)準(zhǔn),頭部應(yīng)該是44字節(jié),如果不是44個字節(jié)則不進(jìn)行轉(zhuǎn)換文件    return false;    //先刪除目標(biāo)文件   File destfile = new File(destinationPath);   if (destfile.exists())    destfile.delete();    //合成所有的pcm文件的數(shù)據(jù),寫到目標(biāo)文件   try {    buffer = new byte[1024 * 4]; // Length of All Files, Total Size    InputStream inStream = null;    OutputStream ouStream = null;     ouStream = new BufferedOutputStream(new FileOutputStream(      destinationPath));    ouStream.write(h, 0, h.length);    inStream = new BufferedInputStream(new FileInputStream(file));    int size = inStream.read(buffer);    while (size != -1) {     ouStream.write(buffer);     size = inStream.read(buffer);    }    inStream.close();    ouStream.close();   } catch (FileNotFoundException e) {    Log.e("PcmToWav", e.getMessage());    return false;   } catch (IOException ioe) {    Log.e("PcmToWav", ioe.getMessage());    return false;   }   if (deletePcmFile) {    file.delete();   }   Log.i("PcmToWav", "makePCMFileToWAVFile success!" + new SimpleDateFormat("yyyy-MM-dd hh:mm").format(new Date()));   return true;   }   /**   * 清除文件   *   * @param filePathList   */  private static void clearFiles(List<String> filePathList) {   for (int i = 0; i < filePathList.size(); i++) {    File file = new File(filePathList.get(i));    if (file.exists()) {     file.delete();    }   }  }  } 

3、WaveHeader類:

package com.hxl.pauserecord.record;  import java.io.ByteArrayOutputStream; import java.io.IOException;  /**  * Created by HXL on 16/3/9.  * wav文件頭  */ public class WaveHeader {  public final char fileID[] = {'R', 'I', 'F', 'F'};  public int fileLength;  public char wavTag[] = {'W', 'A', 'V', 'E'};;  public char FmtHdrID[] = {'f', 'm', 't', ' '};  public int FmtHdrLeth;  public short FormatTag;  public short Channels;  public int SamplesPerSec;  public int AvgBytesPerSec;  public short BlockAlign;  public short BitsPerSample;  public char DataHdrID[] = {'d','a','t','a'};  public int DataHdrLeth;   public byte[] getHeader() throws IOException {   ByteArrayOutputStream bos = new ByteArrayOutputStream();   WriteChar(bos, fileID);   WriteInt(bos, fileLength);   WriteChar(bos, wavTag);   WriteChar(bos, FmtHdrID);   WriteInt(bos,FmtHdrLeth);   WriteShort(bos,FormatTag);   WriteShort(bos,Channels);   WriteInt(bos,SamplesPerSec);   WriteInt(bos,AvgBytesPerSec);   WriteShort(bos,BlockAlign);   WriteShort(bos,BitsPerSample);   WriteChar(bos,DataHdrID);   WriteInt(bos,DataHdrLeth);   bos.flush();   byte[] r = bos.toByteArray();   bos.close();   return r;  }   private void WriteShort(ByteArrayOutputStream bos, int s) throws IOException {   byte[] mybyte = new byte[2];   mybyte[1] =(byte)( (s << 16) >> 24 );   mybyte[0] =(byte)( (s << 24) >> 24 );   bos.write(mybyte);  }    private void WriteInt(ByteArrayOutputStream bos, int n) throws IOException {   byte[] buf = new byte[4];   buf[3] =(byte)( n >> 24 );   buf[2] =(byte)( (n << 8) >> 24 );   buf[1] =(byte)( (n << 16) >> 24 );   buf[0] =(byte)( (n << 24) >> 24 );   bos.write(buf);  }   private void WriteChar(ByteArrayOutputStream bos, char[] id) {   for (int i=0; i<id.length; i++) {    char c = id[i];    bos.write(c);   }  } } 

接下來是效果圖。。。個人為人做APP界面一定要美觀,而且要非常美觀,不然誰會用你的東西!so~~

android,錄音暫停,android錄音暫停繼續(xù)

好吧,請大家撇開UI看功能~正如預(yù)期的一樣,每點擊暫停一次會生成一個pcm文件,當(dāng)點擊停止的時候,將所有的錄音整合成一個可播放的.wav文件

接下來,項目源碼:點擊下載

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 延长县| 宁晋县| 冀州市| 邯郸市| 阳东县| 始兴县| 公安县| 顺义区| 黔西县| 惠来县| 德昌县| 礼泉县| 类乌齐县| 勃利县| 任丘市| 昌宁县| 镇江市| 佛坪县| 瑞昌市| 饶平县| 凤庆县| 山东| 漳浦县| 西安市| 杭锦旗| 嵩明县| 宁晋县| 广平县| 民丰县| 惠东县| 正宁县| 汶川县| 肥东县| 来安县| 玛纳斯县| 绥宁县| 兴隆县| 洪洞县| 石林| 浑源县| 嘉荫县|