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.");
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."
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.");
726         }
727 
728         mNativeBufferSizeInBytes = audioBufferSize;
729     }
730 
731 
732 
733     /**
734      * Releases the native AudioRecord resources.
735      * The object can no longer be used and the reference should be set to null
736      * after a call to release()
737      */
release()738     public void release() {
739         try {
740             stop();
741         } catch(IllegalStateException ise) {
742             // don't raise an exception, we're releasing the resources.
743         }
744         native_release();
745         mState = STATE_UNINITIALIZED;
746     }
747 
748 
749     @Override
finalize()750     protected void finalize() {
751         // will cause stop() to be called, and if appropriate, will handle fixed volume recording
752         release();
753     }
754 
755 
756     //--------------------------------------------------------------------------
757     // Getters
758     //--------------------
759     /**
760      * Returns the configured audio sink sample rate in Hz.
761      * The sink sample rate never changes after construction.
762      * If the constructor had a specific sample rate, then the sink sample rate is that value.
763      * If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED},
764      * then the sink sample rate is a route-dependent default value based on the source [sic].
765      */
getSampleRate()766     public int getSampleRate() {
767         return mSampleRate;
768     }
769 
770     /**
771      * Returns the audio recording source.
772      * @see MediaRecorder.AudioSource
773      */
getAudioSource()774     public int getAudioSource() {
775         return mRecordSource;
776     }
777 
778     /**
779      * Returns the configured audio data encoding. See {@link AudioFormat#ENCODING_PCM_8BIT},
780      * {@link AudioFormat#ENCODING_PCM_16BIT}, and {@link AudioFormat#ENCODING_PCM_FLOAT}.
781      */
getAudioFormat()782     public int getAudioFormat() {
783         return mAudioFormat;
784     }
785 
786     /**
787      * Returns the configured channel position mask.
788      * <p> See {@link AudioFormat#CHANNEL_IN_MONO}
789      * and {@link AudioFormat#CHANNEL_IN_STEREO}.
790      * This method may return {@link AudioFormat#CHANNEL_INVALID} if
791      * a channel index mask is used.
792      * Consider {@link #getFormat()} instead, to obtain an {@link AudioFormat},
793      * which contains both the channel position mask and the channel index mask.
794      */
getChannelConfiguration()795     public int getChannelConfiguration() {
796         return mChannelMask;
797     }
798 
799     /**
800      * Returns the configured <code>AudioRecord</code> format.
801      * @return an {@link AudioFormat} containing the
802      * <code>AudioRecord</code> parameters at the time of configuration.
803      */
getFormat()804     public @NonNull AudioFormat getFormat() {
805         AudioFormat.Builder builder = new AudioFormat.Builder()
806             .setSampleRate(mSampleRate)
807             .setEncoding(mAudioFormat);
808         if (mChannelMask != AudioFormat.CHANNEL_INVALID) {
809             builder.setChannelMask(mChannelMask);
810         }
811         if (mChannelIndexMask != AudioFormat.CHANNEL_INVALID  /* 0 */) {
812             builder.setChannelIndexMask(mChannelIndexMask);
813         }
814         return builder.build();
815     }
816 
817     /**
818      * Returns the configured number of channels.
819      */
getChannelCount()820     public int getChannelCount() {
821         return mChannelCount;
822     }
823 
824     /**
825      * Returns the state of the AudioRecord instance. This is useful after the
826      * AudioRecord instance has been created to check if it was initialized
827      * properly. This ensures that the appropriate hardware resources have been
828      * acquired.
829      * @see AudioRecord#STATE_INITIALIZED
830      * @see AudioRecord#STATE_UNINITIALIZED
831      */
getState()832     public int getState() {
833         return mState;
834     }
835 
836     /**
837      * Returns the recording state of the AudioRecord instance.
838      * @see AudioRecord#RECORDSTATE_STOPPED
839      * @see AudioRecord#RECORDSTATE_RECORDING
840      */
getRecordingState()841     public int getRecordingState() {
842         synchronized (mRecordingStateLock) {
843             return mRecordingState;
844         }
845     }
846 
847     /**
848      *  Returns the frame count of the native <code>AudioRecord</code> buffer.
849      *  This is greater than or equal to the bufferSizeInBytes converted to frame units
850      *  specified in the <code>AudioRecord</code> constructor or Builder.
851      *  The native frame count may be enlarged to accommodate the requirements of the
852      *  source on creation or if the <code>AudioRecord</code>
853      *  is subsequently rerouted.
854      *  @return current size in frames of the <code>AudioRecord</code> buffer.
855      *  @throws IllegalStateException
856      */
getBufferSizeInFrames()857     public int getBufferSizeInFrames() {
858         return native_get_buffer_size_in_frames();
859     }
860 
861     /**
862      * Returns the notification marker position expressed in frames.
863      */
getNotificationMarkerPosition()864     public int getNotificationMarkerPosition() {
865         return native_get_marker_pos();
866     }
867 
868     /**
869      * Returns the notification update period expressed in frames.
870      */
getPositionNotificationPeriod()871     public int getPositionNotificationPeriod() {
872         return native_get_pos_update_period();
873     }
874 
875     /**
876      * Poll for an {@link AudioTimestamp} on demand.
877      * <p>
878      * The AudioTimestamp reflects the frame delivery information at
879      * the earliest point available in the capture pipeline.
880      * <p>
881      * Calling {@link #startRecording()} following a {@link #stop()} will reset
882      * the frame count to 0.
883      *
884      * @param outTimestamp a caller provided non-null AudioTimestamp instance,
885      *        which is updated with the AudioRecord frame delivery information upon success.
886      * @param timebase one of
887      *        {@link AudioTimestamp#TIMEBASE_BOOTTIME AudioTimestamp.TIMEBASE_BOOTTIME} or
888      *        {@link AudioTimestamp#TIMEBASE_MONOTONIC AudioTimestamp.TIMEBASE_MONOTONIC},
889      *        used to select the clock for the AudioTimestamp time.
890      * @return {@link #SUCCESS} if a timestamp is available,
891      *         or {@link #ERROR_INVALID_OPERATION} if a timestamp not available.
892      */
getTimestamp(@onNull AudioTimestamp outTimestamp, @AudioTimestamp.Timebase int timebase)893      public int getTimestamp(@NonNull AudioTimestamp outTimestamp,
894              @AudioTimestamp.Timebase int timebase)
895      {
896          if (outTimestamp == null ||
897                  (timebase != AudioTimestamp.TIMEBASE_BOOTTIME
898                  && timebase != AudioTimestamp.TIMEBASE_MONOTONIC)) {
899              throw new IllegalArgumentException();
900          }
901          return native_get_timestamp(outTimestamp, timebase);
902      }
903 
904     /**
905      * Returns the minimum buffer size required for the successful creation of an AudioRecord
906      * object, in byte units.
907      * Note that this size doesn't guarantee a smooth recording under load, and higher values
908      * should be chosen according to the expected frequency at which the AudioRecord instance
909      * will be polled for new data.
910      * See {@link #AudioRecord(int, int, int, int, int)} for more information on valid
911      * configuration values.
912      * @param sampleRateInHz the sample rate expressed in Hertz.
913      *   {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted.
914      * @param channelConfig describes the configuration of the audio channels.
915      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
916      *   {@link AudioFormat#CHANNEL_IN_STEREO}
917      * @param audioFormat the format in which the audio data is represented.
918      *   See {@link AudioFormat#ENCODING_PCM_16BIT}.
919      * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the
920      *  hardware, or an invalid parameter was passed,
921      *  or {@link #ERROR} if the implementation was unable to query the hardware for its
922      *  input properties,
923      *   or the minimum buffer size expressed in bytes.
924      * @see #AudioRecord(int, int, int, int, int)
925      */
getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)926     static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
927         int channelCount = 0;
928         switch (channelConfig) {
929         case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
930         case AudioFormat.CHANNEL_IN_MONO:
931         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
932             channelCount = 1;
933             break;
934         case AudioFormat.CHANNEL_IN_STEREO:
935         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
936         case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
937             channelCount = 2;
938             break;
939         case AudioFormat.CHANNEL_INVALID:
940         default:
941             loge("getMinBufferSize(): Invalid channel configuration.");
942             return ERROR_BAD_VALUE;
943         }
944 
945         int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
946         if (size == 0) {
947             return ERROR_BAD_VALUE;
948         }
949         else if (size == -1) {
950             return ERROR;
951         }
952         else {
953             return size;
954         }
955     }
956 
957     /**
958      * Returns the audio session ID.
959      *
960      * @return the ID of the audio session this AudioRecord belongs to.
961      */
getAudioSessionId()962     public int getAudioSessionId() {
963         return mSessionId;
964     }
965 
966     //---------------------------------------------------------
967     // Transport control methods
968     //--------------------
969     /**
970      * Starts recording from the AudioRecord instance.
971      * @throws IllegalStateException
972      */
startRecording()973     public void startRecording()
974     throws IllegalStateException {
975         if (mState != STATE_INITIALIZED) {
976             throw new IllegalStateException("startRecording() called on an "
977                     + "uninitialized AudioRecord.");
978         }
979 
980         // start recording
981         synchronized(mRecordingStateLock) {
982             if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) {
983                 handleFullVolumeRec(true);
984                 mRecordingState = RECORDSTATE_RECORDING;
985             }
986         }
987     }
988 
989     /**
990      * Starts recording from the AudioRecord instance when the specified synchronization event
991      * occurs on the specified audio session.
992      * @throws IllegalStateException
993      * @param syncEvent event that triggers the capture.
994      * @see MediaSyncEvent
995      */
startRecording(MediaSyncEvent syncEvent)996     public void startRecording(MediaSyncEvent syncEvent)
997     throws IllegalStateException {
998         if (mState != STATE_INITIALIZED) {
999             throw new IllegalStateException("startRecording() called on an "
1000                     + "uninitialized AudioRecord.");
1001         }
1002 
1003         // start recording
1004         synchronized(mRecordingStateLock) {
1005             if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) {
1006                 handleFullVolumeRec(true);
1007                 mRecordingState = RECORDSTATE_RECORDING;
1008             }
1009         }
1010     }
1011 
1012     /**
1013      * Stops recording.
1014      * @throws IllegalStateException
1015      */
stop()1016     public void stop()
1017     throws IllegalStateException {
1018         if (mState != STATE_INITIALIZED) {
1019             throw new IllegalStateException("stop() called on an uninitialized AudioRecord.");
1020         }
1021 
1022         // stop recording
1023         synchronized(mRecordingStateLock) {
1024             handleFullVolumeRec(false);
1025             native_stop();
1026             mRecordingState = RECORDSTATE_STOPPED;
1027         }
1028     }
1029 
1030     private final IBinder mICallBack = new Binder();
handleFullVolumeRec(boolean starting)1031     private void handleFullVolumeRec(boolean starting) {
1032         if (!mIsSubmixFullVolume) {
1033             return;
1034         }
1035         final IBinder b = ServiceManager.getService(android.content.Context.AUDIO_SERVICE);
1036         final IAudioService ias = IAudioService.Stub.asInterface(b);
1037         try {
1038             ias.forceRemoteSubmixFullVolume(starting, mICallBack);
1039         } catch (RemoteException e) {
1040             Log.e(TAG, "Error talking to AudioService when handling full submix volume", e);
1041         }
1042     }
1043 
1044     //---------------------------------------------------------
1045     // Audio data supply
1046     //--------------------
1047     /**
1048      * Reads audio data from the audio hardware for recording into a byte array.
1049      * The format specified in the AudioRecord constructor should be
1050      * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
1051      * @param audioData the array to which the recorded audio data is written.
1052      * @param offsetInBytes index in audioData from which the data is written expressed in bytes.
1053      * @param sizeInBytes the number of requested bytes.
1054      * @return zero or the positive number of bytes that were read, or one of the following
1055      *    error codes. The number of bytes will not exceed sizeInBytes.
1056      * <ul>
1057      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1058      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1059      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1060      *    needs to be recreated. The dead object error code is not returned if some data was
1061      *    successfully transferred. In this case, the error is returned at the next read()</li>
1062      * <li>{@link #ERROR} in case of other error</li>
1063      * </ul>
1064      */
read(@onNull byte[] audioData, int offsetInBytes, int sizeInBytes)1065     public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) {
1066         return read(audioData, offsetInBytes, sizeInBytes, READ_BLOCKING);
1067     }
1068 
1069     /**
1070      * Reads audio data from the audio hardware for recording into a byte array.
1071      * The format specified in the AudioRecord constructor should be
1072      * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
1073      * The format can be {@link AudioFormat#ENCODING_PCM_16BIT}, but this is deprecated.
1074      * @param audioData the array to which the recorded audio data is written.
1075      * @param offsetInBytes index in audioData to which the data is written expressed in bytes.
1076      *        Must not be negative, or cause the data access to go out of bounds of the array.
1077      * @param sizeInBytes the number of requested bytes.
1078      *        Must not be negative, or cause the data access to go out of bounds of the array.
1079      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1080      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1081      *     is read.
1082      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1083      *     reading as much audio data as possible without blocking.
1084      * @return zero or the positive number of bytes that were read, or one of the following
1085      *    error codes. The number of bytes will be a multiple of the frame size in bytes
1086      *    not to exceed sizeInBytes.
1087      * <ul>
1088      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1089      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1090      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1091      *    needs to be recreated. The dead object error code is not returned if some data was
1092      *    successfully transferred. In this case, the error is returned at the next read()</li>
1093      * <li>{@link #ERROR} in case of other error</li>
1094      * </ul>
1095      */
read(@onNull byte[] audioData, int offsetInBytes, int sizeInBytes, @ReadMode int readMode)1096     public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
1097             @ReadMode int readMode) {
1098         if (mState != STATE_INITIALIZED  || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
1099             return ERROR_INVALID_OPERATION;
1100         }
1101 
1102         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1103             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1104             return ERROR_BAD_VALUE;
1105         }
1106 
1107         if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
1108                 || (offsetInBytes + sizeInBytes < 0)  // detect integer overflow
1109                 || (offsetInBytes + sizeInBytes > audioData.length)) {
1110             return ERROR_BAD_VALUE;
1111         }
1112 
1113         return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes,
1114                 readMode == READ_BLOCKING);
1115     }
1116 
1117     /**
1118      * Reads audio data from the audio hardware for recording into a short array.
1119      * The format specified in the AudioRecord constructor should be
1120      * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
1121      * @param audioData the array to which the recorded audio data is written.
1122      * @param offsetInShorts index in audioData to which the data is written expressed in shorts.
1123      *        Must not be negative, or cause the data access to go out of bounds of the array.
1124      * @param sizeInShorts the number of requested shorts.
1125      *        Must not be negative, or cause the data access to go out of bounds of the array.
1126      * @return zero or the positive number of shorts that were read, or one of the following
1127      *    error codes. The number of shorts will be a multiple of the channel count not to exceed
1128      *    sizeInShorts.
1129      * <ul>
1130      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1131      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1132      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1133      *    needs to be recreated. The dead object error code is not returned if some data was
1134      *    successfully transferred. In this case, the error is returned at the next read()</li>
1135      * <li>{@link #ERROR} in case of other error</li>
1136      * </ul>
1137      */
read(@onNull short[] audioData, int offsetInShorts, int sizeInShorts)1138     public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) {
1139         return read(audioData, offsetInShorts, sizeInShorts, READ_BLOCKING);
1140     }
1141 
1142     /**
1143      * Reads audio data from the audio hardware for recording into a short array.
1144      * The format specified in the AudioRecord constructor should be
1145      * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
1146      * @param audioData the array to which the recorded audio data is written.
1147      * @param offsetInShorts index in audioData from which the data is written expressed in shorts.
1148      *        Must not be negative, or cause the data access to go out of bounds of the array.
1149      * @param sizeInShorts the number of requested shorts.
1150      *        Must not be negative, or cause the data access to go out of bounds of the array.
1151      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1152      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1153      *     is read.
1154      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1155      *     reading as much audio data as possible without blocking.
1156      * @return zero or the positive number of shorts that were read, or one of the following
1157      *    error codes. The number of shorts will be a multiple of the channel count not to exceed
1158      *    sizeInShorts.
1159      * <ul>
1160      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1161      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1162      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1163      *    needs to be recreated. The dead object error code is not returned if some data was
1164      *    successfully transferred. In this case, the error is returned at the next read()</li>
1165      * <li>{@link #ERROR} in case of other error</li>
1166      * </ul>
1167      */
read(@onNull short[] audioData, int offsetInShorts, int sizeInShorts, @ReadMode int readMode)1168     public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
1169             @ReadMode int readMode) {
1170         if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
1171             return ERROR_INVALID_OPERATION;
1172         }
1173 
1174         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1175             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1176             return ERROR_BAD_VALUE;
1177         }
1178 
1179         if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
1180                 || (offsetInShorts + sizeInShorts < 0)  // detect integer overflow
1181                 || (offsetInShorts + sizeInShorts > audioData.length)) {
1182             return ERROR_BAD_VALUE;
1183         }
1184 
1185         return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts,
1186                 readMode == READ_BLOCKING);
1187     }
1188 
1189     /**
1190      * Reads audio data from the audio hardware for recording into a float array.
1191      * The format specified in the AudioRecord constructor should be
1192      * {@link AudioFormat#ENCODING_PCM_FLOAT} to correspond to the data in the array.
1193      * @param audioData the array to which the recorded audio data is written.
1194      * @param offsetInFloats index in audioData from which the data is written.
1195      *        Must not be negative, or cause the data access to go out of bounds of the array.
1196      * @param sizeInFloats the number of requested floats.
1197      *        Must not be negative, or cause the data access to go out of bounds of the array.
1198      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1199      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1200      *     is read.
1201      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1202      *     reading as much audio data as possible without blocking.
1203      * @return zero or the positive number of floats that were read, or one of the following
1204      *    error codes. The number of floats will be a multiple of the channel count not to exceed
1205      *    sizeInFloats.
1206      * <ul>
1207      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1208      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1209      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1210      *    needs to be recreated. The dead object error code is not returned if some data was
1211      *    successfully transferred. In this case, the error is returned at the next read()</li>
1212      * <li>{@link #ERROR} in case of other error</li>
1213      * </ul>
1214      */
read(@onNull float[] audioData, int offsetInFloats, int sizeInFloats, @ReadMode int readMode)1215     public int read(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
1216             @ReadMode int readMode) {
1217         if (mState == STATE_UNINITIALIZED) {
1218             Log.e(TAG, "AudioRecord.read() called in invalid state STATE_UNINITIALIZED");
1219             return ERROR_INVALID_OPERATION;
1220         }
1221 
1222         if (mAudioFormat != AudioFormat.ENCODING_PCM_FLOAT) {
1223             Log.e(TAG, "AudioRecord.read(float[] ...) requires format ENCODING_PCM_FLOAT");
1224             return ERROR_INVALID_OPERATION;
1225         }
1226 
1227         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1228             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1229             return ERROR_BAD_VALUE;
1230         }
1231 
1232         if ((audioData == null) || (offsetInFloats < 0) || (sizeInFloats < 0)
1233                 || (offsetInFloats + sizeInFloats < 0)  // detect integer overflow
1234                 || (offsetInFloats + sizeInFloats > audioData.length)) {
1235             return ERROR_BAD_VALUE;
1236         }
1237 
1238         return native_read_in_float_array(audioData, offsetInFloats, sizeInFloats,
1239                 readMode == READ_BLOCKING);
1240     }
1241 
1242     /**
1243      * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
1244      * is not a direct buffer, this method will always return 0.
1245      * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
1246      * unchanged after a call to this method.
1247      * The representation of the data in the buffer will depend on the format specified in
1248      * the AudioRecord constructor, and will be native endian.
1249      * @param audioBuffer the direct buffer to which the recorded audio data is written.
1250      * Data is written to audioBuffer.position().
1251      * @param sizeInBytes the number of requested bytes. It is recommended but not enforced
1252      *    that the number of bytes requested be a multiple of the frame size (sample size in
1253      *    bytes multiplied by the channel count).
1254      * @return zero or the positive number of bytes that were read, or one of the following
1255      *    error codes. The number of bytes will not exceed sizeInBytes and will be truncated to be
1256      *    a multiple of the frame size.
1257      * <ul>
1258      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1259      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1260      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1261      *    needs to be recreated. The dead object error code is not returned if some data was
1262      *    successfully transferred. In this case, the error is returned at the next read()</li>
1263      * <li>{@link #ERROR} in case of other error</li>
1264      * </ul>
1265      */
read(@onNull ByteBuffer audioBuffer, int sizeInBytes)1266     public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes) {
1267         return read(audioBuffer, sizeInBytes, READ_BLOCKING);
1268     }
1269 
1270     /**
1271      * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
1272      * is not a direct buffer, this method will always return 0.
1273      * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
1274      * unchanged after a call to this method.
1275      * The representation of the data in the buffer will depend on the format specified in
1276      * the AudioRecord constructor, and will be native endian.
1277      * @param audioBuffer the direct buffer to which the recorded audio data is written.
1278      * Data is written to audioBuffer.position().
1279      * @param sizeInBytes the number of requested bytes. It is recommended but not enforced
1280      *    that the number of bytes requested be a multiple of the frame size (sample size in
1281      *    bytes multiplied by the channel count).
1282      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1283      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1284      *     is read.
1285      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1286      *     reading as much audio data as possible without blocking.
1287      * @return zero or the positive number of bytes that were read, or one of the following
1288      *    error codes. The number of bytes will not exceed sizeInBytes and will be truncated to be
1289      *    a multiple of the frame size.
1290      * <ul>
1291      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1292      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1293      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1294      *    needs to be recreated. The dead object error code is not returned if some data was
1295      *    successfully transferred. In this case, the error is returned at the next read()</li>
1296      * <li>{@link #ERROR} in case of other error</li>
1297      * </ul>
1298      */
read(@onNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode)1299     public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode) {
1300         if (mState != STATE_INITIALIZED) {
1301             return ERROR_INVALID_OPERATION;
1302         }
1303 
1304         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1305             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1306             return ERROR_BAD_VALUE;
1307         }
1308 
1309         if ( (audioBuffer == null) || (sizeInBytes < 0) ) {
1310             return ERROR_BAD_VALUE;
1311         }
1312 
1313         return native_read_in_direct_buffer(audioBuffer, sizeInBytes, readMode == READ_BLOCKING);
1314     }
1315 
1316     //--------------------------------------------------------------------------
1317     // Initialization / configuration
1318     //--------------------
1319     /**
1320      * Sets the listener the AudioRecord notifies when a previously set marker is reached or
1321      * for each periodic record head position update.
1322      * @param listener
1323      */
setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener)1324     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener) {
1325         setRecordPositionUpdateListener(listener, null);
1326     }
1327 
1328     /**
1329      * Sets the listener the AudioRecord notifies when a previously set marker is reached or
1330      * for each periodic record head position update.
1331      * Use this method to receive AudioRecord events in the Handler associated with another
1332      * thread than the one in which you created the AudioRecord instance.
1333      * @param listener
1334      * @param handler the Handler that will receive the event notification messages.
1335      */
setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, Handler handler)1336     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener,
1337                                                     Handler handler) {
1338         synchronized (mPositionListenerLock) {
1339 
1340             mPositionListener = listener;
1341 
1342             if (listener != null) {
1343                 if (handler != null) {
1344                     mEventHandler = new NativeEventHandler(this, handler.getLooper());
1345                 } else {
1346                     // no given handler, use the looper the AudioRecord was created in
1347                     mEventHandler = new NativeEventHandler(this, mInitializationLooper);
1348                 }
1349             } else {
1350                 mEventHandler = null;
1351             }
1352         }
1353 
1354     }
1355 
1356 
1357     /**
1358      * Sets the marker position at which the listener is called, if set with
1359      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
1360      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
1361      * @param markerInFrames marker position expressed in frames
1362      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
1363      *  {@link #ERROR_INVALID_OPERATION}
1364      */
setNotificationMarkerPosition(int markerInFrames)1365     public int setNotificationMarkerPosition(int markerInFrames) {
1366         if (mState == STATE_UNINITIALIZED) {
1367             return ERROR_INVALID_OPERATION;
1368         }
1369         return native_set_marker_pos(markerInFrames);
1370     }
1371 
1372     /**
1373      * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord.
1374      * Note: The query is only valid if the AudioRecord is currently recording. If it is not,
1375      * <code>getRoutedDevice()</code> will return null.
1376      */
1377     @Override
getRoutedDevice()1378     public AudioDeviceInfo getRoutedDevice() {
1379         int deviceId = native_getRoutedDeviceId();
1380         if (deviceId == 0) {
1381             return null;
1382         }
1383         AudioDeviceInfo[] devices =
1384                 AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
1385         for (int i = 0; i < devices.length; i++) {
1386             if (devices[i].getId() == deviceId) {
1387                 return devices[i];
1388             }
1389         }
1390         return null;
1391     }
1392 
1393     /*
1394      * Call BEFORE adding a routing callback handler.
1395      */
testEnableNativeRoutingCallbacksLocked()1396     private void testEnableNativeRoutingCallbacksLocked() {
1397         if (mRoutingChangeListeners.size() == 0) {
1398             native_enableDeviceCallback();
1399         }
1400     }
1401 
1402     /*
1403      * Call AFTER removing a routing callback handler.
1404      */
testDisableNativeRoutingCallbacksLocked()1405     private void testDisableNativeRoutingCallbacksLocked() {
1406         if (mRoutingChangeListeners.size() == 0) {
1407             native_disableDeviceCallback();
1408         }
1409     }
1410 
1411     //--------------------------------------------------------------------------
1412     // (Re)Routing Info
1413     //--------------------
1414     /**
1415      * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
1416      * {@link AudioRecord#addOnRoutingChangedListener} by an app to receive
1417      * (re)routing notifications.
1418      */
1419     @GuardedBy("mRoutingChangeListeners")
1420     private ArrayMap<AudioRouting.OnRoutingChangedListener,
1421             NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
1422 
1423     /**
1424      * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of
1425      * routing changes on this AudioRecord.
1426      * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
1427      * notifications of rerouting events.
1428      * @param handler  Specifies the {@link Handler} object for the thread on which to execute
1429      * the callback. If <code>null</code>, the {@link Handler} associated with the main
1430      * {@link Looper} will be used.
1431      */
1432     @Override
addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, android.os.Handler handler)1433     public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
1434             android.os.Handler handler) {
1435         synchronized (mRoutingChangeListeners) {
1436             if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
1437                 testEnableNativeRoutingCallbacksLocked();
1438                 mRoutingChangeListeners.put(
1439                         listener, new NativeRoutingEventHandlerDelegate(this, listener,
1440                                 handler != null ? handler : new Handler(mInitializationLooper)));
1441             }
1442         }
1443     }
1444 
1445     /**
1446      * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
1447     * to receive rerouting notifications.
1448     * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
1449     * to remove.
1450     */
1451     @Override
removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener)1452     public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
1453         synchronized (mRoutingChangeListeners) {
1454             if (mRoutingChangeListeners.containsKey(listener)) {
1455                 mRoutingChangeListeners.remove(listener);
1456                 testDisableNativeRoutingCallbacksLocked();
1457             }
1458         }
1459     }
1460 
1461     //--------------------------------------------------------------------------
1462     // (Re)Routing Info
1463     //--------------------
1464     /**
1465      * Defines the interface by which applications can receive notifications of
1466      * routing changes for the associated {@link AudioRecord}.
1467      *
1468      * @deprecated users should switch to the general purpose
1469      *             {@link AudioRouting.OnRoutingChangedListener} class instead.
1470      */
1471     @Deprecated
1472     public interface OnRoutingChangedListener extends AudioRouting.OnRoutingChangedListener {
1473         /**
1474          * Called when the routing of an AudioRecord changes from either and
1475          * explicit or policy rerouting. Use {@link #getRoutedDevice()} to
1476          * retrieve the newly routed-from device.
1477          */
onRoutingChanged(AudioRecord audioRecord)1478         public void onRoutingChanged(AudioRecord audioRecord);
1479 
1480         @Override
onRoutingChanged(AudioRouting router)1481         default public void onRoutingChanged(AudioRouting router) {
1482             if (router instanceof AudioRecord) {
1483                 onRoutingChanged((AudioRecord) router);
1484             }
1485         }
1486     }
1487 
1488     /**
1489      * Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes
1490      * on this AudioRecord.
1491      * @param listener The {@link OnRoutingChangedListener} interface to receive notifications
1492      * of rerouting events.
1493      * @param handler  Specifies the {@link Handler} object for the thread on which to execute
1494      * the callback. If <code>null</code>, the {@link Handler} associated with the main
1495      * {@link Looper} will be used.
1496      * @deprecated users should switch to the general purpose
1497      *             {@link AudioRouting.OnRoutingChangedListener} class instead.
1498      */
1499     @Deprecated
addOnRoutingChangedListener(OnRoutingChangedListener listener, android.os.Handler handler)1500     public void addOnRoutingChangedListener(OnRoutingChangedListener listener,
1501             android.os.Handler handler) {
1502         addOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener, handler);
1503     }
1504 
1505     /**
1506       * Removes an {@link OnRoutingChangedListener} which has been previously added
1507      * to receive rerouting notifications.
1508      * @param listener The previously added {@link OnRoutingChangedListener} interface to remove.
1509      * @deprecated users should switch to the general purpose
1510      *             {@link AudioRouting.OnRoutingChangedListener} class instead.
1511      */
1512     @Deprecated
removeOnRoutingChangedListener(OnRoutingChangedListener listener)1513     public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) {
1514         removeOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener);
1515     }
1516 
1517     /**
1518      * Helper class to handle the forwarding of native events to the appropriate listener
1519      * (potentially) handled in a different thread
1520      */
1521     private class NativeRoutingEventHandlerDelegate {
1522         private final Handler mHandler;
1523 
NativeRoutingEventHandlerDelegate(final AudioRecord record, final AudioRouting.OnRoutingChangedListener listener, Handler handler)1524         NativeRoutingEventHandlerDelegate(final AudioRecord record,
1525                                    final AudioRouting.OnRoutingChangedListener listener,
1526                                    Handler handler) {
1527             // find the looper for our new event handler
1528             Looper looper;
1529             if (handler != null) {
1530                 looper = handler.getLooper();
1531             } else {
1532                 // no given handler, use the looper the AudioRecord was created in
1533                 looper = mInitializationLooper;
1534             }
1535 
1536             // construct the event handler with this looper
1537             if (looper != null) {
1538                 // implement the event handler delegate
1539                 mHandler = new Handler(looper) {
1540                     @Override
1541                     public void handleMessage(Message msg) {
1542                         if (record == null) {
1543                             return;
1544                         }
1545                         switch(msg.what) {
1546                         case AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
1547                             if (listener != null) {
1548                                 listener.onRoutingChanged(record);
1549                             }
1550                             break;
1551                         default:
1552                             loge("Unknown native event type: " + msg.what);
1553                             break;
1554                         }
1555                     }
1556                 };
1557             } else {
1558                 mHandler = null;
1559             }
1560         }
1561 
getHandler()1562         Handler getHandler() {
1563             return mHandler;
1564         }
1565     }
1566 
1567     /**
1568      * Sends device list change notification to all listeners.
1569      */
broadcastRoutingChange()1570     private void broadcastRoutingChange() {
1571         AudioManager.resetAudioPortGeneration();
1572         synchronized (mRoutingChangeListeners) {
1573             for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) {
1574                 Handler handler = delegate.getHandler();
1575                 if (handler != null) {
1576                     handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
1577                 }
1578             }
1579         }
1580     }
1581 
1582     /**
1583      * Sets the period at which the listener is called, if set with
1584      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
1585      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
1586      * It is possible for notifications to be lost if the period is too small.
1587      * @param periodInFrames update period expressed in frames
1588      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
1589      */
setPositionNotificationPeriod(int periodInFrames)1590     public int setPositionNotificationPeriod(int periodInFrames) {
1591         if (mState == STATE_UNINITIALIZED) {
1592             return ERROR_INVALID_OPERATION;
1593         }
1594         return native_set_pos_update_period(periodInFrames);
1595     }
1596 
1597     //--------------------------------------------------------------------------
1598     // Explicit Routing
1599     //--------------------
1600     private AudioDeviceInfo mPreferredDevice = null;
1601 
1602     /**
1603      * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
1604      * the input to this AudioRecord.
1605      * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio source.
1606      *  If deviceInfo is null, default routing is restored.
1607      * @return true if successful, false if the specified {@link AudioDeviceInfo} is non-null and
1608      * does not correspond to a valid audio input device.
1609      */
1610     @Override
setPreferredDevice(AudioDeviceInfo deviceInfo)1611     public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
1612         // Do some validation....
1613         if (deviceInfo != null && !deviceInfo.isSource()) {
1614             return false;
1615         }
1616 
1617         int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
1618         boolean status = native_setInputDevice(preferredDeviceId);
1619         if (status == true) {
1620             synchronized (this) {
1621                 mPreferredDevice = deviceInfo;
1622             }
1623         }
1624         return status;
1625     }
1626 
1627     /**
1628      * Returns the selected input specified by {@link #setPreferredDevice}. Note that this
1629      * is not guarenteed to correspond to the actual device being used for recording.
1630      */
1631     @Override
getPreferredDevice()1632     public AudioDeviceInfo getPreferredDevice() {
1633         synchronized (this) {
1634             return mPreferredDevice;
1635         }
1636     }
1637 
1638     //---------------------------------------------------------
1639     // Interface definitions
1640     //--------------------
1641     /**
1642      * Interface definition for a callback to be invoked when an AudioRecord has
1643      * reached a notification marker set by {@link AudioRecord#setNotificationMarkerPosition(int)}
1644      * or for periodic updates on the progress of the record head, as set by
1645      * {@link AudioRecord#setPositionNotificationPeriod(int)}.
1646      */
1647     public interface OnRecordPositionUpdateListener  {
1648         /**
1649          * Called on the listener to notify it that the previously set marker has been reached
1650          * by the recording head.
1651          */
onMarkerReached(AudioRecord recorder)1652         void onMarkerReached(AudioRecord recorder);
1653 
1654         /**
1655          * Called on the listener to periodically notify it that the record head has reached
1656          * a multiple of the notification period.
1657          */
onPeriodicNotification(AudioRecord recorder)1658         void onPeriodicNotification(AudioRecord recorder);
1659     }
1660 
1661 
1662 
1663     //---------------------------------------------------------
1664     // Inner classes
1665     //--------------------
1666 
1667     /**
1668      * Helper class to handle the forwarding of native events to the appropriate listener
1669      * (potentially) handled in a different thread
1670      */
1671     private class NativeEventHandler extends Handler {
1672         private final AudioRecord mAudioRecord;
1673 
NativeEventHandler(AudioRecord recorder, Looper looper)1674         NativeEventHandler(AudioRecord recorder, Looper looper) {
1675             super(looper);
1676             mAudioRecord = recorder;
1677         }
1678 
1679         @Override
handleMessage(Message msg)1680         public void handleMessage(Message msg) {
1681             OnRecordPositionUpdateListener listener = null;
1682             synchronized (mPositionListenerLock) {
1683                 listener = mAudioRecord.mPositionListener;
1684             }
1685 
1686             switch (msg.what) {
1687             case NATIVE_EVENT_MARKER:
1688                 if (listener != null) {
1689                     listener.onMarkerReached(mAudioRecord);
1690                 }
1691                 break;
1692             case NATIVE_EVENT_NEW_POS:
1693                 if (listener != null) {
1694                     listener.onPeriodicNotification(mAudioRecord);
1695                 }
1696                 break;
1697             default:
1698                 loge("Unknown native event type: " + msg.what);
1699                 break;
1700             }
1701         }
1702     }
1703 
1704     //---------------------------------------------------------
1705     // Java methods called from the native side
1706     //--------------------
1707     @SuppressWarnings("unused")
postEventFromNative(Object audiorecord_ref, int what, int arg1, int arg2, Object obj)1708     private static void postEventFromNative(Object audiorecord_ref,
1709             int what, int arg1, int arg2, Object obj) {
1710         //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
1711         AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get();
1712         if (recorder == null) {
1713             return;
1714         }
1715 
1716         if (what == AudioSystem.NATIVE_EVENT_ROUTING_CHANGE) {
1717             recorder.broadcastRoutingChange();
1718             return;
1719         }
1720 
1721         if (recorder.mEventHandler != null) {
1722             Message m =
1723                 recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj);
1724             recorder.mEventHandler.sendMessage(m);
1725         }
1726 
1727     }
1728 
1729 
1730     //---------------------------------------------------------
1731     // Native methods called from the Java side
1732     //--------------------
1733 
native_setup(Object audiorecord_this, Object attributes, int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, int buffSizeInBytes, int[] sessionId, String opPackageName, long nativeRecordInJavaObj)1734     private native final int native_setup(Object audiorecord_this,
1735             Object /*AudioAttributes*/ attributes,
1736             int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
1737             int buffSizeInBytes, int[] sessionId, String opPackageName,
1738             long nativeRecordInJavaObj);
1739 
1740     // TODO remove: implementation calls directly into implementation of native_release()
native_finalize()1741     private native final void native_finalize();
1742 
1743     /**
1744      * @hide
1745      */
native_release()1746     public native final void native_release();
1747 
native_start(int syncEvent, int sessionId)1748     private native final int native_start(int syncEvent, int sessionId);
1749 
native_stop()1750     private native final void native_stop();
1751 
native_read_in_byte_array(byte[] audioData, int offsetInBytes, int sizeInBytes, boolean isBlocking)1752     private native final int native_read_in_byte_array(byte[] audioData,
1753             int offsetInBytes, int sizeInBytes, boolean isBlocking);
1754 
native_read_in_short_array(short[] audioData, int offsetInShorts, int sizeInShorts, boolean isBlocking)1755     private native final int native_read_in_short_array(short[] audioData,
1756             int offsetInShorts, int sizeInShorts, boolean isBlocking);
1757 
native_read_in_float_array(float[] audioData, int offsetInFloats, int sizeInFloats, boolean isBlocking)1758     private native final int native_read_in_float_array(float[] audioData,
1759             int offsetInFloats, int sizeInFloats, boolean isBlocking);
1760 
native_read_in_direct_buffer(Object jBuffer, int sizeInBytes, boolean isBlocking)1761     private native final int native_read_in_direct_buffer(Object jBuffer,
1762             int sizeInBytes, boolean isBlocking);
1763 
native_get_buffer_size_in_frames()1764     private native final int native_get_buffer_size_in_frames();
1765 
native_set_marker_pos(int marker)1766     private native final int native_set_marker_pos(int marker);
native_get_marker_pos()1767     private native final int native_get_marker_pos();
1768 
native_set_pos_update_period(int updatePeriod)1769     private native final int native_set_pos_update_period(int updatePeriod);
native_get_pos_update_period()1770     private native final int native_get_pos_update_period();
1771 
native_get_min_buff_size( int sampleRateInHz, int channelCount, int audioFormat)1772     static private native final int native_get_min_buff_size(
1773             int sampleRateInHz, int channelCount, int audioFormat);
1774 
native_setInputDevice(int deviceId)1775     private native final boolean native_setInputDevice(int deviceId);
native_getRoutedDeviceId()1776     private native final int native_getRoutedDeviceId();
native_enableDeviceCallback()1777     private native final void native_enableDeviceCallback();
native_disableDeviceCallback()1778     private native final void native_disableDeviceCallback();
1779 
native_get_timestamp(@onNull AudioTimestamp outTimestamp, @AudioTimestamp.Timebase int timebase)1780     private native final int native_get_timestamp(@NonNull AudioTimestamp outTimestamp,
1781             @AudioTimestamp.Timebase int timebase);
1782 
1783     //---------------------------------------------------------
1784     // Utility methods
1785     //------------------
1786 
logd(String msg)1787     private static void logd(String msg) {
1788         Log.d(TAG, msg);
1789     }
1790 
loge(String msg)1791     private static void loge(String msg) {
1792         Log.e(TAG, msg);
1793     }
1794 }
1795