简体   繁体   中英

Audio Record and Playback Failing - Android AudioRecord & AudioTrack

I am writing an Android Application for Recording and playing back audio in a loop. Like an echo (Record, Play, run in a loop).

I have successfully written the application for Recording and playing using a temp file, (write into file, read from the same file).
Doing the same using a intermediate buffer is failing.

Here is my code:

public class BufferMain extends ActionBarActivity {
private String TAG = "AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER";

private boolean isRunning = false;

private AudioRecord recorder = null;
private AudioTrack track = null;

/* Buffer used to record and Playback Audio */
byte buffer[] = new byte[640];
int bufferSize;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_buffer_main);

    enableButton(R.id.StartButton,true);
    enableButton(R.id.StopButton,false);

    /* Assign Button Click Handlers */
    ((Button)findViewById(R.id.StartButton)).setOnClickListener(btnClick);
    ((Button)findViewById(R.id.StopButton)).setOnClickListener(btnClick);

    Log.d(TAG, "\n ==Starting Application.. ==");
}

/* Method for Recording and Playing in a loop */
public void run_loop (boolean isRunning)
{
    int readbytes, writebytes, state;
    Log.d(TAG, "===== Entering Loop ===== ");

    if (isRunning == true) {
        do {
            bufferSize = 640; /* since configuration would return 640 size in buffer */
            recorder = findAudioRecord(recorder);
            if (recorder == null) {
                Log.e(TAG, "====== findAudioRecord : Returned Error! =======");
                return;
            }

            if (recorder.STATE_INITIALIZED == recorder.getState())
            {
                recorder.startRecording();

                readbytes = 0;              /* Reset read for next Iteration */
                readbytes = recorder.read(buffer, 0, bufferSize);

                /* Error Checking Code for AudioRecord */
                if(-1 == checkAudioRecordforError(readbytes)) 
                {
                    Log.d(TAG, "========= Read Error =========");
                    return;
                }

                Log.d(TAG, "\n\n===== Read : Sizeof Buffer:"+buffer.length+"=== readbytes: ["+readbytes+"]=====");
                recorder.stop();
                recorder.release();

            }else {
                state = recorder.getState();
                Log.d(TAG, "========= Else Part : state : "+state+"=========");
            }

            Log.d(TAG, "========= Reading Completed =========");


            /** ======== API for Playing ===========  **/

            track = findAudioTrack(track);
            if (track == null) {
                Log.e(TAG, "========= findAudioTrack : Returned Error! ========== ");
                return;
            }

            if (track.STATE_INITIALIZED == track.getState()) 
            {
                writebytes = 0;                             /* Reset write bytes for next Iteration */
                track.play();

                writebytes = track.write(buffer, 0, bufferSize);
                Log.d(TAG, "\n\n===== Write : Sizeof Buffer:"+ bufferSize +"==== writebytes: ["+writebytes+"]======== ");

                /* Error Checking Code for AudioRecord */
                if (-1 == checkAudioTrackforError(writebytes)) 
                {
                    Log.d(TAG, "========= Write Error =========");
                    return;
                }

                track.stop();
                track.release();
            }
            else {
                state = track.getState();
                Log.d(TAG, "========= Else Part : state : "+state+"=========");
            }

        } while(true);
    }
    return;
}
/* Method for Initializing   AudioTrack for Playing Purpose */
public AudioTrack findAudioTrack (AudioTrack track)
{
    Log.d(TAG, "========== Initialising Playing API ============");

    bufferSize = AudioTrack.getMinBufferSize(8000, 
            AudioFormat.CHANNEL_OUT_MONO, 
            AudioFormat.ENCODING_PCM_16BIT);        /* Return 640 */

    Log.d(TAG, "========= AudioTrack ==> bufferSize : "+bufferSize+"=========");

    if (bufferSize != AudioTrack.ERROR_BAD_VALUE) 
    {
        track = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, 
                AudioFormat.CHANNEL_OUT_MONO, 
                AudioFormat.ENCODING_PCM_16BIT, bufferSize, 
                AudioTrack.MODE_STREAM);

        if (track.getState() == AudioTrack.STATE_UNINITIALIZED) {
            Log.e(TAG, "=========== AudioTrack UnInitilaised ===========");
            return null;
        }
    }
    return track;
}

/* Method for Initializing AudioRecord for Recording Purpose */
public AudioRecord findAudioRecord (AudioRecord recorder)
{
    Log.d(TAG, "======== Initializing Record API ==========");

    bufferSize = AudioRecord.getMinBufferSize(8000,
            AudioFormat.CHANNEL_IN_MONO,
            AudioFormat.ENCODING_PCM_16BIT);


    if (bufferSize != AudioRecord.ERROR_BAD_VALUE) 
    {
        recorder = new AudioRecord(AudioSource.DEFAULT, 8000, 
                AudioFormat.CHANNEL_IN_MONO,
                AudioFormat.ENCODING_PCM_16BIT, bufferSize);

        if (recorder.getState() == AudioRecord.STATE_UNINITIALIZED) {
            Log.e(TAG, "========= AudioRecord UnInitilaised ============= ");
            return null;
        }
    }
    return recorder;
}

/* Method for Error Checking - AudioRecord */
public int checkAudioRecordforError(int readbytes)
{
    if (readbytes ==  recorder.ERROR_INVALID_OPERATION || readbytes ==  recorder.ERROR_BAD_VALUE) 
    {
        if(readbytes == AudioRecord.ERROR_INVALID_OPERATION)
            Log.d(TAG, "========= read Error : ERROR_INVALID_OPERATION ===========");
        else if (readbytes == AudioRecord.ERROR_BAD_VALUE)
            Log.d(TAG, "========= read Error : ERROR_BAD_VALUE ===========");
        else if (readbytes == AudioRecord.ERROR)
            Log.d(TAG, "========= read Error : ERROR Unknown ===========");
        return -1;
    }
    return readbytes;
}

/* Method for Error Checking - AudioTrack */
public int checkAudioTrackforError(int writebytes)
{
    if (writebytes ==  track.ERROR_INVALID_OPERATION || writebytes ==  track.ERROR_BAD_VALUE)
    {
        if(writebytes == track.ERROR_INVALID_OPERATION)
            Log.d(TAG, "========= read Error : ERROR_INVALID_OPERATION ===========");
        else if (writebytes == track.ERROR_BAD_VALUE)
            Log.d(TAG, "========= read Error : ERROR_BAD_VALUE ===========");
        else if (writebytes == track.ERROR)
            Log.d(TAG, "========= read Error : ERROR Unknown ===========");
        return -1;
    }
    return writebytes;
}

/* Method for Mapping Button Click */
private View.OnClickListener btnClick = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        switch(v.getId()){
        case R.id.StartButton:
        {
            Log.d(TAG, "======= Start Recording =======");
            isRunning = true;
            Log.d(TAG, "========== isRunning = true =============");
            run_loop (isRunning);
            enableButton(R.id.StartButton,false);
            enableButton(R.id.StopButton,true);
            break;
        }
        case R.id.StopButton:
        {
            Log.d(TAG, "======== Stop Recording =========");
            isRunning = false;
            Log.d(TAG, "========== isRunning = false =============");
            run_loop (isRunning);
            enableButton(R.id.StopButton,false);
            enableButton(R.id.StartButton,true);
            break;
        }
        }
    }
}; 
/* Function to Enable/Disable Buttons */
private void enableButton(int id,boolean isEnable){
    ((Button)findViewById(id)).setEnabled(isEnable);
}
}

There is no read write failure anywhere.

Logcat Output:

D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ==Starting Application.. ==
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ========Start Recording========
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ========== isRunning = true =============
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ===== Entering Loop ===== 
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): =========== Initializing Record API =======
E/ACDB-LOADER(  213): Error: ACDB AudProc vol returned = -19
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ===== Read : Sizeof Buffer:640=== readbytes: [640]=====
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ========= Reading Completed =========
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ========== Initializing Playing API     ========
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ========= AudioTrack ==> bufferSize : 640=========
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): ===== Write : Sizeof Buffer:640==== writebytes: [640]======== 
D/AUDIO_RECORD_PLAYBACK_SAURABH_BUFFER( 3885): =========Initialising Record API =========
E/ACDB-LOADER(  213): Error: ACDB AudProc vol returned = -19

I need to verify if E/ACDB-LOADER( 213): Error: ACDB AudProc vol returned = -19 is responsible for the same.
The above Audio Configuration is for Google Nexus 5 . Might fails to initialize on other devices.

The Android GUI contains two buttons Start and Stop .

Please help me resolve the above Issue.

The above Issue has been fixed.

The Problem wasn't with :
E/ACDB-LOADER( 213): Error: ACDB AudProc vol returned = -19

I have corrected the Code and Updated it in this Answer: Audio Recording and Streaming in Android

Code Changes:

  1. There is no need to Initialize AudioRecord and AudioTrack Object more than once (Must not be part of loop).
  2. There shouldn't be any delay in Read and Write.
    Only Read/Write should be running in a Loop.

This way I'm able to Record Audio and Play the same in a loop, using a buffer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM