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