【问题标题】:AudioRecord records intermittent sound in Android L Developer PreviewAudioRecord 在 Android L Developer Preview 中录制断断续续的声音
【发布时间】:2014-10-07 12:54:33
【问题描述】:

我正在使用 AudioRecord 以 PCM16LE 格式、8000Hz、1 声道录制声音。在 Android 2.3.3-4.4.4 版本中录制正常,但在 Android L(5.0) Developer Preview(在 nexus 5、nexus 7 和模拟器上)录制奇怪的间歇性声音。

以下是录制的声音示例(前半部分 - 录音,后半部分 - 播放): https://www.dropbox.com/s/3wcgufua5pphwtt/android_l_sound_record_error.m4a?dl=0

我尝试使用不同的采样率(4000、16000)和 8 位播放录制的声音,但声音一直断断续续。这个声音可能有什么问题?

我正在使用此 AudioRecordTask 通过 getAudioRecord() 录制音频以初始化输入(操作期间未返回错误;接收大小与 internalBufferSize 值相同的音频块):

public final int SAMPLING_RATE = 8000;

private AudioRecord getAudioRecord() {
    int internalBufferSize = AudioRecord.getMinBufferSize(SAMPLING_RATE,
            AudioFormat.CHANNEL_IN_MONO,
            AudioFormat.ENCODING_PCM_16BIT); //returns 640

    internalBufferSize = 8000; //also tried returned value (640) and values 2560, 30000 - no changes 

    final int SOURCE;
    if (Build.VERSION.SDK_INT < 11) {
        SOURCE = MediaRecorder.AudioSource.MIC;
    } else {
        SOURCE = MediaRecorder.AudioSource.VOICE_COMMUNICATION;
    }

    AudioRecord record = new AudioRecord(SOURCE,
            SAMPLING_RATE,
            AudioFormat.CHANNEL_IN_MONO,
            AudioFormat.ENCODING_PCM_16BIT,
            internalBufferSize);

    int state = record.getState();
    if (state != AudioRecord.STATE_INITIALIZED) {
        try {
            record.release();
        } catch (Exception e) {
        }
        return null;
    }

    if (record.getState() == android.media.AudioRecord.STATE_INITIALIZED) {
        record.startRecording();
    } else {
        record.release();
        return null;
    }
    return record;
}

private class AudioRecordTask extends AsyncTask<Void, Void, Void> {
    final int PARTIAL_BUFFER_SIZE = SAMPLING_RATE;
    final int NECESSARY_BUFFER_SIZE = 15 * PARTIAL_BUFFER_SIZE * Short.SIZE / 8;
    final int FULL_BUFFER_SIZE = NECESSARY_BUFFER_SIZE * 2; //XXX: * 2 for the case when system returns more data than needed
    short[] mBuffer;
    int mTotalSize;
    int mTotalSizeInBytes;
    boolean mResult;
    private Object mLock = new Object();

    @Override
    protected void onPreExecute()
    {
        mIsRecording = true;

        mBuffer = new short[FULL_BUFFER_SIZE];
        mTotalSize = 0;
        mTotalSizeInBytes = 0;
        mResult = false;
    }

    @Override
    protected Void doInBackground(Void... arg0) {
        synchronized (mLock) {
            android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
            AudioRecord record = getAudioRecord();
            if (record == null) {
                mResult = false;
                return null;
            }

            for (int i = 0; i < 15 * 100; i++) { //XXX: * 100 to record enough data (system can return lesser than needed)
                int datalen = record.read(mBuffer, mTotalSize, PARTIAL_BUFFER_SIZE);
                if (datalen > 0) {
                    mTotalSize += datalen;
                    mTotalSizeInBytes = mTotalSize*2;
                } else {
                    Log.w("", "error " + datalen + " in AudioRecord.read");
                }
                if (isCancelled() || mTotalSizeInBytes > NECESSARY_BUFFER_SIZE) {
                    break;
                }
            }
            if (record.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
                record.stop();
            }

            record.release();
            mResult = true;
            return null;
        }
    }

    @Override
    protected void onPostExecute(Void r) {
        synchronized (mLock) {
            mIsRecording = false;
            fin();
        }
    }

    @Override
    protected void onCancelled() {
        //XXX: on old Androids (e.g. 2.3.3) onCancelled being called while doInBackground is still running
        synchronized (mLock) {
            mIsRecording = false;
            if (mAbort) {
                return;
            }
            fin();
        }
    }

    private void fin() {
        if (mResult && mTotalSizeInBytes > 0) {
            sendRecordedAudioToServer(mBuffer, mTotalSize, mTotalSizeInBytes);
        } else {
            showError(null);
        }
    }
}

【问题讨论】:

    标签: android audio android-5.0-lollipop audiorecord


    【解决方案1】:

    这是 Android L 开发者预览版中的一个错误:https://code.google.com/p/android-developer-preview/issues/detail?id=1492

    AudioRecord.read for short[] 缓冲区参数返回字节值而不是短裤值。

    作为一种解决方法,使用带有 byte[] 缓冲区的 AudioRecord.read。

    【讨论】:

    • 这似乎在已发布的 5.0 中得到修复,但是存在一个相关问题,即偏移参数错误地加倍 - 请参阅 code.google.com/p/android/issues/detail?id=80866 在尝试提交我被告知的补丁时,该补丁也已在内部修复,虽然不知道它何时会出现在版本中。
    • 我刚刚在 5.0.2 中遇到了这个(我认为)。这是否意味着如果使用 byte[] 缓冲区读取,它一切正常,包括偏移参数,还是仍然加倍?
    • 当使用 byte[] 缓冲区时,包括偏移在内一切正常(5.0 和 5.0.1 上是这样,5.0.2 上还没有测试过)
    • 5.0-5.02 中存在 offset 参数的明显问题,但似乎在 5.1 中已修复
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-22
    • 1970-01-01
    • 1970-01-01
    • 2018-10-15
    • 1970-01-01
    相关资源
    最近更新 更多