E/AudioRecord(5152): Could not get audio input for record source 1
E/AudioRecord-JNI(5152): Error creating AudioRecord instance: initialization check failed.
09-22 16:37:26.277: E/com.harlan.wavdemo.ExtAudioRecorder(2232): start() called on illegal state
09-22 16:37:31.157: E/com.harlan.wavdemo.ExtAudioRecorder(2232): prepare() method called on illegal state
09-22 16:37:31.157: E/com.harlan.wavdemo.ExtAudioRecorder(2232): start() called on illegal state
E/AudioRecord-Java(5152): [ android.media.AudioRecord ] Error code -20 when initializing native AudioRecord object.
09-22 16:37:26.277: E/com.harlan.wavdemo.ExtAudioRecorder(2232): prepare() method called on illegal state
开发项目工程中我使用的是ExtAudioRecorder工具类来录制wav文件。
这个类在索尼l36h就正常使用,但放在lt26i上面,就会出现以上问题。
百思不得其解。
百度之,说是重启之后就好了,链接如下:
http://stackoverflow.com/questions/4342482/cannot-access-audiorecorder
可是重启之后,使用一次,还是会出现以上问题。
这可不是个好方法。
遂研究之。
吭哧吭哧研究过程%……%%¥%¥…………TU&^略过。。。。。
研究之后发现,这个ExtAudioRecorder工具类还是有缺陷的,改之。
简而言之,就是把原类中没有顾及到的情况考虑到了。
最终结果类如下:
<span style="font-family:Microsoft YaHei;font-size:18px;">package com.harlan.util;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.media.MediaRecorder.AudioSource;
import android.os.Environment;
import com.harlan.base.C;
public class WavRecorder {
private static final String TAG = WavRecorder.class.getSimpleName();
private final static int[] sampleRates = { 44100, 22050, 11025, 8000 };
private static WavRecorder result ;
public static WavRecorder getInstanse(Boolean recordingCompressed) {
if(result!=null){
return result;
}
if (recordingCompressed) {
result = new WavRecorder(false, AudioSource.MIC, sampleRates[3],
AudioFormat.CHANNEL_IN_STEREO,
AudioFormat.ENCODING_PCM_16BIT);
} else {
int i = 3;
do {
result = new WavRecorder(true, AudioSource.MIC, sampleRates[i],
AudioFormat.CHANNEL_IN_STEREO,
AudioFormat.ENCODING_PCM_16BIT);
} while ((++i < sampleRates.length)
& !(result.getState() == WavRecorder.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
LogTrace.d(TAG, "updateListener","recording is ing");
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]);
// LogTrace.e(TAG, "updateListener 16bit curSample",
// curSample + "");
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(WavRecorder.class.getName(),
// "Error occured in updateListener, recording is aborted");
LogTrace.d(TAG, "updateListener", "record succ");
// stop();
reset();
}
}
public void onMarkerReached(AudioRecord recorder) {
// NOT USED
}
};
/**
*
*
* Default constructor
*
* 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
*
*/
@SuppressWarnings("deprecation")
public WavRecorder(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);
LogTrace.w(TAG,"WavRecorder",
"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.CAMCORDER);
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) {
LogTrace.e(TAG,"WavRecorder", e.getMessage());
} else {
LogTrace.e(TAG,"WavRecorder", "Unknown error occured while initializing recording");
}
state = State.ERROR;
}
}
/**
* Sets output file path, call directly after construction/reset.
*
* @param output
* file path
*
*/
public void setOutputFile(String argPath) {
try {
if (state == State.INITIALIZING) {
filePath = argPath;
if (!rUncompressed) {
mediaRecorder.setOutputFile(filePath);
}
}
} catch (Exception e) {
if (e.getMessage() != null) {
LogTrace.e(TAG,"setOutputFile",e.getMessage());
} else {
LogTrace.e(TAG,"setOutputFile","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() {
LogTrace.d(TAG, "prepare prepare state:",state+"");
LogTrace.d(TAG, "prepare prepare filePath:",filePath+"");
LogTrace.d(TAG, "prepare audioRecorder.getState():",audioRecorder.getState()+"");
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 {
LogTrace.e(TAG,"prepare","prepare() method called on uninitialized recorder");
state = State.ERROR;
}
} else {
mediaRecorder.prepare();
state = State.READY;
}
}else if (state == State.STOPPED||state == State.ERROR){
String fileTempPath = filePath;
reset();
setOutputFile(fileTempPath);
prepare();
} else {
LogTrace.e(TAG,"prepare","prepare() method called on illegal state");
release();
state = State.ERROR;
}
} catch (Exception e) {
if (e.getMessage() != null) {
LogTrace.e(TAG,"prepare",e.getMessage());
} else {
LogTrace.e(TAG,"prepare","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) {
LogTrace.e(TAG,"release","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.CAMCORDER);
mediaRecorder
.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder
.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
}
state = State.INITIALIZING;
}
} catch (Exception e) {
LogTrace.e(TAG,"reset",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.setRecordPositionUpdateListener(updateListener);
audioRecorder.setPositionNotificationPeriod(framePeriod);
audioRecorder.startRecording();
audioRecorder.read(buffer, 0, buffer.length);
} else {
mediaRecorder.start();
}
state = State.RECORDING;
} else {
LogTrace.e(TAG,"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(36 + payloadSize));
randomAccessWriter.seek(40); // Write size to Subchunk2Size
// field
randomAccessWriter.writeInt(Integer
.reverseBytes(payloadSize));
randomAccessWriter.close();
} catch (IOException e) {
LogTrace.e(TAG,"stop","I/O exception occured while closing output file");
state = State.ERROR;
}
} else {
mediaRecorder.stop();
}
state = State.STOPPED;
} else {
LogTrace.e(TAG,"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格式文件
*
* @param path
* : 文件路径
*/
public void recordChat(String fileName) {
if (!Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED)) {
return;
}
String file = new String(makeFileStroagePath().getAbsolutePath() + "/"
+ fileName);
// 设置输出文件
setOutputFile(file);
prepare();
// 开始录音
start();
}
/**
* 停止录音
*
* @param mediaRecorder
* 待停止的录音机
* @return 返回
*/
public void stopRecord() {
stop();
release();
}
public File makeFileStroagePath() {
File file = new File(C.normal.voice_path);
try {
if (!file.exists()) {
file.mkdirs();
return file;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return file;
}
}
</span>