OSDN Git Service

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