2013-08-01 29 views
2

經過1-2小時的錄音後,我收到W/AudioRecord(17145): obtainBuffer timed out (is the CPU pegged?) user=11b7f820, server=11b7f820。顯然,自從AudioRecord的read()讀取0字節後停止錄製。我爲此苦苦掙扎了2周,還沒有找到解決方案。下面是我如何初始化audioRecord對象:AudioRecord在1-2小時後停止錄音

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; 
    } 

我讀了一個輔助線程。請注意我試圖使用positionNotificationListener,但結果是一樣的。

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(從控制檯添加錯誤 - com.audioRec.android.recorder是我的應用程序):

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 

請幫助我。我唯一想到的解決方案是檢查連續2次讀取(0)字節並再次停止/啓動audioRecord,但會導致0,5秒的丟失記錄。

+0

這是兩個不同設備之間的一致嗎?因爲如果它是一個製造商的差異,那麼它可能是一個更大的問題的跡象。 – JoxTraex

+0

我注意到我的Xperia Z.我今天會嘗試用Galaxy mini來查看結果。我懷疑我Z的Stamina模式是「有罪」,因爲當從商店使用另一個錄音應用程序時,我收到一個通知:「Recordin應用程序阻止Stamina模式節省電池...」該應用程序能夠使手機變弱,但我的不。今天我會用另一部手機進行測試,並讓你知道 –

+1

關於Galaxy mini的作品OK。測試了2:30小時,錄音沒有停止。 –

回答

0

音頻API已知會在某些特定設備上損壞。

我的建議是:

a。默認情況下執行正常行爲(只需保持記錄,直到需要正常停止)。 我認爲問題只出現在特定的型號上,所以默認行爲將適用於大多數用戶的設備。

b。通過Build.MODEL識別設備類型,並創建一個需要解決方法的設備模型的字符串陣列。例如,將您自己的設備模型添加到列表中,並將其從用戶報告中擴展(如果有的話)。

c。在您的邏輯中,檢查您是否在需要解決方法的設備上運行 - 如果是,請執行啓發式驗證問題 - 從AudioRecord連續讀取0個字節 - 然後重新啓動。

我發現最好是在特殊條件下依靠設備模型查詢來隔離變通方法,以防止「正常」代碼變髒。

+0

感謝您的回答。我已經這樣做了:如果連續2次讀取返回0,重新啓動audioRecord,強制屏幕開啓(變暗)(如果用戶沒有從設置中取消選中該屬性)並繼續錄製。但是,正如你所建議的那樣,我的代碼變得很髒,所以你的方法更加優雅,2有兩種閱讀/處理記錄的方式。問題是我必須等到用戶抱怨記錄在一段時間後停止並將他們的手機添加到列表中。 –

+0

如果具有相同問題的設備過多,則還可以將該解決方法作爲默認行爲(假設它不會中斷正常設備上的應用程序)。 – SirKnigget