Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.media;
     18 
     19 import java.lang.ref.WeakReference;
     20 import java.nio.ByteBuffer;
     21 
     22 import android.os.Handler;
     23 import android.os.Looper;
     24 import android.os.Message;
     25 import android.util.Log;
     26 
     27 /**
     28  * The AudioRecord class manages the audio resources for Java applications
     29  * to record audio from the audio input hardware of the platform. This is
     30  * achieved by "pulling" (reading) the data from the AudioRecord object. The
     31  * application is responsible for polling the AudioRecord object in time using one of
     32  * the following three methods:  {@link #read(byte[],int, int)}, {@link #read(short[], int, int)}
     33  * or {@link #read(ByteBuffer, int)}. The choice of which method to use will be based
     34  * on the audio data storage format that is the most convenient for the user of AudioRecord.
     35  * <p>Upon creation, an AudioRecord object initializes its associated audio buffer that it will
     36  * fill with the new audio data. The size of this buffer, specified during the construction,
     37  * determines how long an AudioRecord can record before "over-running" data that has not
     38  * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
     39  * the total recording buffer size.
     40  */
     41 public class AudioRecord
     42 {
     43     //---------------------------------------------------------
     44     // Constants
     45     //--------------------
     46     /**
     47      *  indicates AudioRecord state is not successfully initialized.
     48      */
     49     public static final int STATE_UNINITIALIZED = 0;
     50     /**
     51      *  indicates AudioRecord state is ready to be used
     52      */
     53     public static final int STATE_INITIALIZED   = 1;
     54 
     55     /**
     56      * indicates AudioRecord recording state is not recording
     57      */
     58     public static final int RECORDSTATE_STOPPED = 1;  // matches SL_RECORDSTATE_STOPPED
     59     /**
     60      * indicates AudioRecord recording state is recording
     61      */
     62     public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING
     63 
     64     // Error codes:
     65     // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp
     66     /**
     67      * Denotes a successful operation.
     68      */
     69     public static final int SUCCESS                 = 0;
     70     /**
     71      * Denotes a generic operation failure.
     72      */
     73     public static final int ERROR                   = -1;
     74     /**
     75      * Denotes a failure due to the use of an invalid value.
     76      */
     77     public static final int ERROR_BAD_VALUE         = -2;
     78     /**
     79      * Denotes a failure due to the improper use of a method.
     80      */
     81     public static final int ERROR_INVALID_OPERATION = -3;
     82 
     83     private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      = -16;
     84     private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK  = -17;
     85     private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       = -18;
     86     private static final int AUDIORECORD_ERROR_SETUP_INVALIDSOURCE       = -19;
     87     private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    = -20;
     88 
     89     // Events:
     90     // to keep in sync with frameworks/av/include/media/AudioRecord.h
     91     /**
     92      * Event id denotes when record head has reached a previously set marker.
     93      */
     94     private static final int NATIVE_EVENT_MARKER  = 2;
     95     /**
     96      * Event id denotes when previously set update period has elapsed during recording.
     97      */
     98     private static final int NATIVE_EVENT_NEW_POS = 3;
     99 
    100     private final static String TAG = "android.media.AudioRecord";
    101 
    102 
    103     //---------------------------------------------------------
    104     // Used exclusively by native code
    105     //--------------------
    106     /**
    107      * Accessed by native methods: provides access to C++ AudioRecord object
    108      */
    109     @SuppressWarnings("unused")
    110     private int mNativeRecorderInJavaObj;
    111 
    112     /**
    113      * Accessed by native methods: provides access to the callback data.
    114      */
    115     @SuppressWarnings("unused")
    116     private int mNativeCallbackCookie;
    117 
    118 
    119     //---------------------------------------------------------
    120     // Member variables
    121     //--------------------
    122     /**
    123      * The audio data sampling rate in Hz.
    124      */
    125     private int mSampleRate;
    126     /**
    127      * The number of input audio channels (1 is mono, 2 is stereo)
    128      */
    129     private int mChannelCount;
    130     /**
    131      * The audio channel mask
    132      */
    133     private int mChannelMask;
    134     /**
    135      * The encoding of the audio samples.
    136      * @see AudioFormat#ENCODING_PCM_8BIT
    137      * @see AudioFormat#ENCODING_PCM_16BIT
    138      */
    139     private int mAudioFormat;
    140     /**
    141      * Where the audio data is recorded from.
    142      */
    143     private int mRecordSource;
    144     /**
    145      * Indicates the state of the AudioRecord instance.
    146      */
    147     private int mState = STATE_UNINITIALIZED;
    148     /**
    149      * Indicates the recording state of the AudioRecord instance.
    150      */
    151     private int mRecordingState = RECORDSTATE_STOPPED;
    152     /**
    153      * Lock to make sure mRecordingState updates are reflecting the actual state of the object.
    154      */
    155     private final Object mRecordingStateLock = new Object();
    156     /**
    157      * The listener the AudioRecord notifies when the record position reaches a marker
    158      * or for periodic updates during the progression of the record head.
    159      *  @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)
    160      *  @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)
    161      */
    162     private OnRecordPositionUpdateListener mPositionListener = null;
    163     /**
    164      * Lock to protect position listener updates against event notifications
    165      */
    166     private final Object mPositionListenerLock = new Object();
    167     /**
    168      * Handler for marker events coming from the native code
    169      */
    170     private NativeEventHandler mEventHandler = null;
    171     /**
    172      * Looper associated with the thread that creates the AudioRecord instance
    173      */
    174     private Looper mInitializationLooper = null;
    175     /**
    176      * Size of the native audio buffer.
    177      */
    178     private int mNativeBufferSizeInBytes = 0;
    179     /**
    180      * Audio session ID
    181      */
    182     private int mSessionId = 0;
    183 
    184     //---------------------------------------------------------
    185     // Constructor, Finalize
    186     //--------------------
    187     /**
    188      * Class constructor.
    189      * @param audioSource the recording source. See {@link MediaRecorder.AudioSource} for
    190      *    recording source definitions.
    191      * @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only
    192      *   rate that is guaranteed to work on all devices, but other rates such as 22050,
    193      *   16000, and 11025 may work on some devices.
    194      * @param channelConfig describes the configuration of the audio channels.
    195      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
    196      *   {@link AudioFormat#CHANNEL_IN_STEREO}.  {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
    197      *   to work on all devices.
    198      * @param audioFormat the format in which the audio data is represented.
    199      *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
    200      *   {@link AudioFormat#ENCODING_PCM_8BIT}
    201      * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
    202      *   to during the recording. New audio data can be read from this buffer in smaller chunks
    203      *   than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
    204      *   required buffer size for the successful creation of an AudioRecord instance. Using values
    205      *   smaller than getMinBufferSize() will result in an initialization failure.
    206      * @throws java.lang.IllegalArgumentException
    207      */
    208     public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
    209             int bufferSizeInBytes)
    210     throws IllegalArgumentException {
    211         mRecordingState = RECORDSTATE_STOPPED;
    212 
    213         // remember which looper is associated with the AudioRecord instanciation
    214         if ((mInitializationLooper = Looper.myLooper()) == null) {
    215             mInitializationLooper = Looper.getMainLooper();
    216         }
    217 
    218         audioParamCheck(audioSource, sampleRateInHz, channelConfig, audioFormat);
    219 
    220         audioBuffSizeCheck(bufferSizeInBytes);
    221 
    222         // native initialization
    223         int[] session = new int[1];
    224         session[0] = 0;
    225         //TODO: update native initialization when information about hardware init failure
    226         //      due to capture device already open is available.
    227         int initResult = native_setup( new WeakReference<AudioRecord>(this),
    228                 mRecordSource, mSampleRate, mChannelMask, mAudioFormat, mNativeBufferSizeInBytes,
    229                 session);
    230         if (initResult != SUCCESS) {
    231             loge("Error code "+initResult+" when initializing native AudioRecord object.");
    232             return; // with mState == STATE_UNINITIALIZED
    233         }
    234 
    235         mSessionId = session[0];
    236 
    237         mState = STATE_INITIALIZED;
    238     }
    239 
    240 
    241     // Convenience method for the constructor's parameter checks.
    242     // This is where constructor IllegalArgumentException-s are thrown
    243     // postconditions:
    244     //    mRecordSource is valid
    245     //    mChannelCount is valid
    246     //    mChannelMask is valid
    247     //    mAudioFormat is valid
    248     //    mSampleRate is valid
    249     private void audioParamCheck(int audioSource, int sampleRateInHz,
    250                                  int channelConfig, int audioFormat) {
    251 
    252         //--------------
    253         // audio source
    254         if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) ||
    255              ((audioSource > MediaRecorder.getAudioSourceMax()) &&
    256               (audioSource != MediaRecorder.AudioSource.HOTWORD)) )  {
    257             throw new IllegalArgumentException("Invalid audio source.");
    258         }
    259         mRecordSource = audioSource;
    260 
    261         //--------------
    262         // sample rate
    263         if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
    264             throw new IllegalArgumentException(sampleRateInHz
    265                     + "Hz is not a supported sample rate.");
    266         }
    267         mSampleRate = sampleRateInHz;
    268 
    269         //--------------
    270         // channel config
    271         switch (channelConfig) {
    272         case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
    273         case AudioFormat.CHANNEL_IN_MONO:
    274         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
    275             mChannelCount = 1;
    276             mChannelMask = AudioFormat.CHANNEL_IN_MONO;
    277             break;
    278         case AudioFormat.CHANNEL_IN_STEREO:
    279         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
    280             mChannelCount = 2;
    281             mChannelMask = AudioFormat.CHANNEL_IN_STEREO;
    282             break;
    283         case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
    284             mChannelCount = 2;
    285             mChannelMask = channelConfig;
    286             break;
    287         default:
    288             throw new IllegalArgumentException("Unsupported channel configuration.");
    289         }
    290 
    291         //--------------
    292         // audio format
    293         switch (audioFormat) {
    294         case AudioFormat.ENCODING_DEFAULT:
    295             mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
    296             break;
    297         case AudioFormat.ENCODING_PCM_16BIT:
    298         case AudioFormat.ENCODING_PCM_8BIT:
    299             mAudioFormat = audioFormat;
    300             break;
    301         default:
    302             throw new IllegalArgumentException("Unsupported sample encoding."
    303                     + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT.");
    304         }
    305     }
    306 
    307 
    308     // Convenience method for the contructor's audio buffer size check.
    309     // preconditions:
    310     //    mChannelCount is valid
    311     //    mAudioFormat is AudioFormat.ENCODING_PCM_8BIT OR AudioFormat.ENCODING_PCM_16BIT
    312     // postcondition:
    313     //    mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
    314     private void audioBuffSizeCheck(int audioBufferSize) {
    315         // NB: this section is only valid with PCM data.
    316         // To update when supporting compressed formats
    317         int frameSizeInBytes = mChannelCount
    318             * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
    319         if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
    320             throw new IllegalArgumentException("Invalid audio buffer size.");
    321         }
    322 
    323         mNativeBufferSizeInBytes = audioBufferSize;
    324     }
    325 
    326 
    327 
    328     /**
    329      * Releases the native AudioRecord resources.
    330      * The object can no longer be used and the reference should be set to null
    331      * after a call to release()
    332      */
    333     public void release() {
    334         try {
    335             stop();
    336         } catch(IllegalStateException ise) {
    337             // don't raise an exception, we're releasing the resources.
    338         }
    339         native_release();
    340         mState = STATE_UNINITIALIZED;
    341     }
    342 
    343 
    344     @Override
    345     protected void finalize() {
    346         native_finalize();
    347     }
    348 
    349 
    350     //--------------------------------------------------------------------------
    351     // Getters
    352     //--------------------
    353     /**
    354      * Returns the configured audio data sample rate in Hz
    355      */
    356     public int getSampleRate() {
    357         return mSampleRate;
    358     }
    359 
    360     /**
    361      * Returns the audio recording source.
    362      * @see MediaRecorder.AudioSource
    363      */
    364     public int getAudioSource() {
    365         return mRecordSource;
    366     }
    367 
    368     /**
    369      * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT}
    370      * and {@link AudioFormat#ENCODING_PCM_8BIT}.
    371      */
    372     public int getAudioFormat() {
    373         return mAudioFormat;
    374     }
    375 
    376     /**
    377      * Returns the configured channel configuration.
    378      * See {@link AudioFormat#CHANNEL_IN_MONO}
    379      * and {@link AudioFormat#CHANNEL_IN_STEREO}.
    380      */
    381     public int getChannelConfiguration() {
    382         return mChannelMask;
    383     }
    384 
    385     /**
    386      * Returns the configured number of channels.
    387      */
    388     public int getChannelCount() {
    389         return mChannelCount;
    390     }
    391 
    392     /**
    393      * Returns the state of the AudioRecord instance. This is useful after the
    394      * AudioRecord instance has been created to check if it was initialized
    395      * properly. This ensures that the appropriate hardware resources have been
    396      * acquired.
    397      * @see AudioRecord#STATE_INITIALIZED
    398      * @see AudioRecord#STATE_UNINITIALIZED
    399      */
    400     public int getState() {
    401         return mState;
    402     }
    403 
    404     /**
    405      * Returns the recording state of the AudioRecord instance.
    406      * @see AudioRecord#RECORDSTATE_STOPPED
    407      * @see AudioRecord#RECORDSTATE_RECORDING
    408      */
    409     public int getRecordingState() {
    410         synchronized (mRecordingStateLock) {
    411             return mRecordingState;
    412         }
    413     }
    414 
    415     /**
    416      * Returns the notification marker position expressed in frames.
    417      */
    418     public int getNotificationMarkerPosition() {
    419         return native_get_marker_pos();
    420     }
    421 
    422     /**
    423      * Returns the notification update period expressed in frames.
    424      */
    425     public int getPositionNotificationPeriod() {
    426         return native_get_pos_update_period();
    427     }
    428 
    429     /**
    430      * Returns the minimum buffer size required for the successful creation of an AudioRecord
    431      * object, in byte units.
    432      * Note that this size doesn't guarantee a smooth recording under load, and higher values
    433      * should be chosen according to the expected frequency at which the AudioRecord instance
    434      * will be polled for new data.
    435      * See {@link #AudioRecord(int, int, int, int, int)} for more information on valid
    436      * configuration values.
    437      * @param sampleRateInHz the sample rate expressed in Hertz.
    438      * @param channelConfig describes the configuration of the audio channels.
    439      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
    440      *   {@link AudioFormat#CHANNEL_IN_STEREO}
    441      * @param audioFormat the format in which the audio data is represented.
    442      *   See {@link AudioFormat#ENCODING_PCM_16BIT}.
    443      * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the
    444      *  hardware, or an invalid parameter was passed,
    445      *  or {@link #ERROR} if the implementation was unable to query the hardware for its
    446      *  input properties,
    447      *   or the minimum buffer size expressed in bytes.
    448      * @see #AudioRecord(int, int, int, int, int)
    449      */
    450     static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
    451         int channelCount = 0;
    452         switch (channelConfig) {
    453         case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
    454         case AudioFormat.CHANNEL_IN_MONO:
    455         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
    456             channelCount = 1;
    457             break;
    458         case AudioFormat.CHANNEL_IN_STEREO:
    459         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
    460         case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
    461             channelCount = 2;
    462             break;
    463         case AudioFormat.CHANNEL_INVALID:
    464         default:
    465             loge("getMinBufferSize(): Invalid channel configuration.");
    466             return ERROR_BAD_VALUE;
    467         }
    468 
    469         // PCM_8BIT is not supported at the moment
    470         if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) {
    471             loge("getMinBufferSize(): Invalid audio format.");
    472             return ERROR_BAD_VALUE;
    473         }
    474 
    475         int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
    476         if (size == 0) {
    477             return ERROR_BAD_VALUE;
    478         }
    479         else if (size == -1) {
    480             return ERROR;
    481         }
    482         else {
    483             return size;
    484         }
    485     }
    486 
    487     /**
    488      * Returns the audio session ID.
    489      *
    490      * @return the ID of the audio session this AudioRecord belongs to.
    491      */
    492     public int getAudioSessionId() {
    493         return mSessionId;
    494     }
    495 
    496     //---------------------------------------------------------
    497     // Transport control methods
    498     //--------------------
    499     /**
    500      * Starts recording from the AudioRecord instance.
    501      * @throws IllegalStateException
    502      */
    503     public void startRecording()
    504     throws IllegalStateException {
    505         if (mState != STATE_INITIALIZED) {
    506             throw new IllegalStateException("startRecording() called on an "
    507                     + "uninitialized AudioRecord.");
    508         }
    509 
    510         // start recording
    511         synchronized(mRecordingStateLock) {
    512             if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) {
    513                 mRecordingState = RECORDSTATE_RECORDING;
    514             }
    515         }
    516     }
    517 
    518     /**
    519      * Starts recording from the AudioRecord instance when the specified synchronization event
    520      * occurs on the specified audio session.
    521      * @throws IllegalStateException
    522      * @param syncEvent event that triggers the capture.
    523      * @see MediaSyncEvent
    524      */
    525     public void startRecording(MediaSyncEvent syncEvent)
    526     throws IllegalStateException {
    527         if (mState != STATE_INITIALIZED) {
    528             throw new IllegalStateException("startRecording() called on an "
    529                     + "uninitialized AudioRecord.");
    530         }
    531 
    532         // start recording
    533         synchronized(mRecordingStateLock) {
    534             if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) {
    535                 mRecordingState = RECORDSTATE_RECORDING;
    536             }
    537         }
    538     }
    539 
    540     /**
    541      * Stops recording.
    542      * @throws IllegalStateException
    543      */
    544     public void stop()
    545     throws IllegalStateException {
    546         if (mState != STATE_INITIALIZED) {
    547             throw new IllegalStateException("stop() called on an uninitialized AudioRecord.");
    548         }
    549 
    550         // stop recording
    551         synchronized(mRecordingStateLock) {
    552             native_stop();
    553             mRecordingState = RECORDSTATE_STOPPED;
    554         }
    555     }
    556 
    557 
    558     //---------------------------------------------------------
    559     // Audio data supply
    560     //--------------------
    561     /**
    562      * Reads audio data from the audio hardware for recording into a buffer.
    563      * @param audioData the array to which the recorded audio data is written.
    564      * @param offsetInBytes index in audioData from which the data is written expressed in bytes.
    565      * @param sizeInBytes the number of requested bytes.
    566      * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
    567      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
    568      *    the parameters don't resolve to valid data and indexes.
    569      *    The number of bytes will not exceed sizeInBytes.
    570      */
    571     public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) {
    572         if (mState != STATE_INITIALIZED) {
    573             return ERROR_INVALID_OPERATION;
    574         }
    575 
    576         if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
    577                 || (offsetInBytes + sizeInBytes < 0)  // detect integer overflow
    578                 || (offsetInBytes + sizeInBytes > audioData.length)) {
    579             return ERROR_BAD_VALUE;
    580         }
    581 
    582         return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes);
    583     }
    584 
    585 
    586     /**
    587      * Reads audio data from the audio hardware for recording into a buffer.
    588      * @param audioData the array to which the recorded audio data is written.
    589      * @param offsetInShorts index in audioData from which the data is written expressed in shorts.
    590      * @param sizeInShorts the number of requested shorts.
    591      * @return the number of shorts that were read or or {@link #ERROR_INVALID_OPERATION}
    592      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
    593      *    the parameters don't resolve to valid data and indexes.
    594      *    The number of shorts will not exceed sizeInShorts.
    595      */
    596     public int read(short[] audioData, int offsetInShorts, int sizeInShorts) {
    597         if (mState != STATE_INITIALIZED) {
    598             return ERROR_INVALID_OPERATION;
    599         }
    600 
    601         if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
    602                 || (offsetInShorts + sizeInShorts < 0)  // detect integer overflow
    603                 || (offsetInShorts + sizeInShorts > audioData.length)) {
    604             return ERROR_BAD_VALUE;
    605         }
    606 
    607         return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts);
    608     }
    609 
    610 
    611     /**
    612      * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
    613      * is not a direct buffer, this method will always return 0.
    614      * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
    615      * unchanged after a call to this method.
    616      * @param audioBuffer the direct buffer to which the recorded audio data is written.
    617      * @param sizeInBytes the number of requested bytes.
    618      * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
    619      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
    620      *    the parameters don't resolve to valid data and indexes.
    621      *    The number of bytes will not exceed sizeInBytes.
    622      */
    623     public int read(ByteBuffer audioBuffer, int sizeInBytes) {
    624         if (mState != STATE_INITIALIZED) {
    625             return ERROR_INVALID_OPERATION;
    626         }
    627 
    628         if ( (audioBuffer == null) || (sizeInBytes < 0) ) {
    629             return ERROR_BAD_VALUE;
    630         }
    631 
    632         return native_read_in_direct_buffer(audioBuffer, sizeInBytes);
    633     }
    634 
    635 
    636     //--------------------------------------------------------------------------
    637     // Initialization / configuration
    638     //--------------------
    639     /**
    640      * Sets the listener the AudioRecord notifies when a previously set marker is reached or
    641      * for each periodic record head position update.
    642      * @param listener
    643      */
    644     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener) {
    645         setRecordPositionUpdateListener(listener, null);
    646     }
    647 
    648     /**
    649      * Sets the listener the AudioRecord notifies when a previously set marker is reached or
    650      * for each periodic record head position update.
    651      * Use this method to receive AudioRecord events in the Handler associated with another
    652      * thread than the one in which you created the AudioTrack instance.
    653      * @param listener
    654      * @param handler the Handler that will receive the event notification messages.
    655      */
    656     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener,
    657                                                     Handler handler) {
    658         synchronized (mPositionListenerLock) {
    659 
    660             mPositionListener = listener;
    661 
    662             if (listener != null) {
    663                 if (handler != null) {
    664                     mEventHandler = new NativeEventHandler(this, handler.getLooper());
    665                 } else {
    666                     // no given handler, use the looper the AudioRecord was created in
    667                     mEventHandler = new NativeEventHandler(this, mInitializationLooper);
    668                 }
    669             } else {
    670                 mEventHandler = null;
    671             }
    672         }
    673 
    674     }
    675 
    676 
    677     /**
    678      * Sets the marker position at which the listener is called, if set with
    679      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
    680      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
    681      * @param markerInFrames marker position expressed in frames
    682      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
    683      *  {@link #ERROR_INVALID_OPERATION}
    684      */
    685     public int setNotificationMarkerPosition(int markerInFrames) {
    686         if (mState == STATE_UNINITIALIZED) {
    687             return ERROR_INVALID_OPERATION;
    688         }
    689         return native_set_marker_pos(markerInFrames);
    690     }
    691 
    692 
    693     /**
    694      * Sets the period at which the listener is called, if set with
    695      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
    696      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
    697      * It is possible for notifications to be lost if the period is too small.
    698      * @param periodInFrames update period expressed in frames
    699      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
    700      */
    701     public int setPositionNotificationPeriod(int periodInFrames) {
    702         if (mState == STATE_UNINITIALIZED) {
    703             return ERROR_INVALID_OPERATION;
    704         }
    705         return native_set_pos_update_period(periodInFrames);
    706     }
    707 
    708 
    709     //---------------------------------------------------------
    710     // Interface definitions
    711     //--------------------
    712     /**
    713      * Interface definition for a callback to be invoked when an AudioRecord has
    714      * reached a notification marker set by {@link AudioRecord#setNotificationMarkerPosition(int)}
    715      * or for periodic updates on the progress of the record head, as set by
    716      * {@link AudioRecord#setPositionNotificationPeriod(int)}.
    717      */
    718     public interface OnRecordPositionUpdateListener  {
    719         /**
    720          * Called on the listener to notify it that the previously set marker has been reached
    721          * by the recording head.
    722          */
    723         void onMarkerReached(AudioRecord recorder);
    724 
    725         /**
    726          * Called on the listener to periodically notify it that the record head has reached
    727          * a multiple of the notification period.
    728          */
    729         void onPeriodicNotification(AudioRecord recorder);
    730     }
    731 
    732 
    733 
    734     //---------------------------------------------------------
    735     // Inner classes
    736     //--------------------
    737 
    738     /**
    739      * Helper class to handle the forwarding of native events to the appropriate listener
    740      * (potentially) handled in a different thread
    741      */
    742     private class NativeEventHandler extends Handler {
    743 
    744         private final AudioRecord mAudioRecord;
    745 
    746         NativeEventHandler(AudioRecord recorder, Looper looper) {
    747             super(looper);
    748             mAudioRecord = recorder;
    749         }
    750 
    751         @Override
    752         public void handleMessage(Message msg) {
    753             OnRecordPositionUpdateListener listener = null;
    754             synchronized (mPositionListenerLock) {
    755                 listener = mAudioRecord.mPositionListener;
    756             }
    757 
    758             switch (msg.what) {
    759             case NATIVE_EVENT_MARKER:
    760                 if (listener != null) {
    761                     listener.onMarkerReached(mAudioRecord);
    762                 }
    763                 break;
    764             case NATIVE_EVENT_NEW_POS:
    765                 if (listener != null) {
    766                     listener.onPeriodicNotification(mAudioRecord);
    767                 }
    768                 break;
    769             default:
    770                 loge("Unknown native event type: " + msg.what);
    771                 break;
    772             }
    773         }
    774     };
    775 
    776 
    777     //---------------------------------------------------------
    778     // Java methods called from the native side
    779     //--------------------
    780     @SuppressWarnings("unused")
    781     private static void postEventFromNative(Object audiorecord_ref,
    782             int what, int arg1, int arg2, Object obj) {
    783         //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
    784         AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get();
    785         if (recorder == null) {
    786             return;
    787         }
    788 
    789         if (recorder.mEventHandler != null) {
    790             Message m =
    791                 recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj);
    792             recorder.mEventHandler.sendMessage(m);
    793         }
    794 
    795     }
    796 
    797 
    798     //---------------------------------------------------------
    799     // Native methods called from the Java side
    800     //--------------------
    801 
    802     private native final int native_setup(Object audiorecord_this,
    803             int recordSource, int sampleRate, int nbChannels, int audioFormat,
    804             int buffSizeInBytes, int[] sessionId);
    805 
    806     private native final void native_finalize();
    807 
    808     private native final void native_release();
    809 
    810     private native final int native_start(int syncEvent, int sessionId);
    811 
    812     private native final void native_stop();
    813 
    814     private native final int native_read_in_byte_array(byte[] audioData,
    815             int offsetInBytes, int sizeInBytes);
    816 
    817     private native final int native_read_in_short_array(short[] audioData,
    818             int offsetInShorts, int sizeInShorts);
    819 
    820     private native final int native_read_in_direct_buffer(Object jBuffer, int sizeInBytes);
    821 
    822     private native final int native_set_marker_pos(int marker);
    823     private native final int native_get_marker_pos();
    824 
    825     private native final int native_set_pos_update_period(int updatePeriod);
    826     private native final int native_get_pos_update_period();
    827 
    828     static private native final int native_get_min_buff_size(
    829             int sampleRateInHz, int channelCount, int audioFormat);
    830 
    831 
    832     //---------------------------------------------------------
    833     // Utility methods
    834     //------------------
    835 
    836     private static void logd(String msg) {
    837         Log.d(TAG, msg);
    838     }
    839 
    840     private static void loge(String msg) {
    841         Log.e(TAG, msg);
    842     }
    843 
    844 }
    845