Error code -20 when initializing native AudioRecord object.

卫华奥
2023-12-01


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>


相关阅读

相关文章

相关问答