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>