AudioRecord 对象未初始化

Posted

技术标签:

【中文标题】AudioRecord 对象未初始化【英文标题】:AudioRecord object not initializing 【发布时间】:2011-06-18 03:24:37 【问题描述】:

在下面的代码中,我的 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() 获取正确的状态 重启我的设备后(我尝试了错误的初始化设置后麦克风本身不工作,所以要检查一个是否进入黑洞,用麦克风测试会很容易),然后我尝试了 try-all-the-combination 初始化方法,它有效!谢谢! 【参考方案1】:

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

【讨论】:

^^^ 这个。我必须自己翻阅 Android 源代码才能弄清楚这一点。 这不会像您想象的那么好,因为如果您使用不受支持的采样率,某些 Android 设备将进入地狱的黑洞。让麦克风再次工作的唯一方法是重新启动设备。 我也有过类似的经历,Kevin(但之前不必重新启动)——Android 上的音频系统在所有不同的设备上可能会有所不同,并且会根据版本/设备,以不同的方式恢复等。猜猜它只是一个“客人猜测/努力”。 在一个可以正常工作的示例应用程序上使用 RECORD_AUDIO 权限重新启动后,将此与 Galaxy S5 和 S6 一起使用;一切都是无效的音频格式(如您所料)或重复与 OP 相同的错误(无法获取记录源 1 的音频输入)。 将 bufferSize != AudioRecord.ERROR_BAD_VALUE 更改为 bufferSize != AudioRecord.ERROR_BAD_VALUE && bufferSize != AudioRecord.ERROR 可能是一个想法(考虑:androidxref.com/5.1.1_r6/xref/frameworks/base/media/java/…)【参考方案2】:

我也遇到了同样的问题,解决了

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

进入清单。

由于 Lollipop,您还需要专门询问用户的每个权限。因为他们可能已经撤销了它们。确保已授予权限。

【讨论】:

只是给新手的说明,在Android 6 Marshmallow中,我还必须手动启用应用程序的权限:howtogeek.com/230683/… 实际上@SeanZhu 评论对我有用。我在半夜花了4个小时。顺便说一句,我开始学习 Android 开发已经 24 小时了。【参考方案3】:

根据javadocs,保证所有设备都支持这种格式(用于录制):

44100,AudioFormat.CHANNEL_IN_MONO,AudioFormat.ENCODING_PCM_16BIT。

更改为 CHANNEL_OUT_MONO 进行播放。

【讨论】:

是的,但很多设备确实没有。 是的,文档对此有误。超低端手机往往不支持这一点。 这仍然适用还是标准?【参考方案4】:

在创建下一个对象之前,可以通过使用audioRecord.release(); 来解决初始化少数 AudioRecord 对象的问题... 更多内容:Android AudioRecord - Won't Initialize 2nd time

【讨论】:

【参考方案5】:

现在,对于棒棒糖,您需要专门询问用户的每个权限。确保已授予权限。

【讨论】:

【参考方案6】:

即使在完成上述所有步骤后,我也遇到了同样的问题,但对我有用的是我的操作系统是棉花糖,我必须请求权限

【讨论】:

介意分享对你有用的权限(差不多一年后......)我正在使用 RECORD_AUDIO 和 MODIFY_AUDIO_SETTINGS【参考方案7】:

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

【讨论】:

这对我也有用。我知道它必须是设备而不是代码,因为我没有在工作构建和损坏构建之间进行任何更改。谢谢!【参考方案8】:

如果你的手机系统是Android M或以上,可能需要在Android M申请录音权限。http://developer.android.com/guide/topics/security/permissions.html

【讨论】:

【参考方案9】:

在我的情况下,正如 sean zhu 评论的那样,我必须手动允许 android 7 中的麦克风权限。

【讨论】:

【参考方案10】:

我注意到,当我正在运行的 avd 上的 SDCard 已满时,AudioRecord 构造函数返回 null。您是否尝试过清除 SDCard?

【讨论】:

谢谢..哥们..清除SD卡后..我的问题解决了【参考方案11】:

我认为这与线程不知道您已暂停主要活动并在您停止记录器后仍在尝试记录有关。

我通过更改我的 onResume() 和 onPause() 方法来修改 isRecording 布尔值来解决它。

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


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

然后在您的线程中,将您的 startRecording()stop() 用 if 语句检查 isRecording:

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

【讨论】:

【参考方案12】:

我为使用 Xamarin Android AudioRecord 和 C# 的任何人重写了来自 @DustinB 的答案。

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

【讨论】:

以上是关于AudioRecord 对象未初始化的主要内容,如果未能解决你的问题,请参考以下文章

Android多媒体功能开发(11)——使用AudioRecord类录制音频

Android音频处理——通过AudioRecord去保存PCM文件进行录制,播放,停止,删除功能

MediaRecorder和AudioRecord的区别和联系

Android AudioRecord 初始化延迟

<AudioRecord> "无法获得记录源 1 的音频输入"

Android 开发 AudioRecord音频录制