开发DTMF解码器。我需要的是录制语音呼叫,然后提取频率范围。一切正常,但有一些Android版本,我在设置音频源时出现以下错误
“AudioAttributes的捕获预设3无效”
为了获得正确的参数,我开发了一种算法:
private static final int[] FREQUENCY = {8000, 11025, 16000, 22050, 44100}; // 44100 is guaranteed to work in all devices
private static final int[] CHANNEL_CONFIGURATION = {AudioFormat.CHANNEL_IN_MONO,
AudioFormat.CHANNEL_IN_STEREO};
private static final int[] AUDIO_ENCODING = {AudioFormat.ENCODING_DEFAULT,
AudioFormat.ENCODING_PCM_8BIT,
AudioFormat.ENCODING_PCM_16BIT};
for (int i = 0; i < FREQUENCY.length && !found; i ++) {
for (int j = 0; j < CHANNEL_CONFIGURATION.length && !found; j ++) {
for (int k = 0; k < AUDIO_ENCODING.length && !found; k ++) {
try {
bufferSize = AudioRecord.getMinBufferSize(FREQUENCY[i], CHANNEL_CONFIGURATION[j], AUDIO_ENCODING[k]);
if (bufferSize != AudioRecord.ERROR_BAD_VALUE && bufferSize != AudioRecord.ERROR) {
audioRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_DOWNLINK, FREQUENCY[i], CHANNEL_CONFIGURATION[j], AUDIO_ENCODING[k], bufferSize);
found = true;
}
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
}
}
为了设置AudioRecord,没有为api 19或22找到正确的参数。在每种情况下都会引发异常。 我对此非常感兴趣。我没有考虑使用MediaRecoder类,因为我无法直接从重新编码器读取缓冲区,这对于dtmf解码过程至关重要。我也看过一些dtmf开源解码器,但所有这些都有这个问题
答案 0 :(得分:1)
Android官方BUG
AudioRecord.java它的构造函数public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,int bufferSizeInBytes)
可能不推荐使用(我认为), IllegalArgumentException 直接抛出,另一个下面的构造函数方法(特别是 PUBLID FOR PUBLIC API ):
/**
* @hide
* CANDIDATE FOR PUBLIC API
* Class constructor with {@link AudioAttributes} and {@link AudioFormat}.
* @param attributes a non-null {@link AudioAttributes} instance. Use
* {@link AudioAttributes.Builder#setCapturePreset(int)} for configuring the capture
* preset for this instance.
* @param format a non-null {@link AudioFormat} instance describing the format of the data
* that will be recorded through this AudioRecord. See {@link AudioFormat.Builder} for
* configuring the audio format parameters such as encoding, channel mask and sample rate.
* @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
* to during the recording. New audio data can be read from this buffer in smaller chunks
* than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
* required buffer size for the successful creation of an AudioRecord instance. Using values
* smaller than getMinBufferSize() will result in an initialization failure.
* @param sessionId ID of audio session the AudioRecord must be attached to, or
* {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at construction
* time. See also {@link AudioManager#generateAudioSessionId()} to obtain a session ID before
* construction.
* @throws IllegalArgumentException
*/
public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,int sessionId) throws IllegalArgumentException {
}
你可以尝试
/** Voice call uplink + downlink audio source */
public static final int VOICE_CALL = 4;
/**
* @hide
* Sets the capture preset.
* Use this audio attributes configuration method when building an {@link AudioRecord}
* instance with {@link AudioRecord#AudioRecord(AudioAttributes, AudioFormat, int)}.
* @param preset one of {@link MediaRecorder.AudioSource#DEFAULT},
* {@link MediaRecorder.AudioSource#MIC}, {@link MediaRecorder.AudioSource#CAMCORDER},
* {@link MediaRecorder.AudioSource#VOICE_RECOGNITION} or
* {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}.
* @return the same Builder instance.
*/
@SystemApi
public Builder setCapturePreset(int preset) {
//....
Log.e(TAG, "Invalid capture preset " + preset + " for AudioAttributes");
}
答案 1 :(得分:1)
某些Android版本禁用此功能。如果您有Android源代码,您可以使其工作。我目前正在使用cyanogenmod,所以我已经定制了AudioAttributes.java类,以便在它发生时不引发异常。
我们只需通过在switch / case结构中添加我们想要的所有音频源来改变AudioAttributes.java中的setCapturePreset()方法。
这是原作:
/**
* @hide
* Sets the capture preset.
* Use this audio attributes configuration method when building an {@link AudioRecord}
* instance with {@link AudioRecord#AudioRecord(AudioAttributes, AudioFormat, int)}.
* @param preset one of {@link MediaRecorder.AudioSource#DEFAULT},
* {@link MediaRecorder.AudioSource#MIC}, {@link MediaRecorder.AudioSource#CAMCORDER},
* {@link MediaRecorder.AudioSource#VOICE_RECOGNITION} or
* {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}.
* @return the same Builder instance.
*/
@SystemApi
public Builder setCapturePreset(int preset) {
switch (preset) {
case MediaRecorder.AudioSource.DEFAULT:
case MediaRecorder.AudioSource.MIC:
case MediaRecorder.AudioSource.CAMCORDER:
case MediaRecorder.AudioSource.VOICE_RECOGNITION:
case MediaRecorder.AudioSource.VOICE_COMMUNICATION:
case MediaRecorder.AudioSource.VOICE_DOWNLINK:
case MediaRecorder.AudioSource.VOICE_UPLINK:
case MediaRecorder.AudioSource.VOICE_CALL:
mSource = preset;
break;
default:
Log.e(TAG, "Invalid capture preset " + preset + " for AudioAttributes");
}
return this;
}
我用这个替换了:
<button on-touch="click()">
Avvia Scansione
</button>