2011-01-30 2 views
49

В приведенном ниже коде мой объект audioRecord не инициализируется. Я попытался переместить его на метод onCreate и сделал его глобальным. Я зарегистрировал состояние и возвращает значение 1, что означает готовность к использованию. Отладчик говорит, что startRecording вызывается на неинициализированном объекте. Он также говорит, что он не может получить источник звука.Объект AudioRecord не инициализируется

Почему я получаю эти ошибки?

package com.tecmark; 

    import java.io.BufferedOutputStream; 
    import java.io.DataOutputStream; 
    import java.io.File; 
    import java.io.FileOutputStream; 
    import android.app.Activity; 
    import android.media.AudioFormat; 
    import android.media.AudioRecord; 
    import android.media.MediaRecorder; 
    import android.os.Bundle; 
    import android.os.Environment; 
    import android.util.Log; 
    import android.view.View; 
    import android.widget.TextView; 

    public class recorder extends Activity { 

     private Thread thread; 
     private boolean isRecording; 
     private AudioRecord recorder; 
     private FileOutputStream os; 
     private BufferedOutputStream bos; 
     private DataOutputStream dos; 
     private TextView text; 
     private int audioSource = MediaRecorder.AudioSource.MIC; 
     private int sampleRate = 22050; 
     private int channel = AudioFormat.CHANNEL_CONFIGURATION_MONO; 
     private int encoding = AudioFormat.ENCODING_PCM_16BIT; 
     private int result = 0; 
     private int bufferSize; 
     private byte[] buffer; 

     /** Called when the activity is first created. */ 
     @Override 
     public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      setContentView(R.layout.main); 

      Log.v("onCreate", "layout set, about to init audiorec obj"); 
      text = (TextView)findViewById(R.id.TextView01); 

      bufferSize = AudioRecord.getMinBufferSize(sampleRate,channel,encoding); 
      buffer = new byte[bufferSize]; 

      recorder = new AudioRecord(audioSource, sampleRate,channel,encoding, 
        AudioRecord.getMinBufferSize(sampleRate, channel,encoding)); 
      Log.i("recorder obj state",""+recorder.getRecordingState()); 
     } 

     public void onClickPlay(View v){ 

     } 


     public void record(){ 
      Log.i("inside record method", "******"); 
     File path = Environment.getExternalStorageDirectory(); 
      Log.v("file path", ""+path.getAbsolutePath()); 

      File file = new File(path, "test.wav"); 

      if(file.exists()){ 
      file.delete(); 
      } 

      path.mkdirs(); 
      Log.v("file path", ""+file.getAbsolutePath()); 

      try { 
      os = new FileOutputStream(file); 
      bos = new BufferedOutputStream(os);    
       dos = new DataOutputStream(bos);   
      } catch (Exception e1) { 
      e1.printStackTrace(); 
      } 

      int bufferSize = AudioRecord.getMinBufferSize(sampleRate,channel,encoding); 
      byte[] buffer = new byte[bufferSize]; 
      recorder.startRecording(); 
      isRecording = true; 
      try{ 
       while (isRecording){ 
      result = recorder.read(buffer, 0, bufferSize); 
      for(int a=0; a<result;a++){ 
       dos.write(buffer[a]); 

       if(!isRecording){ 
        recorder.stop();   
        break; 
       } 

      } 

      } 
      dos.flush(); 
      dos.close(); 
     }catch(Exception e){ 
      e.printStackTrace(); 
     } 

    }// end of record method 

    public void onClickStop(View v){ 
     Log.v("onClickStop", "stop clicked"); 
     isRecording=false; 
    } 
    public void onClickReverse(View v){ 
     Log.v("onClickReverse", "reverse clicked"); 
    } 
    public void onClickRecord(View v){ 
     Log.v("onClickRecourd", "record clicked, thread gona start"); 
     text.setText("recording"); 
     thread = new Thread(new Runnable() { 
      public void run() { 
       isRecording = true; 
       record(); 
      } 
     }); 

     thread.start(); 
     isRecording = false; 
    } 
}//end of class 

Logcat

01-30 15:23:16.724: ERROR/AudioRecord(12817): Could not get audio input for record source 1 01-30 15:23:16.729: 
ERROR/AudioRecord-JNI(12817): Error creating AudioRecord instance: initialization check failed. 01-30 15:23:16.729: 
ERROR/AudioRecord-Java(12817): [ android.media.AudioRecord ] Error code 
-20 when initializing native AudioRecord object. 01-30 15:23:16.729: INFO/recorder obj state(12817): 1 01-30 15:23:16.729: 
WARN/dalvikvm(12817): threadid=13: thread exiting with uncaught exception (group=0x4001b180) 01-30 15:23:16.729: 
ERROR/AndroidRuntime(12817): Uncaught handler: thread Thread-7 exiting due to uncaught exception 01-30 15:23:16.739: 
ERROR/AndroidRuntime(12817): java.lang.IllegalStateException: startRecording() called on an uninitialized AudioRecord. 01-30 15:23:16.739: 
ERROR/AndroidRuntime(12817):  at android.media.AudioRecord.startRecording(AudioRecord.java:495) 01-30 15:23:16.739: 
ERROR/AndroidRuntime(12817):  at com.tecmark.recorder.record(recorder.java:114) 01-30 15:23:16.739: 
ERROR/AndroidRuntime(12817):  at com.tecmark.recorder$1.run(recorder.java:175) 01-30 15:23:16.739: 
ERROR/AndroidRuntime(12817):  at java.lang.Thread.run(Thread.java:1096) 
+0

использовать recorder.getState(), чтобы получить правильное состояние – Tom

+0

После перезагрузки моего устройства (которое сам микрофон не работает после того, как я попытался установить неправильную настройку инициализации, чтобы проверить, вошел ли в черную дыру или нет, тестирование с помощью микрофона будет легким), затем я попытался использовать метод инициализации try-all-the-combination, и он работает! спасибо! – WTing

ответ

83

Трюк с использованием AudioRecord является то, что каждое устройство может иметь различные параметры инициализации, поэтому вам придется создать метод, который перебирает все возможные комбинации битовых скоростей, кодирование и т. д.

private static int[] mSampleRates = new int[] { 8000, 11025, 22050, 44100 }; 
public AudioRecord findAudioRecord() { 
    for (int rate : mSampleRates) { 
     for (short audioFormat : new short[] { AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT }) { 
      for (short channelConfig : new short[] { AudioFormat.CHANNEL_IN_MONO, AudioFormat.CHANNEL_IN_STEREO }) { 
       try { 
        Log.d(C.TAG, "Attempting rate " + rate + "Hz, bits: " + audioFormat + ", channel: " 
          + channelConfig); 
        int bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat); 

        if (bufferSize != AudioRecord.ERROR_BAD_VALUE) { 
         // check if we can instantiate and have a success 
         AudioRecord recorder = new AudioRecord(AudioSource.DEFAULT, rate, channelConfig, audioFormat, bufferSize); 

         if (recorder.getState() == AudioRecord.STATE_INITIALIZED) 
          return recorder; 
        } 
       } catch (Exception e) { 
        Log.e(C.TAG, rate + "Exception, keep trying.",e); 
       } 
      } 
     } 
    } 
    return null; 
} 

AudioRecord recorder = findAudioRecord(); 
recorder.release(); 
+3

^^^ это. Мне пришлось просканировать исходный код Android, чтобы понять это сам. – Vagrant

+0

все еще говорит, что то же самое для меня не работает –

+6

Это не будет работать так хорошо, как вы думаете, потому что некоторые устройства Android войдут в Black Hole of Hell, если вы используете неподдерживаемую частоту дискретизации. Единственный способ снова заставить микрофон работать - перезагрузить устройство. –

1

Я заметил, что когда SD-карта на avd, которую я запускаю, заполняет конструкцию AudioRecord r возвращает null. Вы пробовали очистить SDCard?

+0

спасибо .. приятель .. после очистки SD-карты .. моя проблема решена –

9

Согласно Javadocs, все устройства гарантированно поддерживают этот формат (для записи):

44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT.

Переход к CHANNEL_OUT_MONO для воспроизведения.

+7

Да, но много устройств действительно нет. –

+3

Да, документы ошибочны. Телефоны с низким уровнем доступа, как правило, не поддерживают это. –

+0

это все еще верно или это стандарт? – Jeremy

85

Я была такая же проблема, она была решена, поставив

<uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission> 

в манифесте.

С Lollipop вы также должны спросить пользователя о каждом разрешении. Поскольку они, возможно, отозвали их. Убедитесь, что разрешение предоставлено.

+5

просто записка для новичков, в Android 6 Marshmallow, мне также нужно вручную разрешить разрешение для приложения: https://www.howtogeek.com/230683/how-to-manage-app-permissions-on-android- 6.0/ –

2

Просто у той же проблемы. Решением было перезапустить устройство. Во время игры с кодом я не выпустил объект AudioRecord, который явно заставлял звуковое устройство застревать. Чтобы проверить, работает ли аудиоустройство или нет, я загрузил Audalyzer из Google Play.

+0

Это работало и на меня. Я знал, что это должно быть устройство, а не код, потому что я ничего не менял между рабочей сборкой и сломанной. Благодаря! – CodyMace

3

Проблема с инициализацией несколько объектов AudioRecord может фиксированной с помощью audioRecord.release(); перед созданием следующего объекта ... Подробнее здесь: Android AudioRecord - Won't Initialize 2nd time

0

Я думаю, что это имеет отношение к нити, не зная, что вы приостановили основные и по-прежнему пытается записать после того, как вы остановили рекордер.

Я решил это, изменив методы onResume() и onPause(), чтобы изменить isRecording boolean.

public void onResume() { 
    ... 
    isRecording = true; 
} 

public void onPause() { 
    ... 
    isRecording = false; 
} 

Затем в потоке, окружают как ваш startRecording() и stop() с тем, если-заявления проверки для isRecording:

if(isRecording) 
    recorder.startRecording(); 
... 
if(isRecording) 
    recorder.stop(); // which you've done 
0

Я переписал ответ от @DustinB для тех, кто использует Xamarin Android AudioRecord с C# ,

int[] sampleRates = new int[] { 44100, 22050, 11025, 8000 }; 
Encoding[] encodings = new Encoding[] { Encoding.Pcm8bit, Encoding.Pcm16bit }; 
ChannelIn[] channelConfigs = new ChannelIn[]{ ChannelIn.Mono, ChannelIn.Stereo }; 

//Not all of the formats are supported on each device 
foreach (int sampleRate in sampleRates) 
{ 
    foreach (Encoding encoding in encodings) 
    { 
     foreach (ChannelIn channelConfig in channelConfigs) 
     { 
      try 
      { 
       Console.WriteLine("Attempting rate " + sampleRate + "Hz, bits: " + encoding + ", channel: " + channelConfig); 
       int bufferSize = AudioRecord.GetMinBufferSize(sampleRate, channelConfig, encoding); 

       if (bufferSize > 0) 
       { 
        // check if we can instantiate and have a success 
        AudioRecord recorder = new AudioRecord(AudioSource.Mic, sampleRate, channelConfig, encoding, bufferSize); 

        if (recorder.State == State.Initialized) 
        { 
         mBufferSize = bufferSize; 
         mSampleRate = sampleRate; 
         mChannelConfig = channelConfig; 
         mEncoding = encoding; 
         recorder.Release(); 
         recorder = null; 
         return true; 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(sampleRate + "Exception, keep trying." + ex.Message); 
      } 
     } 
    } 
} 
4

Теперь, с lollipop, вам нужно конкретно спросить пользователя о каждом разрешении. Убедитесь, что разрешение предоставлено.

3

Даже после выполнения всех перечисленных выше шагов, которые я получал один и тот же вопрос, какие работали меня было то, что мой os был зефиром, и я должен был просить разрешения.

+0

Разум, разделяющий разрешения, которые сработали для вас (почти год спустя ...) Я использую RECORD_AUDIO и MODIFY_AUDIO_SETTINGS – darkpbj

1

В моем случае мне пришлось вручную разрешить разрешение в android 7 для микрофона, как прокомментировал sean zhu.

Смежные вопросы