I solved it I am pleased to report and my app now works on all Android
phones Nexus One's LG's, HTC etc:

At last I can answer a question on this forum instead of just posting
them :-) The solution it seems is to request chunks of data from the
record device of size minBufferSize which you get using this code:

static
    {
        minBufferSize = AudioRecord.getMinBufferSize(sampleRate,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
        buffer = new byte[minBufferSize];
    }

If there isnt minBufferSize bytes left, then you have to request the
amount thats left to read. See how I calculate toRead below.
bufferReadResult will return exactly how many bytes were read and this
is what you use to advance your global buffer counter.  Interestingly,
minBufferSize varies quite a bit on the phones I have tested. I copy
the 16 bit PCM audio data into an array of floats as I perform DSP on
the buffer at a later stage (in C++). If anyone is interested in how I
do this let me know and I'd be happy to explain. Here is the full code
for my Record AyncTask class. If anything is not clear, let me know:

package org.tunepal;

import android.app.AlertDialog;
import android.media.AudioRecord;
import android.os.AsyncTask;
import android.media.*;

/**
 *
 * @author Bryan Duggan
 */
public class Recorder extends AsyncTask<Void, Integer, Void>
{

    static int sampleRate = 22050;
    static int recordTime = 12;
    static int numSamples = sampleRate * recordTime;

    public static float[] signal = new float[numSamples];

    static int minBufferSize;
    public static byte[] buffer;

    static
    {
        minBufferSize = AudioRecord.getMinBufferSize(sampleRate,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
        buffer = new byte[minBufferSize];
    }

    String message;
    boolean error = false;

    AudioRecord audioRecord = null;
    private RecordActivity context = null;



    /**
     * @return the recordActivity
     */
    public RecordActivity getRecordActivity()
    {
        return context;
    }

    /**
     * @param recordActivity the recordActivity to set
     */
    public void setRecordActivity(RecordActivity recordActivity)
    {
        this.context = recordActivity;
    }

    public Recorder(RecordActivity recordActivity)
    {
        this.context = recordActivity;
    }

    @Override
    protected void onPostExecute(Void arg)
    {
        context.progress.setProgress(0);
        context.imgRecord.setImageResource(R.drawable.micro_off);
        context.txtStatus.setText("");
        if (!error)
        {
            context.finishedRecording();
        }
        else
        {
            AlertDialog.Builder builder = new
AlertDialog.Builder(context);
            builder.setTitle("Tunepal");
            builder.setMessage(message);
            builder.setPositiveButton("Ok", null);
            builder.setCancelable(true);
            builder.show();
        }
    }

    @Override
    protected void onPreExecute()
    {
        context.imgRecord.setImageResource(R.drawable.micro_no);
        context.progress.setProgress(0);
        context.progress.setMax(sampleRate * recordTime * 2);
        context.txtStatus.setText("");


    }

    @Override
    protected void onCancelled()
    {
        context.progress.setProgress(0);
        context.imgRecord.setImageResource(R.drawable.micro_off);
        context.txtStatus.setText("");
        doneRecording();
    }

    public synchronized void doneRecording()
    {
        if (audioRecord != null)
        {
            try
            {
                audioRecord.stop();
            } catch (IllegalStateException e)
            {
                System.out.println("ALREADY STOPPED");
            }
            audioRecord.release();
            audioRecord = null;
        }
    }

     protected void onProgressUpdate(Integer... progress) {
         context.progress.setProgress(progress[0].intValue());
     }

    @Override
    protected Void doInBackground(Void... arg0)
    {
        try
        {
            System.out.println("Recording started");

        audioRecord = null;
        System.gc();
        int totalBytes = sampleRate * recordTime * 2;
        audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
Config.getInt("SAMPLE_RATE"), AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, totalBytes);
        audioRecord.startRecording();

        int startAt = 0;
        error = false;
        // read in blocks
        while (startAt < totalBytes)
        {
            int toRead = 0;
            if (startAt + minBufferSize >= totalBytes)
            {
                toRead = totalBytes - startAt;
            }
            else
            {
                toRead = minBufferSize;
            }
            int bufferReadResult = audioRecord.read(buffer, 0,
toRead);
            if (bufferReadResult ==
AudioRecord.ERROR_INVALID_OPERATION)
            {
                message = "Sorry! Tunepal had a problem recording:
ERROR_INVALID_OPERATION";
                error = true;
                break;
            }
            if (bufferReadResult == AudioRecord.ERROR_BAD_VALUE)
            {
                message = "Sorry! Tunepal had a problem recording:
ERROR_BAD_VALUE";
                error = true;
                break;
            }
            System.out.println(bufferReadResult + " bytes read");
            if (!isCancelled())
            {
                int signalStart = startAt / 2; // // In samples rather
than bytes
                int frameSize = bufferReadResult / 2; // In samples
                // Copy the frame of audio from the buffer into the
global float buffer
                for (int i = 0; i < frameSize; i++)
                {
                    int signalIndex = signalStart + i;
                    signal[signalIndex] = ((buffer[(i * 2) + 1] << 8)
+ buffer[i * 2]);
                }
                startAt += bufferReadResult;
                publishProgress(new Integer(startAt));
            }
            else
            {
                break;
            }
        }
        if (! isCancelled())
        {
            doneRecording();
        }
        error = false;
        }
        catch (Exception e)
        {
            message = e.getMessage();
            error = true;
        }

        return null;
    }

    void setContext(RecordActivity aThis)
    {
        context = aThis;
    }
}

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to