文章

[摘]音视频学习系列第(二)篇---音频采集和播放之AudioTrack

文章目录

AudioTrackMediaPlayerSoundPool的区别

  1. mediaplayer适合长时间播放音乐
  2. soundpool适合短时间的音频片段,如游戏声音,按键声音
  3. audiotrack更接近底层,更灵活,播放的是pcm音频数据

AudioTrack的使用

public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
        int bufferSizeInBytes, int mode)
  1. streamType

音频管理策略,如我们在小米手机调节音量时,会出现3种声音调节的类型,音乐,铃声,闹钟 该参数的可选值在AudioManager类中,如:

STREAM_MUSCI:音乐声
STREAM_RING:铃声
STREAM_NOTIFICATION:通知声
  1. sampleRateInHz

采样率,看源码知道,范围在4000~192000

public static final int SAMPLE_RATE_HZ_MIN = 4000;
public static final int SAMPLE_RATE_HZ_MAX = 192000;
  1. channelConfig

通道数的配置,可选值在AudioFormat中以常量值定义,常用的如下

public static final int CHANNEL_IN_LEFT = 0x4;
public static final int CHANNEL_IN_RIGHT = 0x8;
public static final int CHANNEL_IN_FRONT = 0x10;
//单通道
public static final int CHANNEL_IN_MONO = CHANNEL_IN_FRONT;   
//双通道
public static final int CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT);
  1. audioFormat

用来配置数据位宽,可选值在可选值在AudioFormat中以常量值定义,常用的如下

public static final int ENCODING_PCM_16BIT = 2;
public static final int ENCODING_PCM_8BIT = 3;
  1. bufferSizeInBytes

配置的是AudioTrack内部音频缓冲区的大小,同样AudioTrack提供了获取缓冲区大小的方法

AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
  1. mode

AudioTrack有两种播放方式 MODE_STATIC和MODE_STREAM前者是一次性将所有数据写入播放缓冲区,然后播放 后者是一边写入一边播放

音频播放方法

mAudioTrack.play();  //开始播放
mAudioTrack.stop(); //停止播放
mAudioTrack.write(audioData,offsetInBytes,sizeInBytes);//将pcm数据写入缓冲区

示例代码

public class AudioPlayer {

private static final String TAG = "AudioPlayer";

private final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_MUSIC;  //流音乐
private final int DEFAULT_RATE = 44100;    //采样率
private final int DEFAULT_CHANNEL = AudioFormat.CHANNEL_IN_STEREO;   //双通道(左右声道)
private final int DEFAULT_FORMAT = AudioFormat.ENCODING_PCM_16BIT;   //数据位宽16位
private static final int DEFAULT_PLAY_MODE = AudioTrack.MODE_STREAM;


private AudioTrack mAudioTrack;
private int mMinBufferSize;


private boolean isPlaying=false;



public void startPlay(){
    startPlay(DEFAULT_STREAM_TYPE,DEFAULT_RATE,DEFAULT_CHANNEL,DEFAULT_FORMAT);

}

public void startPlay(int streamType, int sampleRateInHz, int channelConfig, int audioFormat){
    if(isPlaying){
        Log.d(TAG,"AudioPlayer has played");
        return;
    }

    mMinBufferSize = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
    if (mMinBufferSize == AudioRecord.ERROR_BAD_VALUE) {
        Log.d(TAG, "Invalid parameter");
        return;
    }


    mAudioTrack=new AudioTrack(streamType,sampleRateInHz,channelConfig,audioFormat,
            mMinBufferSize,DEFAULT_PLAY_MODE);
    if(mAudioTrack.getState()==AudioTrack.STATE_UNINITIALIZED){
        Log.d(TAG, "AudioTrack initialize fail");
        return;
    }

    isPlaying=true;
}

public void stopPlay(){
    if(!isPlaying){
        Log.d(TAG, "AudioTrack is not playing");
        return;
    }

    if(mAudioTrack.getPlayState()==AudioTrack.PLAYSTATE_PLAYING){
        mAudioTrack.stop();
    }

    mAudioTrack.release();
    isPlaying=false;
}


private void play(byte[] audioData,int offsetInBytes, int sizeInBytes){
    if(!isPlaying){
        Log.d(TAG, "AudioTrack not start");
        return;
    }

    if(sizeInBytes<mMinBufferSize){
        Log.d(TAG, "audio data not enough");
        //return;
    }

    if(mAudioTrack.write(audioData,offsetInBytes,sizeInBytes)!=mMinBufferSize){
        Log.d(TAG, "AudioTrack can not write all the data");
    }

    mAudioTrack.play();
    Log.d(TAG, "played  "+sizeInBytes+"  bytes");
  }
}

测试

//原始音频的录入和播放
public class AudioPCMActivity extends DemoActivity {

private Button btn_audio_record;
private Button btn_audio_record_play;


private AudioCapture audioCapture;
private AudioPlayer audioPlayer;

private PcmFileWriter pcmFileWriter;
private PcmFileReader pcmFileReader;
private boolean isReading;

private String path="";


@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    setContentView(R.layout.activity_media_audio);
    super.onCreate(savedInstanceState);
}

@Override
public void initHead() {

}

@Override
public void initView() {
    btn_audio_record=findViewById(R.id.btn_audio_record);
    btn_audio_record_play=findViewById(R.id.btn_audio_record_play);
}

@Override
public void initData() {
    path=FileUtil.getAudioDir(this)+"/audioTest.pcm";
    audioCapture=new AudioCapture();
    audioPlayer=new AudioPlayer();
    pcmFileReader=new PcmFileReader();
    pcmFileWriter=new PcmFileWriter();

    String des = "录音权限被禁止,我们需要打开录音权限";
    String[] permissions = new String[]{Manifest.permission.RECORD_AUDIO};
    baseAt.requestPermissions(des, permissions, 100, new PermissionsResultListener() {
        @Override
        public void onPermissionGranted() {

        }
        @Override
        public void onPermissionDenied() {
            finish();

        }
    });

}

@Override
public void initEvent() {
    btn_audio_record.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if(event.getAction()==MotionEvent.ACTION_DOWN){
                Log.d("TAG","按住");
                start();
            }else if(event.getAction()==MotionEvent.ACTION_UP){
                Log.d("TAG","松开");
                stop();
            }
            return false;
        }
    });

    btn_audio_record_play.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            play();

        }
    });

}

//播放录音
private void play(){
    isReading=true;
    pcmFileReader.openFile(path);
    audioPlayer.startPlay();
    new AudioTrackThread().start();
}

private class AudioTrackThread extends Thread{
    @Override
    public void run() {
        byte[] buffer = new byte[1024];
        while (isReading && pcmFileReader.read(buffer,0,buffer.length)>0){
            audioPlayer.play(buffer,0,buffer.length);
        }
        audioPlayer.stopPlay();
        pcmFileReader.closeFile();
    }
}


//开始录音
private void start(){
    pcmFileWriter.openFile(path);
    btn_audio_record.setText("松开 结束");
    audioCapture.startRecord();
    audioCapture.setOnAudioFrameCaptureListener(new AudioCapture.onAudioFrameCaptureListener() {
        @Override
        public void onAudioFrameCapture(byte[] audioData) {
            pcmFileWriter.write(audioData,0,audioData.length);

        }
    });
}

//结束录音
private void stop(){
    btn_audio_record.setText("按住 录音");
    audioCapture.stopRecord();
    pcmFileWriter.closeFile();
  }
}

摘抄

1.《音视频学习系列第(二)篇---音频采集和播放

发表评论