2014-10-07 20 views
7

Ich nehme Sound mit AudioRecord im PCM16LE-Format, 8000Hz, 1Kanal auf. Es nimmt in den Android-Versionen 2.3.3-4.4.4 gut auf, zeichnet aber in Android L (5.0) Developer Preview seltsames intermittierendes Geräusch auf (auf Nexus 5, Nexus 7 und Emulator).AudioRecord zeichnet intermittierenden Sound in Android L auf Entwicklervorschau

Hier ist die Probe des aufgenommenen Tons (die erste Hälfte - Aufnahme, die zweite Hälfte - Wiedergabe): https://www.dropbox.com/s/3wcgufua5pphwtt/android_l_sound_record_error.m4a?dl=0

Ich versuchte aufgenommenen Ton mit verschiedener Sample-Rate (4000, 16000) und als 8bit zu spielen, aber der Ton bleibt intermittierend. Was könnte das Problem an diesem Sound sein?

Ich verwende dieses AudioRecordTask mit getAudioRecord Audio aufnehmen() zur Eingabe der Initialisierung (keine Fehler während des Betriebs zurück; Audio-Stücke empfangen zu internalBufferSize Wert sized gleich):

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

Antwort

4

Es ist ein Fehler in Android L Entwicklervorschau: https://code.google.com/p/android-developer-preview/issues/detail?id=1492

AudioRecord.read for short [] Pufferargument gibt Wert in Byte statt Wert in Kurzschlüssen zurück.

Als Workaround verwenden Sie AudioRecord.read mit Byte [] Puffer.

+0

Dies scheint in Release 5.0 behoben zu sein, es gibt jedoch ein ähnliches Problem, bei dem der Offset-Parameter fälschlicherweise verdoppelt wird - siehe https://code.google.com/p/android/issues/detail?id=80866 beim Versuch um einen Patch zu senden wurde mir gesagt, dass das auch intern behoben wird, allerdings keine Ahnung wann es in einer Veröffentlichung erscheinen wird. –

+0

Ich bin gerade in diese (glaube ich) in 5.0.2 abgestürzt. Bedeutet dies, dass, wenn das Byte [] buffer read verwendet wird, alles richtig funktioniert, einschließlich des Offset-Parameters, oder ist das immer noch verdoppelt? – nmw01223

+0

bei der Verwendung von Byte [] Puffer ist alles ok einschließlich Offset (es war so auf 5.0 und 5.0.1, noch nicht auf 5.0.2 getestet) –