2014-10-07 23 views
7

Nagrywam dźwięk z AudioRecord w formacie PCM16LE, 8000Hz, 1 kanał. Nagrywa w systemie Android w wersjach 2.3.3-4.4.4, ale rejestruje dziwne przerywane dźwięki w Androidzie L (5.0) Developer Preview (na nexusie 5, nexusie 7 i emulatorze).AudioRecord nagrywa przerywany dźwięk w Androidzie L Preview Preview

Oto próbka nagrywanego dźwięku (pierwsza połowa - zapisu, druga połowa - odtwarzanie): https://www.dropbox.com/s/3wcgufua5pphwtt/android_l_sound_record_error.m4a?dl=0

Próbowałem grać nagrany dźwięk przy użyciu różnych częstotliwości próbkowania (4000, 16000) oraz jako 8bit ale dźwięk nie jest przerywany. Jakim problemem może być ten dźwięk?

Używam tego AudioRecordTask do nagrywania dźwięku z getAudioRecord() przez inicjowanie wejściowy (bez błędów zwracanych podczas operacji; otrzymaniu fragmentów dźwiękowych sized równie wartości 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); 
     } 
    } 
} 

Odpowiedz

4

Jest to błąd w Android L Podgląd programisty: https://code.google.com/p/android-developer-preview/issues/detail?id=1492

AudioRecord.read dla krótkiego argumentu buforowego [] zwraca wartość w bajtach zamiast wartości w krótkich.

Jako obejście użyj funkcji AudioRecord.read z buforem bajtowym [].

+0

Wygląda na to, że naprawiono błąd w wersji 5.0, jednak istnieje problem z błędem podwojenia parametru odsunięcia - patrz https://code.google.com/p/android/issues/detail?id=80866 podczas próby aby przesłać łatkę, powiedziano mi, że jest również poprawiona wewnętrznie, ale nie ma pojęcia, kiedy pojawi się w wydaniu. –

+0

Właśnie wpadłem na to (jak sądzę) w 5.0.2. Czy to oznacza, że ​​jeśli używany jest odczyt bufora bajtowego [], wszystko działa poprawnie, łącznie z parametrem przesunięcia, czy jest jeszcze podwojony? – nmw01223

+0

przy korzystaniu z bufora bajtowego [] wszystko jest ok łącznie z offsetem (tak było w 5.0 i 5.0.1, jeszcze nie testowałem w wersji 5.0.2) –