文章目录
AudioTrack,MediaPlayer,SoundPool的区别
- mediaplayer适合长时间播放音乐
- soundpool适合短时间的音频片段,如游戏声音,按键声音
- audiotrack更接近底层,更灵活,播放的是pcm音频数据
AudioTrack的使用
public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)
- streamType
音频管理策略,如我们在小米手机调节音量时,会出现3种声音调节的类型,音乐,铃声,闹钟 该参数的可选值在AudioManager类中,如:
STREAM_MUSCI:音乐声 STREAM_RING:铃声 STREAM_NOTIFICATION:通知声
- sampleRateInHz
采样率,看源码知道,范围在4000~192000
public static final int SAMPLE_RATE_HZ_MIN = 4000; public static final int SAMPLE_RATE_HZ_MAX = 192000;
- 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);
- audioFormat
用来配置数据位宽,可选值在可选值在AudioFormat中以常量值定义,常用的如下
public static final int ENCODING_PCM_16BIT = 2; public static final int ENCODING_PCM_8BIT = 3;
- bufferSizeInBytes
配置的是AudioTrack内部音频缓冲区的大小,同样AudioTrack提供了获取缓冲区大小的方法
AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
- 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(); } }