音频记录对象未初始化

63
在下面的代码中,我的audioRecord对象没有初始化。我尝试将其移动到onCreate方法并将其设为全局变量。我已经记录了状态,并返回了一个值为1,表示可以使用。调试器说startRecording被调用时对象未初始化。它还说无法获取音频源。
我为什么会得到这些错误?
    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)

使用 recorder.getState() 获取正确的状态。 - Tom
重启设备后(由于我在错误的初始化设置上尝试后麦克风本身不工作,因此为了检查是否进入了黑洞,使用麦克风进行测试将是一件容易的事情),然后我尝试了尝试所有组合的初始化方法,它起作用了!谢谢! - WTing
12个回答

95

使用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();

4
我需要爬取 Android 源代码才能理解这个问题的答案。 - Vagrant
7
如果使用不支持的采样率,一些安卓设备会陷入"地狱黑洞",这意味着事情并不像你想象的那么顺利。要让麦克风再次工作,唯一的方法是重新启动设备。请注意,这个问题可能会影响到你的用户体验。 - Learn OpenGL ES
我也有类似的经历,Kevin(但以前没有必须重新启动过)—— Android 上的音频系统在所有不同的设备上可能都不同,并且根据版本/设备的不同表现出非常不同的行为,恢复方式也不同。猜测只能是一个“客人猜测/努力”。 - DustinB
1
在Galaxy S5和S6上使用,之前进行了清理重启操作,并在一个据说可以正常工作的样例应用程序中授予了RECORD_AUDIO权限;但一切都是无效的音频格式(可能正常情况下会出现)或与OP相同的错误(无法获取记录源1的音频输入)。 - Tom
也许将bufferSize!= AudioRecord.ERROR_BAD_VALUE更改为bufferSize!= AudioRecord.ERROR_BAD_VALUE && bufferSize!= AudioRecord.ERROR可能是个好主意(考虑:http://androidxref.com/5.1.1_r6/xref/frameworks/base/media/java/android/media/AudioRecord.java#553) - JohanShogun
我运行了这段代码,每次尝试都得到相同的错误。还在清单文件中添加了权限。也重新启动了设备。还进行了清理构建。 - Curtis

92
我遇到了同样的问题,解决方法是将

放入代码中。
<uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>

添加到清单文件中。

自Lollipop版本以来,您需要明确请求每个权限,因为用户可能已经撤销了它们。请确保已授予权限。


6
注意新手,如果你使用的是Android 6 Marshmallow系统,在应用程序中需要手动启用权限。 参考链接:https://www.howtogeek.com/230683/how-to-manage-app-permissions-on-android-6.0/ - Sean Zhu
实际上@SeanZhu的评论对我很有帮助。我在深夜花了4个小时。顺便说一下,我开始学习Android开发已经24小时了。 - venugopal

10
根据javadocs的说明,所有设备都保证支持此格式(用于录音):

44100、AudioFormat.CHANNEL_IN_MONO、AudioFormat.ENCODING_PCM_16BIT。

播放时将其更改为CHANNEL_OUT_MONO。


8
是的,但很多设备其实并不支持。 - Yaroslav Mytkalyk
3
是的,文档在这方面是错误的。超低端手机往往不支持这个功能。 - w.donahue
这是否仍然适用或者它已经成为标准了? - Jeremy

4

即使我完成了上述所有步骤,仍然遇到同样的问题。对我有用的是我的操作系统是棉花糖版本,所以我需要请求权限


能否分享一下您使用的权限(已经快一年了...)我正在使用RECORD_AUDIO和MODIFY_AUDIO_SETTINGS。 - darkpbj

4
现在,使用Lollipop系统,您需要为每个权限明确向用户请求许可。请确保已授权该权限。

4

2

2

我遇到了同样的问题。 解决方法是重新启动设备。在编写代码时,我没有释放AudioRecord对象,这显然导致音频设备卡住了。 为了测试音频设备是否工作,我从Google Play下载了Audalyzer。


这对我也起作用了。我知道问题应该是硬件设备而不是代码,因为在一个正常构建版本和一个错误的版本之间我没有改变任何东西。谢谢! - CodyMace

2

在我的情况下,我需要手动允许Android 7中的麦克风权限,就像Sean Zhu所评论的那样。


1

我注意到当我运行的AVD上的SD卡满了时,AudioRecord构造函数会返回null。你尝试过清空SD卡吗?


谢谢,伙计。清空SD卡后,我的问题得到了解决。 - Rahul Baradia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接