【问题标题】:Android Recording Call parametersAndroid录音通话参数
【发布时间】:2015-11-06 13:41:10
【问题描述】:

我正在开发一个 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());
                }
            }
        }
    }

没有为 api 19 或 22 找到正确的参数来设置 AudioRecord。在每种情况下都会引发异常。 我对此很感兴趣。我没有考虑使用 MediaRecoder 类,因为我无法直接从重新编码器读取缓冲区,这对于 dtmf 解码过程至关重要。我也看过一些 dtmf 开源解码器,但是都有这个问题

【问题讨论】:

    标签: android format call record


    【解决方案1】:

    结论

    Android官方BUG

    第一

    AudioRecord.java它的构造函数public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,int bufferSizeInBytes)可能不推荐使用(我认为),一个IllegalArgumentException被直接抛出,另一个构造方法如下(尤其是公共 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");
        }
    

    参考资源

    AudioRecord.java

    AudioAttributes.java

    AudioAttributes.java

    @SystemApi @hide

    https://code.google.com/p/android/issues/detail?id=2117&q=call%20recorder&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

    https://code.google.com/p/android/issues/detail?id=4075

    【讨论】:

    • 您好,感谢您的回复。当我这样做时,我得到一个反射 InvocationTarget 异常: Constructor cons = AudioRecord.class.getConstructor(AudioAttributes.class, AudioFormat.class, int.class, int.class); audioRecord = (AudioRecord) cons.newInstance(attrs.build(), format.build(), bufferSize, AudioManager.AUDIO_SESSION_ID_GENERATE); - - 有任何想法吗?我用 api 22 编译
    【解决方案2】:

    一些安卓版本禁用了这个功能。如果你有安卓源代码,你可以让它工作。我目前正在使用 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:
                    mSource = preset;
                    break;
                default:
                    Log.e(TAG, "Invalid capture preset " + preset + " for AudioAttributes");
            }
            return this;
        }
    

    我用这个代替了:

    /**
         * @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;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-24
      • 1970-01-01
      相关资源
      最近更新 更多