MediaRecorder/MediaPlayer
在Android手机上面,音频的处理比视频还要复杂,这真是出人意料。在前面的博文《 Android开发笔记(五十七)录像录音与播放》中,介绍了视频/音频的录制与播放,其中录像用的是MediaRecorder类,播放用的是MediaPlayer类。虽然Android还提供了专门的视频视图VideoView,但是该控件并非新的东西,而是继承了MediaRecorder和MediaPlayer,所以严格来说,Android上面只有一种视频的录制和播放方式。可是音频就大不一样了,Android提供了两种录音方式,以及至少三种常用的播音方式。两种录音方式分别是MediaRecorder类和AudioRecord类,而播音方式包括MediaPlayer类、AudioTrack类和SoundPool类,它们的使用场合各有千秋,且待笔者下面细细道来。首先是MediaRecorder与MediaPlayer,这对组合即可用于录像,也可单独录制音频。它们处理的音频文件是压缩过的编码文件,通常用于录制和播放音乐,是最经常用到的。MediaRecorder与MediaPlayer在处理音频和视频时,整体流程是一样的,只有在部分方法的调用上有所差异,下面分别把录音/播音有关的方法列出来。
MediaRecorder的录音相关方法:
reset : 重置录制资源
prepare : 准备录制
start : 开始录制
stop : 结束录制
release : 释放录制资源
setOnErrorListener : 设置错误监听器。可监听服务器异常以及未知错误的事件。
setOnInfoListener : 设置信息监听器。可监听录制结束事件,包括达到录制时长或者达到录制大小。
setAudioSource : 设置音频来源。一般使用麦克风AudioSource.MIC。
setOutputFormat : 设置媒体输出格式。OutputFormat.AMR_NB表示窄带格式,OutputFormat.AMR_WB表示宽带格式,AAC_ADTS表示高级的音频传输流格式。该方法要在setVideoEncoder之前调用,不然调用setAudioEncoder时会报错“java.lang.IllegalStateException”。
setAudioEncoder : 设置音频编码器。AudioEncoder.AMR_NB表示窄带编码,AudioEncoder.AMR_WB表示宽带编码,AudioEncoder.AAC表示低复杂度的高级编码,AudioEncoder.HE_AAC表示高效率的高级编码,AudioEncoder.AAC_ELD表示增强型低延迟的高级编码。
注意:setAudioEncoder应在setOutputFormat之后执行,否则会出现“setAudioEncoder called in an invalid state(2)”的异常。
setAudioSamplingRate : 设置音频的采样率,单位赫兹(Hz)。该方法为可选,AMRNB默认8khz,AMRWB默认16khz。
setAudioChannels : 设置音频的声道数。1表示单声道,2表示双声道。该方法为可选
setAudioEncodingBitRate : 设置音频每秒录制的字节数。越大则音频越清晰。该方法为可选
setMaxDuration : 设置录制时长。单位毫秒。
setMaxFileSize : 设置录制的媒体大小。单位字节。
setOutputFile : 设置输出文件的路径。
MediaPlayer的播音相关方法:
reset : 重置播放器
prepare : 准备播放
start : 开始播放
pause : 暂停播放
stop : 停止播放
setOnPreparedListener : 设置准备播放监听器。
setOnCompletionListener : 设置结束播放监听器。
setOnSeekCompleteListener : 设置播放拖动监听器。
create : 创建指定Uri的播放器。
setDataSource : 设置播放数据来源。create与setDataSource只需设置其一。
setVolume : 设置音量。第一个参数是左声道,第二个参数是右声道,取值在0-1之间。
setAudioStreamType : 设置音频流的类型。AudioManager.STREAM_MUSIC表示音乐,AudioManager.STREAM_RING表示铃声,AudioManager.STREAM_ALARM表示闹钟,AudioManager.STREAM_NOTIFICATION表示通知。
setLooping : 设置是否循环播放。
isPlaying : 判断是否正在播放。
seekTo : 拖动播放进度到指定位置。
getCurrentPosition : 获取当前播放进度所在的位置。
getDuration : 获取播放时长。
下面是MediaRecorder与MediaPlayer组合处理音频的示例代码:
import java.io.File;
import com.example.exmaudio.util.Utils;
import android.app.Activity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaRecorder.AudioEncoder;
import android.media.MediaRecorder.AudioSource;
import android.media.MediaRecorder.OnErrorListener;
import android.media.MediaRecorder.OnInfoListener;
import android.media.MediaRecorder;
import android.media.MediaRecorder.OutputFormat;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.View.OnClickListener;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView;
public class MediaRecordActivity extends Activity
implements OnClickListener, OnErrorListener, OnInfoListener {
private static final String TAG = "MediaRecordActivity";
private TextView tv_record;
private Button btn_start;
private Button btn_stop;
private MediaRecorder mMediaRecorder;
private TextView tv_play;
private Button btn_play;
private Button btn_pause;
private MediaPlayer mMediaPlayer;
private int mPosition;
private boolean bFirstPlay = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_media_record);
tv_record = (TextView) findViewById(R.id.tv_record);
btn_start = (Button) findViewById(R.id.btn_start);
btn_stop = (Button) findViewById(R.id.btn_stop);
tv_play = (TextView) this.findViewById(R.id.tv_play);
btn_play = (Button) findViewById(R.id.btn_play);
btn_pause = (Button) findViewById(R.id.btn_pause);
btn_start.setOnClickListener(this);
btn_stop.setOnClickListener(this);
btn_play.setOnClickListener(this);
btn_pause.setOnClickListener(this);
btn_start.setEnabled(true);
btn_stop.setEnabled(false);
btn_play.setEnabled(false);
btn_pause.setEnabled(false);
initPlay();
}
private void initPlay() {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
btn_play.setEnabled(true);
btn_pause.setEnabled(false);
bFirstPlay = true;
mHandler.removeCallbacks(mPlayRun);
mPlayTime = 0;
}
});
}
private void preplay() {
try {
mMediaPlayer.reset();
//mMediaPlayer.setVolume(0.5f, 0.5f); //设置音量,可选
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
String path = mRecordFile.getAbsolutePath();
mMediaPlayer.setDataSource(path);
Log.d(TAG, "audio path = "+path);
mMediaPlayer.prepare();
} catch (Exception e) {
Log.d(TAG, "mMediaPlayer.prepare error: "+e.getMessage());
}
mPlayTime = 0;
}
private void startPlay() {
try {
if (bFirstPlay == true) {
preplay();
bFirstPlay = false;
}
mMediaPlayer.start();
} catch (Exception e) {
Log.d(TAG, "mMediaPlayer.start error: " + e.getMessage());
}
btn_play.setEnabled(false);
btn_pause.setEnabled(true);
mHandler.post(mPlayRun);
}
@Override
protected void onPause() {
// 先判断是否正在播放
if (mMediaPlayer.isPlaying()) {
// 如果正在播放我们就先保存这个播放位置
mPosition = mMediaPlayer.getCurrentPosition();
mMediaPlayer.stop();
mHandler.removeCallbacks(mPlayRun);
}
super.onPause();
}
@Override
protected void onResume() {
if (mMediaPlayer!=null && mPosition>0) {
mMediaPlayer.seekTo(mPosition);
mMediaPlayer.start();
mHandler.post(mPlayRun);
}
super.onResume();
}
private void startRecord() {
createRecordDir();
mMediaRecorder = new MediaRecorder();
mMediaRecorder.reset();
mMediaRecorder.setOnErrorListener(this);
mMediaRecorder.setOnInfoListener(this);
mMediaRecorder.setAudioSource(AudioSource.MIC); //音频源
mMediaRecorder.setOutputFormat(OutputFormat.AMR_NB);
mMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB); //音频格式
//mMediaRecorder.setAudioSamplingRate(8); //音频的采样率。可选
//mMediaRecorder.setAudioChannels(2); //音频的声道数。可选
//mMediaRecorder.setAudioEncodingBitRate(1024); //音频每秒录制的字节数。可选
mMediaRecorder.setMaxDuration(10 * 1000); //设置录制时长
//mMediaRecorder.setMaxFileSize(1024*1024*10); //setMaxFileSize与setMaxDuration设置其一即可
mMediaRecorder.setOutputFile(mRecordFile.getAbsolutePath());
try {
mMediaRecorder.prepare();
mMediaRecorder.start();
} catch (Exception e) {
Log.d(TAG, "mMediaRecorder.start error: " + e.getMessage());
}
btn_start.setEnabled(false);
btn_stop.setEnabled(true);
mRecordTime = 0;
mHandler.post(mRecordRun);
}
private File mRecordFile = null;
private void createRecordDir() {
File sampleDir = new File(Environment.getExternalStorageDirectory()
+ File.separator + "Download" + File.separator);
if (!sampleDir.exists()) {
sampleDir.mkdirs();
}
File recordDir = sampleDir;
try {
mRecordF