zoukankan      html  css  js  c++  java
  • AudioRecord 录制播放PCM音频

    AudioRecord 与 MediaRecorder 区别
    AudioRecord 基于字节流录制,输出的是pcm数据,未进行压缩,直接保存的pcm文件不能被播放器识别播放。
    可以对音频文件进行实时处理,直播类中对录制的声音进行变声编辑。
    MediaRecorder 是基于AudioRecord之上,进行了封装,使用简单,由于本身对录制的音频进行压缩,编码,无法对音频进行实时处理编辑。适用于普通的音频录制。
    配合MediaPlayer 进行播放。
    public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
    int bufferSizeInBytes)
    AudioRecord 构造函数
    AudioSource  音频源, 常用MediaRecorder.AudioSource.MIC(麦克风音频源)
    SampleRateInHz  采样率,(采样率用赫兹表示。44100Hz是目前唯一的*保证适用于所有设备的费率)
    ChannelConfig  音频声道
    AudioFormat  返回音频数据格式
    BufferSizeInBytes 缓冲区大小
    录制流程:
    • 构造AudioRecord 对象
    • startRecording() 开始采集
    • 在线程中将采集数据写入pcm文件
    • stop() 停止采集
      public void record(){
          mAudioRecord.startRecording();
      new Thread(new Runnable() {
          @Override
          public void run() {
                  FileOutputStream fileOutputStream=new FileOutputStream(recordFile);
                  byte[] buffer=new byte[mBufferSizeInBytes];
                  while(isRecording){
                      int read=mAudioRecord.read(buffer,0,mBufferSizeInBytes);
                      if(AudioRecord.ERROR_INVALID_OPERATION!=read){
                          fileOutputStream.write(buffer);
                      }
                  }
                  fileOutputStream.close();
              }
          }).start();
      
      }
      public void stopRecord(){
          isRecording=false;
          if(mAudioRecord.getState()==AudioRecord.RECORDSTATE_RECORDING){
              mAudioRecord.stop();
           }
           mAudioRecord.release();
      }
      使用AudioTrack播放
      • 构造AudioTrack
      • play() 
      • 在线程中write() 写入pcm文件流
      • release()回收资源
      与MediaPlayer的区别
      MediaPlayer可以播放多种格式的声音文件,例如MP3,AAC,WAV,OGG,MIDI等。MediaPlayer会在framework层创建对应的音频解码器。而AudioTrack只能播放已经解码的PCM流,如果对比支持的文件格式的话则是AudioTrack只支持wav格式的音频文件,因为wav格式的音频文件大部分都是PCM流。AudioTrack不创建解码器,只能播放不需要解码的wav文件
      构造函数
      public AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
      int mode, int sessionId)
      mAudioTrack.play();
      new Thread(new Runnable(){
          @Override
          public void run() {
              
      try {
      FileInputStream fileInputStream=new FileInputStream(filePath);
      byte[] tempBuffer=new byte[mWriteMinBufferSize];
      while (fileInputStream.available()>0){
      int readCount= fileInputStream.read(tempBuffer);
      if (readCount== AudioTrack.ERROR_INVALID_OPERATION||readCount==AudioTrack.ERROR_BAD_VALUE){
      continue;
      }
      if (readCount!=0&&readCount!=-1){
      mAudioTrack.write(tempBuffer,0,readCount);
      }
      }
      Log.e("TAG","end");
      } catch (Exception e) {
      e.printStackTrace();
      }
      
          }
      }).start();

      实例:使用AudioRecord 采集PCM,AudioTrack 播放

      package com.rexkell.mediaapplication;
      
      import android.media.AudioAttributes;
      import android.media.AudioFormat;
      import android.media.AudioManager;
      import android.media.AudioRecord;
      import android.media.AudioTrack;
      import android.media.MediaRecorder;
      import android.os.Bundle;
      import android.support.annotation.Nullable;
      import android.support.v7.app.AppCompatActivity;
      import android.util.Log;
      import android.view.View;
      import android.widget.Button;
      
      import com.rexkell.mediaapplication.media.MediaConfig;
      
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.util.concurrent.Executors;
      
      /**
      * author: rexkell
      * date: 2019/7/22
      * explain:
      */
      public class AudioRecordActivity extends AppCompatActivity {
          boolean isRecording=false;
          //音频源 MIC指的是麦克风
          private final int mAudioSource= MediaRecorder.AudioSource.MIC;
          //(MediaRecoder 的采样率通常是8000Hz AAC的通常是44100Hz。 设置采样率为44100,目前为常用的采样率,官方文档表示这个值可以兼容所有的设置)
          private final int SampleRateInHz=44100; //采样率
          //输入声道
          private final int channelInMono= AudioFormat.CHANNEL_CONFIGURATION_MONO;
          private final int channelOutMono=AudioFormat.CHANNEL_OUT_MONO;
          //指定音频量化位数 ,在AudioFormaat类中指定了以下各种可能的常量。通常我们选择ENCODING_PCM_16BIT和ENCODING_PCM_8BIT PCM代表的是脉冲编码调制,它实际上是原始音频样本。
          //因此可以设置每个样本的分辨率为16位或者8位,16位将占用更多的空间和处理能力,表示的音频也更加接近真实
          private final int mAudioFormat=AudioFormat.ENCODING_PCM_16BIT;
          //指定缓冲区大小
          private int mBufferSizeInBytes;
          private String filePath;
      
          private int mWriteMinBufferSize;
          private AudioAttributes mAudioAttributes;
          AudioRecord mAudioRecord;
          AudioTrack mAudioTrack;
          @Override
          protected void onCreate(@Nullable Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.ac_audio_record);
              filePath=getExternalFilesDir("Music").getPath()+"/test.pcm";
              initAudioRecord();
          }
          private void initAudioRecord(){
            mBufferSizeInBytes=AudioRecord.getMinBufferSize(SampleRateInHz,channelInMono,mAudioFormat);
            mWriteMinBufferSize=AudioTrack.getMinBufferSize(SampleRateInHz,channelInMono,mAudioFormat);
            mAudioRecord=new AudioRecord(mAudioSource,SampleRateInHz,channelInMono,mAudioFormat,mBufferSizeInBytes);
      
            AudioFormat audioFormat=new AudioFormat.Builder().setSampleRate(SampleRateInHz).setEncoding(mAudioFormat).setChannelMask(channelOutMono).build();
            mAudioAttributes=new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build();
            mAudioTrack=new AudioTrack(mAudioAttributes,audioFormat,mWriteMinBufferSize, AudioTrack.MODE_STREAM, AudioManager.AUDIO_SESSION_ID_GENERATE);
            File recordFile=new File(filePath);
           if (!recordFile.exists()){
               try {
                   recordFile.createNewFile();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
      
          }
          public void record(View view){
              isRecording=!isRecording;
              String text=isRecording?"结束":"录制";
              ((Button)view).setText(text);
              if (isRecording){
                  final File recordFile=new File(filePath);
                  if (recordFile.exists()){
                      recordFile.delete();
                      try {
                          recordFile.createNewFile();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
                  mAudioRecord.startRecording();
                  Executors.newSingleThreadExecutor().execute(new Runnable() {
                      @Override
                      public void run() {
                          try {
                              FileOutputStream fileOutputStream=new FileOutputStream(recordFile);
                              byte[] buffer=new byte[mBufferSizeInBytes];
                              while (isRecording){
                                  int read=mAudioRecord.read(buffer,0,mBufferSizeInBytes);
                                  if (AudioRecord.ERROR_INVALID_OPERATION!=read){
                                      fileOutputStream.write(buffer);
                                  }
                              }
                              fileOutputStream.close();
                          } catch (Exception e) {
                              e.printStackTrace();
                          }
                      }
                  });
              }else {
                  if (mAudioRecord!=null&&isRecording){
                      if (mAudioRecord.getState()==AudioRecord.RECORDSTATE_RECORDING){
                          mAudioRecord.stop();
                      }
                      mAudioRecord.release();
                      isRecording=false;
                  }
      
              }
      
          }
          public void play(View view){
              mAudioTrack.play();
              Executors.newSingleThreadExecutor().execute(new Runnable() {
                  @Override
                  public void run() {
                      try {
                          FileInputStream fileInputStream=new FileInputStream(filePath);
                          byte[] tempBuffer=new byte[mWriteMinBufferSize];
                          while (fileInputStream.available()>0){
                             int readCount= fileInputStream.read(tempBuffer);
                             if (readCount== AudioTrack.ERROR_INVALID_OPERATION||readCount==AudioTrack.ERROR_BAD_VALUE){
                                 continue;
                             }
                             if (readCount!=0&&readCount!=-1){
                                 mAudioTrack.write(tempBuffer,0,readCount);
                             }
                          }
                          Log.e("TAG","end");
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                  }
              });
          }
      
          @Override
          protected void onDestroy() {
             if (mAudioRecord!=null){
                 mAudioRecord.release();
                 mAudioRecord=null;
             }
             if (mAudioTrack!=null){
                 mAudioTrack.release();
                 mAudioTrack=null;
             }
             super.onDestroy();
          }
      }
  • 相关阅读:
    linux和window双系统下修改系统启动项
    linux下定位文件
    gcc/g++命令
    asp.net(C#)清除全部Session与单个Session
    响应式布局简介
    JS MD5
    遍历 DataSet
    标题背景圆角 随意宽度
    position
    vertical-align:middle图片或者按钮垂直居中
  • 原文地址:https://www.cnblogs.com/changeMsBlog/p/11256453.html
Copyright © 2011-2022 走看看