Domanda

I receive W/AudioRecord(17145): obtainBuffer timed out (is the CPU pegged?) user=11b7f820, server=11b7f820 after 1-2 hours of recording. Obviously the recording stops since the read() from AudioRecord read 0 bytes. I am struggling with this for over 2 weeks and no solution found yet. Here is how I initialize audioRecord object:

private void initPCMRecorder() throws Exception {
        Log.d(getClass().getName(), "Initializing AudioRecord...");
        int channelConfig = nChannels == 1 ? AudioFormat.CHANNEL_IN_MONO: AudioFormat.CHANNEL_IN_STEREO;  
        bufferSize = AudioRecord.getMinBufferSize(sRate, channelConfig, aFormat);
        if (bufferSize == AudioRecord.ERROR_BAD_VALUE)
            Log.e(getClass().getName(), "Bad encoding value, see logcat");                  
        else if (bufferSize == AudioRecord.ERROR)
            Log.e(getClass().getName(), "Error creating buffer size");

        bufferSize *= 3;
        buffer = new byte[bufferSize];

        //check if is not yet released
        if(aRecorder != null){
            try {
                aRecorder.release();    
            } catch (Exception e) {
                Log.e(getClass().getName(), e.getMessage(), e);
            }           
        }

        System.out.println("Source="+aSource+"; sampRate="+sRate+"; format="+aFormat+"; bufSize="+bufferSize);
        aRecorder = new AudioRecord(aSource, sRate, channelConfig, aFormat, bufferSize);
        if (aRecorder.getState() != AudioRecord.STATE_INITIALIZED) {
            throw new Exception("" + ErrorCodes.ERROR_CODE_0);
        }
        Log.d(getClass().getName(), "AudioRecord Initialized");
        state = State.INITIALIZING;
    }

and I read in a secondary thread. Please note I tried to use positionNotificationListener, but the result was the same.

public void run() {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);

    while (!stopped) {
        while (!suspend) {
            int result = aRecorder.read(buffer, 0, buffer.length);
            if(result == AudioRecord.ERROR_INVALID_OPERATION){
                Log.e(getClass().getName(), "aRecorder.read() returns ERROR_INVALID_OPERATION !!!");
                continue;
            }else if(result == AudioRecord.ERROR_BAD_VALUE){
                Log.e(getClass().getName(), "aRecorder.read() returns ERROR_BAD_VALUE !!!");
                continue;
            }else if(result == 0){
                Log.w(getClass().getName(), "SKIP audio block.");
                continue;
            }

            payloadSize += buffer.length;

            //data processing/writing is done in another thread 
            WAVData audioData = new WAVData(buffer);
            audioData.setGain(rGain);
            audioData.setBitsPerSamples(bitsPerSample);
            audioData.setNrChannels(nChannels);
            if(writersArray.size()>=1)
                writersArray.get(writersArray.size() - 1).add(audioData);
        }
        // lock here
        synchronized (lock) {
            try {
                lock.wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
        }
    }
}

EDIT (adding error from console - com.audioRec.android.recorder is my app):

08-02 12:30:38.162: D/dalvikvm(1451): GC_CONCURRENT freed 7867K, 36% free 18889K/29447K, paused 17ms+8ms, total 151ms
08-02 12:30:38.953: D/dalvikvm(1451): GC_FOR_ALLOC freed 36K, 36% free 18892K/29447K, paused 46ms, total 47ms
08-02 12:30:39.063: D/dalvikvm(1451): GC_CONCURRENT freed <1K, 29% free 21196K/29447K, paused 18ms+6ms, total 108ms
08-02 12:30:59.004: W/AudioRecord(703): obtainBuffer timed out (is the CPU pegged?) user=00f49160, server=00f49160
08-02 12:30:59.515: W/AudioRecord(703): obtainBuffer timed out (is the CPU pegged?) user=00f49160, server=00f49160
08-02 12:31:00.035: W/AudioRecord(703): obtainBuffer timed out (is the CPU pegged?) user=00f49160, server=00f49160
08-02 12:31:00.526: W/com.audioRec.android.recorder.AudioRecorder$RecorderThread(703): SKIP audio block.
08-02 12:31:00.766: W/AudioRecord(703): obtainBuffer timed out (is the CPU pegged?) user=00f49160, server=00f49160
08-02 12:31:01.297: W/AudioRecord(703): obtainBuffer timed out (is the CPU pegged?) user=00f49160, server=00f49160
08-02 12:31:01.797: W/AudioRecord(703): obtainBuffer timed out (is the CPU pegged?) user=00f49160, server=00f49160
08-02 12:31:02.308: W/AudioRecord(703): obtainBuffer timed out (is the CPU pegged?) user=00f49160, server=00f49160
08-02 12:31:02.558: W/com.audioRec.android.recorder.AudioRecorder$RecorderThread(703): SKIP audio block.
08-02 12:31:02.558: D/com.audioRec.android.recorder.AudioRecorder$RecorderThread(703): MUST RESET AUDIORECORD....obtainBuffer timed out ?
08-02 12:31:02.568: D/com.audioRec.android.recorder.AudioRecorder$AudioRecordCalibrator(703): Calibrating AudioRecord object...
08-02 12:31:08.494: E/alsa_pcm(257): Arec: error5
08-02 12:31:08.494: W/AudioStreamInALSA(257): pcm_read() returned error n -5, Recovering from error
08-02 12:31:08.615: E/ALSADevice(257): standby handle h 0x4234f358
08-02 12:31:08.645: D/alsa_ucm(257): snd_use_case_set(): uc_mgr 0x42e24fb8 identifier _dismod value Capture Music
08-02 12:31:08.645: D/alsa_ucm(257): Set mixer controls for Capture Music enable 0
08-02 12:31:08.655: D/alsa_ucm(257): Setting mixer control: MultiMedia1 Mixer SLIM_0_TX, value: 0
08-02 12:31:08.655: E/ALSADevice(257): Number of modifiers 0
08-02 12:31:08.655: E/ALSADevice(257): usecase_type is 0

Please HELP me with this. The only solution that comes in my mind is to check for 2 consecutive read() that reads 0 bytes and stop/start the audioRecord again, but will cause 0,5 seconds of lost recording.

È stato utile?

Soluzione

The audio APIs are known to be broken on some particular devices.

What I suggest is:

a. Perform the normal behavior by default (just keep recording until you need to stop normally). I assume that the problem appears only on specific models, so the default behavior will work on most users' devices.

b. Identify the device type by Build.MODEL and create a String array of device models that require the workaround. For example, add your own device model to the list, and also extend it from user reports (if you have any).

c. In your logic, check if you're running on a device that requires the workaround - and if so, perform your heuristic for identifying the problem - sequential reading of 0 bytes from AudioRecord - and then restart it.

I found that it's best to isolate workarounds like that in special conditions that depend on a device model query, to prevent your "normal" code from getting dirty.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top