Oferch
Oferch

Reputation: 71

Audio record on Android - long time to preform read operation

I have an android application that records audio with the AudioRecord object and gets the data via the notifications. I request a notification every 64ms, and gets it, but from time to to time, on some of the phones when I do the actual read from the AudioRecorder object, it takes it few seconds to return. Any idea what might lead to such a thing?

Below is a skeleton of what I do.

        private void  GetRecorder()
        {
            int sampleRate = 16000;
            int framePeriod = (int)(sampleRate * 64/ 1000);
            int bufferSize = framePeriod * 16/ 8;

            recorder = new AudioRecord(AudioSource.MIC, sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
            recorder.setPositionNotificationPeriod(framePeriod);
            recorder.setRecordPositionUpdateListener(this.mRecordListener);
        }           

        private OnRecordPositionUpdateListener mRecordListener = new OnRecordPositionUpdateListener() 
        {
            long start = System.currentTimeMillis();
            long readTime = 0;
            long maxReadTime = 0;
            int frames = 0;

            @Override
            public void onPeriodicNotification(AudioRecord local_recorder) 
            {
                int buffPos = 0;
                int framePeriod = (int)(16000 * 64 / 1000);

                long beforeRead = System.currentTimeMillis();
                int readBytes = local_recorder.read(bufferQue.pool[queLocation].audioBuffer, buffPos, Math.min(framePeriod, framePeriod - buffPos));
                long afterRead = System.currentTimeMillis();

                if (afterRead - beforeRead > maxReadTime) maxReadTime = afterRead - beforeRead;
                readTime += afterRead - beforeRead;

                //This section each 10 secs if didn't get enough frame and print the data
                frames++;
                if (System.currentTimeMillis() - start  > 10000)
                {
                  if (frames < 110)
                  {
                      log4j.info("In last 10 secs: " + frames + ", read time was " + readTime + " Max read time was " + maxReadTime);
                  }
                  readTime = 0;
                  maxReadTime = 0;
                  frames = 0;
                  start = System.currentTimeMillis();
                }
             }

            @Override
            public void onMarkerReached(AudioRecord recorder) {
            }

        };

Upvotes: 0

Views: 643

Answers (2)

user3673178
user3673178

Reputation: 11

if you are testing on a physical device with API level >=23 then the read function takes four parameters .. the last one being the option of setting READ_BLOCKING or READ_NONBLOCKING.

Upvotes: 1

Alexandru Circus
Alexandru Circus

Reputation: 5538

local_recorder.read(bufferQue.pool[queLocation].audioBuffer, buffPos, Math.min(framePeriod, framePeriod - buffPos));

read is a blocking method - it will block the thread (main thread in your case) until there are enough data to fill your requested buffersSize - solution is to perform the read in a secondary thread. Put the line I wrote above in a thread - that's it.

You requested: "give me 64 ms of recording". answer:"Ok, but wait until I have enough data. It might be glitches, storming outside, etc, so you will have to wait..." . Conclusion: do a worker thread to wait for it. Resume thread -> read done -> pause thread -> resume again from the listener, -> et

Upvotes: 0

Related Questions