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