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 android.annotation.CallbackExecutor;
20 import android.annotation.FloatRange;
21 import android.annotation.IntDef;
22 import android.annotation.IntRange;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.annotation.RequiresPermission;
26 import android.annotation.SystemApi;
27 import android.annotation.TestApi;
28 import android.app.ActivityThread;
29 import android.compat.annotation.UnsupportedAppUsage;
30 import android.content.AttributionSource;
31 import android.content.AttributionSource.ScopedParcelState;
32 import android.content.Context;
33 import android.media.MediaRecorder.Source;
34 import android.media.audiopolicy.AudioMix;
35 import android.media.audiopolicy.AudioPolicy;
36 import android.media.metrics.LogSessionId;
37 import android.media.projection.MediaProjection;
38 import android.os.Binder;
39 import android.os.Build;
40 import android.os.Handler;
41 import android.os.IBinder;
42 import android.os.Looper;
43 import android.os.Message;
44 import android.os.Parcel;
45 import android.os.PersistableBundle;
46 import android.os.RemoteException;
47 import android.os.ServiceManager;
48 import android.util.ArrayMap;
49 import android.util.Log;
50 import android.util.Pair;
51 
52 import com.android.internal.annotations.GuardedBy;
53 import com.android.internal.util.Preconditions;
54 
55 import java.io.IOException;
56 import java.lang.annotation.Retention;
57 import java.lang.annotation.RetentionPolicy;
58 import java.lang.ref.WeakReference;
59 import java.nio.ByteBuffer;
60 import java.util.ArrayList;
61 import java.util.Iterator;
62 import java.util.List;
63 import java.util.Objects;
64 import java.util.concurrent.Executor;
65 
66 /**
67  * The AudioRecord class manages the audio resources for Java applications
68  * to record audio from the audio input hardware of the platform. This is
69  * achieved by "pulling" (reading) the data from the AudioRecord object. The
70  * application is responsible for polling the AudioRecord object in time using one of
71  * the following three methods:  {@link #read(byte[],int, int)}, {@link #read(short[], int, int)}
72  * or {@link #read(ByteBuffer, int)}. The choice of which method to use will be based
73  * on the audio data storage format that is the most convenient for the user of AudioRecord.
74  * <p>Upon creation, an AudioRecord object initializes its associated audio buffer that it will
75  * fill with the new audio data. The size of this buffer, specified during the construction,
76  * determines how long an AudioRecord can record before "over-running" data that has not
77  * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
78  * the total recording buffer size.</p>
79  * <p>
80  * Applications creating an AudioRecord instance need
81  * {@link android.Manifest.permission#RECORD_AUDIO} or the Builder will throw
82  * {@link java.lang.UnsupportedOperationException} on
83  * {@link android.media.AudioRecord.Builder#build build()},
84  * and the constructor will return an instance in state
85  * {@link #STATE_UNINITIALIZED}.</p>
86  */
87 public class AudioRecord implements AudioRouting, MicrophoneDirection,
88         AudioRecordingMonitor, AudioRecordingMonitorClient
89 {
90     //---------------------------------------------------------
91     // Constants
92     //--------------------
93 
94 
95     /**
96      *  indicates AudioRecord state is not successfully initialized.
97      */
98     public static final int STATE_UNINITIALIZED = 0;
99     /**
100      *  indicates AudioRecord state is ready to be used
101      */
102     public static final int STATE_INITIALIZED   = 1;
103 
104     /**
105      * indicates AudioRecord recording state is not recording
106      */
107     public static final int RECORDSTATE_STOPPED = 1;  // matches SL_RECORDSTATE_STOPPED
108     /**
109      * indicates AudioRecord recording state is recording
110      */
111     public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING
112 
113     /**
114      * Denotes a successful operation.
115      */
116     public  static final int SUCCESS                               = AudioSystem.SUCCESS;
117     /**
118      * Denotes a generic operation failure.
119      */
120     public  static final int ERROR                                 = AudioSystem.ERROR;
121     /**
122      * Denotes a failure due to the use of an invalid value.
123      */
124     public  static final int ERROR_BAD_VALUE                       = AudioSystem.BAD_VALUE;
125     /**
126      * Denotes a failure due to the improper use of a method.
127      */
128     public  static final int ERROR_INVALID_OPERATION               = AudioSystem.INVALID_OPERATION;
129     /**
130      * An error code indicating that the object reporting it is no longer valid and needs to
131      * be recreated.
132      */
133     public  static final int ERROR_DEAD_OBJECT                     = AudioSystem.DEAD_OBJECT;
134 
135     // Error codes:
136     // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp
137     private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      = -16;
138     private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK  = -17;
139     private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       = -18;
140     private static final int AUDIORECORD_ERROR_SETUP_INVALIDSOURCE       = -19;
141     private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    = -20;
142 
143     // Events:
144     // to keep in sync with frameworks/av/include/media/AudioRecord.h
145     /**
146      * Event id denotes when record head has reached a previously set marker.
147      */
148     private static final int NATIVE_EVENT_MARKER  = 2;
149     /**
150      * Event id denotes when previously set update period has elapsed during recording.
151      */
152     private static final int NATIVE_EVENT_NEW_POS = 3;
153 
154     private final static String TAG = "android.media.AudioRecord";
155 
156     /** @hide */
157     public final static String SUBMIX_FIXED_VOLUME = "fixedVolume";
158 
159     /** @hide */
160     @IntDef({
161         READ_BLOCKING,
162         READ_NON_BLOCKING
163     })
164     @Retention(RetentionPolicy.SOURCE)
165     public @interface ReadMode {}
166 
167     /**
168      * The read mode indicating the read operation will block until all data
169      * requested has been read.
170      */
171     public final static int READ_BLOCKING = 0;
172 
173     /**
174      * The read mode indicating the read operation will return immediately after
175      * reading as much audio data as possible without blocking.
176      */
177     public final static int READ_NON_BLOCKING = 1;
178 
179     //---------------------------------------------------------
180     // Used exclusively by native code
181     //--------------------
182     /**
183      * Accessed by native methods: provides access to C++ AudioRecord object
184      * Is 0 after release()
185      */
186     @SuppressWarnings("unused")
187     @UnsupportedAppUsage
188     private long mNativeRecorderInJavaObj;
189 
190     /**
191      * Accessed by native methods: provides access to the callback data.
192      */
193     @SuppressWarnings("unused")
194     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
195     private long mNativeCallbackCookie;
196 
197     /**
198      * Accessed by native methods: provides access to the JNIDeviceCallback instance.
199      */
200     @SuppressWarnings("unused")
201     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
202     private long mNativeDeviceCallback;
203 
204 
205     //---------------------------------------------------------
206     // Member variables
207     //--------------------
208     private AudioPolicy mAudioCapturePolicy;
209 
210     /**
211      * The audio data sampling rate in Hz.
212      * Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}.
213      */
214     private int mSampleRate; // initialized by all constructors via audioParamCheck()
215     /**
216      * The number of input audio channels (1 is mono, 2 is stereo)
217      */
218     private int mChannelCount;
219     /**
220      * The audio channel position mask
221      */
222     private int mChannelMask;
223     /**
224      * The audio channel index mask
225      */
226     private int mChannelIndexMask;
227     /**
228      * The encoding of the audio samples.
229      * @see AudioFormat#ENCODING_PCM_8BIT
230      * @see AudioFormat#ENCODING_PCM_16BIT
231      * @see AudioFormat#ENCODING_PCM_FLOAT
232      */
233     private int mAudioFormat;
234     /**
235      * Where the audio data is recorded from.
236      */
237     private int mRecordSource;
238     /**
239      * Indicates the state of the AudioRecord instance.
240      */
241     private int mState = STATE_UNINITIALIZED;
242     /**
243      * Indicates the recording state of the AudioRecord instance.
244      */
245     private int mRecordingState = RECORDSTATE_STOPPED;
246     /**
247      * Lock to make sure mRecordingState updates are reflecting the actual state of the object.
248      */
249     private final Object mRecordingStateLock = new Object();
250     /**
251      * The listener the AudioRecord notifies when the record position reaches a marker
252      * or for periodic updates during the progression of the record head.
253      *  @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)
254      *  @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)
255      */
256     private OnRecordPositionUpdateListener mPositionListener = null;
257     /**
258      * Lock to protect position listener updates against event notifications
259      */
260     private final Object mPositionListenerLock = new Object();
261     /**
262      * Handler for marker events coming from the native code
263      */
264     private NativeEventHandler mEventHandler = null;
265     /**
266      * Looper associated with the thread that creates the AudioRecord instance
267      */
268     @UnsupportedAppUsage
269     private Looper mInitializationLooper = null;
270     /**
271      * Size of the native audio buffer.
272      */
273     private int mNativeBufferSizeInBytes = 0;
274     /**
275      * Audio session ID
276      */
277     private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
278     /**
279      * AudioAttributes
280      */
281     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
282     private AudioAttributes mAudioAttributes;
283     private boolean mIsSubmixFullVolume = false;
284 
285     /**
286      * The log session id used for metrics.
287      * {@link LogSessionId#LOG_SESSION_ID_NONE} here means it is not set.
288      */
289     @NonNull private LogSessionId mLogSessionId = LogSessionId.LOG_SESSION_ID_NONE;
290 
291     //---------------------------------------------------------
292     // Constructor, Finalize
293     //--------------------
294     /**
295      * Class constructor.
296      * Though some invalid parameters will result in an {@link IllegalArgumentException} exception,
297      * other errors do not.  Thus you should call {@link #getState()} immediately after construction
298      * to confirm that the object is usable.
299      * @param audioSource the recording source.
300      *   See {@link MediaRecorder.AudioSource} for the recording source definitions.
301      * @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only
302      *   rate that is guaranteed to work on all devices, but other rates such as 22050,
303      *   16000, and 11025 may work on some devices.
304      *   {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
305      *   which is usually the sample rate of the source.
306      *   {@link #getSampleRate()} can be used to retrieve the actual sample rate chosen.
307      * @param channelConfig describes the configuration of the audio channels.
308      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
309      *   {@link AudioFormat#CHANNEL_IN_STEREO}.  {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
310      *   to work on all devices.
311      * @param audioFormat the format in which the audio data is to be returned.
312      *   See {@link AudioFormat#ENCODING_PCM_8BIT}, {@link AudioFormat#ENCODING_PCM_16BIT},
313      *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
314      * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
315      *   to during the recording. New audio data can be read from this buffer in smaller chunks
316      *   than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
317      *   required buffer size for the successful creation of an AudioRecord instance. Using values
318      *   smaller than getMinBufferSize() will result in an initialization failure.
319      * @throws java.lang.IllegalArgumentException
320      */
321     @RequiresPermission(android.Manifest.permission.RECORD_AUDIO)
AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)322     public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
323             int bufferSizeInBytes)
324     throws IllegalArgumentException {
325         this((new AudioAttributes.Builder())
326                     .setInternalCapturePreset(audioSource)
327                     .build(),
328                 (new AudioFormat.Builder())
329                     .setChannelMask(getChannelMaskFromLegacyConfig(channelConfig,
330                                         true/*allow legacy configurations*/))
331                     .setEncoding(audioFormat)
332                     .setSampleRate(sampleRateInHz)
333                     .build(),
334                 bufferSizeInBytes,
335                 AudioManager.AUDIO_SESSION_ID_GENERATE);
336     }
337 
338     /**
339      * @hide
340      * Class constructor with {@link AudioAttributes} and {@link AudioFormat}.
341      * @param attributes a non-null {@link AudioAttributes} instance. Use
342      *     {@link AudioAttributes.Builder#setCapturePreset(int)} for configuring the audio
343      *     source for this instance.
344      * @param format a non-null {@link AudioFormat} instance describing the format of the data
345      *     that will be recorded through this AudioRecord. See {@link AudioFormat.Builder} for
346      *     configuring the audio format parameters such as encoding, channel mask and sample rate.
347      * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
348      *   to during the recording. New audio data can be read from this buffer in smaller chunks
349      *   than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
350      *   required buffer size for the successful creation of an AudioRecord instance. Using values
351      *   smaller than getMinBufferSize() will result in an initialization failure.
352      * @param sessionId ID of audio session the AudioRecord must be attached to, or
353      *   {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at construction
354      *   time. See also {@link AudioManager#generateAudioSessionId()} to obtain a session ID before
355      *   construction.
356      * @throws IllegalArgumentException
357      */
358     @SystemApi
359     @RequiresPermission(android.Manifest.permission.RECORD_AUDIO)
AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, int sessionId)360     public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
361             int sessionId) throws IllegalArgumentException {
362         this(attributes, format, bufferSizeInBytes, sessionId,
363                 ActivityThread.currentApplication(), 0 /*maxSharedAudioHistoryMs*/);
364     }
365 
366     /**
367      * @hide
368      * Class constructor with {@link AudioAttributes} and {@link AudioFormat}.
369      * @param attributes a non-null {@link AudioAttributes} instance. Use
370      *     {@link AudioAttributes.Builder#setCapturePreset(int)} for configuring the audio
371      *     source for this instance.
372      * @param format a non-null {@link AudioFormat} instance describing the format of the data
373      *     that will be recorded through this AudioRecord. See {@link AudioFormat.Builder} for
374      *     configuring the audio format parameters such as encoding, channel mask and sample rate.
375      * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
376      *   to during the recording. New audio data can be read from this buffer in smaller chunks
377      *   than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
378      *   required buffer size for the successful creation of an AudioRecord instance. Using values
379      *   smaller than getMinBufferSize() will result in an initialization failure.
380      * @param sessionId ID of audio session the AudioRecord must be attached to, or
381      *   {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at construction
382      *   time. See also {@link AudioManager#generateAudioSessionId()} to obtain a session ID before
383      *   construction.
384      * @param context An optional context on whose behalf the recoding is performed.
385      *
386      * @throws IllegalArgumentException
387      */
AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, int sessionId, @Nullable Context context, int maxSharedAudioHistoryMs)388     private AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
389             int sessionId, @Nullable Context context,
390             int maxSharedAudioHistoryMs) throws IllegalArgumentException {
391         mRecordingState = RECORDSTATE_STOPPED;
392 
393         if (attributes == null) {
394             throw new IllegalArgumentException("Illegal null AudioAttributes");
395         }
396         if (format == null) {
397             throw new IllegalArgumentException("Illegal null AudioFormat");
398         }
399 
400         // remember which looper is associated with the AudioRecord instanciation
401         if ((mInitializationLooper = Looper.myLooper()) == null) {
402             mInitializationLooper = Looper.getMainLooper();
403         }
404 
405         // is this AudioRecord using REMOTE_SUBMIX at full volume?
406         if (attributes.getCapturePreset() == MediaRecorder.AudioSource.REMOTE_SUBMIX) {
407             final AudioAttributes.Builder filteredAttr = new AudioAttributes.Builder();
408             final Iterator<String> tagsIter = attributes.getTags().iterator();
409             while (tagsIter.hasNext()) {
410                 final String tag = tagsIter.next();
411                 if (tag.equalsIgnoreCase(SUBMIX_FIXED_VOLUME)) {
412                     mIsSubmixFullVolume = true;
413                     Log.v(TAG, "Will record from REMOTE_SUBMIX at full fixed volume");
414                 } else { // SUBMIX_FIXED_VOLUME: is not to be propagated to the native layers
415                     filteredAttr.addTag(tag);
416                 }
417             }
418             filteredAttr.setInternalCapturePreset(attributes.getCapturePreset());
419             mAudioAttributes = filteredAttr.build();
420         } else {
421             mAudioAttributes = attributes;
422         }
423 
424         int rate = format.getSampleRate();
425         if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
426             rate = 0;
427         }
428 
429         int encoding = AudioFormat.ENCODING_DEFAULT;
430         if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0)
431         {
432             encoding = format.getEncoding();
433         }
434 
435         audioParamCheck(attributes.getCapturePreset(), rate, encoding);
436 
437         if ((format.getPropertySetMask()
438                 & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) {
439             mChannelIndexMask = format.getChannelIndexMask();
440             mChannelCount = format.getChannelCount();
441         }
442         if ((format.getPropertySetMask()
443                 & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0) {
444             mChannelMask = getChannelMaskFromLegacyConfig(format.getChannelMask(), false);
445             mChannelCount = format.getChannelCount();
446         } else if (mChannelIndexMask == 0) {
447             mChannelMask = getChannelMaskFromLegacyConfig(AudioFormat.CHANNEL_IN_DEFAULT, false);
448             mChannelCount =  AudioFormat.channelCountFromInChannelMask(mChannelMask);
449         }
450 
451         audioBuffSizeCheck(bufferSizeInBytes);
452 
453         AttributionSource attributionSource = (context != null)
454                 ? context.getAttributionSource() : AttributionSource.myAttributionSource();
455         if (attributionSource.getPackageName() == null) {
456             // Command line utility
457             attributionSource = attributionSource.withPackageName("uid:" + Binder.getCallingUid());
458         }
459 
460         int[] sampleRate = new int[] {mSampleRate};
461         int[] session = new int[1];
462         session[0] = sessionId;
463 
464         //TODO: update native initialization when information about hardware init failure
465         //      due to capture device already open is available.
466         try (ScopedParcelState attributionSourceState = attributionSource.asScopedParcelState()) {
467             int initResult = native_setup(new WeakReference<AudioRecord>(this), mAudioAttributes,
468                     sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
469                     mNativeBufferSizeInBytes, session, attributionSourceState.getParcel(),
470                     0 /*nativeRecordInJavaObj*/, maxSharedAudioHistoryMs);
471             if (initResult != SUCCESS) {
472                 loge("Error code " + initResult + " when initializing native AudioRecord object.");
473                 return; // with mState == STATE_UNINITIALIZED
474             }
475         }
476 
477         mSampleRate = sampleRate[0];
478         mSessionId = session[0];
479 
480         mState = STATE_INITIALIZED;
481     }
482 
483     /**
484      * A constructor which explicitly connects a Native (C++) AudioRecord. For use by
485      * the AudioRecordRoutingProxy subclass.
486      * @param nativeRecordInJavaObj A C/C++ pointer to a native AudioRecord
487      * (associated with an OpenSL ES recorder). Note: the caller must ensure a correct
488      * value here as no error checking is or can be done.
489      */
AudioRecord(long nativeRecordInJavaObj)490     /*package*/ AudioRecord(long nativeRecordInJavaObj) {
491         mNativeRecorderInJavaObj = 0;
492         mNativeCallbackCookie = 0;
493         mNativeDeviceCallback = 0;
494 
495         // other initialization...
496         if (nativeRecordInJavaObj != 0) {
497             deferred_connect(nativeRecordInJavaObj);
498         } else {
499             mState = STATE_UNINITIALIZED;
500         }
501     }
502 
503     /**
504      * Sets an {@link AudioPolicy} to automatically unregister when the record is released.
505      *
506      * <p>This is to prevent users of the audio capture API from having to manually unregister the
507      * policy that was used to create the record.
508      */
unregisterAudioPolicyOnRelease(AudioPolicy audioPolicy)509     private void unregisterAudioPolicyOnRelease(AudioPolicy audioPolicy) {
510         mAudioCapturePolicy = audioPolicy;
511     }
512 
513     /**
514      * @hide
515      */
deferred_connect(long nativeRecordInJavaObj)516     /* package */ void deferred_connect(long  nativeRecordInJavaObj) {
517         if (mState != STATE_INITIALIZED) {
518             int[] session = {0};
519             int[] rates = {0};
520             //TODO: update native initialization when information about hardware init failure
521             //      due to capture device already open is available.
522             // Note that for this native_setup, we are providing an already created/initialized
523             // *Native* AudioRecord, so the attributes parameters to native_setup() are ignored.
524             final int initResult;
525             try (ScopedParcelState attributionSourceState = AttributionSource.myAttributionSource()
526                     .asScopedParcelState()) {
527                 initResult = native_setup(new WeakReference<>(this),
528                         null /*mAudioAttributes*/,
529                         rates /*mSampleRates*/,
530                         0 /*mChannelMask*/,
531                         0 /*mChannelIndexMask*/,
532                         0 /*mAudioFormat*/,
533                         0 /*mNativeBufferSizeInBytes*/,
534                         session,
535                         attributionSourceState.getParcel(),
536                         nativeRecordInJavaObj,
537                         0);
538             }
539             if (initResult != SUCCESS) {
540                 loge("Error code "+initResult+" when initializing native AudioRecord object.");
541                 return; // with mState == STATE_UNINITIALIZED
542             }
543 
544             mSessionId = session[0];
545 
546             mState = STATE_INITIALIZED;
547         }
548     }
549 
550     /** @hide */
getAudioAttributes()551     public AudioAttributes getAudioAttributes() {
552         return mAudioAttributes;
553     }
554 
555     /**
556      * Builder class for {@link AudioRecord} objects.
557      * Use this class to configure and create an <code>AudioRecord</code> instance. By setting the
558      * recording source and audio format parameters, you indicate which of
559      * those vary from the default behavior on the device.
560      * <p> Here is an example where <code>Builder</code> is used to specify all {@link AudioFormat}
561      * parameters, to be used by a new <code>AudioRecord</code> instance:
562      *
563      * <pre class="prettyprint">
564      * AudioRecord recorder = new AudioRecord.Builder()
565      *         .setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION)
566      *         .setAudioFormat(new AudioFormat.Builder()
567      *                 .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
568      *                 .setSampleRate(32000)
569      *                 .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
570      *                 .build())
571      *         .setBufferSizeInBytes(2*minBuffSize)
572      *         .build();
573      * </pre>
574      * <p>
575      * If the audio source is not set with {@link #setAudioSource(int)},
576      * {@link MediaRecorder.AudioSource#DEFAULT} is used.
577      * <br>If the audio format is not specified or is incomplete, its channel configuration will be
578      * {@link AudioFormat#CHANNEL_IN_MONO}, and the encoding will be
579      * {@link AudioFormat#ENCODING_PCM_16BIT}.
580      * The sample rate will depend on the device actually selected for capture and can be queried
581      * with {@link #getSampleRate()} method.
582      * <br>If the buffer size is not specified with {@link #setBufferSizeInBytes(int)},
583      * the minimum buffer size for the source is used.
584      */
585     public static class Builder {
586 
587         private static final String ERROR_MESSAGE_SOURCE_MISMATCH =
588                 "Cannot both set audio source and set playback capture config";
589 
590         private AudioPlaybackCaptureConfiguration mAudioPlaybackCaptureConfiguration;
591         private AudioAttributes mAttributes;
592         private AudioFormat mFormat;
593         private Context mContext;
594         private int mBufferSizeInBytes;
595         private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
596         private int mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT;
597         private int mMaxSharedAudioHistoryMs = 0;
598         private static final int PRIVACY_SENSITIVE_DEFAULT = -1;
599         private static final int PRIVACY_SENSITIVE_DISABLED = 0;
600         private static final int PRIVACY_SENSITIVE_ENABLED = 1;
601 
602         /**
603          * Constructs a new Builder with the default values as described above.
604          */
Builder()605         public Builder() {
606         }
607 
608         /**
609          * @param source the audio source.
610          * See {@link MediaRecorder.AudioSource} for the supported audio source definitions.
611          * @return the same Builder instance.
612          * @throws IllegalArgumentException
613          */
setAudioSource(@ource int source)614         public Builder setAudioSource(@Source int source) throws IllegalArgumentException {
615             Preconditions.checkState(
616                     mAudioPlaybackCaptureConfiguration == null,
617                     ERROR_MESSAGE_SOURCE_MISMATCH);
618             if ( (source < MediaRecorder.AudioSource.DEFAULT) ||
619                     (source > MediaRecorder.getAudioSourceMax()) ) {
620                 throw new IllegalArgumentException("Invalid audio source " + source);
621             }
622             mAttributes = new AudioAttributes.Builder()
623                     .setInternalCapturePreset(source)
624                     .build();
625             return this;
626         }
627 
628         /**
629          * Sets the context the record belongs to. This context will be used to pull information,
630          * such as {@link android.content.AttributionSource}, which will be associated with
631          * the AudioRecord. However, the context itself will not be retained by the AudioRecord.
632          * @param context a non-null {@link Context} instance
633          * @return the same Builder instance.
634          */
setContext(@onNull Context context)635         public @NonNull Builder setContext(@NonNull Context context) {
636             Objects.requireNonNull(context);
637             // keep reference, we only copy the data when building
638             mContext = context;
639             return this;
640         }
641 
642         /**
643          * @hide
644          * To be only used by system components. Allows specifying non-public capture presets
645          * @param attributes a non-null {@link AudioAttributes} instance that contains the capture
646          *     preset to be used.
647          * @return the same Builder instance.
648          * @throws IllegalArgumentException
649          */
650         @SystemApi
setAudioAttributes(@onNull AudioAttributes attributes)651         public Builder setAudioAttributes(@NonNull AudioAttributes attributes)
652                 throws IllegalArgumentException {
653             if (attributes == null) {
654                 throw new IllegalArgumentException("Illegal null AudioAttributes argument");
655             }
656             if (attributes.getCapturePreset() == MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID) {
657                 throw new IllegalArgumentException(
658                         "No valid capture preset in AudioAttributes argument");
659             }
660             // keep reference, we only copy the data when building
661             mAttributes = attributes;
662             return this;
663         }
664 
665         /**
666          * Sets the format of the audio data to be captured.
667          * @param format a non-null {@link AudioFormat} instance
668          * @return the same Builder instance.
669          * @throws IllegalArgumentException
670          */
setAudioFormat(@onNull AudioFormat format)671         public Builder setAudioFormat(@NonNull AudioFormat format) throws IllegalArgumentException {
672             if (format == null) {
673                 throw new IllegalArgumentException("Illegal null AudioFormat argument");
674             }
675             // keep reference, we only copy the data when building
676             mFormat = format;
677             return this;
678         }
679 
680         /**
681          * Sets the total size (in bytes) of the buffer where audio data is written
682          * during the recording. New audio data can be read from this buffer in smaller chunks
683          * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
684          * required buffer size for the successful creation of an AudioRecord instance.
685          * Since bufferSizeInBytes may be internally increased to accommodate the source
686          * requirements, use {@link #getBufferSizeInFrames()} to determine the actual buffer size
687          * in frames.
688          * @param bufferSizeInBytes a value strictly greater than 0
689          * @return the same Builder instance.
690          * @throws IllegalArgumentException
691          */
setBufferSizeInBytes(int bufferSizeInBytes)692         public Builder setBufferSizeInBytes(int bufferSizeInBytes) throws IllegalArgumentException {
693             if (bufferSizeInBytes <= 0) {
694                 throw new IllegalArgumentException("Invalid buffer size " + bufferSizeInBytes);
695             }
696             mBufferSizeInBytes = bufferSizeInBytes;
697             return this;
698         }
699 
700         /**
701          * Sets the {@link AudioRecord} to record audio played by other apps.
702          *
703          * @param config Defines what apps to record audio from (i.e., via either their uid or
704          *               the type of audio).
705          * @throws IllegalStateException if called in conjunction with {@link #setAudioSource(int)}.
706          * @throws NullPointerException if {@code config} is null.
707          */
setAudioPlaybackCaptureConfig( @onNull AudioPlaybackCaptureConfiguration config)708         public @NonNull Builder setAudioPlaybackCaptureConfig(
709                 @NonNull AudioPlaybackCaptureConfiguration config) {
710             Preconditions.checkNotNull(
711                     config, "Illegal null AudioPlaybackCaptureConfiguration argument");
712             Preconditions.checkState(
713                     mAttributes == null,
714                     ERROR_MESSAGE_SOURCE_MISMATCH);
715             mAudioPlaybackCaptureConfiguration = config;
716             return this;
717         }
718 
719         /**
720          * Indicates that this capture request is privacy sensitive and that
721          * any concurrent capture is not permitted.
722          * <p>
723          * The default is not privacy sensitive except when the audio source set with
724          * {@link #setAudioSource(int)} is {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION} or
725          * {@link MediaRecorder.AudioSource#CAMCORDER}.
726          * <p>
727          * Always takes precedence over default from audio source when set explicitly.
728          * <p>
729          * Using this API is only permitted when the audio source is one of:
730          * <ul>
731          * <li>{@link MediaRecorder.AudioSource#MIC}</li>
732          * <li>{@link MediaRecorder.AudioSource#CAMCORDER}</li>
733          * <li>{@link MediaRecorder.AudioSource#VOICE_RECOGNITION}</li>
734          * <li>{@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}</li>
735          * <li>{@link MediaRecorder.AudioSource#UNPROCESSED}</li>
736          * <li>{@link MediaRecorder.AudioSource#VOICE_PERFORMANCE}</li>
737          * </ul>
738          * Invoking {@link #build()} will throw an UnsupportedOperationException if this
739          * condition is not met.
740          * @param privacySensitive True if capture from this AudioRecord must be marked as privacy
741          * sensitive, false otherwise.
742          */
setPrivacySensitive(boolean privacySensitive)743         public @NonNull Builder setPrivacySensitive(boolean privacySensitive) {
744             mPrivacySensitive =
745                 privacySensitive ? PRIVACY_SENSITIVE_ENABLED : PRIVACY_SENSITIVE_DISABLED;
746             return this;
747         }
748 
749         /**
750          * @hide
751          * To be only used by system components.
752          * @param sessionId ID of audio session the AudioRecord must be attached to, or
753          *     {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at
754          *     construction time.
755          * @return the same Builder instance.
756          * @throws IllegalArgumentException
757          */
758         @SystemApi
setSessionId(int sessionId)759         public Builder setSessionId(int sessionId) throws IllegalArgumentException {
760             if (sessionId < 0) {
761                 throw new IllegalArgumentException("Invalid session ID " + sessionId);
762             }
763             // Do not override a session ID previously set with setSharedAudioEvent()
764             if (mSessionId == AudioManager.AUDIO_SESSION_ID_GENERATE) {
765                 mSessionId = sessionId;
766             } else {
767                 Log.e(TAG, "setSessionId() called twice or after setSharedAudioEvent()");
768             }
769             return this;
770         }
771 
buildAudioPlaybackCaptureRecord()772         private @NonNull AudioRecord buildAudioPlaybackCaptureRecord() {
773             AudioMix audioMix = mAudioPlaybackCaptureConfiguration.createAudioMix(mFormat);
774             MediaProjection projection = mAudioPlaybackCaptureConfiguration.getMediaProjection();
775             AudioPolicy audioPolicy = new AudioPolicy.Builder(/*context=*/ null)
776                     .setMediaProjection(projection)
777                     .addMix(audioMix).build();
778 
779             int error = AudioManager.registerAudioPolicyStatic(audioPolicy);
780             if (error != 0) {
781                 throw new UnsupportedOperationException("Error: could not register audio policy");
782             }
783 
784             AudioRecord record = audioPolicy.createAudioRecordSink(audioMix);
785             if (record == null) {
786                 throw new UnsupportedOperationException("Cannot create AudioRecord");
787             }
788             record.unregisterAudioPolicyOnRelease(audioPolicy);
789             return record;
790         }
791 
792         /**
793          * @hide
794          * Specifies the maximum duration in the past of the this AudioRecord's capture buffer
795          * that can be shared with another app by calling
796          * {@link AudioRecord#shareAudioHistory(String, long)}.
797          * @param maxSharedAudioHistoryMillis the maximum duration that will be available
798          *                                    in milliseconds.
799          * @return the same Builder instance.
800          * @throws IllegalArgumentException
801          *
802          */
803         @SystemApi
804         @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD)
setMaxSharedAudioHistoryMillis(long maxSharedAudioHistoryMillis)805         public @NonNull Builder setMaxSharedAudioHistoryMillis(long maxSharedAudioHistoryMillis)
806                 throws IllegalArgumentException {
807             if (maxSharedAudioHistoryMillis <= 0
808                     || maxSharedAudioHistoryMillis > MAX_SHARED_AUDIO_HISTORY_MS) {
809                 throw new IllegalArgumentException("Illegal maxSharedAudioHistoryMillis argument");
810             }
811             mMaxSharedAudioHistoryMs = (int) maxSharedAudioHistoryMillis;
812             return this;
813         }
814 
815         /**
816          * @hide
817          * Indicates that this AudioRecord will use the audio history shared by another app's
818          * AudioRecord. See {@link AudioRecord#shareAudioHistory(String, long)}.
819          * The audio session ID set with {@link AudioRecord.Builder#setSessionId(int)} will be
820          * ignored if this method is used.
821          * @param event The {@link MediaSyncEvent} provided by the app sharing its audio history
822          *              with this AudioRecord.
823          * @return the same Builder instance.
824          * @throws IllegalArgumentException
825          */
826         @SystemApi
setSharedAudioEvent(@onNull MediaSyncEvent event)827         public @NonNull Builder setSharedAudioEvent(@NonNull MediaSyncEvent event)
828                 throws IllegalArgumentException {
829             Objects.requireNonNull(event);
830             if (event.getType() != MediaSyncEvent.SYNC_EVENT_SHARE_AUDIO_HISTORY) {
831                 throw new IllegalArgumentException(
832                         "Invalid event type " + event.getType());
833             }
834             if (event.getAudioSessionId() == AudioSystem.AUDIO_SESSION_ALLOCATE) {
835                 throw new IllegalArgumentException(
836                         "Invalid session ID " + event.getAudioSessionId());
837             }
838             // This prevails over a session ID set with setSessionId()
839             mSessionId = event.getAudioSessionId();
840             return this;
841         }
842 
843         /**
844          * @return a new {@link AudioRecord} instance successfully initialized with all
845          *     the parameters set on this <code>Builder</code>.
846          * @throws UnsupportedOperationException if the parameters set on the <code>Builder</code>
847          *     were incompatible, or if they are not supported by the device,
848          *     or if the device was not available.
849          */
850         @RequiresPermission(android.Manifest.permission.RECORD_AUDIO)
build()851         public AudioRecord build() throws UnsupportedOperationException {
852             if (mAudioPlaybackCaptureConfiguration != null) {
853                 return buildAudioPlaybackCaptureRecord();
854             }
855 
856             if (mFormat == null) {
857                 mFormat = new AudioFormat.Builder()
858                         .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
859                         .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
860                         .build();
861             } else {
862                 if (mFormat.getEncoding() == AudioFormat.ENCODING_INVALID) {
863                     mFormat = new AudioFormat.Builder(mFormat)
864                             .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
865                             .build();
866                 }
867                 if (mFormat.getChannelMask() == AudioFormat.CHANNEL_INVALID
868                         && mFormat.getChannelIndexMask() == AudioFormat.CHANNEL_INVALID) {
869                     mFormat = new AudioFormat.Builder(mFormat)
870                             .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
871                             .build();
872                 }
873             }
874             if (mAttributes == null) {
875                 mAttributes = new AudioAttributes.Builder()
876                         .setInternalCapturePreset(MediaRecorder.AudioSource.DEFAULT)
877                         .build();
878             }
879 
880             // If mPrivacySensitive is default, the privacy flag is already set
881             // according to audio source in audio attributes.
882             if (mPrivacySensitive != PRIVACY_SENSITIVE_DEFAULT) {
883                 int source = mAttributes.getCapturePreset();
884                 if (source == MediaRecorder.AudioSource.REMOTE_SUBMIX
885                         || source == MediaRecorder.AudioSource.RADIO_TUNER
886                         || source == MediaRecorder.AudioSource.VOICE_DOWNLINK
887                         || source == MediaRecorder.AudioSource.VOICE_UPLINK
888                         || source == MediaRecorder.AudioSource.VOICE_CALL
889                         || source == MediaRecorder.AudioSource.ECHO_REFERENCE) {
890                     throw new UnsupportedOperationException(
891                             "Cannot request private capture with source: " + source);
892                 }
893 
894                 mAttributes = new AudioAttributes.Builder(mAttributes)
895                         .setInternalCapturePreset(source)
896                         .setPrivacySensitive(mPrivacySensitive == PRIVACY_SENSITIVE_ENABLED)
897                         .build();
898             }
899 
900             try {
901                 // If the buffer size is not specified,
902                 // use a single frame for the buffer size and let the
903                 // native code figure out the minimum buffer size.
904                 if (mBufferSizeInBytes == 0) {
905                     mBufferSizeInBytes = mFormat.getChannelCount()
906                             * mFormat.getBytesPerSample(mFormat.getEncoding());
907                 }
908                 final AudioRecord record = new AudioRecord(
909                         mAttributes, mFormat, mBufferSizeInBytes, mSessionId, mContext,
910                                     mMaxSharedAudioHistoryMs);
911                 if (record.getState() == STATE_UNINITIALIZED) {
912                     // release is not necessary
913                     throw new UnsupportedOperationException("Cannot create AudioRecord");
914                 }
915                 return record;
916             } catch (IllegalArgumentException e) {
917                 throw new UnsupportedOperationException(e.getMessage());
918             }
919         }
920     }
921 
922     // Convenience method for the constructor's parameter checks.
923     // This, getChannelMaskFromLegacyConfig and audioBuffSizeCheck are where constructor
924     // IllegalArgumentException-s are thrown
getChannelMaskFromLegacyConfig(int inChannelConfig, boolean allowLegacyConfig)925     private static int getChannelMaskFromLegacyConfig(int inChannelConfig,
926             boolean allowLegacyConfig) {
927         int mask;
928         switch (inChannelConfig) {
929         case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
930         case AudioFormat.CHANNEL_IN_MONO:
931         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
932             mask = AudioFormat.CHANNEL_IN_MONO;
933             break;
934         case AudioFormat.CHANNEL_IN_STEREO:
935         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
936             mask = AudioFormat.CHANNEL_IN_STEREO;
937             break;
938         case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
939             mask = inChannelConfig;
940             break;
941         default:
942             throw new IllegalArgumentException("Unsupported channel configuration.");
943         }
944 
945         if (!allowLegacyConfig && ((inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_MONO)
946                 || (inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_STEREO))) {
947             // only happens with the constructor that uses AudioAttributes and AudioFormat
948             throw new IllegalArgumentException("Unsupported deprecated configuration.");
949         }
950 
951         return mask;
952     }
953 
954     // postconditions:
955     //    mRecordSource is valid
956     //    mAudioFormat is valid
957     //    mSampleRate is valid
audioParamCheck(int audioSource, int sampleRateInHz, int audioFormat)958     private void audioParamCheck(int audioSource, int sampleRateInHz, int audioFormat)
959             throws IllegalArgumentException {
960 
961         //--------------
962         // audio source
963         if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) ||
964              ((audioSource > MediaRecorder.getAudioSourceMax()) &&
965               (audioSource != MediaRecorder.AudioSource.RADIO_TUNER) &&
966               (audioSource != MediaRecorder.AudioSource.ECHO_REFERENCE) &&
967               (audioSource != MediaRecorder.AudioSource.HOTWORD)) )  {
968             throw new IllegalArgumentException("Invalid audio source " + audioSource);
969         }
970         mRecordSource = audioSource;
971 
972         //--------------
973         // sample rate
974         if ((sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN ||
975                 sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) &&
976                 sampleRateInHz != AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
977             throw new IllegalArgumentException(sampleRateInHz
978                     + "Hz is not a supported sample rate.");
979         }
980         mSampleRate = sampleRateInHz;
981 
982         //--------------
983         // audio format
984         switch (audioFormat) {
985             case AudioFormat.ENCODING_DEFAULT:
986                 mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
987                 break;
988             case AudioFormat.ENCODING_PCM_24BIT_PACKED:
989             case AudioFormat.ENCODING_PCM_32BIT:
990             case AudioFormat.ENCODING_PCM_FLOAT:
991             case AudioFormat.ENCODING_PCM_16BIT:
992             case AudioFormat.ENCODING_PCM_8BIT:
993                 mAudioFormat = audioFormat;
994                 break;
995             default:
996                 throw new IllegalArgumentException("Unsupported sample encoding " + audioFormat
997                         + ". Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT,"
998                         + " ENCODING_PCM_24BIT_PACKED, ENCODING_PCM_32BIT,"
999                         + " or ENCODING_PCM_FLOAT.");
1000         }
1001     }
1002 
1003 
1004     // Convenience method for the contructor's audio buffer size check.
1005     // preconditions:
1006     //    mChannelCount is valid
1007     //    mAudioFormat is AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT,
1008     //                 or AudioFormat.ENCODING_PCM_FLOAT
1009     // postcondition:
1010     //    mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
audioBuffSizeCheck(int audioBufferSize)1011     private void audioBuffSizeCheck(int audioBufferSize) throws IllegalArgumentException {
1012         // NB: this section is only valid with PCM data.
1013         // To update when supporting compressed formats
1014         int frameSizeInBytes = mChannelCount
1015             * (AudioFormat.getBytesPerSample(mAudioFormat));
1016         if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
1017             throw new IllegalArgumentException("Invalid audio buffer size " + audioBufferSize
1018                     + " (frame size " + frameSizeInBytes + ")");
1019         }
1020 
1021         mNativeBufferSizeInBytes = audioBufferSize;
1022     }
1023 
1024 
1025 
1026     /**
1027      * Releases the native AudioRecord resources.
1028      * The object can no longer be used and the reference should be set to null
1029      * after a call to release()
1030      */
release()1031     public void release() {
1032         try {
1033             stop();
1034         } catch(IllegalStateException ise) {
1035             // don't raise an exception, we're releasing the resources.
1036         }
1037         if (mAudioCapturePolicy != null) {
1038             AudioManager.unregisterAudioPolicyAsyncStatic(mAudioCapturePolicy);
1039             mAudioCapturePolicy = null;
1040         }
1041         native_release();
1042         mState = STATE_UNINITIALIZED;
1043     }
1044 
1045 
1046     @Override
finalize()1047     protected void finalize() {
1048         // will cause stop() to be called, and if appropriate, will handle fixed volume recording
1049         release();
1050     }
1051 
1052 
1053     //--------------------------------------------------------------------------
1054     // Getters
1055     //--------------------
1056     /**
1057      * Returns the configured audio sink sample rate in Hz.
1058      * The sink sample rate never changes after construction.
1059      * If the constructor had a specific sample rate, then the sink sample rate is that value.
1060      * If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED},
1061      * then the sink sample rate is a route-dependent default value based on the source [sic].
1062      */
getSampleRate()1063     public int getSampleRate() {
1064         return mSampleRate;
1065     }
1066 
1067     /**
1068      * Returns the audio recording source.
1069      * @see MediaRecorder.AudioSource
1070      */
getAudioSource()1071     public int getAudioSource() {
1072         return mRecordSource;
1073     }
1074 
1075     /**
1076      * Returns the configured audio data encoding. See {@link AudioFormat#ENCODING_PCM_8BIT},
1077      * {@link AudioFormat#ENCODING_PCM_16BIT}, and {@link AudioFormat#ENCODING_PCM_FLOAT}.
1078      */
getAudioFormat()1079     public int getAudioFormat() {
1080         return mAudioFormat;
1081     }
1082 
1083     /**
1084      * Returns the configured channel position mask.
1085      * <p> See {@link AudioFormat#CHANNEL_IN_MONO}
1086      * and {@link AudioFormat#CHANNEL_IN_STEREO}.
1087      * This method may return {@link AudioFormat#CHANNEL_INVALID} if
1088      * a channel index mask is used.
1089      * Consider {@link #getFormat()} instead, to obtain an {@link AudioFormat},
1090      * which contains both the channel position mask and the channel index mask.
1091      */
getChannelConfiguration()1092     public int getChannelConfiguration() {
1093         return mChannelMask;
1094     }
1095 
1096     /**
1097      * Returns the configured <code>AudioRecord</code> format.
1098      * @return an {@link AudioFormat} containing the
1099      * <code>AudioRecord</code> parameters at the time of configuration.
1100      */
getFormat()1101     public @NonNull AudioFormat getFormat() {
1102         AudioFormat.Builder builder = new AudioFormat.Builder()
1103             .setSampleRate(mSampleRate)
1104             .setEncoding(mAudioFormat);
1105         if (mChannelMask != AudioFormat.CHANNEL_INVALID) {
1106             builder.setChannelMask(mChannelMask);
1107         }
1108         if (mChannelIndexMask != AudioFormat.CHANNEL_INVALID  /* 0 */) {
1109             builder.setChannelIndexMask(mChannelIndexMask);
1110         }
1111         return builder.build();
1112     }
1113 
1114     /**
1115      * Returns the configured number of channels.
1116      */
getChannelCount()1117     public int getChannelCount() {
1118         return mChannelCount;
1119     }
1120 
1121     /**
1122      * Returns the state of the AudioRecord instance. This is useful after the
1123      * AudioRecord instance has been created to check if it was initialized
1124      * properly. This ensures that the appropriate hardware resources have been
1125      * acquired.
1126      * @see AudioRecord#STATE_INITIALIZED
1127      * @see AudioRecord#STATE_UNINITIALIZED
1128      */
getState()1129     public int getState() {
1130         return mState;
1131     }
1132 
1133     /**
1134      * Returns the recording state of the AudioRecord instance.
1135      * @see AudioRecord#RECORDSTATE_STOPPED
1136      * @see AudioRecord#RECORDSTATE_RECORDING
1137      */
getRecordingState()1138     public int getRecordingState() {
1139         synchronized (mRecordingStateLock) {
1140             return mRecordingState;
1141         }
1142     }
1143 
1144     /**
1145      *  Returns the frame count of the native <code>AudioRecord</code> buffer.
1146      *  This is greater than or equal to the bufferSizeInBytes converted to frame units
1147      *  specified in the <code>AudioRecord</code> constructor or Builder.
1148      *  The native frame count may be enlarged to accommodate the requirements of the
1149      *  source on creation or if the <code>AudioRecord</code>
1150      *  is subsequently rerouted.
1151      *  @return current size in frames of the <code>AudioRecord</code> buffer.
1152      *  @throws IllegalStateException
1153      */
getBufferSizeInFrames()1154     public int getBufferSizeInFrames() {
1155         return native_get_buffer_size_in_frames();
1156     }
1157 
1158     /**
1159      * Returns the notification marker position expressed in frames.
1160      */
getNotificationMarkerPosition()1161     public int getNotificationMarkerPosition() {
1162         return native_get_marker_pos();
1163     }
1164 
1165     /**
1166      * Returns the notification update period expressed in frames.
1167      */
getPositionNotificationPeriod()1168     public int getPositionNotificationPeriod() {
1169         return native_get_pos_update_period();
1170     }
1171 
1172     /**
1173      * Poll for an {@link AudioTimestamp} on demand.
1174      * <p>
1175      * The AudioTimestamp reflects the frame delivery information at
1176      * the earliest point available in the capture pipeline.
1177      * <p>
1178      * Calling {@link #startRecording()} following a {@link #stop()} will reset
1179      * the frame count to 0.
1180      *
1181      * @param outTimestamp a caller provided non-null AudioTimestamp instance,
1182      *        which is updated with the AudioRecord frame delivery information upon success.
1183      * @param timebase one of
1184      *        {@link AudioTimestamp#TIMEBASE_BOOTTIME AudioTimestamp.TIMEBASE_BOOTTIME} or
1185      *        {@link AudioTimestamp#TIMEBASE_MONOTONIC AudioTimestamp.TIMEBASE_MONOTONIC},
1186      *        used to select the clock for the AudioTimestamp time.
1187      * @return {@link #SUCCESS} if a timestamp is available,
1188      *         or {@link #ERROR_INVALID_OPERATION} if a timestamp not available.
1189      */
getTimestamp(@onNull AudioTimestamp outTimestamp, @AudioTimestamp.Timebase int timebase)1190      public int getTimestamp(@NonNull AudioTimestamp outTimestamp,
1191              @AudioTimestamp.Timebase int timebase)
1192      {
1193          if (outTimestamp == null ||
1194                  (timebase != AudioTimestamp.TIMEBASE_BOOTTIME
1195                  && timebase != AudioTimestamp.TIMEBASE_MONOTONIC)) {
1196              throw new IllegalArgumentException();
1197          }
1198          return native_get_timestamp(outTimestamp, timebase);
1199      }
1200 
1201     /**
1202      * Returns the minimum buffer size required for the successful creation of an AudioRecord
1203      * object, in byte units.
1204      * Note that this size doesn't guarantee a smooth recording under load, and higher values
1205      * should be chosen according to the expected frequency at which the AudioRecord instance
1206      * will be polled for new data.
1207      * See {@link #AudioRecord(int, int, int, int, int)} for more information on valid
1208      * configuration values.
1209      * @param sampleRateInHz the sample rate expressed in Hertz.
1210      *   {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted.
1211      * @param channelConfig describes the configuration of the audio channels.
1212      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
1213      *   {@link AudioFormat#CHANNEL_IN_STEREO}
1214      * @param audioFormat the format in which the audio data is represented.
1215      *   See {@link AudioFormat#ENCODING_PCM_16BIT}.
1216      * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the
1217      *  hardware, or an invalid parameter was passed,
1218      *  or {@link #ERROR} if the implementation was unable to query the hardware for its
1219      *  input properties,
1220      *   or the minimum buffer size expressed in bytes.
1221      * @see #AudioRecord(int, int, int, int, int)
1222      */
getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)1223     static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
1224         int channelCount = 0;
1225         switch (channelConfig) {
1226         case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
1227         case AudioFormat.CHANNEL_IN_MONO:
1228         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
1229             channelCount = 1;
1230             break;
1231         case AudioFormat.CHANNEL_IN_STEREO:
1232         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
1233         case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
1234             channelCount = 2;
1235             break;
1236         case AudioFormat.CHANNEL_INVALID:
1237         default:
1238             loge("getMinBufferSize(): Invalid channel configuration.");
1239             return ERROR_BAD_VALUE;
1240         }
1241 
1242         int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
1243         if (size == 0) {
1244             return ERROR_BAD_VALUE;
1245         }
1246         else if (size == -1) {
1247             return ERROR;
1248         }
1249         else {
1250             return size;
1251         }
1252     }
1253 
1254     /**
1255      * Returns the audio session ID.
1256      *
1257      * @return the ID of the audio session this AudioRecord belongs to.
1258      */
getAudioSessionId()1259     public int getAudioSessionId() {
1260         return mSessionId;
1261     }
1262 
1263     /**
1264      * Returns whether this AudioRecord is marked as privacy sensitive or not.
1265      * <p>
1266      * See {@link Builder#setPrivacySensitive(boolean)}
1267      * <p>
1268      * @return true if privacy sensitive, false otherwise
1269      */
isPrivacySensitive()1270     public boolean isPrivacySensitive() {
1271         return (mAudioAttributes.getAllFlags() & AudioAttributes.FLAG_CAPTURE_PRIVATE) != 0;
1272     }
1273 
1274     //---------------------------------------------------------
1275     // Transport control methods
1276     //--------------------
1277     /**
1278      * Starts recording from the AudioRecord instance.
1279      * @throws IllegalStateException
1280      */
startRecording()1281     public void startRecording()
1282     throws IllegalStateException {
1283         if (mState != STATE_INITIALIZED) {
1284             throw new IllegalStateException("startRecording() called on an "
1285                     + "uninitialized AudioRecord.");
1286         }
1287 
1288         // start recording
1289         synchronized(mRecordingStateLock) {
1290             if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) {
1291                 handleFullVolumeRec(true);
1292                 mRecordingState = RECORDSTATE_RECORDING;
1293             }
1294         }
1295     }
1296 
1297     /**
1298      * Starts recording from the AudioRecord instance when the specified synchronization event
1299      * occurs on the specified audio session.
1300      * @throws IllegalStateException
1301      * @param syncEvent event that triggers the capture.
1302      * @see MediaSyncEvent
1303      */
startRecording(MediaSyncEvent syncEvent)1304     public void startRecording(MediaSyncEvent syncEvent)
1305     throws IllegalStateException {
1306         if (mState != STATE_INITIALIZED) {
1307             throw new IllegalStateException("startRecording() called on an "
1308                     + "uninitialized AudioRecord.");
1309         }
1310 
1311         // start recording
1312         synchronized(mRecordingStateLock) {
1313             if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) {
1314                 handleFullVolumeRec(true);
1315                 mRecordingState = RECORDSTATE_RECORDING;
1316             }
1317         }
1318     }
1319 
1320     /**
1321      * Stops recording.
1322      * @throws IllegalStateException
1323      */
stop()1324     public void stop()
1325     throws IllegalStateException {
1326         if (mState != STATE_INITIALIZED) {
1327             throw new IllegalStateException("stop() called on an uninitialized AudioRecord.");
1328         }
1329 
1330         // stop recording
1331         synchronized(mRecordingStateLock) {
1332             handleFullVolumeRec(false);
1333             native_stop();
1334             mRecordingState = RECORDSTATE_STOPPED;
1335         }
1336     }
1337 
1338     private final IBinder mICallBack = new Binder();
handleFullVolumeRec(boolean starting)1339     private void handleFullVolumeRec(boolean starting) {
1340         if (!mIsSubmixFullVolume) {
1341             return;
1342         }
1343         final IBinder b = ServiceManager.getService(android.content.Context.AUDIO_SERVICE);
1344         final IAudioService ias = IAudioService.Stub.asInterface(b);
1345         try {
1346             ias.forceRemoteSubmixFullVolume(starting, mICallBack);
1347         } catch (RemoteException e) {
1348             Log.e(TAG, "Error talking to AudioService when handling full submix volume", e);
1349         }
1350     }
1351 
1352     //---------------------------------------------------------
1353     // Audio data supply
1354     //--------------------
1355     /**
1356      * Reads audio data from the audio hardware for recording into a byte array.
1357      * The format specified in the AudioRecord constructor should be
1358      * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
1359      * @param audioData the array to which the recorded audio data is written.
1360      * @param offsetInBytes index in audioData from which the data is written expressed in bytes.
1361      * @param sizeInBytes the number of requested bytes.
1362      * @return zero or the positive number of bytes that were read, or one of the following
1363      *    error codes. The number of bytes will not exceed sizeInBytes.
1364      * <ul>
1365      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1366      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1367      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1368      *    needs to be recreated. The dead object error code is not returned if some data was
1369      *    successfully transferred. In this case, the error is returned at the next read()</li>
1370      * <li>{@link #ERROR} in case of other error</li>
1371      * </ul>
1372      */
read(@onNull byte[] audioData, int offsetInBytes, int sizeInBytes)1373     public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) {
1374         return read(audioData, offsetInBytes, sizeInBytes, READ_BLOCKING);
1375     }
1376 
1377     /**
1378      * Reads audio data from the audio hardware for recording into a byte array.
1379      * The format specified in the AudioRecord constructor should be
1380      * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
1381      * The format can be {@link AudioFormat#ENCODING_PCM_16BIT}, but this is deprecated.
1382      * @param audioData the array to which the recorded audio data is written.
1383      * @param offsetInBytes index in audioData to which the data is written expressed in bytes.
1384      *        Must not be negative, or cause the data access to go out of bounds of the array.
1385      * @param sizeInBytes the number of requested bytes.
1386      *        Must not be negative, or cause the data access to go out of bounds of the array.
1387      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1388      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1389      *     is read.
1390      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1391      *     reading as much audio data as possible without blocking.
1392      * @return zero or the positive number of bytes that were read, or one of the following
1393      *    error codes. The number of bytes will be a multiple of the frame size in bytes
1394      *    not to exceed sizeInBytes.
1395      * <ul>
1396      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1397      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1398      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1399      *    needs to be recreated. The dead object error code is not returned if some data was
1400      *    successfully transferred. In this case, the error is returned at the next read()</li>
1401      * <li>{@link #ERROR} in case of other error</li>
1402      * </ul>
1403      */
read(@onNull byte[] audioData, int offsetInBytes, int sizeInBytes, @ReadMode int readMode)1404     public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
1405             @ReadMode int readMode) {
1406         // Note: we allow reads of extended integers into a byte array.
1407         if (mState != STATE_INITIALIZED  || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
1408             return ERROR_INVALID_OPERATION;
1409         }
1410 
1411         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1412             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1413             return ERROR_BAD_VALUE;
1414         }
1415 
1416         if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
1417                 || (offsetInBytes + sizeInBytes < 0)  // detect integer overflow
1418                 || (offsetInBytes + sizeInBytes > audioData.length)) {
1419             return ERROR_BAD_VALUE;
1420         }
1421 
1422         return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes,
1423                 readMode == READ_BLOCKING);
1424     }
1425 
1426     /**
1427      * Reads audio data from the audio hardware for recording into a short array.
1428      * The format specified in the AudioRecord constructor should be
1429      * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
1430      * @param audioData the array to which the recorded audio data is written.
1431      * @param offsetInShorts index in audioData to which the data is written expressed in shorts.
1432      *        Must not be negative, or cause the data access to go out of bounds of the array.
1433      * @param sizeInShorts the number of requested shorts.
1434      *        Must not be negative, or cause the data access to go out of bounds of the array.
1435      * @return zero or the positive number of shorts that were read, or one of the following
1436      *    error codes. The number of shorts will be a multiple of the channel count not to exceed
1437      *    sizeInShorts.
1438      * <ul>
1439      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1440      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1441      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1442      *    needs to be recreated. The dead object error code is not returned if some data was
1443      *    successfully transferred. In this case, the error is returned at the next read()</li>
1444      * <li>{@link #ERROR} in case of other error</li>
1445      * </ul>
1446      */
read(@onNull short[] audioData, int offsetInShorts, int sizeInShorts)1447     public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) {
1448         return read(audioData, offsetInShorts, sizeInShorts, READ_BLOCKING);
1449     }
1450 
1451     /**
1452      * Reads audio data from the audio hardware for recording into a short array.
1453      * The format specified in the AudioRecord constructor should be
1454      * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
1455      * @param audioData the array to which the recorded audio data is written.
1456      * @param offsetInShorts index in audioData from which the data is written expressed in shorts.
1457      *        Must not be negative, or cause the data access to go out of bounds of the array.
1458      * @param sizeInShorts the number of requested shorts.
1459      *        Must not be negative, or cause the data access to go out of bounds of the array.
1460      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1461      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1462      *     is read.
1463      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1464      *     reading as much audio data as possible without blocking.
1465      * @return zero or the positive number of shorts that were read, or one of the following
1466      *    error codes. The number of shorts will be a multiple of the channel count not to exceed
1467      *    sizeInShorts.
1468      * <ul>
1469      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1470      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1471      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1472      *    needs to be recreated. The dead object error code is not returned if some data was
1473      *    successfully transferred. In this case, the error is returned at the next read()</li>
1474      * <li>{@link #ERROR} in case of other error</li>
1475      * </ul>
1476      */
read(@onNull short[] audioData, int offsetInShorts, int sizeInShorts, @ReadMode int readMode)1477     public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
1478             @ReadMode int readMode) {
1479         if (mState != STATE_INITIALIZED
1480                 || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT
1481                 // use ByteBuffer instead for later encodings
1482                 || mAudioFormat > AudioFormat.ENCODING_LEGACY_SHORT_ARRAY_THRESHOLD) {
1483             return ERROR_INVALID_OPERATION;
1484         }
1485 
1486         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1487             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1488             return ERROR_BAD_VALUE;
1489         }
1490 
1491         if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
1492                 || (offsetInShorts + sizeInShorts < 0)  // detect integer overflow
1493                 || (offsetInShorts + sizeInShorts > audioData.length)) {
1494             return ERROR_BAD_VALUE;
1495         }
1496         return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts,
1497                 readMode == READ_BLOCKING);
1498     }
1499 
1500     /**
1501      * Reads audio data from the audio hardware for recording into a float array.
1502      * The format specified in the AudioRecord constructor should be
1503      * {@link AudioFormat#ENCODING_PCM_FLOAT} to correspond to the data in the array.
1504      * @param audioData the array to which the recorded audio data is written.
1505      * @param offsetInFloats index in audioData from which the data is written.
1506      *        Must not be negative, or cause the data access to go out of bounds of the array.
1507      * @param sizeInFloats the number of requested floats.
1508      *        Must not be negative, or cause the data access to go out of bounds of the array.
1509      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1510      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1511      *     is read.
1512      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1513      *     reading as much audio data as possible without blocking.
1514      * @return zero or the positive number of floats that were read, or one of the following
1515      *    error codes. The number of floats will be a multiple of the channel count not to exceed
1516      *    sizeInFloats.
1517      * <ul>
1518      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1519      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1520      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1521      *    needs to be recreated. The dead object error code is not returned if some data was
1522      *    successfully transferred. In this case, the error is returned at the next read()</li>
1523      * <li>{@link #ERROR} in case of other error</li>
1524      * </ul>
1525      */
read(@onNull float[] audioData, int offsetInFloats, int sizeInFloats, @ReadMode int readMode)1526     public int read(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
1527             @ReadMode int readMode) {
1528         if (mState == STATE_UNINITIALIZED) {
1529             Log.e(TAG, "AudioRecord.read() called in invalid state STATE_UNINITIALIZED");
1530             return ERROR_INVALID_OPERATION;
1531         }
1532 
1533         if (mAudioFormat != AudioFormat.ENCODING_PCM_FLOAT) {
1534             Log.e(TAG, "AudioRecord.read(float[] ...) requires format ENCODING_PCM_FLOAT");
1535             return ERROR_INVALID_OPERATION;
1536         }
1537 
1538         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1539             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1540             return ERROR_BAD_VALUE;
1541         }
1542 
1543         if ((audioData == null) || (offsetInFloats < 0) || (sizeInFloats < 0)
1544                 || (offsetInFloats + sizeInFloats < 0)  // detect integer overflow
1545                 || (offsetInFloats + sizeInFloats > audioData.length)) {
1546             return ERROR_BAD_VALUE;
1547         }
1548 
1549         return native_read_in_float_array(audioData, offsetInFloats, sizeInFloats,
1550                 readMode == READ_BLOCKING);
1551     }
1552 
1553     /**
1554      * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
1555      * is not a direct buffer, this method will always return 0.
1556      * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
1557      * unchanged after a call to this method.
1558      * The representation of the data in the buffer will depend on the format specified in
1559      * the AudioRecord constructor, and will be native endian.
1560      * @param audioBuffer the direct buffer to which the recorded audio data is written.
1561      * Data is written to audioBuffer.position().
1562      * @param sizeInBytes the number of requested bytes. It is recommended but not enforced
1563      *    that the number of bytes requested be a multiple of the frame size (sample size in
1564      *    bytes multiplied by the channel count).
1565      * @return zero or the positive number of bytes that were read, or one of the following
1566      *    error codes. The number of bytes will not exceed sizeInBytes and will be truncated to be
1567      *    a multiple of the frame size.
1568      * <ul>
1569      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1570      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1571      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1572      *    needs to be recreated. The dead object error code is not returned if some data was
1573      *    successfully transferred. In this case, the error is returned at the next read()</li>
1574      * <li>{@link #ERROR} in case of other error</li>
1575      * </ul>
1576      */
read(@onNull ByteBuffer audioBuffer, int sizeInBytes)1577     public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes) {
1578         return read(audioBuffer, sizeInBytes, READ_BLOCKING);
1579     }
1580 
1581     /**
1582      * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
1583      * is not a direct buffer, this method will always return 0.
1584      * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
1585      * unchanged after a call to this method.
1586      * The representation of the data in the buffer will depend on the format specified in
1587      * the AudioRecord constructor, and will be native endian.
1588      * @param audioBuffer the direct buffer to which the recorded audio data is written.
1589      * Data is written to audioBuffer.position().
1590      * @param sizeInBytes the number of requested bytes. It is recommended but not enforced
1591      *    that the number of bytes requested be a multiple of the frame size (sample size in
1592      *    bytes multiplied by the channel count).
1593      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1594      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1595      *     is read.
1596      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1597      *     reading as much audio data as possible without blocking.
1598      * @return zero or the positive number of bytes that were read, or one of the following
1599      *    error codes. The number of bytes will not exceed sizeInBytes and will be truncated to be
1600      *    a multiple of the frame size.
1601      * <ul>
1602      * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li>
1603      * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li>
1604      * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and
1605      *    needs to be recreated. The dead object error code is not returned if some data was
1606      *    successfully transferred. In this case, the error is returned at the next read()</li>
1607      * <li>{@link #ERROR} in case of other error</li>
1608      * </ul>
1609      */
read(@onNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode)1610     public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode) {
1611         if (mState != STATE_INITIALIZED) {
1612             return ERROR_INVALID_OPERATION;
1613         }
1614 
1615         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1616             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1617             return ERROR_BAD_VALUE;
1618         }
1619 
1620         if ( (audioBuffer == null) || (sizeInBytes < 0) ) {
1621             return ERROR_BAD_VALUE;
1622         }
1623 
1624         return native_read_in_direct_buffer(audioBuffer, sizeInBytes, readMode == READ_BLOCKING);
1625     }
1626 
1627     /**
1628      *  Return Metrics data about the current AudioTrack instance.
1629      *
1630      * @return a {@link PersistableBundle} containing the set of attributes and values
1631      * available for the media being handled by this instance of AudioRecord
1632      * The attributes are descibed in {@link MetricsConstants}.
1633      *
1634      * Additional vendor-specific fields may also be present in
1635      * the return value.
1636      */
getMetrics()1637     public PersistableBundle getMetrics() {
1638         PersistableBundle bundle = native_getMetrics();
1639         return bundle;
1640     }
1641 
native_getMetrics()1642     private native PersistableBundle native_getMetrics();
1643 
1644     //--------------------------------------------------------------------------
1645     // Initialization / configuration
1646     //--------------------
1647     /**
1648      * Sets the listener the AudioRecord notifies when a previously set marker is reached or
1649      * for each periodic record head position update.
1650      * @param listener
1651      */
setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener)1652     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener) {
1653         setRecordPositionUpdateListener(listener, null);
1654     }
1655 
1656     /**
1657      * Sets the listener the AudioRecord notifies when a previously set marker is reached or
1658      * for each periodic record head position update.
1659      * Use this method to receive AudioRecord events in the Handler associated with another
1660      * thread than the one in which you created the AudioRecord instance.
1661      * @param listener
1662      * @param handler the Handler that will receive the event notification messages.
1663      */
setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, Handler handler)1664     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener,
1665                                                     Handler handler) {
1666         synchronized (mPositionListenerLock) {
1667 
1668             mPositionListener = listener;
1669 
1670             if (listener != null) {
1671                 if (handler != null) {
1672                     mEventHandler = new NativeEventHandler(this, handler.getLooper());
1673                 } else {
1674                     // no given handler, use the looper the AudioRecord was created in
1675                     mEventHandler = new NativeEventHandler(this, mInitializationLooper);
1676                 }
1677             } else {
1678                 mEventHandler = null;
1679             }
1680         }
1681 
1682     }
1683 
1684 
1685     /**
1686      * Sets the marker position at which the listener is called, if set with
1687      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
1688      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
1689      * @param markerInFrames marker position expressed in frames
1690      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
1691      *  {@link #ERROR_INVALID_OPERATION}
1692      */
setNotificationMarkerPosition(int markerInFrames)1693     public int setNotificationMarkerPosition(int markerInFrames) {
1694         if (mState == STATE_UNINITIALIZED) {
1695             return ERROR_INVALID_OPERATION;
1696         }
1697         return native_set_marker_pos(markerInFrames);
1698     }
1699 
1700     /**
1701      * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord.
1702      * Note: The query is only valid if the AudioRecord is currently recording. If it is not,
1703      * <code>getRoutedDevice()</code> will return null.
1704      */
1705     @Override
getRoutedDevice()1706     public AudioDeviceInfo getRoutedDevice() {
1707         int deviceId = native_getRoutedDeviceId();
1708         if (deviceId == 0) {
1709             return null;
1710         }
1711         return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_INPUTS);
1712     }
1713 
1714     /**
1715      * Must match the native definition in frameworks/av/service/audioflinger/Audioflinger.h.
1716      */
1717     private static final long MAX_SHARED_AUDIO_HISTORY_MS = 5000;
1718 
1719     /**
1720      * @hide
1721      * returns the maximum duration in milliseconds of the audio history that can be requested
1722      * to be made available to other clients using the same session with
1723      * {@Link Builder#setMaxSharedAudioHistory(long)}.
1724      */
1725     @SystemApi
getMaxSharedAudioHistoryMillis()1726     public static long getMaxSharedAudioHistoryMillis() {
1727         return MAX_SHARED_AUDIO_HISTORY_MS;
1728     }
1729 
1730     /**
1731      * @hide
1732      *
1733      * A privileged app with permission CAPTURE_AUDIO_HOTWORD can share part of its recent
1734      * capture history on a given AudioRecord with the following steps:
1735      * 1) Specify the maximum time in the past that will be available for other apps by calling
1736      * {@link Builder#setMaxSharedAudioHistoryMillis(long)} when creating the AudioRecord.
1737      * 2) Start recording and determine where the other app should start capturing in the past.
1738      * 3) Call this method with the package name of the app the history will be shared with and
1739      * the intended start time for this app's capture relative to this AudioRecord's start time.
1740      * 4) Communicate the {@link MediaSyncEvent} returned by this method to the other app.
1741      * 5) The other app will use the MediaSyncEvent when creating its AudioRecord with
1742      * {@link Builder#setSharedAudioEvent(MediaSyncEvent).
1743      * 6) Only after the other app has started capturing can this app stop capturing and
1744      * release its AudioRecord.
1745      * This method is intended to be called only once: if called multiple times, only the last
1746      * request will be honored.
1747      * The implementation is "best effort": if the specified start time if too far in the past
1748      * compared to the max available history specified, the start time will be adjusted to the
1749      * start of the available history.
1750      * @param sharedPackage the package the history will be shared with
1751      * @param startFromMillis the start time, relative to the initial start time of this
1752      *        AudioRecord, at which the other AudioRecord will start.
1753      * @return a {@link MediaSyncEvent} to be communicated to the app this AudioRecord's audio
1754      *         history will be shared with.
1755      * @throws IllegalArgumentException
1756      * @throws SecurityException
1757      */
1758     @SystemApi
1759     @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD)
shareAudioHistory(@onNull String sharedPackage, @IntRange(from = 0) long startFromMillis)1760     @NonNull public MediaSyncEvent shareAudioHistory(@NonNull String sharedPackage,
1761                                   @IntRange(from = 0) long startFromMillis) {
1762         Objects.requireNonNull(sharedPackage);
1763         if (startFromMillis < 0) {
1764             throw new IllegalArgumentException("Illegal negative sharedAudioHistoryMs argument");
1765         }
1766         int status = native_shareAudioHistory(sharedPackage, startFromMillis);
1767         if (status == AudioSystem.BAD_VALUE) {
1768             throw new IllegalArgumentException("Illegal sharedAudioHistoryMs argument");
1769         } else if (status == AudioSystem.PERMISSION_DENIED) {
1770             throw new SecurityException("permission CAPTURE_AUDIO_HOTWORD required");
1771         }
1772         MediaSyncEvent event =
1773                 MediaSyncEvent.createEvent(MediaSyncEvent.SYNC_EVENT_SHARE_AUDIO_HISTORY);
1774         event.setAudioSessionId(mSessionId);
1775         return event;
1776     }
1777 
1778     /*
1779      * Call BEFORE adding a routing callback handler.
1780      */
1781     @GuardedBy("mRoutingChangeListeners")
testEnableNativeRoutingCallbacksLocked()1782     private void testEnableNativeRoutingCallbacksLocked() {
1783         if (mRoutingChangeListeners.size() == 0) {
1784             native_enableDeviceCallback();
1785         }
1786     }
1787 
1788     /*
1789      * Call AFTER removing a routing callback handler.
1790      */
1791     @GuardedBy("mRoutingChangeListeners")
testDisableNativeRoutingCallbacksLocked()1792     private void testDisableNativeRoutingCallbacksLocked() {
1793         if (mRoutingChangeListeners.size() == 0) {
1794             native_disableDeviceCallback();
1795         }
1796     }
1797 
1798     //--------------------------------------------------------------------------
1799     // (Re)Routing Info
1800     //--------------------
1801     /**
1802      * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
1803      * {@link AudioRecord#addOnRoutingChangedListener} by an app to receive
1804      * (re)routing notifications.
1805      */
1806     @GuardedBy("mRoutingChangeListeners")
1807     private ArrayMap<AudioRouting.OnRoutingChangedListener,
1808             NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
1809 
1810     /**
1811      * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of
1812      * routing changes on this AudioRecord.
1813      * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
1814      * notifications of rerouting events.
1815      * @param handler  Specifies the {@link Handler} object for the thread on which to execute
1816      * the callback. If <code>null</code>, the {@link Handler} associated with the main
1817      * {@link Looper} will be used.
1818      */
1819     @Override
addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, android.os.Handler handler)1820     public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
1821             android.os.Handler handler) {
1822         synchronized (mRoutingChangeListeners) {
1823             if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
1824                 testEnableNativeRoutingCallbacksLocked();
1825                 mRoutingChangeListeners.put(
1826                         listener, new NativeRoutingEventHandlerDelegate(this, listener,
1827                                 handler != null ? handler : new Handler(mInitializationLooper)));
1828             }
1829         }
1830     }
1831 
1832     /**
1833      * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
1834     * to receive rerouting notifications.
1835     * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
1836     * to remove.
1837     */
1838     @Override
removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener)1839     public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
1840         synchronized (mRoutingChangeListeners) {
1841             if (mRoutingChangeListeners.containsKey(listener)) {
1842                 mRoutingChangeListeners.remove(listener);
1843                 testDisableNativeRoutingCallbacksLocked();
1844             }
1845         }
1846     }
1847 
1848     //--------------------------------------------------------------------------
1849     // (Re)Routing Info
1850     //--------------------
1851     /**
1852      * Defines the interface by which applications can receive notifications of
1853      * routing changes for the associated {@link AudioRecord}.
1854      *
1855      * @deprecated users should switch to the general purpose
1856      *             {@link AudioRouting.OnRoutingChangedListener} class instead.
1857      */
1858     @Deprecated
1859     public interface OnRoutingChangedListener extends AudioRouting.OnRoutingChangedListener {
1860         /**
1861          * Called when the routing of an AudioRecord changes from either and
1862          * explicit or policy rerouting. Use {@link #getRoutedDevice()} to
1863          * retrieve the newly routed-from device.
1864          */
onRoutingChanged(AudioRecord audioRecord)1865         public void onRoutingChanged(AudioRecord audioRecord);
1866 
1867         @Override
onRoutingChanged(AudioRouting router)1868         default public void onRoutingChanged(AudioRouting router) {
1869             if (router instanceof AudioRecord) {
1870                 onRoutingChanged((AudioRecord) router);
1871             }
1872         }
1873     }
1874 
1875     /**
1876      * Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes
1877      * on this AudioRecord.
1878      * @param listener The {@link OnRoutingChangedListener} interface to receive notifications
1879      * of rerouting events.
1880      * @param handler  Specifies the {@link Handler} object for the thread on which to execute
1881      * the callback. If <code>null</code>, the {@link Handler} associated with the main
1882      * {@link Looper} will be used.
1883      * @deprecated users should switch to the general purpose
1884      *             {@link AudioRouting.OnRoutingChangedListener} class instead.
1885      */
1886     @Deprecated
addOnRoutingChangedListener(OnRoutingChangedListener listener, android.os.Handler handler)1887     public void addOnRoutingChangedListener(OnRoutingChangedListener listener,
1888             android.os.Handler handler) {
1889         addOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener, handler);
1890     }
1891 
1892     /**
1893       * Removes an {@link OnRoutingChangedListener} which has been previously added
1894      * to receive rerouting notifications.
1895      * @param listener The previously added {@link OnRoutingChangedListener} interface to remove.
1896      * @deprecated users should switch to the general purpose
1897      *             {@link AudioRouting.OnRoutingChangedListener} class instead.
1898      */
1899     @Deprecated
removeOnRoutingChangedListener(OnRoutingChangedListener listener)1900     public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) {
1901         removeOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener);
1902     }
1903 
1904     /**
1905      * Sends device list change notification to all listeners.
1906      */
broadcastRoutingChange()1907     private void broadcastRoutingChange() {
1908         AudioManager.resetAudioPortGeneration();
1909         synchronized (mRoutingChangeListeners) {
1910             for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) {
1911                 delegate.notifyClient();
1912             }
1913         }
1914     }
1915 
1916     /**
1917      * Sets the period at which the listener is called, if set with
1918      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
1919      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
1920      * It is possible for notifications to be lost if the period is too small.
1921      * @param periodInFrames update period expressed in frames
1922      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
1923      */
setPositionNotificationPeriod(int periodInFrames)1924     public int setPositionNotificationPeriod(int periodInFrames) {
1925         if (mState == STATE_UNINITIALIZED) {
1926             return ERROR_INVALID_OPERATION;
1927         }
1928         return native_set_pos_update_period(periodInFrames);
1929     }
1930 
1931     //--------------------------------------------------------------------------
1932     // Explicit Routing
1933     //--------------------
1934     private AudioDeviceInfo mPreferredDevice = null;
1935 
1936     /**
1937      * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
1938      * the input to this AudioRecord.
1939      * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio source.
1940      *  If deviceInfo is null, default routing is restored.
1941      * @return true if successful, false if the specified {@link AudioDeviceInfo} is non-null and
1942      * does not correspond to a valid audio input device.
1943      */
1944     @Override
setPreferredDevice(AudioDeviceInfo deviceInfo)1945     public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
1946         // Do some validation....
1947         if (deviceInfo != null && !deviceInfo.isSource()) {
1948             return false;
1949         }
1950 
1951         int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
1952         boolean status = native_setInputDevice(preferredDeviceId);
1953         if (status == true) {
1954             synchronized (this) {
1955                 mPreferredDevice = deviceInfo;
1956             }
1957         }
1958         return status;
1959     }
1960 
1961     /**
1962      * Returns the selected input specified by {@link #setPreferredDevice}. Note that this
1963      * is not guarenteed to correspond to the actual device being used for recording.
1964      */
1965     @Override
getPreferredDevice()1966     public AudioDeviceInfo getPreferredDevice() {
1967         synchronized (this) {
1968             return mPreferredDevice;
1969         }
1970     }
1971 
1972     //--------------------------------------------------------------------------
1973     // Microphone information
1974     //--------------------
1975     /**
1976      * Returns a lists of {@link MicrophoneInfo} representing the active microphones.
1977      * By querying channel mapping for each active microphone, developer can know how
1978      * the microphone is used by each channels or a capture stream.
1979      * Note that the information about the active microphones may change during a recording.
1980      * See {@link AudioManager#registerAudioDeviceCallback} to be notified of changes
1981      * in the audio devices, querying the active microphones then will return the latest
1982      * information.
1983      *
1984      * @return a lists of {@link MicrophoneInfo} representing the active microphones.
1985      * @throws IOException if an error occurs
1986      */
getActiveMicrophones()1987     public List<MicrophoneInfo> getActiveMicrophones() throws IOException {
1988         ArrayList<MicrophoneInfo> activeMicrophones = new ArrayList<>();
1989         int status = native_get_active_microphones(activeMicrophones);
1990         if (status != AudioManager.SUCCESS) {
1991             if (status != AudioManager.ERROR_INVALID_OPERATION) {
1992                 Log.e(TAG, "getActiveMicrophones failed:" + status);
1993             }
1994             Log.i(TAG, "getActiveMicrophones failed, fallback on routed device info");
1995         }
1996         AudioManager.setPortIdForMicrophones(activeMicrophones);
1997 
1998         // Use routed device when there is not information returned by hal.
1999         if (activeMicrophones.size() == 0) {
2000             AudioDeviceInfo device = getRoutedDevice();
2001             if (device != null) {
2002                 MicrophoneInfo microphone = AudioManager.microphoneInfoFromAudioDeviceInfo(device);
2003                 ArrayList<Pair<Integer, Integer>> channelMapping = new ArrayList<>();
2004                 for (int i = 0; i < mChannelCount; i++) {
2005                     channelMapping.add(new Pair(i, MicrophoneInfo.CHANNEL_MAPPING_DIRECT));
2006                 }
2007                 microphone.setChannelMapping(channelMapping);
2008                 activeMicrophones.add(microphone);
2009             }
2010         }
2011         return activeMicrophones;
2012     }
2013 
2014     //--------------------------------------------------------------------------
2015     // Implementation of AudioRecordingMonitor interface
2016     //--------------------
2017 
2018     AudioRecordingMonitorImpl mRecordingInfoImpl =
2019             new AudioRecordingMonitorImpl((AudioRecordingMonitorClient) this);
2020 
2021     /**
2022      * Register a callback to be notified of audio capture changes via a
2023      * {@link AudioManager.AudioRecordingCallback}. A callback is received when the capture path
2024      * configuration changes (pre-processing, format, sampling rate...) or capture is
2025      * silenced/unsilenced by the system.
2026      * @param executor {@link Executor} to handle the callbacks.
2027      * @param cb non-null callback to register
2028      */
registerAudioRecordingCallback(@onNull @allbackExecutor Executor executor, @NonNull AudioManager.AudioRecordingCallback cb)2029     public void registerAudioRecordingCallback(@NonNull @CallbackExecutor Executor executor,
2030             @NonNull AudioManager.AudioRecordingCallback cb) {
2031         mRecordingInfoImpl.registerAudioRecordingCallback(executor, cb);
2032     }
2033 
2034     /**
2035      * Unregister an audio recording callback previously registered with
2036      * {@link #registerAudioRecordingCallback(Executor, AudioManager.AudioRecordingCallback)}.
2037      * @param cb non-null callback to unregister
2038      */
unregisterAudioRecordingCallback(@onNull AudioManager.AudioRecordingCallback cb)2039     public void unregisterAudioRecordingCallback(@NonNull AudioManager.AudioRecordingCallback cb) {
2040         mRecordingInfoImpl.unregisterAudioRecordingCallback(cb);
2041     }
2042 
2043     /**
2044      * Returns the current active audio recording for this audio recorder.
2045      * @return a valid {@link AudioRecordingConfiguration} if this recorder is active
2046      * or null otherwise.
2047      * @see AudioRecordingConfiguration
2048      */
getActiveRecordingConfiguration()2049     public @Nullable AudioRecordingConfiguration getActiveRecordingConfiguration() {
2050         return mRecordingInfoImpl.getActiveRecordingConfiguration();
2051     }
2052 
2053     //---------------------------------------------------------
2054     // Implementation of AudioRecordingMonitorClient interface
2055     //--------------------
2056     /**
2057      * @hide
2058      */
getPortId()2059     public int getPortId() {
2060         if (mNativeRecorderInJavaObj == 0) {
2061             return 0;
2062         }
2063         try {
2064             return native_getPortId();
2065         } catch (IllegalStateException e) {
2066             return 0;
2067         }
2068     }
2069 
2070     //--------------------------------------------------------------------------
2071     // MicrophoneDirection
2072     //--------------------
2073     /**
2074      * Specifies the logical microphone (for processing). Applications can use this to specify
2075      * which side of the device to optimize capture from. Typically used in conjunction with
2076      * the camera capturing video.
2077      *
2078      * @return true if sucessful.
2079      */
setPreferredMicrophoneDirection(@irectionMode int direction)2080     public boolean setPreferredMicrophoneDirection(@DirectionMode int direction) {
2081         return native_set_preferred_microphone_direction(direction) == AudioSystem.SUCCESS;
2082     }
2083 
2084     /**
2085      * Specifies the zoom factor (i.e. the field dimension) for the selected microphone
2086      * (for processing). The selected microphone is determined by the use-case for the stream.
2087      *
2088      * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle),
2089      * though 0 (no zoom) to 1 (maximum zoom).
2090      * @return true if sucessful.
2091      */
setPreferredMicrophoneFieldDimension( @loatRangefrom = -1.0, to = 1.0) float zoom)2092     public boolean setPreferredMicrophoneFieldDimension(
2093                             @FloatRange(from = -1.0, to = 1.0) float zoom) {
2094         Preconditions.checkArgument(
2095                 zoom >= -1 && zoom <= 1, "Argument must fall between -1 & 1 (inclusive)");
2096         return native_set_preferred_microphone_field_dimension(zoom) == AudioSystem.SUCCESS;
2097     }
2098 
2099     /**
2100      * Sets a {@link LogSessionId} instance to this AudioRecord for metrics collection.
2101      *
2102      * @param logSessionId a {@link LogSessionId} instance which is used to
2103      *        identify this object to the metrics service. Proper generated
2104      *        Ids must be obtained from the Java metrics service and should
2105      *        be considered opaque. Use
2106      *        {@link LogSessionId#LOG_SESSION_ID_NONE} to remove the
2107      *        logSessionId association.
2108      * @throws IllegalStateException if AudioRecord not initialized.
2109      */
setLogSessionId(@onNull LogSessionId logSessionId)2110     public void setLogSessionId(@NonNull LogSessionId logSessionId) {
2111         Objects.requireNonNull(logSessionId);
2112         if (mState == STATE_UNINITIALIZED) {
2113             throw new IllegalStateException("AudioRecord not initialized");
2114         }
2115         String stringId = logSessionId.getStringId();
2116         native_setLogSessionId(stringId);
2117         mLogSessionId = logSessionId;
2118     }
2119 
2120     /**
2121      * Returns the {@link LogSessionId}.
2122      */
2123     @NonNull
getLogSessionId()2124     public LogSessionId getLogSessionId() {
2125         return mLogSessionId;
2126     }
2127 
2128     //---------------------------------------------------------
2129     // Interface definitions
2130     //--------------------
2131     /**
2132      * Interface definition for a callback to be invoked when an AudioRecord has
2133      * reached a notification marker set by {@link AudioRecord#setNotificationMarkerPosition(int)}
2134      * or for periodic updates on the progress of the record head, as set by
2135      * {@link AudioRecord#setPositionNotificationPeriod(int)}.
2136      */
2137     public interface OnRecordPositionUpdateListener  {
2138         /**
2139          * Called on the listener to notify it that the previously set marker has been reached
2140          * by the recording head.
2141          */
onMarkerReached(AudioRecord recorder)2142         void onMarkerReached(AudioRecord recorder);
2143 
2144         /**
2145          * Called on the listener to periodically notify it that the record head has reached
2146          * a multiple of the notification period.
2147          */
onPeriodicNotification(AudioRecord recorder)2148         void onPeriodicNotification(AudioRecord recorder);
2149     }
2150 
2151 
2152 
2153     //---------------------------------------------------------
2154     // Inner classes
2155     //--------------------
2156 
2157     /**
2158      * Helper class to handle the forwarding of native events to the appropriate listener
2159      * (potentially) handled in a different thread
2160      */
2161     private class NativeEventHandler extends Handler {
2162         private final AudioRecord mAudioRecord;
2163 
NativeEventHandler(AudioRecord recorder, Looper looper)2164         NativeEventHandler(AudioRecord recorder, Looper looper) {
2165             super(looper);
2166             mAudioRecord = recorder;
2167         }
2168 
2169         @Override
handleMessage(Message msg)2170         public void handleMessage(Message msg) {
2171             OnRecordPositionUpdateListener listener = null;
2172             synchronized (mPositionListenerLock) {
2173                 listener = mAudioRecord.mPositionListener;
2174             }
2175 
2176             switch (msg.what) {
2177             case NATIVE_EVENT_MARKER:
2178                 if (listener != null) {
2179                     listener.onMarkerReached(mAudioRecord);
2180                 }
2181                 break;
2182             case NATIVE_EVENT_NEW_POS:
2183                 if (listener != null) {
2184                     listener.onPeriodicNotification(mAudioRecord);
2185                 }
2186                 break;
2187             default:
2188                 loge("Unknown native event type: " + msg.what);
2189                 break;
2190             }
2191         }
2192     }
2193 
2194     //---------------------------------------------------------
2195     // Java methods called from the native side
2196     //--------------------
2197     @SuppressWarnings("unused")
2198     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
postEventFromNative(Object audiorecord_ref, int what, int arg1, int arg2, Object obj)2199     private static void postEventFromNative(Object audiorecord_ref,
2200             int what, int arg1, int arg2, Object obj) {
2201         //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
2202         AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get();
2203         if (recorder == null) {
2204             return;
2205         }
2206 
2207         if (what == AudioSystem.NATIVE_EVENT_ROUTING_CHANGE) {
2208             recorder.broadcastRoutingChange();
2209             return;
2210         }
2211 
2212         if (recorder.mEventHandler != null) {
2213             Message m =
2214                 recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj);
2215             recorder.mEventHandler.sendMessage(m);
2216         }
2217 
2218     }
2219 
2220 
2221     //---------------------------------------------------------
2222     // Native methods called from the Java side
2223     //--------------------
2224 
2225     /**
2226      * @deprecated Use native_setup that takes an {@link AttributionSource} object
2227      * @return
2228      */
2229     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
2230             publicAlternatives = "{@code AudioRecord.Builder}")
2231     @Deprecated
native_setup(Object audiorecordThis, Object attributes, int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, int buffSizeInBytes, int[] sessionId, String opPackageName, long nativeRecordInJavaObj)2232     private int native_setup(Object audiorecordThis,
2233             Object /*AudioAttributes*/ attributes,
2234             int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
2235             int buffSizeInBytes, int[] sessionId, String opPackageName,
2236             long nativeRecordInJavaObj) {
2237         AttributionSource attributionSource = AttributionSource.myAttributionSource()
2238                 .withPackageName(opPackageName);
2239         try (ScopedParcelState attributionSourceState = attributionSource.asScopedParcelState()) {
2240             return native_setup(audiorecordThis, attributes, sampleRate, channelMask,
2241                     channelIndexMask, audioFormat, buffSizeInBytes, sessionId,
2242                     attributionSourceState.getParcel(), nativeRecordInJavaObj, 0);
2243         }
2244     }
2245 
native_setup(Object audiorecordThis, Object attributes, int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, int buffSizeInBytes, int[] sessionId, @NonNull Parcel attributionSource, long nativeRecordInJavaObj, int maxSharedAudioHistoryMs)2246     private native int native_setup(Object audiorecordThis,
2247             Object /*AudioAttributes*/ attributes,
2248             int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
2249             int buffSizeInBytes, int[] sessionId, @NonNull Parcel attributionSource,
2250             long nativeRecordInJavaObj, int maxSharedAudioHistoryMs);
2251 
2252     // TODO remove: implementation calls directly into implementation of native_release()
native_finalize()2253     private native void native_finalize();
2254 
2255     /**
2256      * @hide
2257      */
2258     @UnsupportedAppUsage
native_release()2259     public native final void native_release();
2260 
native_start(int syncEvent, int sessionId)2261     private native final int native_start(int syncEvent, int sessionId);
2262 
native_stop()2263     private native final void native_stop();
2264 
native_read_in_byte_array(byte[] audioData, int offsetInBytes, int sizeInBytes, boolean isBlocking)2265     private native final int native_read_in_byte_array(byte[] audioData,
2266             int offsetInBytes, int sizeInBytes, boolean isBlocking);
2267 
native_read_in_short_array(short[] audioData, int offsetInShorts, int sizeInShorts, boolean isBlocking)2268     private native final int native_read_in_short_array(short[] audioData,
2269             int offsetInShorts, int sizeInShorts, boolean isBlocking);
2270 
native_read_in_float_array(float[] audioData, int offsetInFloats, int sizeInFloats, boolean isBlocking)2271     private native final int native_read_in_float_array(float[] audioData,
2272             int offsetInFloats, int sizeInFloats, boolean isBlocking);
2273 
native_read_in_direct_buffer(Object jBuffer, int sizeInBytes, boolean isBlocking)2274     private native final int native_read_in_direct_buffer(Object jBuffer,
2275             int sizeInBytes, boolean isBlocking);
2276 
native_get_buffer_size_in_frames()2277     private native final int native_get_buffer_size_in_frames();
2278 
native_set_marker_pos(int marker)2279     private native final int native_set_marker_pos(int marker);
native_get_marker_pos()2280     private native final int native_get_marker_pos();
2281 
native_set_pos_update_period(int updatePeriod)2282     private native final int native_set_pos_update_period(int updatePeriod);
native_get_pos_update_period()2283     private native final int native_get_pos_update_period();
2284 
native_get_min_buff_size( int sampleRateInHz, int channelCount, int audioFormat)2285     static private native final int native_get_min_buff_size(
2286             int sampleRateInHz, int channelCount, int audioFormat);
2287 
native_setInputDevice(int deviceId)2288     private native final boolean native_setInputDevice(int deviceId);
native_getRoutedDeviceId()2289     private native final int native_getRoutedDeviceId();
native_enableDeviceCallback()2290     private native final void native_enableDeviceCallback();
native_disableDeviceCallback()2291     private native final void native_disableDeviceCallback();
2292 
native_get_timestamp(@onNull AudioTimestamp outTimestamp, @AudioTimestamp.Timebase int timebase)2293     private native final int native_get_timestamp(@NonNull AudioTimestamp outTimestamp,
2294             @AudioTimestamp.Timebase int timebase);
2295 
native_get_active_microphones( ArrayList<MicrophoneInfo> activeMicrophones)2296     private native final int native_get_active_microphones(
2297             ArrayList<MicrophoneInfo> activeMicrophones);
2298 
2299     /**
2300      * @throws IllegalStateException
2301      */
native_getPortId()2302     private native int native_getPortId();
2303 
native_set_preferred_microphone_direction(int direction)2304     private native int native_set_preferred_microphone_direction(int direction);
native_set_preferred_microphone_field_dimension(float zoom)2305     private native int native_set_preferred_microphone_field_dimension(float zoom);
2306 
native_setLogSessionId(@ullable String logSessionId)2307     private native void native_setLogSessionId(@Nullable String logSessionId);
2308 
native_shareAudioHistory(@onNull String sharedPackage, long startFromMs)2309     private native int native_shareAudioHistory(@NonNull String sharedPackage, long startFromMs);
2310 
2311     //---------------------------------------------------------
2312     // Utility methods
2313     //------------------
2314 
logd(String msg)2315     private static void logd(String msg) {
2316         Log.d(TAG, msg);
2317     }
2318 
loge(String msg)2319     private static void loge(String msg) {
2320         Log.e(TAG, msg);
2321     }
2322 
2323     public static final class MetricsConstants
2324     {
MetricsConstants()2325         private MetricsConstants() {}
2326 
2327         // MM_PREFIX is slightly different than TAG, used to avoid cut-n-paste errors.
2328         private static final String MM_PREFIX = "android.media.audiorecord.";
2329 
2330         /**
2331          * Key to extract the audio data encoding for this track
2332          * from the {@link AudioRecord#getMetrics} return value.
2333          * The value is a {@code String}.
2334          */
2335         public static final String ENCODING = MM_PREFIX + "encoding";
2336 
2337         /**
2338          * Key to extract the source type for this track
2339          * from the {@link AudioRecord#getMetrics} return value.
2340          * The value is a {@code String}.
2341          */
2342         public static final String SOURCE = MM_PREFIX + "source";
2343 
2344         /**
2345          * Key to extract the estimated latency through the recording pipeline
2346          * from the {@link AudioRecord#getMetrics} return value.
2347          * This is in units of milliseconds.
2348          * The value is an {@code int}.
2349          * @deprecated Not properly supported in the past.
2350          */
2351         @Deprecated
2352         public static final String LATENCY = MM_PREFIX + "latency";
2353 
2354         /**
2355          * Key to extract the sink sample rate for this record track in Hz
2356          * from the {@link AudioRecord#getMetrics} return value.
2357          * The value is an {@code int}.
2358          */
2359         public static final String SAMPLERATE = MM_PREFIX + "samplerate";
2360 
2361         /**
2362          * Key to extract the number of channels being recorded in this record track
2363          * from the {@link AudioRecord#getMetrics} return value.
2364          * The value is an {@code int}.
2365          */
2366         public static final String CHANNELS = MM_PREFIX + "channels";
2367 
2368         /**
2369          * Use for testing only. Do not expose.
2370          * The native channel mask.
2371          * The value is a {@code long}.
2372          * @hide
2373          */
2374         @TestApi
2375         public static final String CHANNEL_MASK = MM_PREFIX + "channelMask";
2376 
2377 
2378         /**
2379          * Use for testing only. Do not expose.
2380          * The port id of this input port in audioserver.
2381          * The value is an {@code int}.
2382          * @hide
2383          */
2384         @TestApi
2385         public static final String PORT_ID = MM_PREFIX + "portId";
2386 
2387         /**
2388          * Use for testing only. Do not expose.
2389          * The buffer frameCount.
2390          * The value is an {@code int}.
2391          * @hide
2392          */
2393         @TestApi
2394         public static final String FRAME_COUNT = MM_PREFIX + "frameCount";
2395 
2396         /**
2397          * Use for testing only. Do not expose.
2398          * The actual record track attributes used.
2399          * The value is a {@code String}.
2400          * @hide
2401          */
2402         @TestApi
2403         public static final String ATTRIBUTES = MM_PREFIX + "attributes";
2404 
2405         /**
2406          * Use for testing only. Do not expose.
2407          * The buffer frameCount
2408          * The value is a {@code double}.
2409          * @hide
2410          */
2411         @TestApi
2412         public static final String DURATION_MS = MM_PREFIX + "durationMs";
2413 
2414         /**
2415          * Use for testing only. Do not expose.
2416          * The number of times the record track has started
2417          * The value is a {@code long}.
2418          * @hide
2419          */
2420         @TestApi
2421         public static final String START_COUNT = MM_PREFIX + "startCount";
2422     }
2423 }
2424