63

In the below code my audioRecord object is not initializing. I tried moving it to the onCreate method and made it a global. I've logged the state and that returns a value of 1 which means ready to use. The debugger says that startRecording is being called on an uninitialized object. It is also saying that it could not get the audio source.

Why am I getting these errors?

    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)
codeMagic
  • 44,549
  • 13
  • 77
  • 93
turtleboy
  • 8,210
  • 27
  • 100
  • 199
  • use recorder.getState() to get the correct state – Tom Jan 30 '11 at 15:52
  • After rebooting my device (which the mic itself is not working after I tried on wrong initialization setting, so to check whether one has entered a blackhole or not, testing with microphone will be an easy one), then i tried on the try-all-the-combination initialization method and it works! thanks! – WTing Feb 02 '17 at 13:27

12 Answers12

95

The trick with using AudioRecord is that each device may have different initialization settings, so you will have to create a method that loops over all possible combinations of bit rates, encoding, etc.

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();
WorkingMatt
  • 639
  • 8
  • 24
DustinB
  • 11,037
  • 5
  • 46
  • 54
  • 4
    ^^^ this. I had to crawl through the Android source code to figure this out myself. – Vagrant Mar 26 '11 at 05:33
  • 7
    This isn't going to work as well as you think because some Android devices will enter a Black Hole of Hell if you use an unsupported sample rate. The only way to get the microphone to work again is to reboot the device. – Learn OpenGL ES Oct 22 '12 at 19:16
  • I've also had similar experiences, Kevin (but haven't had to reboot before) -- the audio system on Android can be different on all the various devices and can behave very differently depending on the version/device, recover differently, etc. Guess it just has to be a 'guest guess/effort. – DustinB Oct 27 '12 at 22:09
  • 1
    Used this with galaxy S5 and S6 after clean restarts with RECORD_AUDIO permission on a sample app that supposedly works; everything was either Invalid audio format (as you'd probably expect) or a repeat of the same error as the OP (Could not get audio input for record source 1). – Tom Jun 24 '15 at 00:31
  • Might be an idea to change bufferSize != AudioRecord.ERROR_BAD_VALUE into bufferSize != AudioRecord.ERROR_BAD_VALUE && bufferSize != AudioRecord.ERROR (consider: http://androidxref.com/5.1.1_r6/xref/frameworks/base/media/java/android/media/AudioRecord.java#553) – JohanShogun Jul 15 '15 at 16:09
  • I ran this code and it got the same error on every attempt. Also added the permission to the manifest. Also restarted the device. Also did clean build. – Curtis Jul 07 '16 at 18:14
92

I had the same issue, it was solved by putting

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

into the manifest.

Since Lollipop, you also need to specifically ask the user for each permission. As they may have revoked them. Make sure the permission is granted.

William
  • 20,150
  • 8
  • 49
  • 91
user833970
  • 2,729
  • 3
  • 26
  • 41
  • 6
    just a note for newcomers, in Android 6 Marshmallow, I also have to manually enable the permission for the app: https://www.howtogeek.com/230683/how-to-manage-app-permissions-on-android-6.0/ – Sean Zhu Feb 23 '17 at 11:51
  • Actually @SeanZhu comment worked for me. I spent 4 hours in the middle of night. By the way it has been 24 hours since I started learning Android development. – venugopal Apr 04 '19 at 09:55
10

According to the javadocs, all devices are guaranteed to support this format (for recording):

44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT.

Change to CHANNEL_OUT_MONO for playback.

Ivan
  • 2,632
  • 1
  • 24
  • 12
4

Problem with initializing few AudioRecord objects could by fixed by using audioRecord.release(); before creating next object... More here: Android AudioRecord - Won't Initialize 2nd time

Community
  • 1
  • 1
Sirtarius
  • 128
  • 8
4

Now, with lollipop, you need to specifically ask the user for each permission. Make sure the permission is granted.

Ruchir Baronia
  • 7,406
  • 5
  • 48
  • 83
4

Even after doing all of the above steps I was getting the same issue, what worked for me was that my os was marshmallow and I had to ask for permissions.

Marlon
  • 1,839
  • 2
  • 19
  • 42
Aniruddha K.M
  • 7,361
  • 3
  • 43
  • 52
  • Mind sharing the permissions that worked for you (almost a year later...) I'm using RECORD_AUDIO and MODIFY_AUDIO_SETTINGS – darkpbj Aug 06 '17 at 18:43
2

Just had the same problem. The solution was to restart the device. While playing with the code I did not release the AudioRecord Object which obviously caused the audio device to stuck. To test whether the audio device worked or not I downloaded Audalyzer from Google Play.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Que
  • 31
  • 1
  • This worked for me as well. I knew it had to be the device and not the code because I didn't change anything between a working build and a broken one. Thanks! – CodyMace May 14 '15 at 22:38
2

If your mobile phone system is Android M or above,perhaps you need to apply record audio permission in Android M.http://developer.android.com/guide/topics/security/permissions.html

Chuanhang.gu
  • 870
  • 9
  • 13
2

in my case I had to manually allow the permission in android 7 for microphone, as sean zhu commented.

Eugene Lisitsky
  • 12,113
  • 5
  • 38
  • 59
1

I noticed that when the SDCard on the avd I am running gets full the AudioRecord constructor returns null. Have you tried clearing the SDCard?

aqf
  • 11
  • 1
0

I think this has to do with the thread not knowing that you've paused the main activity and still trying to record after you've stopped the recorder.

I solved it by changing my onResume() and onPause() methods to modify the isRecording boolean.

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

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

Then in your thread, surround both your startRecording() and stop() with if-statements checking for isRecording:

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

I rewrote the answer from @DustinB for anyone who is using Xamarin Android AudioRecord with 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);
            }
        }
    }
}
Gandalf458
  • 2,139
  • 1
  • 21
  • 36