1.按住录制松开录制完成
2.录制倒计时
3.Seekbar展示
4.录制视频声音大小展示
废话不多说 直接上代码 注释很详细
**
* [camera.setDisplayOrientation(90);// 设置预览视频时时竖屏]
*
* @author ly
* @version 1.0
* @date 2016年8月1日 下午4:10:37
**/
@SuppressLint("NewApi")
public class VideoActivity extends Activity implements Callback,
MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener {
private SurfaceView mSurfaceview;
private Button mBtnStartPress;// 开始停止录制按键
private MediaRecorder mRecorder;// 录制视频的类
private SurfaceHolder mSurfaceHolder;// 显示视频
private Camera camera;
private int flag = 1;
private View rcChat_popup;//显示出音量大小
private Handler mHandler = new Handler();
private long startVoiceT, endVoiceT;
private static final int POLL_INTERVAL = 300;
private Chronometer timedown;//显示倒计时
private LinearLayout voice_rcd_hint_rcding;
private long timeTotalInS = 0;
private long timeLeftInS = 0;
private ImageView volume;
private ProgressBar mProgressBar;
private int mRecordMaxTime = 10;// 一次拍摄的最长时间
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 1:// 开始录制
// timeView.setText(time + "s");
break;
case 2:// 录制结束
Toast.makeText(VideoActivity.this, "录制完成", Toast.LENGTH_SHORT).show();
break;
}
}
;
};
private CamcorderProfile mProfile;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题栏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏
getWindow().setFormat(PixelFormat.TRANSLUCENT); // 选择支持半透明模式,在有surfaceview的activity中使用。
setContentView(R.layout.video_layout);// 加载布局
mSurfaceview = (SurfaceView) findViewById(R.id.surfaceview);
mBtnStartPress = (Button) findViewById(R.id.btn_press);
rcChat_popup = this.findViewById(R.id.rcChat_popup);
timedown = (Chronometer) findViewById(R.id.timedown);
voice_rcd_hint_rcding = (LinearLayout) this.findViewById(R.id.voice_rcd_hint_rcding);
volume = (ImageView) this.findViewById(R.id.volume);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mProgressBar.setMax(mRecordMaxTime);//设置最大值
mBtnStartPress.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
// TODO Auto-generated method stub
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mBtnStartPress.setBackgroundColor(getResources().getColor(R.color.actionbar_blue));
mBtnStartPress.setText("松开 结束");
mBtnStartPress.setTextColor(getResources().getColor(R.color.voice));
int[] location = new int[2];
mBtnStartPress.getLocationInWindow(location); // 获取在当前窗口内的绝对坐标
int btn_rc_Y = location[1];
int btn_rc_X = location[0];
if (flag == 1) {
if (!Environment.getExternalStorageDirectory().exists()) {
Toast.makeText(VideoActivity.this, "No SDCard", Toast.LENGTH_LONG).show();
return false;
}
System.out.println(event.getY() + "..." + btn_rc_Y + "...." + event.getX() + "...." + btn_rc_X);
if (event.getY() < btn_rc_Y && event.getX() > btn_rc_X) {//判断手势按下的位置是否是语音录制按钮的范围内
rcChat_popup.setVisibility(View.VISIBLE);
mHandler.postDelayed(new Runnable() {
public void run() {
}
}, 300);
startVoiceT = SystemClock.currentThreadTimeMillis();
recordMedia();
down();
timedown.setVisibility(View.VISIBLE);
//设置录音时间
initTimer(mRecordMaxTime);
timedown.start();
flag = 2;
}
}
} else if (event.getAction() == MotionEvent.ACTION_UP) {
mBtnStartPress.setBackgroundColor(getResources().getColor(R.color.voice));
mBtnStartPress.setText("按住 拍摄");
mBtnStartPress.setTextColor(Color.BLACK);
timedown.stop();
if (flag == 2) {
rcChat_popup.setVisibility(View.GONE);
timedown.setVisibility(View.GONE);
up();
flag = 1;
} else {
voice_rcd_hint_rcding.setVisibility(View.GONE);
up();
endVoiceT = SystemClock.currentThreadTimeMillis();
flag = 1;
int time = (int) ((endVoiceT - startVoiceT) / 1000);
System.out.println(time);
}
}
return false;
}
});
SurfaceHolder holder = mSurfaceview.getHolder();// 取得holder
holder.addCallback(this); // holder加入回调接口
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置,要不出错.
mProfile = CamcorderProfile.get(0, 6);
}
public void recordMedia() {
mHandler.postDelayed(mPollTask, POLL_INTERVAL);
// 获取类的实例
recorder = ExtAudioRecorder.getInstanse(true); // false为未压缩的录音(WAV) true为压缩的
recorder.recordChat(Environment.getExternalStorageDirectory()
.getAbsolutePath()+ File.separator, "upload_media.wav");
//开始录音
}
private Runnable mSleepTask = new Runnable() {
public void run() {
up();
}
};
private ExtAudioRecorder recorder = null;
private Runnable mPollTask = new Runnable() {
public void run() {
double amp = recorder.getAmplitude();
// double amp = mSensor.getAmplitude();
updateDisplay(amp);
mHandler.postDelayed(mPollTask, POLL_INTERVAL);
}
};
private void updateDisplay(double signalEMA) {
switch ((int) signalEMA) {
case 0:
case 1:
volume.setImageResource(R.drawable.amp1);
break;
case 2:
case 3:
volume.setImageResource(R.drawable.amp2);
break;
case 4:
case 5:
volume.setImageResource(R.drawable.amp3);
break;
case 6:
case 7:
volume.setImageResource(R.drawable.amp4);
break;
case 8:
case 9:
volume.setImageResource(R.drawable.amp5);
break;
case 10:
case 11:
volume.setImageResource(R.drawable.amp6);
break;
default:
volume.setImageResource(R.drawable.amp7);
break;
}
}
/**
* 初始化计时器,计时器是通过widget.Chronometer来实现的
*
* @param total 一共多少秒
*/
private void initTimer(int total) {
this.timeTotalInS = total;
this.timeLeftInS = total;
timedown.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
@Override
public void onChronometerTick(Chronometer chronometer) {
if (timeLeftInS <= 0) {
Toast.makeText(VideoActivity.this, "录像时间到", Toast.LENGTH_SHORT).show();
timedown.stop();
//录像停止
rcChat_popup.setVisibility(View.GONE);
timedown.setVisibility(View.GONE);
return;
}
timeLeftInS--;
refreshTimeLeft();
// 设置进度条
mProgressBar.setProgress((int) (mRecordMaxTime - timeLeftInS));
}
});
}
private void refreshTimeLeft() {
this.timedown.setText("录音时间剩余:" + timeLeftInS);
//TODO 格式化字符串
}
public void down(){
// 开始
if (mRecorder == null) {
mRecorder = new MediaRecorder(); // 创建mediarecorder的对象
}
try {
camera.unlock();
mRecorder.setCamera(camera);
mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);// 这两项需要放在setOutputFormat之前
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);// 设置录制视频源为Camera(相机)
//mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);//
// 设置录制完成后视频的封装格式THREE_GPP为3gp.MPEG_4为mp4
//1.8 以上
mRecorder.setProfile(mProfile);//这句是让视频文件在PC端也能视频竖屏播放的保证,跟下面注释了的不能联用
// 这两项需要放在setOutputFormat之后
// mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
// mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);// 设置录制的视频编码h263
//
// mRecorder.setVideoSize(800, 480);// 设置视频录制的分辨率。必须放在设置编码和格式的后面,否则报错
// mRecorder.setVideoFrameRate(30);// 设置录制的视频帧率。必须放在设置编码和格式的后面,否则报错
mRecorder.setMaxDuration(10000);// 设置最大的录制时间
// mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
// 设置路径
String path = getSDPath();
if (path != null) {
File dir = new File(path + "/TestCameraFile");
if (!dir.exists()) {
dir.mkdir();
}
path = dir + "/" + getDate() + ".mp4";
mRecorder.setOutputFile(path);
mRecorder.setOrientationHint(90);
mRecorder.prepare();// 准备录制
mRecorder.start(); // 开始录制
mRecorder.setOnErrorListener(this);
mRecorder.setOnInfoListener(this);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void up(){
// 停止
mHandler.removeCallbacks(mSleepTask);
mHandler.removeCallbacks(mPollTask);
try {
mRecorder.stop(); //停止
mRecorder.reset(); // 重置
mProgressBar.setProgress(0);
handler.sendEmptyMessageDelayed(2, 1000);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 使用时间对录像起名
*
* @return
*/
public static String getDate() {
Calendar ca = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
String date = sdf.format(ca.getTimeInMillis());
return date;
}
/**
* 获取SD path
*
* @return
*/
public String getSDPath() {
File sdDir = null;
boolean sdCardExist = Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED); // 判断sd卡是否存在
if (sdCardExist) {
sdDir = Environment.getExternalStorageDirectory();// 获取跟目录
// Toast.makeText(this,sdDir.toString(),Toast.LENGTH_LONG).show();
return sdDir.toString();
} else {
Toast.makeText(this, "没有SD卡", Toast.LENGTH_LONG).show();
}
return null;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
camera = Camera.open(); // 获取Camera实例
try {
camera.setPreviewDisplay(holder);
mSurfaceview.setLayoutParams(new LinearLayout.LayoutParams(width,
height));
} catch (Exception e) {
// 如果出现异常,则释放Camera对象
camera.release();
}
camera.setDisplayOrientation(90);// 设置预览视频时时竖屏
// 启动预览功能
camera.startPreview();
// 将holder,这个holder为开始在onCreate里面取得的holder,将它赋给mSurfaceHolder
mSurfaceHolder = holder;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// 将holder,这个holder为开始在onCreate里面取得的holder,将它赋给mSurfaceHolder
mSurfaceHolder = holder;
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
// surfaceDestroyed的时候同时对象设置为null
mSurfaceview = null;
mSurfaceHolder = null;
if (mRecorder != null) {
mRecorder.release(); // Now the object cannot be reused
mRecorder = null;
}
if (camera != null) {
camera.release();
camera = null;
}
}
@Override
public void onInfo(MediaRecorder arg0, int what, int arg2) {
// TODO Auto-generated method stub
if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
} else if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
}
}
@Override
public void onError(MediaRecorder arg0, int what, int extra) {
// TODO Auto-generated method stub
if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) {
}
}
}
布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<SurfaceView
android:id="@+id/surfaceview"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="15" />
<ProgressBar
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.3"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:progress="0"
android:id="@+id/progressBar"
android:layout_gravity="center_horizontal" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/voice"
android:orientation="horizontal">
<TextView
android:id="@+id/textView1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_weight="2"
android:gravity="center"
android:text="0S"
android:visibility="gone" />
<Chronometer
android:id="@+id/timedown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="30:00"
android:textColor="@color/actionbar_blue"
android:textSize="13sp"
android:visibility="gone" />
<Button
android:id="@+id/stops"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_weight="9"
android:background="@color/voice"
android:text="点击 录制"
android:textSize="16dp"
android:visibility="gone" />
<Button
android:id="@+id/btn_press"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_weight="9"
android:background="@color/voice"
android:text="按住 录制"
android:textSize="16dp" />
<LinearLayout
android:id="@+id/rcChat_popup"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="3"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="vertical">
<include
layout="@layout/rcd_hint_window"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
音频的一个类,为了展示出录制视频声音大小
public class ExtAudioRecorder {
private final static int[] sampleRates = {44100, 22050, 11025, 8000, 5512};
private static ExtAudioRecorder result = null;
public static ExtAudioRecorder getInstanse(Boolean recordingCompressed) {
if (recordingCompressed) {
result = new ExtAudioRecorder(false, AudioSource.MIC,
sampleRates[3], AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_8BIT);
} else {
int i = 2;
// do {
result = new ExtAudioRecorder(true, AudioSource.MIC,
sampleRates[i], AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
// } while ((++i < sampleRates.length)
// & !(result.getState() == ExtAudioRecorder.State.INITIALIZING));
}
return result;
}
/**
* INITIALIZING : recorder is initializing; READY : recorder has been
* initialized, recorder not yet started RECORDING : recording ERROR :
* reconstruction needed STOPPED: reset needed
*/
public enum State {
INITIALIZING, READY, RECORDING, ERROR, STOPPED
}
;
public static final boolean RECORDING_UNCOMPRESSED = true;
public static final boolean RECORDING_COMPRESSED = false;
// The interval in which the recorded samples are output to the file
// Used only in uncompressed mode
private static final int TIMER_INTERVAL = 120;
// Toggles uncompressed recording on/off; RECORDING_UNCOMPRESSED /
// RECORDING_COMPRESSED
private boolean rUncompressed;
// Recorder used for uncompressed recording
private AudioRecord audioRecorder = null;
// Recorder used for compressed recording
private MediaRecorder mediaRecorder = null;
// Stores current amplitude (only in uncompressed mode)
private int cAmplitude = 0;
// Output file path
private String filePath = null;
// Recorder state; see State
private State state;
// File writer (only in uncompressed mode)
private RandomAccessFile randomAccessWriter;
// Number of channels, sample rate, sample size(size in bits), buffer size,
// audio source, sample size(see AudioFormat)
private short nChannels;
private int sRate;
private short bSamples;
private int bufferSize;
private int aSource;
private int aFormat;
// Number of frames written to file on each output(only in uncompressed
// mode)
private int framePeriod;
// Buffer for output(only in uncompressed mode)
private byte[] buffer;
// Number of bytes written to file after header(only in uncompressed mode)
// after stop() is called, this size is written to the header/data chunk in
// the wave file
private int payloadSize;
/**
* Returns the state of the recorder in a RehearsalAudioRecord.State typed
* object. Useful, as no exceptions are thrown.
*
* @return recorder state
*/
public State getState() {
return state;
}
/*
*
* Method used for recording.
*/
private AudioRecord.OnRecordPositionUpdateListener updateListener = new AudioRecord.OnRecordPositionUpdateListener() {
public void onPeriodicNotification(AudioRecord recorder) {
audioRecorder.read(buffer, 0, buffer.length); // Fill buffer
try {
randomAccessWriter.write(buffer); // Write buffer to file
payloadSize += buffer.length;
if (bSamples == 16) {
for (int i = 0; i < buffer.length / 2; i++) { // 16bit
// sample
// size
short curSample = getShort(buffer[i * 2],
buffer[i * 2 + 1]);
if (curSample > cAmplitude) { // Check amplitude
cAmplitude = curSample;
}
}
} else { // 8bit sample size
for (int i = 0; i < buffer.length; i++) {
if (buffer[i] > cAmplitude) { // Check amplitude
cAmplitude = buffer[i];
}
}
}
} catch (IOException e) {
Log.e(ExtAudioRecorder.class.getName(),
"Error occured in updateListener, recording is aborted");
// stop();
}
}
public void onMarkerReached(AudioRecord recorder) {
// NOT USED
}
};
/**
* Default constructor
* <p/>
* Instantiates a new recorder, in case of compressed recording the
* parameters can be left as 0. In case of errors, no exception is thrown,
* but the state is set to ERROR
*/
public ExtAudioRecorder(boolean uncompressed, int audioSource,
int sampleRate, int channelConfig, int audioFormat) {
try {
rUncompressed = uncompressed;
if (rUncompressed) { // RECORDING_UNCOMPRESSED
if (audioFormat == AudioFormat.ENCODING_PCM_16BIT) {
bSamples = 16;
} else {
bSamples = 8;
}
if (channelConfig == AudioFormat.CHANNEL_CONFIGURATION_MONO) {
nChannels = 1;
} else {
nChannels = 2;
}
aSource = audioSource;
sRate = sampleRate;
aFormat = audioFormat;
framePeriod = sampleRate * TIMER_INTERVAL / 1000;
bufferSize = framePeriod * 2 * bSamples * nChannels / 8;
if (bufferSize < AudioRecord.getMinBufferSize(sampleRate,
channelConfig, audioFormat)) { // Check to make sure
// buffer size is not
// smaller than the
// smallest allowed one
bufferSize = AudioRecord.getMinBufferSize(sampleRate,
channelConfig, audioFormat);
// Set frame period and timer interval accordingly
framePeriod = bufferSize / (2 * bSamples * nChannels / 8);
Log.w(ExtAudioRecorder.class.getName(),
"Increasing buffer size to "
+ Integer.toString(bufferSize));
}
audioRecorder = new AudioRecord(audioSource, sampleRate,
channelConfig, audioFormat, bufferSize);
if (audioRecorder.getState() != AudioRecord.STATE_INITIALIZED)
throw new Exception("AudioRecord initialization failed");
audioRecorder.setRecordPositionUpdateListener(updateListener);
audioRecorder.setPositionNotificationPeriod(framePeriod);
} else { // RECORDING_COMPRESSED
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder
.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder
.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
}
cAmplitude = 0;
filePath = null;
state = State.INITIALIZING;
} catch (Exception e) {
if (e.getMessage() != null) {
Log.e(ExtAudioRecorder.class.getName(), e.getMessage());
} else {
Log.e(ExtAudioRecorder.class.getName(),
"Unknown error occured while initializing recording");
}
state = State.ERROR;
}
}
/**
* Sets output file path, call directly after construction/reset.
*
*/
public void setOutputFile(String argPath) {
try {
if (state == State.INITIALIZING) {
filePath = argPath;
if (!rUncompressed) {
mediaRecorder.setOutputFile(filePath);
}
}
} catch (Exception e) {
if (e.getMessage() != null) {
Log.e(ExtAudioRecorder.class.getName(), e.getMessage());
} else {
Log.e(ExtAudioRecorder.class.getName(),
"Unknown error occured while setting output path");
}
state = State.ERROR;
}
}
/**
* Returns the largest amplitude sampled since the last call to this method.
*
* @return returns the largest amplitude since the last call, or 0 when not
* in recording state.
*/
public int getMaxAmplitude() {
if (state == State.RECORDING) {
if (rUncompressed) {
int result = cAmplitude;
cAmplitude = 0;
return result;
} else {
try {
return mediaRecorder.getMaxAmplitude();
} catch (IllegalStateException e) {
return 0;
}
}
} else {
return 0;
}
}
/**
* Prepares the recorder for recording, in case the recorder is not in the
* INITIALIZING state and the file path was not set the recorder is set to
* the ERROR state, which makes a reconstruction necessary. In case
* uncompressed recording is toggled, the header of the wave file is
* written. In case of an exception, the state is changed to ERROR
*/
public void prepare() {
try {
if (state == State.INITIALIZING) {
if (rUncompressed) {
if ((audioRecorder.getState() == AudioRecord.STATE_INITIALIZED)
& (filePath != null)) {
// write file header
randomAccessWriter = new RandomAccessFile(filePath,
"rw");
randomAccessWriter.setLength(0); // Set file length to
// 0, to prevent
// unexpected
// behavior in case
// the file already
// existed
randomAccessWriter.writeBytes("RIFF");
randomAccessWriter.writeInt(0); // Final file size not
// known yet, write 0
randomAccessWriter.writeBytes("WAVE");
randomAccessWriter.writeBytes("fmt ");
randomAccessWriter.writeInt(Integer.reverseBytes(16)); // Sub-chunk
// size,
// 16
// for
// PCM
randomAccessWriter.writeShort(Short
.reverseBytes((short) 1)); // AudioFormat, 1 for
// PCM
randomAccessWriter.writeShort(Short
.reverseBytes(nChannels));// Number of channels,
// 1 for mono, 2 for
// stereo
randomAccessWriter
.writeInt(Integer.reverseBytes(sRate)); // Sample
// rate
randomAccessWriter.writeInt(Integer.reverseBytes(sRate
* bSamples * nChannels / 8)); // Byte rate,
// SampleRate*NumberOfChannels*BitsPerSample/8
randomAccessWriter
.writeShort(Short
.reverseBytes((short) (nChannels
* bSamples / 8))); // Block
// align,
// NumberOfChannels*BitsPerSample/8
randomAccessWriter.writeShort(Short
.reverseBytes(bSamples)); // Bits per sample
randomAccessWriter.writeBytes("data");
randomAccessWriter.writeInt(0); // Data chunk size not
// known yet, write 0
buffer = new byte[framePeriod * bSamples / 8
* nChannels];
state = State.READY;
} else {
Log.e(ExtAudioRecorder.class.getName(),
"prepare() method called on uninitialized recorder");
state = State.ERROR;
}
} else {
mediaRecorder.prepare();
state = State.READY;
}
} else {
Log.e(ExtAudioRecorder.class.getName(),
"prepare() method called on illegal state");
release();
state = State.ERROR;
}
} catch (Exception e) {
if (e.getMessage() != null) {
Log.e(ExtAudioRecorder.class.getName(), e.getMessage());
} else {
Log.e(ExtAudioRecorder.class.getName(),
"Unknown error occured in prepare()");
}
state = State.ERROR;
}
}
/**
* Releases the resources associated with this class, and removes the
* unnecessary files, when necessary
*/
public void release() {
if (state == State.RECORDING) {
stop();
} else {
if ((state == State.READY) & (rUncompressed)) {
try {
randomAccessWriter.close(); // Remove prepared file
} catch (IOException e) {
Log.e(ExtAudioRecorder.class.getName(),
"I/O exception occured while closing output file");
}
(new File(filePath)).delete();
}
}
if (rUncompressed) {
if (audioRecorder != null) {
audioRecorder.release();
}
} else {
if (mediaRecorder != null) {
mediaRecorder.release();
}
}
}
/**
* Resets the recorder to the INITIALIZING state, as if it was just created.
* In case the class was in RECORDING state, the recording is stopped. In
* case of exceptions the class is set to the ERROR state.
*/
public void reset() {
try {
if (state != State.ERROR) {
release();
filePath = null; // Reset file path
cAmplitude = 0; // Reset amplitude
if (rUncompressed) {
audioRecorder = new AudioRecord(aSource, sRate,
nChannels + 1, aFormat, bufferSize);
} else {
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder
.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder
.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
}
state = State.INITIALIZING;
}
} catch (Exception e) {
Log.e(ExtAudioRecorder.class.getName(), e.getMessage());
state = State.ERROR;
}
}
/**
* Starts the recording, and sets the state to RECORDING. Call after
* prepare().
*/
public void start() {
if (state == State.READY) {
if (rUncompressed) {
payloadSize = 0;
audioRecorder.startRecording();
audioRecorder.read(buffer, 0, buffer.length);
} else {
mediaRecorder.start();
}
state = State.RECORDING;
} else {
Log.e(ExtAudioRecorder.class.getName(),
"start() called on illegal state");
state = State.ERROR;
}
}
/**
* Stops the recording, and sets the state to STOPPED. In case of further
* usage, a reset is needed. Also finalizes the wave file in case of
* uncompressed recording.
*/
public void stop() {
if (state == State.RECORDING) {
if (rUncompressed) {
audioRecorder.stop();
try {
randomAccessWriter.seek(4); // Write size to RIFF header
randomAccessWriter.writeInt(Integer
.reverseBytes(32 + payloadSize));
randomAccessWriter.seek(40); // Write size to Subchunk2Size
// field
randomAccessWriter.writeInt(Integer
.reverseBytes(payloadSize));
randomAccessWriter.close();
} catch (IOException e) {
Log.e(ExtAudioRecorder.class.getName(),
"I/O exception occured while closing output file");
state = State.ERROR;
}
} else {
try{
mediaRecorder.stop();
}catch(Exception e){
}finally {
state = State.STOPPED;
}
}
state = State.STOPPED;
} else {
Log.e(ExtAudioRecorder.class.getName(),
"stop() called on illegal state");
state = State.ERROR;
}
}
/*
*
* Converts a byte[2] to a short, in LITTLE_ENDIAN format
*/
private short getShort(byte argB1, byte argB2) {
return (short) (argB1 | (argB2 << 8));
}
/**
* 录制wav格式文件
*
*/
public File recordChat(String savePath, String fileName) {
File dir = new File(savePath);
// 如果该目录没有存在,则新建目录
if (dir.list() == null) {
dir.mkdirs();
}
// 获取录音文件
File file = new File(savePath + fileName);
// 设置输出文件
result.setOutputFile(savePath + fileName);
result.prepare();
// 开始录音
result.start();
return file;
}
/**
* 停止录音
*
* mediaRecorder 待停止的录音机
* @return 返回
*/
public void stopRecord() {
if (result != null) {
result.stop();
result.release();
result = null;
}
}
public double getAmplitude() {
if (result != null)
return (result.getMaxAmplitude() / 2700.0);
else
return 0;
}
}
权限 习惯弄很多 省的麻烦
<!-- 授予录音权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_READ" />
<uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />