• 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.annotation.Retention;
20 import java.lang.annotation.RetentionPolicy;
21 import java.lang.ref.WeakReference;
22 import java.nio.ByteBuffer;
23 import java.util.Collection;
24 import java.util.Iterator;
25 
26 import android.annotation.IntDef;
27 import android.annotation.NonNull;
28 import android.annotation.SystemApi;
29 import android.app.ActivityThread;
30 import android.os.Binder;
31 import android.os.Handler;
32 import android.os.IBinder;
33 import android.os.Looper;
34 import android.os.Message;
35 import android.os.RemoteException;
36 import android.os.ServiceManager;
37 import android.util.ArrayMap;
38 import android.util.Log;
39 
40 import com.android.internal.annotations.GuardedBy;
41 
42 /**
43  * The AudioRecord class manages the audio resources for Java applications
44  * to record audio from the audio input hardware of the platform. This is
45  * achieved by "pulling" (reading) the data from the AudioRecord object. The
46  * application is responsible for polling the AudioRecord object in time using one of
47  * the following three methods:  {@link #read(byte[],int, int)}, {@link #read(short[], int, int)}
48  * or {@link #read(ByteBuffer, int)}. The choice of which method to use will be based
49  * on the audio data storage format that is the most convenient for the user of AudioRecord.
50  * <p>Upon creation, an AudioRecord object initializes its associated audio buffer that it will
51  * fill with the new audio data. The size of this buffer, specified during the construction,
52  * determines how long an AudioRecord can record before "over-running" data that has not
53  * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
54  * the total recording buffer size.
55  */
56 public class AudioRecord implements AudioRouting
57 {
58     //---------------------------------------------------------
59     // Constants
60     //--------------------
61 
62 
63     /**
64      *  indicates AudioRecord state is not successfully initialized.
65      */
66     public static final int STATE_UNINITIALIZED = 0;
67     /**
68      *  indicates AudioRecord state is ready to be used
69      */
70     public static final int STATE_INITIALIZED   = 1;
71 
72     /**
73      * indicates AudioRecord recording state is not recording
74      */
75     public static final int RECORDSTATE_STOPPED = 1;  // matches SL_RECORDSTATE_STOPPED
76     /**
77      * indicates AudioRecord recording state is recording
78      */
79     public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING
80 
81     /**
82      * Denotes a successful operation.
83      */
84     public  static final int SUCCESS                               = AudioSystem.SUCCESS;
85     /**
86      * Denotes a generic operation failure.
87      */
88     public  static final int ERROR                                 = AudioSystem.ERROR;
89     /**
90      * Denotes a failure due to the use of an invalid value.
91      */
92     public  static final int ERROR_BAD_VALUE                       = AudioSystem.BAD_VALUE;
93     /**
94      * Denotes a failure due to the improper use of a method.
95      */
96     public  static final int ERROR_INVALID_OPERATION               = AudioSystem.INVALID_OPERATION;
97     /**
98      * An error code indicating that the object reporting it is no longer valid and needs to
99      * be recreated.
100      */
101     public  static final int ERROR_DEAD_OBJECT                     = AudioSystem.DEAD_OBJECT;
102 
103     // Error codes:
104     // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp
105     private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      = -16;
106     private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK  = -17;
107     private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       = -18;
108     private static final int AUDIORECORD_ERROR_SETUP_INVALIDSOURCE       = -19;
109     private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    = -20;
110 
111     // Events:
112     // to keep in sync with frameworks/av/include/media/AudioRecord.h
113     /**
114      * Event id denotes when record head has reached a previously set marker.
115      */
116     private static final int NATIVE_EVENT_MARKER  = 2;
117     /**
118      * Event id denotes when previously set update period has elapsed during recording.
119      */
120     private static final int NATIVE_EVENT_NEW_POS = 3;
121 
122     private final static String TAG = "android.media.AudioRecord";
123 
124     /** @hide */
125     public final static String SUBMIX_FIXED_VOLUME = "fixedVolume";
126 
127     /** @hide */
128     @IntDef({
129         READ_BLOCKING,
130         READ_NON_BLOCKING
131     })
132     @Retention(RetentionPolicy.SOURCE)
133     public @interface ReadMode {}
134 
135     /**
136      * The read mode indicating the read operation will block until all data
137      * requested has been read.
138      */
139     public final static int READ_BLOCKING = 0;
140 
141     /**
142      * The read mode indicating the read operation will return immediately after
143      * reading as much audio data as possible without blocking.
144      */
145     public final static int READ_NON_BLOCKING = 1;
146 
147     //---------------------------------------------------------
148     // Used exclusively by native code
149     //--------------------
150     /**
151      * Accessed by native methods: provides access to C++ AudioRecord object
152      */
153     @SuppressWarnings("unused")
154     private long mNativeRecorderInJavaObj;
155 
156     /**
157      * Accessed by native methods: provides access to the callback data.
158      */
159     @SuppressWarnings("unused")
160     private long mNativeCallbackCookie;
161 
162     /**
163      * Accessed by native methods: provides access to the JNIDeviceCallback instance.
164      */
165     @SuppressWarnings("unused")
166     private long mNativeDeviceCallback;
167 
168 
169     //---------------------------------------------------------
170     // Member variables
171     //--------------------
172     /**
173      * The audio data sampling rate in Hz.
174      * Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}.
175      */
176     private int mSampleRate; // initialized by all constructors via audioParamCheck()
177     /**
178      * The number of input audio channels (1 is mono, 2 is stereo)
179      */
180     private int mChannelCount;
181     /**
182      * The audio channel position mask
183      */
184     private int mChannelMask;
185     /**
186      * The audio channel index mask
187      */
188     private int mChannelIndexMask;
189     /**
190      * The encoding of the audio samples.
191      * @see AudioFormat#ENCODING_PCM_8BIT
192      * @see AudioFormat#ENCODING_PCM_16BIT
193      * @see AudioFormat#ENCODING_PCM_FLOAT
194      */
195     private int mAudioFormat;
196     /**
197      * Where the audio data is recorded from.
198      */
199     private int mRecordSource;
200     /**
201      * Indicates the state of the AudioRecord instance.
202      */
203     private int mState = STATE_UNINITIALIZED;
204     /**
205      * Indicates the recording state of the AudioRecord instance.
206      */
207     private int mRecordingState = RECORDSTATE_STOPPED;
208     /**
209      * Lock to make sure mRecordingState updates are reflecting the actual state of the object.
210      */
211     private final Object mRecordingStateLock = new Object();
212     /**
213      * The listener the AudioRecord notifies when the record position reaches a marker
214      * or for periodic updates during the progression of the record head.
215      *  @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)
216      *  @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)
217      */
218     private OnRecordPositionUpdateListener mPositionListener = null;
219     /**
220      * Lock to protect position listener updates against event notifications
221      */
222     private final Object mPositionListenerLock = new Object();
223     /**
224      * Handler for marker events coming from the native code
225      */
226     private NativeEventHandler mEventHandler = null;
227     /**
228      * Looper associated with the thread that creates the AudioRecord instance
229      */
230     private Looper mInitializationLooper = null;
231     /**
232      * Size of the native audio buffer.
233      */
234     private int mNativeBufferSizeInBytes = 0;
235     /**
236      * Audio session ID
237      */
238     private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
239     /**
240      * AudioAttributes
241      */
242     private AudioAttributes mAudioAttributes;
243     private boolean mIsSubmixFullVolume = false;
244 
245     //---------------------------------------------------------
246     // Constructor, Finalize
247     //--------------------
248     /**
249      * Class constructor.
250      * Though some invalid parameters will result in an {@link IllegalArgumentException} exception,
251      * other errors do not.  Thus you should call {@link #getState()} immediately after construction
252      * to confirm that the object is usable.
253      * @param audioSource the recording source.
254      *   See {@link MediaRecorder.AudioSource} for the recording source definitions.
255      * @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only
256      *   rate that is guaranteed to work on all devices, but other rates such as 22050,
257      *   16000, and 11025 may work on some devices.
258      *   {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
259      *   which is usually the sample rate of the source.
260      *   {@link #getSampleRate()} can be used to retrieve the actual sample rate chosen.
261      * @param channelConfig describes the configuration of the audio channels.
262      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
263      *   {@link AudioFormat#CHANNEL_IN_STEREO}.  {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
264      *   to work on all devices.
265      * @param audioFormat the format in which the audio data is to be returned.
266      *   See {@link AudioFormat#ENCODING_PCM_8BIT}, {@link AudioFormat#ENCODING_PCM_16BIT},
267      *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
268      * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
269      *   to during the recording. New audio data can be read from this buffer in smaller chunks
270      *   than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
271      *   required buffer size for the successful creation of an AudioRecord instance. Using values
272      *   smaller than getMinBufferSize() will result in an initialization failure.
273      * @throws java.lang.IllegalArgumentException
274      */
AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)275     public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
276             int bufferSizeInBytes)
277     throws IllegalArgumentException {
278         this((new AudioAttributes.Builder())
279                     .setInternalCapturePreset(audioSource)
280                     .build(),
281                 (new AudioFormat.Builder())
282                     .setChannelMask(getChannelMaskFromLegacyConfig(channelConfig,
283                                         true/*allow legacy configurations*/))
284                     .setEncoding(audioFormat)
285                     .setSampleRate(sampleRateInHz)
286                     .build(),
287                 bufferSizeInBytes,
288                 AudioManager.AUDIO_SESSION_ID_GENERATE);
289     }
290 
291     /**
292      * @hide
293      * Class constructor with {@link AudioAttributes} and {@link AudioFormat}.
294      * @param attributes a non-null {@link AudioAttributes} instance. Use
295      *     {@link AudioAttributes.Builder#setAudioSource(int)} for configuring the audio
296      *     source for this instance.
297      * @param format a non-null {@link AudioFormat} instance describing the format of the data
298      *     that will be recorded through this AudioRecord. See {@link AudioFormat.Builder} for
299      *     configuring the audio format parameters such as encoding, channel mask and sample rate.
300      * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
301      *   to during the recording. New audio data can be read from this buffer in smaller chunks
302      *   than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
303      *   required buffer size for the successful creation of an AudioRecord instance. Using values
304      *   smaller than getMinBufferSize() will result in an initialization failure.
305      * @param sessionId ID of audio session the AudioRecord must be attached to, or
306      *   {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at construction
307      *   time. See also {@link AudioManager#generateAudioSessionId()} to obtain a session ID before
308      *   construction.
309      * @throws IllegalArgumentException
310      */
311     @SystemApi
AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, int sessionId)312     public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
313             int sessionId) throws IllegalArgumentException {
314         mRecordingState = RECORDSTATE_STOPPED;
315 
316         if (attributes == null) {
317             throw new IllegalArgumentException("Illegal null AudioAttributes");
318         }
319         if (format == null) {
320             throw new IllegalArgumentException("Illegal null AudioFormat");
321         }
322 
323         // remember which looper is associated with the AudioRecord instanciation
324         if ((mInitializationLooper = Looper.myLooper()) == null) {
325             mInitializationLooper = Looper.getMainLooper();
326         }
327 
328         // is this AudioRecord using REMOTE_SUBMIX at full volume?
329         if (attributes.getCapturePreset() == MediaRecorder.AudioSource.REMOTE_SUBMIX) {
330             final AudioAttributes.Builder filteredAttr = new AudioAttributes.Builder();
331             final Iterator<String> tagsIter = attributes.getTags().iterator();
332             while (tagsIter.hasNext()) {
333                 final String tag = tagsIter.next();
334                 if (tag.equalsIgnoreCase(SUBMIX_FIXED_VOLUME)) {
335                     mIsSubmixFullVolume = true;
336                     Log.v(TAG, "Will record from REMOTE_SUBMIX at full fixed volume");
337                 } else { // SUBMIX_FIXED_VOLUME: is not to be propagated to the native layers
338                     filteredAttr.addTag(tag);
339                 }
340             }
341             filteredAttr.setInternalCapturePreset(attributes.getCapturePreset());
342             mAudioAttributes = filteredAttr.build();
343         } else {
344             mAudioAttributes = attributes;
345         }
346 
347         int rate = format.getSampleRate();
348         if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
349             rate = 0;
350         }
351 
352         int encoding = AudioFormat.ENCODING_DEFAULT;
353         if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0)
354         {
355             encoding = format.getEncoding();
356         }
357 
358         audioParamCheck(attributes.getCapturePreset(), rate, encoding);
359 
360         if ((format.getPropertySetMask()
361                 & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) {
362             mChannelIndexMask = format.getChannelIndexMask();
363             mChannelCount = format.getChannelCount();
364         }
365         if ((format.getPropertySetMask()
366                 & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0) {
367             mChannelMask = getChannelMaskFromLegacyConfig(format.getChannelMask(), false);
368             mChannelCount = format.getChannelCount();
369         } else if (mChannelIndexMask == 0) {
370             mChannelMask = getChannelMaskFromLegacyConfig(AudioFormat.CHANNEL_IN_DEFAULT, false);
371             mChannelCount =  AudioFormat.channelCountFromInChannelMask(mChannelMask);
372         }
373 
374         audioBuffSizeCheck(bufferSizeInBytes);
375 
376         int[] sampleRate = new int[] {mSampleRate};
377         int[] session = new int[1];
378         session[0] = sessionId;
379         //TODO: update native initialization when information about hardware init failure
380         //      due to capture device already open is available.
381         int initResult = native_setup( new WeakReference<AudioRecord>(this),
382                 mAudioAttributes, sampleRate, mChannelMask, mChannelIndexMask,
383                 mAudioFormat, mNativeBufferSizeInBytes,
384                 session, ActivityThread.currentOpPackageName(), 0 /*nativeRecordInJavaObj*/);
385         if (initResult != SUCCESS) {
386             loge("Error code "+initResult+" when initializing native AudioRecord object.");
387             return; // with mState == STATE_UNINITIALIZED
388         }
389 
390         mSampleRate = sampleRate[0];
391         mSessionId = session[0];
392 
393         mState = STATE_INITIALIZED;
394     }
395 
396     /**
397      * A constructor which explicitly connects a Native (C++) AudioRecord. For use by
398      * the AudioRecordRoutingProxy subclass.
399      * @param nativeRecordInJavaObj A C/C++ pointer to a native AudioRecord
400      * (associated with an OpenSL ES recorder). Note: the caller must ensure a correct
401      * value here as no error checking is or can be done.
402      */
AudioRecord(long nativeRecordInJavaObj)403     /*package*/ AudioRecord(long nativeRecordInJavaObj) {
404         mNativeRecorderInJavaObj = 0;
405         mNativeCallbackCookie = 0;
406         mNativeDeviceCallback = 0;
407 
408         // other initialization...
409         if (nativeRecordInJavaObj != 0) {
410             deferred_connect(nativeRecordInJavaObj);
411         } else {
412             mState = STATE_UNINITIALIZED;
413         }
414     }
415 
416     /**
417      * @hide
418      */
deferred_connect(long nativeRecordInJavaObj)419     /* package */ void deferred_connect(long  nativeRecordInJavaObj) {
420         if (mState != STATE_INITIALIZED) {
421             int[] session = { 0 };
422             int[] rates = { 0 };
423             //TODO: update native initialization when information about hardware init failure
424             //      due to capture device already open is available.
425             // Note that for this native_setup, we are providing an already created/initialized
426             // *Native* AudioRecord, so the attributes parameters to native_setup() are ignored.
427             int initResult = native_setup(new WeakReference<AudioRecord>(this),
428                     null /*mAudioAttributes*/,
429                     rates /*mSampleRates*/,
430                     0 /*mChannelMask*/,
431                     0 /*mChannelIndexMask*/,
432                     0 /*mAudioFormat*/,
433                     0 /*mNativeBufferSizeInBytes*/,
434                     session,
435                     ActivityThread.currentOpPackageName(),
436                     nativeRecordInJavaObj);
437             if (initResult != SUCCESS) {
438                 loge("Error code "+initResult+" when initializing native AudioRecord object.");
439                 return; // with mState == STATE_UNINITIALIZED
440             }
441 
442             mSessionId = session[0];
443 
444             mState = STATE_INITIALIZED;
445         }
446     }
447 
448     /**
449      * Builder class for {@link AudioRecord} objects.
450      * Use this class to configure and create an <code>AudioRecord</code> instance. By setting the
451      * recording source and audio format parameters, you indicate which of
452      * those vary from the default behavior on the device.
453      * <p> Here is an example where <code>Builder</code> is used to specify all {@link AudioFormat}
454      * parameters, to be used by a new <code>AudioRecord</code> instance:
455      *
456      * <pre class="prettyprint">
457      * AudioRecord recorder = new AudioRecord.Builder()
458      *         .setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION)
459      *         .setAudioFormat(new AudioFormat.Builder()
460      *                 .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
461      *                 .setSampleRate(32000)
462      *                 .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
463      *                 .build())
464      *         .setBufferSize(2*minBuffSize)
465      *         .build();
466      * </pre>
467      * <p>
468      * If the audio source is not set with {@link #setAudioSource(int)},
469      * {@link MediaRecorder.AudioSource#DEFAULT} is used.
470      * <br>If the audio format is not specified or is incomplete, its channel configuration will be
471      * {@link AudioFormat#CHANNEL_IN_MONO}, and the encoding will be
472      * {@link AudioFormat#ENCODING_PCM_16BIT}.
473      * The sample rate will depend on the device actually selected for capture and can be queried
474      * with {@link #getSampleRate()} method.
475      * <br>If the buffer size is not specified with {@link #setBufferSizeInBytes(int)},
476      * the minimum buffer size for the source is used.
477      */
478     public static class Builder {
479         private AudioAttributes mAttributes;
480         private AudioFormat mFormat;
481         private int mBufferSizeInBytes;
482         private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
483 
484         /**
485          * Constructs a new Builder with the default values as described above.
486          */
Builder()487         public Builder() {
488         }
489 
490         /**
491          * @param source the audio source.
492          * See {@link MediaRecorder.AudioSource} for the supported audio source definitions.
493          * @return the same Builder instance.
494          * @throws IllegalArgumentException
495          */
setAudioSource(int source)496         public Builder setAudioSource(int source) throws IllegalArgumentException {
497             if ( (source < MediaRecorder.AudioSource.DEFAULT) ||
498                     (source > MediaRecorder.getAudioSourceMax()) ) {
499                 throw new IllegalArgumentException("Invalid audio source " + source);
500             }
501             mAttributes = new AudioAttributes.Builder()
502                     .setInternalCapturePreset(source)
503                     .build();
504             return this;
505         }
506 
507         /**
508          * @hide
509          * To be only used by system components. Allows specifying non-public capture presets
510          * @param attributes a non-null {@link AudioAttributes} instance that contains the capture
511          *     preset to be used.
512          * @return the same Builder instance.
513          * @throws IllegalArgumentException
514          */
515         @SystemApi
setAudioAttributes(@onNull AudioAttributes attributes)516         public Builder setAudioAttributes(@NonNull AudioAttributes attributes)
517                 throws IllegalArgumentException {
518             if (attributes == null) {
519                 throw new IllegalArgumentException("Illegal null AudioAttributes argument");
520             }
521             if (attributes.getCapturePreset() == MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID) {
522                 throw new IllegalArgumentException(
523                         "No valid capture preset in AudioAttributes argument");
524             }
525             // keep reference, we only copy the data when building
526             mAttributes = attributes;
527             return this;
528         }
529 
530         /**
531          * Sets the format of the audio data to be captured.
532          * @param format a non-null {@link AudioFormat} instance
533          * @return the same Builder instance.
534          * @throws IllegalArgumentException
535          */
setAudioFormat(@onNull AudioFormat format)536         public Builder setAudioFormat(@NonNull AudioFormat format) throws IllegalArgumentException {
537             if (format == null) {
538                 throw new IllegalArgumentException("Illegal null AudioFormat argument");
539             }
540             // keep reference, we only copy the data when building
541             mFormat = format;
542             return this;
543         }
544 
545         /**
546          * Sets the total size (in bytes) of the buffer where audio data is written
547          * during the recording. New audio data can be read from this buffer in smaller chunks
548          * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
549          * required buffer size for the successful creation of an AudioRecord instance.
550          * Since bufferSizeInBytes may be internally increased to accommodate the source
551          * requirements, use {@link #getBufferSizeInFrames()} to determine the actual buffer size
552          * in frames.
553          * @param bufferSizeInBytes a value strictly greater than 0
554          * @return the same Builder instance.
555          * @throws IllegalArgumentException
556          */
setBufferSizeInBytes(int bufferSizeInBytes)557         public Builder setBufferSizeInBytes(int bufferSizeInBytes) throws IllegalArgumentException {
558             if (bufferSizeInBytes <= 0) {
559                 throw new IllegalArgumentException("Invalid buffer size " + bufferSizeInBytes);
560             }
561             mBufferSizeInBytes = bufferSizeInBytes;
562             return this;
563         }
564 
565         /**
566          * @hide
567          * To be only used by system components.
568          * @param sessionId ID of audio session the AudioRecord must be attached to, or
569          *     {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at
570          *     construction time.
571          * @return the same Builder instance.
572          * @throws IllegalArgumentException
573          */
574         @SystemApi
setSessionId(int sessionId)575         public Builder setSessionId(int sessionId) throws IllegalArgumentException {
576             if (sessionId < 0) {
577                 throw new IllegalArgumentException("Invalid session ID " + sessionId);
578             }
579             mSessionId = sessionId;
580             return this;
581         }
582 
583         /**
584          * @return a new {@link AudioRecord} instance successfully initialized with all
585          *     the parameters set on this <code>Builder</code>.
586          * @throws UnsupportedOperationException if the parameters set on the <code>Builder</code>
587          *     were incompatible, or if they are not supported by the device,
588          *     or if the device was not available.
589          */
build()590         public AudioRecord build() throws UnsupportedOperationException {
591             if (mFormat == null) {
592                 mFormat = new AudioFormat.Builder()
593                         .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
594                         .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
595                         .build();
596             } else {
597                 if (mFormat.getEncoding() == AudioFormat.ENCODING_INVALID) {
598                     mFormat = new AudioFormat.Builder(mFormat)
599                             .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
600                             .build();
601                 }
602                 if (mFormat.getChannelMask() == AudioFormat.CHANNEL_INVALID
603                         && mFormat.getChannelIndexMask() == AudioFormat.CHANNEL_INVALID) {
604                     mFormat = new AudioFormat.Builder(mFormat)
605                             .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
606                             .build();
607                 }
608             }
609             if (mAttributes == null) {
610                 mAttributes = new AudioAttributes.Builder()
611                         .setInternalCapturePreset(MediaRecorder.AudioSource.DEFAULT)
612                         .build();
613             }
614             try {
615                 // If the buffer size is not specified,
616                 // use a single frame for the buffer size and let the
617                 // native code figure out the minimum buffer size.
618                 if (mBufferSizeInBytes == 0) {
619                     mBufferSizeInBytes = mFormat.getChannelCount()
620                             * mFormat.getBytesPerSample(mFormat.getEncoding());
621                 }
622                 final AudioRecord record = new AudioRecord(
623                         mAttributes, mFormat, mBufferSizeInBytes, mSessionId);
624                 if (record.getState() == STATE_UNINITIALIZED) {
625                     // release is not necessary
626                     throw new UnsupportedOperationException("Cannot create AudioRecord");
627                 }
628                 return record;
629             } catch (IllegalArgumentException e) {
630                 throw new UnsupportedOperationException(e.getMessage());
631             }
632         }
633     }
634 
635     // Convenience method for the constructor's parameter checks.
636     // This, getChannelMaskFromLegacyConfig and audioBuffSizeCheck are where constructor
637     // IllegalArgumentException-s are thrown
getChannelMaskFromLegacyConfig(int inChannelConfig, boolean allowLegacyConfig)638     private static int getChannelMaskFromLegacyConfig(int inChannelConfig,
639             boolean allowLegacyConfig) {
640         int mask;
641         switch (inChannelConfig) {
642         case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
643         case AudioFormat.CHANNEL_IN_MONO:
644         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
645             mask = AudioFormat.CHANNEL_IN_MONO;
646             break;
647         case AudioFormat.CHANNEL_IN_STEREO:
648         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
649             mask = AudioFormat.CHANNEL_IN_STEREO;
650             break;
651         case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
652             mask = inChannelConfig;
653             break;
654         default:
655             throw new IllegalArgumentException("Unsupported channel configuration.");
656         }
657 
658         if (!allowLegacyConfig && ((inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_MONO)
659                 || (inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_STEREO))) {
660             // only happens with the constructor that uses AudioAttributes and AudioFormat
661             throw new IllegalArgumentException("Unsupported deprecated configuration.");
662         }
663 
664         return mask;
665     }
666 
667     // postconditions:
668     //    mRecordSource is valid
669     //    mAudioFormat is valid
670     //    mSampleRate is valid
audioParamCheck(int audioSource, int sampleRateInHz, int audioFormat)671     private void audioParamCheck(int audioSource, int sampleRateInHz, int audioFormat)
672             throws IllegalArgumentException {
673 
674         //--------------
675         // audio source
676         if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) ||
677              ((audioSource > MediaRecorder.getAudioSourceMax()) &&
678               (audioSource != MediaRecorder.AudioSource.RADIO_TUNER) &&
679               (audioSource != MediaRecorder.AudioSource.HOTWORD)) )  {
680             throw new IllegalArgumentException("Invalid audio source " + audioSource);
681         }
682         mRecordSource = audioSource;
683 
684         //--------------
685         // sample rate
686         if ((sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN ||
687                 sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) &&
688                 sampleRateInHz != AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
689             throw new IllegalArgumentException(sampleRateInHz
690                     + "Hz is not a supported sample rate.");
691         }
692         mSampleRate = sampleRateInHz;
693 
694         //--------------
695         // audio format
696         switch (audioFormat) {
697         case AudioFormat.ENCODING_DEFAULT:
698             mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
699             break;
700         case AudioFormat.ENCODING_PCM_FLOAT:
701         case AudioFormat.ENCODING_PCM_16BIT:
702         case AudioFormat.ENCODING_PCM_8BIT:
703             mAudioFormat = audioFormat;
704             break;
705         default:
706             throw new IllegalArgumentException("Unsupported sample encoding " + audioFormat
707                     + ". Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, or ENCODING_PCM_FLOAT.");
708         }
709     }
710 
711 
712     // Convenience method for the contructor's audio buffer size check.
713     // preconditions:
714     //    mChannelCount is valid
715     //    mAudioFormat is AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT,
716     //                 or AudioFormat.ENCODING_PCM_FLOAT
717     // postcondition:
718     //    mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
audioBuffSizeCheck(int audioBufferSize)719     private void audioBuffSizeCheck(int audioBufferSize) throws IllegalArgumentException {
720         // NB: this section is only valid with PCM data.
721         // To update when supporting compressed formats
722         int frameSizeInBytes = mChannelCount
723             * (AudioFormat.getBytesPerSample(mAudioFormat));
724         if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
725             throw new IllegalArgumentException("Invalid audio buffer size " + audioBufferSize
726                     + " (frame size " + frameSizeInBytes + ")");
727         }
728 
729         mNativeBufferSizeInBytes = audioBufferSize;
730     }
731 
732 
733 
734     /**
735      * Releases the native AudioRecord resources.
736      * The object can no longer be used and the reference should be set to null
737      * after a call to release()
738      */
release()739     public void release() {
740         try {
741             stop();
742         } catch(IllegalStateException ise) {
743             // don't raise an exception, we're releasing the resources.
744         }
745         native_release();
746         mState = STATE_UNINITIALIZED;
747     }
748 
749 
750     @Override
finalize()751     protected void finalize() {
752         // will cause stop() to be called, and if appropriate, will handle fixed volume recording
753         release();
754     }
755 
756 
757     //--------------------------------------------------------------------------
758     // Getters
759     //--------------------
760     /**
761      * Returns the configured audio sink sample rate in Hz.
762      * The sink sample rate never changes after construction.
763      * If the constructor had a specific sample rate, then the sink sample rate is that value.
764      * If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED},
765      * then the sink sample rate is a route-dependent default value based on the source [sic].
766      */
getSampleRate()767     public int getSampleRate() {
768         return mSampleRate;
769     }
770 
771     /**
772      * Returns the audio recording source.
773      * @see MediaRecorder.AudioSource
774      */
getAudioSource()775     public int getAudioSource() {
776         return mRecordSource;
777     }
778 
779     /**
780      * Returns the configured audio data encoding. See {@link AudioFormat#ENCODING_PCM_8BIT},
781      * {@link AudioFormat#ENCODING_PCM_16BIT}, and {@link AudioFormat#ENCODING_PCM_FLOAT}.
782      */
getAudioFormat()783     public int getAudioFormat() {
784         return mAudioFormat;
785     }
786 
787     /**
788      * Returns the configured channel position mask.
789      * <p> See {@link AudioFormat#CHANNEL_IN_MONO}
790      * and {@link AudioFormat#CHANNEL_IN_STEREO}.
791      * This method may return {@link AudioFormat#CHANNEL_INVALID} if
792      * a channel index mask is used.
793      * Consider {@link #getFormat()} instead, to obtain an {@link AudioFormat},
794      * which contains both the channel position mask and the channel index mask.
795      */
getChannelConfiguration()796     public int getChannelConfiguration() {
797         return mChannelMask;
798     }
799 
800     /**
801      * Returns the configured <code>AudioRecord</code> format.
802      * @return an {@link AudioFormat} containing the
803      * <code>AudioRecord</code> parameters at the time of configuration.
804      */
getFormat()805     public @NonNull AudioFormat getFormat() {
806         AudioFormat.Builder builder = new AudioFormat.Builder()
807             .setSampleRate(mSampleRate)
808             .setEncoding(mAudioFormat);
809         if (mChannelMask != AudioFormat.CHANNEL_INVALID) {
810             builder.setChannelMask(mChannelMask);
811         }
812         if (mChannelIndexMask != AudioFormat.CHANNEL_INVALID  /* 0 */) {
813             builder.setChannelIndexMask(mChannelIndexMask);
814         }
815         return builder.build();
816     }
817 
818     /**
819      * Returns the configured number of channels.
820      */
getChannelCount()821     public int getChannelCount() {
822         return mChannelCount;
823     }
824 
825     /**
826      * Returns the state of the AudioRecord instance. This is useful after the
827      * AudioRecord instance has been created to check if it was initialized
828      * properly. This ensures that the appropriate hardware resources have been
829      * acquired.
830      * @see AudioRecord#STATE_INITIALIZED
831      * @see AudioRecord#STATE_UNINITIALIZED
832      */
getState()833     public int getState() {
834         return mState;
835     }
836 
837     /**
838      * Returns the recording state of the AudioRecord instance.
839      * @see AudioRecord#RECORDSTATE_STOPPED
840      * @see AudioRecord#RECORDSTATE_RECORDING
841      */
getRecordingState()842     public int getRecordingState() {
843         synchronized (mRecordingStateLock) {
844             return mRecordingState;
845         }
846     }
847 
848     /**
849      *  Returns the frame count of the native <code>AudioRecord</code> buffer.
850      *  This is greater than or equal to the bufferSizeInBytes converted to frame units
851      *  specified in the <code>AudioRecord</code> constructor or Builder.
852      *  The native frame count may be enlarged to accommodate the requirements of the
853      *  source on creation or if the <code>AudioRecord</code>
854      *  is subsequently rerouted.
855      *  @return current size in frames of the <code>AudioRecord</code> buffer.
856      *  @throws IllegalStateException
857      */
getBufferSizeInFrames()858     public int getBufferSizeInFrames() {
859         return native_get_buffer_size_in_frames();
860     }
861 
862     /**
863      * Returns the notification marker position expressed in frames.
864      */
getNotificationMarkerPosition()865     public int getNotificationMarkerPosition() {
866         return native_get_marker_pos();
867     }
868 
869     /**
870      * Returns the notification update period expressed in frames.
871      */
getPositionNotificationPeriod()872     public int getPositionNotificationPeriod() {
873         return native_get_pos_update_period();
874     }
875 
876     /**
877      * Poll for an {@link AudioTimestamp} on demand.
878      * <p>
879      * The AudioTimestamp reflects the frame delivery information at
880      * the earliest point available in the capture pipeline.
881      * <p>
882      * Calling {@link #startRecording()} following a {@link #stop()} will reset
883      * the frame count to 0.
884      *
885      * @param outTimestamp a caller provided non-null AudioTimestamp instance,
886      *        which is updated with the AudioRecord frame delivery information upon success.
887      * @param timebase one of
888      *        {@link AudioTimestamp#TIMEBASE_BOOTTIME AudioTimestamp.TIMEBASE_BOOTTIME} or
889      *        {@link AudioTimestamp#TIMEBASE_MONOTONIC AudioTimestamp.TIMEBASE_MONOTONIC},
890      *        used to select the clock for the AudioTimestamp time.
891      * @return {@link #SUCCESS} if a timestamp is available,
892      *         or {@link #ERROR_INVALID_OPERATION} if a timestamp not available.
893      */
getTimestamp(@onNull AudioTimestamp outTimestamp, @AudioTimestamp.Timebase int timebase)894      public int getTimestamp(@NonNull AudioTimestamp outTimestamp,
895              @AudioTimestamp.Timebase int timebase)
896      {
897          if (outTimestamp == null ||
898                  (timebase != AudioTimestamp.TIMEBASE_BOOTTIME
899                  && timebase != AudioTimestamp.TIMEBASE_MONOTONIC)) {
900              throw new IllegalArgumentException();
901          }
902          return native_get_timestamp(outTimestamp, timebase);
903      }
904 
905     /**
906      * Returns the minimum buffer size required for the successful creation of an AudioRecord
907      * object, in byte units.
908      * Note that this size doesn't guarantee a smooth recording under load, and higher values
909      * should be chosen according to the expected frequency at which the AudioRecord instance
910      * will be polled for new data.
911      * See {@link #AudioRecord(int, int, int, int, int)} for more information on valid
912      * configuration values.
913      * @param sampleRateInHz the sample rate expressed in Hertz.
914      *   {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted.
915      * @param channelConfig describes the configuration of the audio channels.
916      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
917      *   {@link AudioFormat#CHANNEL_IN_STEREO}
918      * @param audioFormat the format in which the audio data is represented.
919      *   See {@link AudioFormat#ENCODING_PCM_16BIT}.
920      * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the
921      *  hardware, or an invalid parameter was passed,
922      *  or {@link #ERROR} if the implementation was unable to query the hardware for its
923      *  input properties,
924      *   or the minimum buffer size expressed in bytes.
925      * @see #AudioRecord(int, int, int, int, int)
926      */
getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)927     static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
928         int channelCount = 0;
929         switch (channelConfig) {
930         case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
931         case AudioFormat.CHANNEL_IN_MONO:
932         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
933             channelCount = 1;
934             break;
935         case AudioFormat.CHANNEL_IN_STEREO:
936         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
937         case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
938             channelCount = 2;
939             break;
940         case AudioFormat.CHANNEL_INVALID:
941         default:
942             loge("getMinBufferSize(): Invalid channel configuration.");
943             return ERROR_BAD_VALUE;
944         }
945 
946         int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
947         if (size == 0) {
948             return ERROR_BAD_VALUE;
949         }
950         else if (size == -1) {
951             return ERROR;
952         }
953         else {
954             return size;
955         }
956     }
957 
958     /**
959      * Returns the audio session ID.
960      *
961      * @return the ID of the audio session this AudioRecord belongs to.
962      */
getAudioSessionId()963     public int getAudioSessionId() {
964         return mSessionId;
965     }
966 
967     //---------------------------------------------------------
968     // Transport control methods
969     //--------------------
970     /**
971      * Starts recording from the AudioRecord instance.
972      * @throws IllegalStateException
973      */
startRecording()974     public void startRecording()
975     throws IllegalStateException {
976         if (mState != STATE_INITIALIZED) {
977             throw new IllegalStateException("startRecording() called on an "
978                     + "uninitialized AudioRecord.");
979         }
980 
981         // start recording
982         synchronized(mRecordingStateLock) {
983             if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) {
984                 handleFullVolumeRec(true);
985                 mRecordingState = RECORDSTATE_RECORDING;
986             }
987         }
988     }
989 
990     /**
991      * Starts recording from the AudioRecord instance when the specified synchronization event
992      * occurs on the specified audio session.
993      * @throws IllegalStateException
994      * @param syncEvent event that triggers the capture.
995      * @see MediaSyncEvent
996      */
startRecording(MediaSyncEvent syncEvent)997     public void startRecording(MediaSyncEvent syncEvent)
998     throws IllegalStateException {
999         if (mState != STATE_INITIALIZED) {
1000             throw new IllegalStateException("startRecording() called on an "
1001                     + "uninitialized AudioRecord.");
1002         }
1003 
1004         // start recording
1005         synchronized(mRecordingStateLock) {
1006             if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) {
1007                 handleFullVolumeRec(true);
1008                 mRecordingState = RECORDSTATE_RECORDING;
1009             }
1010         }
1011     }
1012 
1013     /**
1014      * Stops recording.
1015      * @throws IllegalStateException
1016      */
stop()1017     public void stop()
1018     throws IllegalStateException {
1019         if (mState != STATE_INITIALIZED) {
1020             throw new IllegalStateException("stop() called on an uninitialized AudioRecord.");
1021         }
1022 
1023         // stop recording
1024         synchronized(mRecordingStateLock) {
1025             handleFullVolumeRec(false);
1026             native_stop();
1027             mRecordingState = RECORDSTATE_STOPPED;
1028         }
1029     }
1030 
1031     private final IBinder mICallBack = new Binder();
handleFullVolumeRec(boolean starting)1032     private void handleFullVolumeRec(boolean starting) {
1033         if (!mIsSubmixFullVolume) {
1034             return;
1035         }
1036         final IBinder b = ServiceManager.getService(android.content.Context.AUDIO_SERVICE);
1037         final IAudioService ias = IAudioService.Stub.asInterface(b);
1038         try {
1039             ias.forceRemoteSubmixFullVolume(starting, mICallBack);
1040         } catch (RemoteException e) {
1041             Log.e(TAG, "Error talking to AudioService when handling full submix volume", e);
1042         }
1043     }
1044 
1045     //---------------------------------------------------------
1046     // Audio data supply
1047     //--------------------
1048     /**
1049      * Reads audio data from the audio hardware for recording into a byte array.
1050      * The format specified in the AudioRecord constructor should be
1051      * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
1052      * @param audioData the array to which the recorded audio data is written.
1053      * @param offsetInBytes index in audioData from which the data is written expressed in bytes.
1054      * @param sizeInBytes the number of requested bytes.
1055      * @return zero or the positive number of bytes that were read, or one of the following
1056      *    error codes. The number of bytes will not exceed sizeInBytes.
1057      * <ul>
1058      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1059      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1060      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1061      *    needs to be recreated. The dead object error code is not returned if some data was
1062      *    successfully transferred. In this case, the error is returned at the next read()</li>
1063      * <li>{@link #ERROR} in case of other error</li>
1064      * </ul>
1065      */
read(@onNull byte[] audioData, int offsetInBytes, int sizeInBytes)1066     public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) {
1067         return read(audioData, offsetInBytes, sizeInBytes, READ_BLOCKING);
1068     }
1069 
1070     /**
1071      * Reads audio data from the audio hardware for recording into a byte array.
1072      * The format specified in the AudioRecord constructor should be
1073      * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
1074      * The format can be {@link AudioFormat#ENCODING_PCM_16BIT}, but this is deprecated.
1075      * @param audioData the array to which the recorded audio data is written.
1076      * @param offsetInBytes index in audioData to which the data is written expressed in bytes.
1077      *        Must not be negative, or cause the data access to go out of bounds of the array.
1078      * @param sizeInBytes the number of requested bytes.
1079      *        Must not be negative, or cause the data access to go out of bounds of the array.
1080      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1081      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1082      *     is read.
1083      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1084      *     reading as much audio data as possible without blocking.
1085      * @return zero or the positive number of bytes that were read, or one of the following
1086      *    error codes. The number of bytes will be a multiple of the frame size in bytes
1087      *    not to exceed sizeInBytes.
1088      * <ul>
1089      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1090      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1091      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1092      *    needs to be recreated. The dead object error code is not returned if some data was
1093      *    successfully transferred. In this case, the error is returned at the next read()</li>
1094      * <li>{@link #ERROR} in case of other error</li>
1095      * </ul>
1096      */
read(@onNull byte[] audioData, int offsetInBytes, int sizeInBytes, @ReadMode int readMode)1097     public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
1098             @ReadMode int readMode) {
1099         if (mState != STATE_INITIALIZED  || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
1100             return ERROR_INVALID_OPERATION;
1101         }
1102 
1103         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1104             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1105             return ERROR_BAD_VALUE;
1106         }
1107 
1108         if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
1109                 || (offsetInBytes + sizeInBytes < 0)  // detect integer overflow
1110                 || (offsetInBytes + sizeInBytes > audioData.length)) {
1111             return ERROR_BAD_VALUE;
1112         }
1113 
1114         return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes,
1115                 readMode == READ_BLOCKING);
1116     }
1117 
1118     /**
1119      * Reads audio data from the audio hardware for recording into a short array.
1120      * The format specified in the AudioRecord constructor should be
1121      * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
1122      * @param audioData the array to which the recorded audio data is written.
1123      * @param offsetInShorts index in audioData to which the data is written expressed in shorts.
1124      *        Must not be negative, or cause the data access to go out of bounds of the array.
1125      * @param sizeInShorts the number of requested shorts.
1126      *        Must not be negative, or cause the data access to go out of bounds of the array.
1127      * @return zero or the positive number of shorts that were read, or one of the following
1128      *    error codes. The number of shorts will be a multiple of the channel count not to exceed
1129      *    sizeInShorts.
1130      * <ul>
1131      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1132      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1133      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1134      *    needs to be recreated. The dead object error code is not returned if some data was
1135      *    successfully transferred. In this case, the error is returned at the next read()</li>
1136      * <li>{@link #ERROR} in case of other error</li>
1137      * </ul>
1138      */
read(@onNull short[] audioData, int offsetInShorts, int sizeInShorts)1139     public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) {
1140         return read(audioData, offsetInShorts, sizeInShorts, READ_BLOCKING);
1141     }
1142 
1143     /**
1144      * Reads audio data from the audio hardware for recording into a short array.
1145      * The format specified in the AudioRecord constructor should be
1146      * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
1147      * @param audioData the array to which the recorded audio data is written.
1148      * @param offsetInShorts index in audioData from which the data is written expressed in shorts.
1149      *        Must not be negative, or cause the data access to go out of bounds of the array.
1150      * @param sizeInShorts the number of requested shorts.
1151      *        Must not be negative, or cause the data access to go out of bounds of the array.
1152      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1153      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1154      *     is read.
1155      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1156      *     reading as much audio data as possible without blocking.
1157      * @return zero or the positive number of shorts that were read, or one of the following
1158      *    error codes. The number of shorts will be a multiple of the channel count not to exceed
1159      *    sizeInShorts.
1160      * <ul>
1161      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1162      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1163      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1164      *    needs to be recreated. The dead object error code is not returned if some data was
1165      *    successfully transferred. In this case, the error is returned at the next read()</li>
1166      * <li>{@link #ERROR} in case of other error</li>
1167      * </ul>
1168      */
read(@onNull short[] audioData, int offsetInShorts, int sizeInShorts, @ReadMode int readMode)1169     public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
1170             @ReadMode int readMode) {
1171         if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
1172             return ERROR_INVALID_OPERATION;
1173         }
1174 
1175         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1176             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1177             return ERROR_BAD_VALUE;
1178         }
1179 
1180         if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
1181                 || (offsetInShorts + sizeInShorts < 0)  // detect integer overflow
1182                 || (offsetInShorts + sizeInShorts > audioData.length)) {
1183             return ERROR_BAD_VALUE;
1184         }
1185 
1186         return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts,
1187                 readMode == READ_BLOCKING);
1188     }
1189 
1190     /**
1191      * Reads audio data from the audio hardware for recording into a float array.
1192      * The format specified in the AudioRecord constructor should be
1193      * {@link AudioFormat#ENCODING_PCM_FLOAT} to correspond to the data in the array.
1194      * @param audioData the array to which the recorded audio data is written.
1195      * @param offsetInFloats index in audioData from which the data is written.
1196      *        Must not be negative, or cause the data access to go out of bounds of the array.
1197      * @param sizeInFloats the number of requested floats.
1198      *        Must not be negative, or cause the data access to go out of bounds of the array.
1199      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1200      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1201      *     is read.
1202      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1203      *     reading as much audio data as possible without blocking.
1204      * @return zero or the positive number of floats that were read, or one of the following
1205      *    error codes. The number of floats will be a multiple of the channel count not to exceed
1206      *    sizeInFloats.
1207      * <ul>
1208      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1209      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1210      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1211      *    needs to be recreated. The dead object error code is not returned if some data was
1212      *    successfully transferred. In this case, the error is returned at the next read()</li>
1213      * <li>{@link #ERROR} in case of other error</li>
1214      * </ul>
1215      */
read(@onNull float[] audioData, int offsetInFloats, int sizeInFloats, @ReadMode int readMode)1216     public int read(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
1217             @ReadMode int readMode) {
1218         if (mState == STATE_UNINITIALIZED) {
1219             Log.e(TAG, "AudioRecord.read() called in invalid state STATE_UNINITIALIZED");
1220             return ERROR_INVALID_OPERATION;
1221         }
1222 
1223         if (mAudioFormat != AudioFormat.ENCODING_PCM_FLOAT) {
1224             Log.e(TAG, "AudioRecord.read(float[] ...) requires format ENCODING_PCM_FLOAT");
1225             return ERROR_INVALID_OPERATION;
1226         }
1227 
1228         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1229             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1230             return ERROR_BAD_VALUE;
1231         }
1232 
1233         if ((audioData == null) || (offsetInFloats < 0) || (sizeInFloats < 0)
1234                 || (offsetInFloats + sizeInFloats < 0)  // detect integer overflow
1235                 || (offsetInFloats + sizeInFloats > audioData.length)) {
1236             return ERROR_BAD_VALUE;
1237         }
1238 
1239         return native_read_in_float_array(audioData, offsetInFloats, sizeInFloats,
1240                 readMode == READ_BLOCKING);
1241     }
1242 
1243     /**
1244      * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
1245      * is not a direct buffer, this method will always return 0.
1246      * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
1247      * unchanged after a call to this method.
1248      * The representation of the data in the buffer will depend on the format specified in
1249      * the AudioRecord constructor, and will be native endian.
1250      * @param audioBuffer the direct buffer to which the recorded audio data is written.
1251      * Data is written to audioBuffer.position().
1252      * @param sizeInBytes the number of requested bytes. It is recommended but not enforced
1253      *    that the number of bytes requested be a multiple of the frame size (sample size in
1254      *    bytes multiplied by the channel count).
1255      * @return zero or the positive number of bytes that were read, or one of the following
1256      *    error codes. The number of bytes will not exceed sizeInBytes and will be truncated to be
1257      *    a multiple of the frame size.
1258      * <ul>
1259      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1260      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1261      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1262      *    needs to be recreated. The dead object error code is not returned if some data was
1263      *    successfully transferred. In this case, the error is returned at the next read()</li>
1264      * <li>{@link #ERROR} in case of other error</li>
1265      * </ul>
1266      */
read(@onNull ByteBuffer audioBuffer, int sizeInBytes)1267     public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes) {
1268         return read(audioBuffer, sizeInBytes, READ_BLOCKING);
1269     }
1270 
1271     /**
1272      * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
1273      * is not a direct buffer, this method will always return 0.
1274      * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
1275      * unchanged after a call to this method.
1276      * The representation of the data in the buffer will depend on the format specified in
1277      * the AudioRecord constructor, and will be native endian.
1278      * @param audioBuffer the direct buffer to which the recorded audio data is written.
1279      * Data is written to audioBuffer.position().
1280      * @param sizeInBytes the number of requested bytes. It is recommended but not enforced
1281      *    that the number of bytes requested be a multiple of the frame size (sample size in
1282      *    bytes multiplied by the channel count).
1283      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1284      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1285      *     is read.
1286      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1287      *     reading as much audio data as possible without blocking.
1288      * @return zero or the positive number of bytes that were read, or one of the following
1289      *    error codes. The number of bytes will not exceed sizeInBytes and will be truncated to be
1290      *    a multiple of the frame size.
1291      * <ul>
1292      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1293      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1294      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1295      *    needs to be recreated. The dead object error code is not returned if some data was
1296      *    successfully transferred. In this case, the error is returned at the next read()</li>
1297      * <li>{@link #ERROR} in case of other error</li>
1298      * </ul>
1299      */
read(@onNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode)1300     public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode) {
1301         if (mState != STATE_INITIALIZED) {
1302             return ERROR_INVALID_OPERATION;
1303         }
1304 
1305         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1306             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1307             return ERROR_BAD_VALUE;
1308         }
1309 
1310         if ( (audioBuffer == null) || (sizeInBytes < 0) ) {
1311             return ERROR_BAD_VALUE;
1312         }
1313 
1314         return native_read_in_direct_buffer(audioBuffer, sizeInBytes, readMode == READ_BLOCKING);
1315     }
1316 
1317     //--------------------------------------------------------------------------
1318     // Initialization / configuration
1319     //--------------------
1320     /**
1321      * Sets the listener the AudioRecord notifies when a previously set marker is reached or
1322      * for each periodic record head position update.
1323      * @param listener
1324      */
setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener)1325     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener) {
1326         setRecordPositionUpdateListener(listener, null);
1327     }
1328 
1329     /**
1330      * Sets the listener the AudioRecord notifies when a previously set marker is reached or
1331      * for each periodic record head position update.
1332      * Use this method to receive AudioRecord events in the Handler associated with another
1333      * thread than the one in which you created the AudioRecord instance.
1334      * @param listener
1335      * @param handler the Handler that will receive the event notification messages.
1336      */
setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, Handler handler)1337     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener,
1338                                                     Handler handler) {
1339         synchronized (mPositionListenerLock) {
1340 
1341             mPositionListener = listener;
1342 
1343             if (listener != null) {
1344                 if (handler != null) {
1345                     mEventHandler = new NativeEventHandler(this, handler.getLooper());
1346                 } else {
1347                     // no given handler, use the looper the AudioRecord was created in
1348                     mEventHandler = new NativeEventHandler(this, mInitializationLooper);
1349                 }
1350             } else {
1351                 mEventHandler = null;
1352             }
1353         }
1354 
1355     }
1356 
1357 
1358     /**
1359      * Sets the marker position at which the listener is called, if set with
1360      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
1361      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
1362      * @param markerInFrames marker position expressed in frames
1363      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
1364      *  {@link #ERROR_INVALID_OPERATION}
1365      */
setNotificationMarkerPosition(int markerInFrames)1366     public int setNotificationMarkerPosition(int markerInFrames) {
1367         if (mState == STATE_UNINITIALIZED) {
1368             return ERROR_INVALID_OPERATION;
1369         }
1370         return native_set_marker_pos(markerInFrames);
1371     }
1372 
1373     /**
1374      * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord.
1375      * Note: The query is only valid if the AudioRecord is currently recording. If it is not,
1376      * <code>getRoutedDevice()</code> will return null.
1377      */
1378     @Override
getRoutedDevice()1379     public AudioDeviceInfo getRoutedDevice() {
1380         int deviceId = native_getRoutedDeviceId();
1381         if (deviceId == 0) {
1382             return null;
1383         }
1384         AudioDeviceInfo[] devices =
1385                 AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
1386         for (int i = 0; i < devices.length; i++) {
1387             if (devices[i].getId() == deviceId) {
1388                 return devices[i];
1389             }
1390         }
1391         return null;
1392     }
1393 
1394     /*
1395      * Call BEFORE adding a routing callback handler.
1396      */
testEnableNativeRoutingCallbacksLocked()1397     private void testEnableNativeRoutingCallbacksLocked() {
1398         if (mRoutingChangeListeners.size() == 0) {
1399             native_enableDeviceCallback();
1400         }
1401     }
1402 
1403     /*
1404      * Call AFTER removing a routing callback handler.
1405      */
testDisableNativeRoutingCallbacksLocked()1406     private void testDisableNativeRoutingCallbacksLocked() {
1407         if (mRoutingChangeListeners.size() == 0) {
1408             native_disableDeviceCallback();
1409         }
1410     }
1411 
1412     //--------------------------------------------------------------------------
1413     // (Re)Routing Info
1414     //--------------------
1415     /**
1416      * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
1417      * {@link AudioRecord#addOnRoutingChangedListener} by an app to receive
1418      * (re)routing notifications.
1419      */
1420     @GuardedBy("mRoutingChangeListeners")
1421     private ArrayMap<AudioRouting.OnRoutingChangedListener,
1422             NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
1423 
1424     /**
1425      * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of
1426      * routing changes on this AudioRecord.
1427      * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
1428      * notifications of rerouting events.
1429      * @param handler  Specifies the {@link Handler} object for the thread on which to execute
1430      * the callback. If <code>null</code>, the {@link Handler} associated with the main
1431      * {@link Looper} will be used.
1432      */
1433     @Override
addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, android.os.Handler handler)1434     public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
1435             android.os.Handler handler) {
1436         synchronized (mRoutingChangeListeners) {
1437             if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
1438                 testEnableNativeRoutingCallbacksLocked();
1439                 mRoutingChangeListeners.put(
1440                         listener, new NativeRoutingEventHandlerDelegate(this, listener,
1441                                 handler != null ? handler : new Handler(mInitializationLooper)));
1442             }
1443         }
1444     }
1445 
1446     /**
1447      * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
1448     * to receive rerouting notifications.
1449     * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
1450     * to remove.
1451     */
1452     @Override
removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener)1453     public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
1454         synchronized (mRoutingChangeListeners) {
1455             if (mRoutingChangeListeners.containsKey(listener)) {
1456                 mRoutingChangeListeners.remove(listener);
1457                 testDisableNativeRoutingCallbacksLocked();
1458             }
1459         }
1460     }
1461 
1462     //--------------------------------------------------------------------------
1463     // (Re)Routing Info
1464     //--------------------
1465     /**
1466      * Defines the interface by which applications can receive notifications of
1467      * routing changes for the associated {@link AudioRecord}.
1468      *
1469      * @deprecated users should switch to the general purpose
1470      *             {@link AudioRouting.OnRoutingChangedListener} class instead.
1471      */
1472     @Deprecated
1473     public interface OnRoutingChangedListener extends AudioRouting.OnRoutingChangedListener {
1474         /**
1475          * Called when the routing of an AudioRecord changes from either and
1476          * explicit or policy rerouting. Use {@link #getRoutedDevice()} to
1477          * retrieve the newly routed-from device.
1478          */
onRoutingChanged(AudioRecord audioRecord)1479         public void onRoutingChanged(AudioRecord audioRecord);
1480 
1481         @Override
onRoutingChanged(AudioRouting router)1482         default public void onRoutingChanged(AudioRouting router) {
1483             if (router instanceof AudioRecord) {
1484                 onRoutingChanged((AudioRecord) router);
1485             }
1486         }
1487     }
1488 
1489     /**
1490      * Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes
1491      * on this AudioRecord.
1492      * @param listener The {@link OnRoutingChangedListener} interface to receive notifications
1493      * of rerouting events.
1494      * @param handler  Specifies the {@link Handler} object for the thread on which to execute
1495      * the callback. If <code>null</code>, the {@link Handler} associated with the main
1496      * {@link Looper} will be used.
1497      * @deprecated users should switch to the general purpose
1498      *             {@link AudioRouting.OnRoutingChangedListener} class instead.
1499      */
1500     @Deprecated
addOnRoutingChangedListener(OnRoutingChangedListener listener, android.os.Handler handler)1501     public void addOnRoutingChangedListener(OnRoutingChangedListener listener,
1502             android.os.Handler handler) {
1503         addOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener, handler);
1504     }
1505 
1506     /**
1507       * Removes an {@link OnRoutingChangedListener} which has been previously added
1508      * to receive rerouting notifications.
1509      * @param listener The previously added {@link OnRoutingChangedListener} interface to remove.
1510      * @deprecated users should switch to the general purpose
1511      *             {@link AudioRouting.OnRoutingChangedListener} class instead.
1512      */
1513     @Deprecated
removeOnRoutingChangedListener(OnRoutingChangedListener listener)1514     public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) {
1515         removeOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener);
1516     }
1517 
1518     /**
1519      * Helper class to handle the forwarding of native events to the appropriate listener
1520      * (potentially) handled in a different thread
1521      */
1522     private class NativeRoutingEventHandlerDelegate {
1523         private final Handler mHandler;
1524 
NativeRoutingEventHandlerDelegate(final AudioRecord record, final AudioRouting.OnRoutingChangedListener listener, Handler handler)1525         NativeRoutingEventHandlerDelegate(final AudioRecord record,
1526                                    final AudioRouting.OnRoutingChangedListener listener,
1527                                    Handler handler) {
1528             // find the looper for our new event handler
1529             Looper looper;
1530             if (handler != null) {
1531                 looper = handler.getLooper();
1532             } else {
1533                 // no given handler, use the looper the AudioRecord was created in
1534                 looper = mInitializationLooper;
1535             }
1536 
1537             // construct the event handler with this looper
1538             if (looper != null) {
1539                 // implement the event handler delegate
1540                 mHandler = new Handler(looper) {
1541                     @Override
1542                     public void handleMessage(Message msg) {
1543                         if (record == null) {
1544                             return;
1545                         }
1546                         switch(msg.what) {
1547                         case AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
1548                             if (listener != null) {
1549                                 listener.onRoutingChanged(record);
1550                             }
1551                             break;
1552                         default:
1553                             loge("Unknown native event type: " + msg.what);
1554                             break;
1555                         }
1556                     }
1557                 };
1558             } else {
1559                 mHandler = null;
1560             }
1561         }
1562 
getHandler()1563         Handler getHandler() {
1564             return mHandler;
1565         }
1566     }
1567 
1568     /**
1569      * Sends device list change notification to all listeners.
1570      */
broadcastRoutingChange()1571     private void broadcastRoutingChange() {
1572         AudioManager.resetAudioPortGeneration();
1573         synchronized (mRoutingChangeListeners) {
1574             for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) {
1575                 Handler handler = delegate.getHandler();
1576                 if (handler != null) {
1577                     handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
1578                 }
1579             }
1580         }
1581     }
1582 
1583     /**
1584      * Sets the period at which the listener is called, if set with
1585      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
1586      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
1587      * It is possible for notifications to be lost if the period is too small.
1588      * @param periodInFrames update period expressed in frames
1589      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
1590      */
setPositionNotificationPeriod(int periodInFrames)1591     public int setPositionNotificationPeriod(int periodInFrames) {
1592         if (mState == STATE_UNINITIALIZED) {
1593             return ERROR_INVALID_OPERATION;
1594         }
1595         return native_set_pos_update_period(periodInFrames);
1596     }
1597 
1598     //--------------------------------------------------------------------------
1599     // Explicit Routing
1600     //--------------------
1601     private AudioDeviceInfo mPreferredDevice = null;
1602 
1603     /**
1604      * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
1605      * the input to this AudioRecord.
1606      * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio source.
1607      *  If deviceInfo is null, default routing is restored.
1608      * @return true if successful, false if the specified {@link AudioDeviceInfo} is non-null and
1609      * does not correspond to a valid audio input device.
1610      */
1611     @Override
setPreferredDevice(AudioDeviceInfo deviceInfo)1612     public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
1613         // Do some validation....
1614         if (deviceInfo != null && !deviceInfo.isSource()) {
1615             return false;
1616         }
1617 
1618         int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
1619         boolean status = native_setInputDevice(preferredDeviceId);
1620         if (status == true) {
1621             synchronized (this) {
1622                 mPreferredDevice = deviceInfo;
1623             }
1624         }
1625         return status;
1626     }
1627 
1628     /**
1629      * Returns the selected input specified by {@link #setPreferredDevice}. Note that this
1630      * is not guarenteed to correspond to the actual device being used for recording.
1631      */
1632     @Override
getPreferredDevice()1633     public AudioDeviceInfo getPreferredDevice() {
1634         synchronized (this) {
1635             return mPreferredDevice;
1636         }
1637     }
1638 
1639     //---------------------------------------------------------
1640     // Interface definitions
1641     //--------------------
1642     /**
1643      * Interface definition for a callback to be invoked when an AudioRecord has
1644      * reached a notification marker set by {@link AudioRecord#setNotificationMarkerPosition(int)}
1645      * or for periodic updates on the progress of the record head, as set by
1646      * {@link AudioRecord#setPositionNotificationPeriod(int)}.
1647      */
1648     public interface OnRecordPositionUpdateListener  {
1649         /**
1650          * Called on the listener to notify it that the previously set marker has been reached
1651          * by the recording head.
1652          */
onMarkerReached(AudioRecord recorder)1653         void onMarkerReached(AudioRecord recorder);
1654 
1655         /**
1656          * Called on the listener to periodically notify it that the record head has reached
1657          * a multiple of the notification period.
1658          */
onPeriodicNotification(AudioRecord recorder)1659         void onPeriodicNotification(AudioRecord recorder);
1660     }
1661 
1662 
1663 
1664     //---------------------------------------------------------
1665     // Inner classes
1666     //--------------------
1667 
1668     /**
1669      * Helper class to handle the forwarding of native events to the appropriate listener
1670      * (potentially) handled in a different thread
1671      */
1672     private class NativeEventHandler extends Handler {
1673         private final AudioRecord mAudioRecord;
1674 
NativeEventHandler(AudioRecord recorder, Looper looper)1675         NativeEventHandler(AudioRecord recorder, Looper looper) {
1676             super(looper);
1677             mAudioRecord = recorder;
1678         }
1679 
1680         @Override
handleMessage(Message msg)1681         public void handleMessage(Message msg) {
1682             OnRecordPositionUpdateListener listener = null;
1683             synchronized (mPositionListenerLock) {
1684                 listener = mAudioRecord.mPositionListener;
1685             }
1686 
1687             switch (msg.what) {
1688             case NATIVE_EVENT_MARKER:
1689                 if (listener != null) {
1690                     listener.onMarkerReached(mAudioRecord);
1691                 }
1692                 break;
1693             case NATIVE_EVENT_NEW_POS:
1694                 if (listener != null) {
1695                     listener.onPeriodicNotification(mAudioRecord);
1696                 }
1697                 break;
1698             default:
1699                 loge("Unknown native event type: " + msg.what);
1700                 break;
1701             }
1702         }
1703     }
1704 
1705     //---------------------------------------------------------
1706     // Java methods called from the native side
1707     //--------------------
1708     @SuppressWarnings("unused")
postEventFromNative(Object audiorecord_ref, int what, int arg1, int arg2, Object obj)1709     private static void postEventFromNative(Object audiorecord_ref,
1710             int what, int arg1, int arg2, Object obj) {
1711         //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
1712         AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get();
1713         if (recorder == null) {
1714             return;
1715         }
1716 
1717         if (what == AudioSystem.NATIVE_EVENT_ROUTING_CHANGE) {
1718             recorder.broadcastRoutingChange();
1719             return;
1720         }
1721 
1722         if (recorder.mEventHandler != null) {
1723             Message m =
1724                 recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj);
1725             recorder.mEventHandler.sendMessage(m);
1726         }
1727 
1728     }
1729 
1730 
1731     //---------------------------------------------------------
1732     // Native methods called from the Java side
1733     //--------------------
1734 
native_setup(Object audiorecord_this, Object attributes, int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, int buffSizeInBytes, int[] sessionId, String opPackageName, long nativeRecordInJavaObj)1735     private native final int native_setup(Object audiorecord_this,
1736             Object /*AudioAttributes*/ attributes,
1737             int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
1738             int buffSizeInBytes, int[] sessionId, String opPackageName,
1739             long nativeRecordInJavaObj);
1740 
1741     // TODO remove: implementation calls directly into implementation of native_release()
native_finalize()1742     private native final void native_finalize();
1743 
1744     /**
1745      * @hide
1746      */
native_release()1747     public native final void native_release();
1748 
native_start(int syncEvent, int sessionId)1749     private native final int native_start(int syncEvent, int sessionId);
1750 
native_stop()1751     private native final void native_stop();
1752 
native_read_in_byte_array(byte[] audioData, int offsetInBytes, int sizeInBytes, boolean isBlocking)1753     private native final int native_read_in_byte_array(byte[] audioData,
1754             int offsetInBytes, int sizeInBytes, boolean isBlocking);
1755 
native_read_in_short_array(short[] audioData, int offsetInShorts, int sizeInShorts, boolean isBlocking)1756     private native final int native_read_in_short_array(short[] audioData,
1757             int offsetInShorts, int sizeInShorts, boolean isBlocking);
1758 
native_read_in_float_array(float[] audioData, int offsetInFloats, int sizeInFloats, boolean isBlocking)1759     private native final int native_read_in_float_array(float[] audioData,
1760             int offsetInFloats, int sizeInFloats, boolean isBlocking);
1761 
native_read_in_direct_buffer(Object jBuffer, int sizeInBytes, boolean isBlocking)1762     private native final int native_read_in_direct_buffer(Object jBuffer,
1763             int sizeInBytes, boolean isBlocking);
1764 
native_get_buffer_size_in_frames()1765     private native final int native_get_buffer_size_in_frames();
1766 
native_set_marker_pos(int marker)1767     private native final int native_set_marker_pos(int marker);
native_get_marker_pos()1768     private native final int native_get_marker_pos();
1769 
native_set_pos_update_period(int updatePeriod)1770     private native final int native_set_pos_update_period(int updatePeriod);
native_get_pos_update_period()1771     private native final int native_get_pos_update_period();
1772 
native_get_min_buff_size( int sampleRateInHz, int channelCount, int audioFormat)1773     static private native final int native_get_min_buff_size(
1774             int sampleRateInHz, int channelCount, int audioFormat);
1775 
native_setInputDevice(int deviceId)1776     private native final boolean native_setInputDevice(int deviceId);
native_getRoutedDeviceId()1777     private native final int native_getRoutedDeviceId();
native_enableDeviceCallback()1778     private native final void native_enableDeviceCallback();
native_disableDeviceCallback()1779     private native final void native_disableDeviceCallback();
1780 
native_get_timestamp(@onNull AudioTimestamp outTimestamp, @AudioTimestamp.Timebase int timebase)1781     private native final int native_get_timestamp(@NonNull AudioTimestamp outTimestamp,
1782             @AudioTimestamp.Timebase int timebase);
1783 
1784     //---------------------------------------------------------
1785     // Utility methods
1786     //------------------
1787 
logd(String msg)1788     private static void logd(String msg) {
1789         Log.d(TAG, msg);
1790     }
1791 
loge(String msg)1792     private static void loge(String msg) {
1793         Log.e(TAG, msg);
1794     }
1795 }
1796