• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)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
audioParamCheck(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat)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             throw (new IllegalArgumentException("Invalid audio source."));
257         } else {
258             mRecordSource = audioSource;
259         }
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         } else {
267             mSampleRate = sampleRateInHz;
268         }
269 
270         //--------------
271         // channel config
272         mChannelConfiguration = channelConfig;
273 
274         switch (channelConfig) {
275         case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
276         case AudioFormat.CHANNEL_IN_MONO:
277         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
278             mChannelCount = 1;
279             mChannels = AudioFormat.CHANNEL_IN_MONO;
280             break;
281         case AudioFormat.CHANNEL_IN_STEREO:
282         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
283             mChannelCount = 2;
284             mChannels = AudioFormat.CHANNEL_IN_STEREO;
285             break;
286         default:
287             mChannelCount = 0;
288             mChannels = AudioFormat.CHANNEL_INVALID;
289             mChannelConfiguration = AudioFormat.CHANNEL_INVALID;
290             throw (new IllegalArgumentException("Unsupported channel configuration."));
291         }
292 
293         //--------------
294         // audio format
295         switch (audioFormat) {
296         case AudioFormat.ENCODING_DEFAULT:
297             mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
298             break;
299         case AudioFormat.ENCODING_PCM_16BIT:
300         case AudioFormat.ENCODING_PCM_8BIT:
301             mAudioFormat = audioFormat;
302             break;
303         default:
304             mAudioFormat = AudioFormat.ENCODING_INVALID;
305         throw (new IllegalArgumentException("Unsupported sample encoding."
306                 + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT."));
307         }
308     }
309 
310 
311     // Convenience method for the contructor's audio buffer size check.
312     // preconditions:
313     //    mChannelCount is valid
314     //    mAudioFormat is AudioFormat.ENCODING_PCM_8BIT OR AudioFormat.ENCODING_PCM_16BIT
315     // postcondition:
316     //    mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
audioBuffSizeCheck(int audioBufferSize)317     private void audioBuffSizeCheck(int audioBufferSize) {
318         // NB: this section is only valid with PCM data.
319         // To update when supporting compressed formats
320         int frameSizeInBytes = mChannelCount
321             * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
322         if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
323             throw (new IllegalArgumentException("Invalid audio buffer size."));
324         }
325 
326         mNativeBufferSizeInBytes = audioBufferSize;
327     }
328 
329 
330 
331     /**
332      * Releases the native AudioRecord resources.
333      * The object can no longer be used and the reference should be set to null
334      * after a call to release()
335      */
release()336     public void release() {
337         try {
338             stop();
339         } catch(IllegalStateException ise) {
340             // don't raise an exception, we're releasing the resources.
341         }
342         native_release();
343         mState = STATE_UNINITIALIZED;
344     }
345 
346 
347     @Override
finalize()348     protected void finalize() {
349         native_finalize();
350     }
351 
352 
353     //--------------------------------------------------------------------------
354     // Getters
355     //--------------------
356     /**
357      * Returns the configured audio data sample rate in Hz
358      */
getSampleRate()359     public int getSampleRate() {
360         return mSampleRate;
361     }
362 
363     /**
364      * Returns the audio recording source.
365      * @see MediaRecorder.AudioSource
366      */
getAudioSource()367     public int getAudioSource() {
368         return mRecordSource;
369     }
370 
371     /**
372      * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT}
373      * and {@link AudioFormat#ENCODING_PCM_8BIT}.
374      */
getAudioFormat()375     public int getAudioFormat() {
376         return mAudioFormat;
377     }
378 
379     /**
380      * Returns the configured channel configuration.
381      * See {@link AudioFormat#CHANNEL_IN_MONO}
382      * and {@link AudioFormat#CHANNEL_IN_STEREO}.
383      */
getChannelConfiguration()384     public int getChannelConfiguration() {
385         return mChannelConfiguration;
386     }
387 
388     /**
389      * Returns the configured number of channels.
390      */
getChannelCount()391     public int getChannelCount() {
392         return mChannelCount;
393     }
394 
395     /**
396      * Returns the state of the AudioRecord instance. This is useful after the
397      * AudioRecord instance has been created to check if it was initialized
398      * properly. This ensures that the appropriate hardware resources have been
399      * acquired.
400      * @see AudioRecord#STATE_INITIALIZED
401      * @see AudioRecord#STATE_UNINITIALIZED
402      */
getState()403     public int getState() {
404         return mState;
405     }
406 
407     /**
408      * Returns the recording state of the AudioRecord instance.
409      * @see AudioRecord#RECORDSTATE_STOPPED
410      * @see AudioRecord#RECORDSTATE_RECORDING
411      */
getRecordingState()412     public int getRecordingState() {
413         return mRecordingState;
414     }
415 
416     /**
417      * Returns the notification marker position expressed in frames.
418      */
getNotificationMarkerPosition()419     public int getNotificationMarkerPosition() {
420         return native_get_marker_pos();
421     }
422 
423     /**
424      * Returns the notification update period expressed in frames.
425      */
getPositionNotificationPeriod()426     public int getPositionNotificationPeriod() {
427         return native_get_pos_update_period();
428     }
429 
430     /**
431      * Returns the minimum buffer size required for the successful creation of an AudioRecord
432      * object.
433      * Note that this size doesn't guarantee a smooth recording under load, and higher values
434      * should be chosen according to the expected frequency at which the AudioRecord instance
435      * will be polled for new data.
436      * @param sampleRateInHz the sample rate expressed in Hertz.
437      * @param channelConfig describes the configuration of the audio channels.
438      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
439      *   {@link AudioFormat#CHANNEL_IN_STEREO}
440      * @param audioFormat the format in which the audio data is represented.
441      *   See {@link AudioFormat#ENCODING_PCM_16BIT}.
442      * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the
443      *  hardware, or an invalid parameter was passed,
444      *  or {@link #ERROR} if the implementation was unable to query the hardware for its
445      *  output properties,
446      *   or the minimum buffer size expressed in bytes.
447      */
getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)448     static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
449         int channelCount = 0;
450         switch(channelConfig) {
451         case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
452         case AudioFormat.CHANNEL_IN_MONO:
453         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
454             channelCount = 1;
455             break;
456         case AudioFormat.CHANNEL_IN_STEREO:
457         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
458             channelCount = 2;
459             break;
460         case AudioFormat.CHANNEL_INVALID:
461         default:
462             loge("getMinBufferSize(): Invalid channel configuration.");
463             return AudioRecord.ERROR_BAD_VALUE;
464         }
465 
466         // PCM_8BIT is not supported at the moment
467         if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) {
468             loge("getMinBufferSize(): Invalid audio format.");
469             return AudioRecord.ERROR_BAD_VALUE;
470         }
471 
472         int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
473         if (size == 0) {
474             return AudioRecord.ERROR_BAD_VALUE;
475         }
476         else if (size == -1) {
477             return AudioRecord.ERROR;
478         }
479         else {
480             return size;
481         }
482     }
483 
484 
485     //---------------------------------------------------------
486     // Transport control methods
487     //--------------------
488     /**
489      * Starts recording from the AudioRecord instance.
490      * @throws IllegalStateException
491      */
startRecording()492     public void startRecording()
493     throws IllegalStateException {
494         if (mState != STATE_INITIALIZED) {
495             throw(new IllegalStateException("startRecording() called on an "
496                     +"uninitialized AudioRecord."));
497         }
498 
499         // start recording
500         synchronized(mRecordingStateLock) {
501             native_start();
502             mRecordingState = RECORDSTATE_RECORDING;
503         }
504     }
505 
506 
507 
508     /**
509      * Stops recording.
510      * @throws IllegalStateException
511      */
stop()512     public void stop()
513     throws IllegalStateException {
514         if (mState != STATE_INITIALIZED) {
515             throw(new IllegalStateException("stop() called on an uninitialized AudioRecord."));
516         }
517 
518         // stop recording
519         synchronized(mRecordingStateLock) {
520             native_stop();
521             mRecordingState = RECORDSTATE_STOPPED;
522         }
523     }
524 
525 
526     //---------------------------------------------------------
527     // Audio data supply
528     //--------------------
529     /**
530      * Reads audio data from the audio hardware for recording into a buffer.
531      * @param audioData the array to which the recorded audio data is written.
532      * @param offsetInBytes index in audioData from which the data is written expressed in bytes.
533      * @param sizeInBytes the number of requested bytes.
534      * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
535      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
536      *    the parameters don't resolve to valid data and indexes.
537      *    The number of bytes will not exceed sizeInBytes.
538      */
read(byte[] audioData, int offsetInBytes, int sizeInBytes)539     public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) {
540         if (mState != STATE_INITIALIZED) {
541             return ERROR_INVALID_OPERATION;
542         }
543 
544         if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
545                 || (offsetInBytes + sizeInBytes > audioData.length)) {
546             return ERROR_BAD_VALUE;
547         }
548 
549         return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes);
550     }
551 
552 
553     /**
554      * Reads audio data from the audio hardware for recording into a buffer.
555      * @param audioData the array to which the recorded audio data is written.
556      * @param offsetInShorts index in audioData from which the data is written expressed in shorts.
557      * @param sizeInShorts the number of requested shorts.
558      * @return the number of shorts that were read or or {@link #ERROR_INVALID_OPERATION}
559      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
560      *    the parameters don't resolve to valid data and indexes.
561      *    The number of shorts will not exceed sizeInShorts.
562      */
read(short[] audioData, int offsetInShorts, int sizeInShorts)563     public int read(short[] audioData, int offsetInShorts, int sizeInShorts) {
564         if (mState != STATE_INITIALIZED) {
565             return ERROR_INVALID_OPERATION;
566         }
567 
568         if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
569                 || (offsetInShorts + sizeInShorts > audioData.length)) {
570             return ERROR_BAD_VALUE;
571         }
572 
573         return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts);
574     }
575 
576 
577     /**
578      * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
579      * is not a direct buffer, this method will always return 0.
580      * @param audioBuffer the direct buffer to which the recorded audio data is written.
581      * @param sizeInBytes the number of requested bytes.
582      * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
583      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
584      *    the parameters don't resolve to valid data and indexes.
585      *    The number of bytes will not exceed sizeInBytes.
586      */
read(ByteBuffer audioBuffer, int sizeInBytes)587     public int read(ByteBuffer audioBuffer, int sizeInBytes) {
588         if (mState != STATE_INITIALIZED) {
589             return ERROR_INVALID_OPERATION;
590         }
591 
592         if ( (audioBuffer == null) || (sizeInBytes < 0) ) {
593             return ERROR_BAD_VALUE;
594         }
595 
596         return native_read_in_direct_buffer(audioBuffer, sizeInBytes);
597     }
598 
599 
600     //--------------------------------------------------------------------------
601     // Initialization / configuration
602     //--------------------
603     /**
604      * Sets the listener the AudioRecord notifies when a previously set marker is reached or
605      * for each periodic record head position update.
606      * @param listener
607      */
setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener)608     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener) {
609         setRecordPositionUpdateListener(listener, null);
610     }
611 
612     /**
613      * Sets the listener the AudioRecord notifies when a previously set marker is reached or
614      * for each periodic record head position update.
615      * Use this method to receive AudioRecord events in the Handler associated with another
616      * thread than the one in which you created the AudioTrack instance.
617      * @param listener
618      * @param handler the Handler that will receive the event notification messages.
619      */
setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, Handler handler)620     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener,
621                                                     Handler handler) {
622         synchronized (mPositionListenerLock) {
623 
624             mPositionListener = listener;
625 
626             if (listener != null) {
627                 if (handler != null) {
628                     mEventHandler = new NativeEventHandler(this, handler.getLooper());
629                 } else {
630                     // no given handler, use the looper the AudioRecord was created in
631                     mEventHandler = new NativeEventHandler(this, mInitializationLooper);
632                 }
633             } else {
634                 mEventHandler = null;
635             }
636         }
637 
638     }
639 
640 
641     /**
642      * Sets the marker position at which the listener is called, if set with
643      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
644      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
645      * @param markerInFrames marker position expressed in frames
646      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
647      *  {@link #ERROR_INVALID_OPERATION}
648      */
setNotificationMarkerPosition(int markerInFrames)649     public int setNotificationMarkerPosition(int markerInFrames) {
650         return native_set_marker_pos(markerInFrames);
651     }
652 
653 
654     /**
655      * Sets the period at which the listener is called, if set with
656      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
657      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
658      * @param periodInFrames update period expressed in frames
659      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
660      */
setPositionNotificationPeriod(int periodInFrames)661     public int setPositionNotificationPeriod(int periodInFrames) {
662         return native_set_pos_update_period(periodInFrames);
663     }
664 
665 
666     //---------------------------------------------------------
667     // Interface definitions
668     //--------------------
669     /**
670      * Interface definition for a callback to be invoked when an AudioRecord has
671      * reached a notification marker set by {@link AudioRecord#setNotificationMarkerPosition(int)}
672      * or for periodic updates on the progress of the record head, as set by
673      * {@link AudioRecord#setPositionNotificationPeriod(int)}.
674      */
675     public interface OnRecordPositionUpdateListener  {
676         /**
677          * Called on the listener to notify it that the previously set marker has been reached
678          * by the recording head.
679          */
onMarkerReached(AudioRecord recorder)680         void onMarkerReached(AudioRecord recorder);
681 
682         /**
683          * Called on the listener to periodically notify it that the record head has reached
684          * a multiple of the notification period.
685          */
onPeriodicNotification(AudioRecord recorder)686         void onPeriodicNotification(AudioRecord recorder);
687     }
688 
689 
690 
691     //---------------------------------------------------------
692     // Inner classes
693     //--------------------
694 
695     /**
696      * Helper class to handle the forwarding of native events to the appropriate listener
697      * (potentially) handled in a different thread
698      */
699     private class NativeEventHandler extends Handler {
700 
701         private final AudioRecord mAudioRecord;
702 
NativeEventHandler(AudioRecord recorder, Looper looper)703         NativeEventHandler(AudioRecord recorder, Looper looper) {
704             super(looper);
705             mAudioRecord = recorder;
706         }
707 
708         @Override
handleMessage(Message msg)709         public void handleMessage(Message msg) {
710             OnRecordPositionUpdateListener listener = null;
711             synchronized (mPositionListenerLock) {
712                 listener = mAudioRecord.mPositionListener;
713             }
714 
715             switch(msg.what) {
716             case NATIVE_EVENT_MARKER:
717                 if (listener != null) {
718                     listener.onMarkerReached(mAudioRecord);
719                 }
720                 break;
721             case NATIVE_EVENT_NEW_POS:
722                 if (listener != null) {
723                     listener.onPeriodicNotification(mAudioRecord);
724                 }
725                 break;
726             default:
727                 Log.e(TAG, "[ android.media.AudioRecord.NativeEventHandler ] " +
728                         "Unknown event type: " + msg.what);
729             break;
730             }
731         }
732     };
733 
734 
735     //---------------------------------------------------------
736     // Java methods called from the native side
737     //--------------------
738     @SuppressWarnings("unused")
postEventFromNative(Object audiorecord_ref, int what, int arg1, int arg2, Object obj)739     private static void postEventFromNative(Object audiorecord_ref,
740             int what, int arg1, int arg2, Object obj) {
741         //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
742         AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get();
743         if (recorder == null) {
744             return;
745         }
746 
747         if (recorder.mEventHandler != null) {
748             Message m =
749                 recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj);
750             recorder.mEventHandler.sendMessage(m);
751         }
752 
753     }
754 
755 
756     //---------------------------------------------------------
757     // Native methods called from the Java side
758     //--------------------
759 
native_setup(Object audiorecord_this, int recordSource, int sampleRate, int nbChannels, int audioFormat, int buffSizeInBytes)760     private native final int native_setup(Object audiorecord_this,
761             int recordSource, int sampleRate, int nbChannels, int audioFormat, int buffSizeInBytes);
762 
native_finalize()763     private native final void native_finalize();
764 
native_release()765     private native final void native_release();
766 
native_start()767     private native final void native_start();
768 
native_stop()769     private native final void native_stop();
770 
native_read_in_byte_array(byte[] audioData, int offsetInBytes, int sizeInBytes)771     private native final int native_read_in_byte_array(byte[] audioData,
772             int offsetInBytes, int sizeInBytes);
773 
native_read_in_short_array(short[] audioData, int offsetInShorts, int sizeInShorts)774     private native final int native_read_in_short_array(short[] audioData,
775             int offsetInShorts, int sizeInShorts);
776 
native_read_in_direct_buffer(Object jBuffer, int sizeInBytes)777     private native final int native_read_in_direct_buffer(Object jBuffer, int sizeInBytes);
778 
native_set_marker_pos(int marker)779     private native final int native_set_marker_pos(int marker);
native_get_marker_pos()780     private native final int native_get_marker_pos();
781 
native_set_pos_update_period(int updatePeriod)782     private native final int native_set_pos_update_period(int updatePeriod);
native_get_pos_update_period()783     private native final int native_get_pos_update_period();
784 
native_get_min_buff_size( int sampleRateInHz, int channelCount, int audioFormat)785     static private native final int native_get_min_buff_size(
786             int sampleRateInHz, int channelCount, int audioFormat);
787 
788 
789     //---------------------------------------------------------
790     // Utility methods
791     //------------------
792 
logd(String msg)793     private static void logd(String msg) {
794         Log.d(TAG, "[ android.media.AudioRecord ] " + msg);
795     }
796 
loge(String msg)797     private static void loge(String msg) {
798         Log.e(TAG, "[ android.media.AudioRecord ] " + msg);
799     }
800 
801 }
802 
803