Android AudioRecord failing when calling the start

2019-08-13 04:18发布

问题:

I'm trying to record audio in android and store it in an array of bytes, and for that I use Android's AudioRecord built-in class.
I've already used this class before, and all was good, but for some reason, it seems the AudioRecord won't work anymore.

The problem is that the AudioRecord gets initialized and shows no errors, but when it's time to actually record something, by calling its' startRecording() method, something is failing and I don't even get a proper reason why.

This is ALL the output from Logcat after calling this method:

01-18 18:54:49.545  11303-11338/com.mypackage E/android.media.AudioRecord﹕ MediaRecorder prepare   CallingPid =  11303  Callinguid=  10128

01-18 18:54:49.545  11303-11338/com.mypackage E/android.media.AudioRecord﹕ java.lang.Throwable
        at android.media.AudioRecord.startRecording(AudioRecord.java:631)
        at mypackage.AudioRecorder.record(AudioRecorder.java:179)

Of course no audio gets recorded after that, for those wondering if it's just an internal error message.

This is the code for initializing the AudioRecord class:

int bufferSize = AudioRecord.getMinBufferSize(AUDIO_SAMPLE_RATE, RECORDER_CHANNEL, RECORDER_AUDIO_ENCODING);

        if (bufferSize != AudioRecord.ERROR_BAD_VALUE && bufferSize > 0)
        {
            // check if we can instantiate and have a success
            AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, AUDIO_SAMPLE_RATE, RECORDER_CHANNEL,
                    RECORDER_AUDIO_ENCODING, bufferSize);

            if (recorder.getState() == AudioRecord.STATE_INITIALIZED)
            {
                m_Recorder = recorder;
                m_RecordingThread = Executors.newSingleThreadExecutor();
                m_IsInitialized = true;
                return;
            }
        }

When the constants that are used are:

/**
 * Recorded audio's sample rate.
 */
private static final int AUDIO_SAMPLE_RATE = 44100;

/**
 * Recorded audio's channel.
 */
private static final int RECORDER_CHANNEL = AudioFormat.CHANNEL_IN_MONO;

/**
 * Recorded audio's encoding.
 */
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;

The error is happening here:

if (m_Recorder != null)
            m_Recorder.startRecording();

So after seeing this happen a couple of times, I decided to go deeper and try to debug it, going as deep as I can, to the source of error in the AudioRecord class itself, using Jetbrain's decompiler.
For some strange reason, as soon as the app hit the breakpoint located at the source of error, the next step-over couldn't be completed, as the AudioRecord has crashed yet again, with the same error message.

The next step for me was creating a sample project just to test AudioRecord's functionality, but this time I added an AudioTrack as well, that will output all my recordings instantly (a kind of a loopback), in case the AudioRecord class manages to record something, with or without the error.
And so the magic has happened - The app is working, AudioRecord is recording, and AudioTrack is playing.
It seemed really strange that the AudioTrack class suddenly resolved all my issues, so I removed it from my code and tried running the app yet again.
This time, the AudioRecord worked without all problems, and even though I couldn't hear its' output, I can assure you it has been recording.

With a bit of relief, I thought to my myself that I've finally overcame this issue, and I'm ready to move forward, so I added some extra code to encode and decode the recorded audio data.
To hear an output, I returned the code using the AudioTrack class, and ran the app.

Wanna hear a funny thing? The app has crashed with the same error, AGAIN.

Now theoretically the problem could be not releasing the AudioRecord instance when done using it, but I've covered that too from the very beginning.

I've tried looking practically everywhere on the internet for a solution, but it seems as if no one has even encountered a problem like this before.

Also, I'd like to point out that I've tried resetting my device, the ADB plugin, and rebuilding all projects.

I'm using a Meizu MX5 phone, with Android Lollipop(API 21).

回答1:

Well, I solved the problem, or at least a part of it, causing it to work now. The thing is I tried to read more bytes than the size of my pre-allocated buffer, upon calling the read() method of the AudioRecord class.
Although it didn't solve the main issue of this post, which is the strange error message and the uncaught exception, it made the AudioRecord work perfectly, so for me this thread can be seen as answered and closed!



回答2:

Full code

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
//import com.rdt.facerecord.R;
import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class StreamD extends Activity {
private Button startButton,stopButton;

public byte[] buffer;
public static DatagramSocket socket;
private int port=8089;

AudioRecord recorder;

private int sampleRate = 16000 ; // 44100 for music
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;    
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;       
int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig,     audioFormat);
private boolean status = true;

TextView prompt;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stream);

prompt = (TextView)findViewById(R.id.textView1);

startButton = (Button) findViewById (R.id.start_bbb);
stopButton = (Button) findViewById (R.id.stop_bbb);

startButton.setOnClickListener (startListener);
stopButton.setOnClickListener (stopListener);

}

private final OnClickListener stopListener = new OnClickListener() {

@Override
public void onClick(View arg0) {
            status = false;
            recorder.release();

            System.out.println("Recorder released");
}

};

private final OnClickListener startListener = new OnClickListener() {

@Override
public void onClick(View arg0) {
            status = true;
            startStreaming();           
}

};

public void startStreaming() {


Thread streamThread = new Thread(new Runnable() {

    @Override
    public void run() {
        try {

            DatagramSocket socket = new DatagramSocket();

            System.out.println("Socket Created");

            byte[] buffer = new byte[minBufSize];

            System.out.println("Buffer created of size " + minBufSize);

            DatagramPacket packet;

            final InetAddress destination =     InetAddress.getByName("218.000.000.000");

            System.out.println("Address retrieved");


            recorder = new             AudioRecord(MediaRecorder.AudioSource.MIC,sampleRate,channelConfig,audioFormat,m    inBufSize*10);
            System.out.println("Recorder initialized");

            recorder.startRecording();


            while(status == true) {


                //reading data from MIC into buffer
                minBufSize = recorder.read(buffer, 0, buffer.length);

                //putting buffer in the packet
                packet = new DatagramPacket (buffer,buffer.length,destination,port);

                socket.send(packet);
                System.out.println("MinBufferSize: " +minBufSize);

            }



        } catch(UnknownHostException e) {
            System.out.println("UnknownHostException");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IOException");
        } 
    }

});
streamThread.start();
 }
 }

and add permission

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