/media/java/android/media/AudioRecord.java

http://github.com/android/platform_frameworks_base · Java · 2423 lines · 1096 code · 219 blank · 1108 comment · 255 complexity · c79902af1cb590848d566a9fe92bbe3f MD5 · raw file

Large files are truncated click here to view the full file

  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. package android.media;
  17. import android.annotation.CallbackExecutor;
  18. import android.annotation.FloatRange;
  19. import android.annotation.IntDef;
  20. import android.annotation.IntRange;
  21. import android.annotation.NonNull;
  22. import android.annotation.Nullable;
  23. import android.annotation.RequiresPermission;
  24. import android.annotation.SystemApi;
  25. import android.annotation.TestApi;
  26. import android.app.ActivityThread;
  27. import android.compat.annotation.UnsupportedAppUsage;
  28. import android.content.AttributionSource;
  29. import android.content.AttributionSource.ScopedParcelState;
  30. import android.content.Context;
  31. import android.media.MediaRecorder.Source;
  32. import android.media.audiopolicy.AudioMix;
  33. import android.media.audiopolicy.AudioPolicy;
  34. import android.media.metrics.LogSessionId;
  35. import android.media.projection.MediaProjection;
  36. import android.os.Binder;
  37. import android.os.Build;
  38. import android.os.Handler;
  39. import android.os.IBinder;
  40. import android.os.Looper;
  41. import android.os.Message;
  42. import android.os.Parcel;
  43. import android.os.PersistableBundle;
  44. import android.os.RemoteException;
  45. import android.os.ServiceManager;
  46. import android.util.ArrayMap;
  47. import android.util.Log;
  48. import android.util.Pair;
  49. import com.android.internal.annotations.GuardedBy;
  50. import com.android.internal.util.Preconditions;
  51. import java.io.IOException;
  52. import java.lang.annotation.Retention;
  53. import java.lang.annotation.RetentionPolicy;
  54. import java.lang.ref.WeakReference;
  55. import java.nio.ByteBuffer;
  56. import java.util.ArrayList;
  57. import java.util.Iterator;
  58. import java.util.List;
  59. import java.util.Objects;
  60. import java.util.concurrent.Executor;
  61. /**
  62. * The AudioRecord class manages the audio resources for Java applications
  63. * to record audio from the audio input hardware of the platform. This is
  64. * achieved by "pulling" (reading) the data from the AudioRecord object. The
  65. * application is responsible for polling the AudioRecord object in time using one of
  66. * the following three methods: {@link #read(byte[],int, int)}, {@link #read(short[], int, int)}
  67. * or {@link #read(ByteBuffer, int)}. The choice of which method to use will be based
  68. * on the audio data storage format that is the most convenient for the user of AudioRecord.
  69. * <p>Upon creation, an AudioRecord object initializes its associated audio buffer that it will
  70. * fill with the new audio data. The size of this buffer, specified during the construction,
  71. * determines how long an AudioRecord can record before "over-running" data that has not
  72. * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
  73. * the total recording buffer size.</p>
  74. * <p>
  75. * Applications creating an AudioRecord instance need
  76. * {@link android.Manifest.permission#RECORD_AUDIO} or the Builder will throw
  77. * {@link java.lang.UnsupportedOperationException} on
  78. * {@link android.media.AudioRecord.Builder#build build()},
  79. * and the constructor will return an instance in state
  80. * {@link #STATE_UNINITIALIZED}.</p>
  81. */
  82. public class AudioRecord implements AudioRouting, MicrophoneDirection,
  83. AudioRecordingMonitor, AudioRecordingMonitorClient
  84. {
  85. //---------------------------------------------------------
  86. // Constants
  87. //--------------------
  88. /**
  89. * indicates AudioRecord state is not successfully initialized.
  90. */
  91. public static final int STATE_UNINITIALIZED = 0;
  92. /**
  93. * indicates AudioRecord state is ready to be used
  94. */
  95. public static final int STATE_INITIALIZED = 1;
  96. /**
  97. * indicates AudioRecord recording state is not recording
  98. */
  99. public static final int RECORDSTATE_STOPPED = 1; // matches SL_RECORDSTATE_STOPPED
  100. /**
  101. * indicates AudioRecord recording state is recording
  102. */
  103. public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING
  104. /**
  105. * Denotes a successful operation.
  106. */
  107. public static final int SUCCESS = AudioSystem.SUCCESS;
  108. /**
  109. * Denotes a generic operation failure.
  110. */
  111. public static final int ERROR = AudioSystem.ERROR;
  112. /**
  113. * Denotes a failure due to the use of an invalid value.
  114. */
  115. public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
  116. /**
  117. * Denotes a failure due to the improper use of a method.
  118. */
  119. public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
  120. /**
  121. * An error code indicating that the object reporting it is no longer valid and needs to
  122. * be recreated.
  123. */
  124. public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
  125. // Error codes:
  126. // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp
  127. private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT = -16;
  128. private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK = -17;
  129. private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT = -18;
  130. private static final int AUDIORECORD_ERROR_SETUP_INVALIDSOURCE = -19;
  131. private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED = -20;
  132. // Events:
  133. // to keep in sync with frameworks/av/include/media/AudioRecord.h
  134. /**
  135. * Event id denotes when record head has reached a previously set marker.
  136. */
  137. private static final int NATIVE_EVENT_MARKER = 2;
  138. /**
  139. * Event id denotes when previously set update period has elapsed during recording.
  140. */
  141. private static final int NATIVE_EVENT_NEW_POS = 3;
  142. private final static String TAG = "android.media.AudioRecord";
  143. /** @hide */
  144. public final static String SUBMIX_FIXED_VOLUME = "fixedVolume";
  145. /** @hide */
  146. @IntDef({
  147. READ_BLOCKING,
  148. READ_NON_BLOCKING
  149. })
  150. @Retention(RetentionPolicy.SOURCE)
  151. public @interface ReadMode {}
  152. /**
  153. * The read mode indicating the read operation will block until all data
  154. * requested has been read.
  155. */
  156. public final static int READ_BLOCKING = 0;
  157. /**
  158. * The read mode indicating the read operation will return immediately after
  159. * reading as much audio data as possible without blocking.
  160. */
  161. public final static int READ_NON_BLOCKING = 1;
  162. //---------------------------------------------------------
  163. // Used exclusively by native code
  164. //--------------------
  165. /**
  166. * Accessed by native methods: provides access to C++ AudioRecord object
  167. * Is 0 after release()
  168. */
  169. @SuppressWarnings("unused")
  170. @UnsupportedAppUsage
  171. private long mNativeRecorderInJavaObj;
  172. /**
  173. * Accessed by native methods: provides access to the callback data.
  174. */
  175. @SuppressWarnings("unused")
  176. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  177. private long mNativeCallbackCookie;
  178. /**
  179. * Accessed by native methods: provides access to the JNIDeviceCallback instance.
  180. */
  181. @SuppressWarnings("unused")
  182. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  183. private long mNativeDeviceCallback;
  184. //---------------------------------------------------------
  185. // Member variables
  186. //--------------------
  187. private AudioPolicy mAudioCapturePolicy;
  188. /**
  189. * The audio data sampling rate in Hz.
  190. * Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}.
  191. */
  192. private int mSampleRate; // initialized by all constructors via audioParamCheck()
  193. /**
  194. * The number of input audio channels (1 is mono, 2 is stereo)
  195. */
  196. private int mChannelCount;
  197. /**
  198. * The audio channel position mask
  199. */
  200. private int mChannelMask;
  201. /**
  202. * The audio channel index mask
  203. */
  204. private int mChannelIndexMask;
  205. /**
  206. * The encoding of the audio samples.
  207. * @see AudioFormat#ENCODING_PCM_8BIT
  208. * @see AudioFormat#ENCODING_PCM_16BIT
  209. * @see AudioFormat#ENCODING_PCM_FLOAT
  210. */
  211. private int mAudioFormat;
  212. /**
  213. * Where the audio data is recorded from.
  214. */
  215. private int mRecordSource;
  216. /**
  217. * Indicates the state of the AudioRecord instance.
  218. */
  219. private int mState = STATE_UNINITIALIZED;
  220. /**
  221. * Indicates the recording state of the AudioRecord instance.
  222. */
  223. private int mRecordingState = RECORDSTATE_STOPPED;
  224. /**
  225. * Lock to make sure mRecordingState updates are reflecting the actual state of the object.
  226. */
  227. private final Object mRecordingStateLock = new Object();
  228. /**
  229. * The listener the AudioRecord notifies when the record position reaches a marker
  230. * or for periodic updates during the progression of the record head.
  231. * @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)
  232. * @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)
  233. */
  234. private OnRecordPositionUpdateListener mPositionListener = null;
  235. /**
  236. * Lock to protect position listener updates against event notifications
  237. */
  238. private final Object mPositionListenerLock = new Object();
  239. /**
  240. * Handler for marker events coming from the native code
  241. */
  242. private NativeEventHandler mEventHandler = null;
  243. /**
  244. * Looper associated with the thread that creates the AudioRecord instance
  245. */
  246. @UnsupportedAppUsage
  247. private Looper mInitializationLooper = null;
  248. /**
  249. * Size of the native audio buffer.
  250. */
  251. private int mNativeBufferSizeInBytes = 0;
  252. /**
  253. * Audio session ID
  254. */
  255. private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
  256. /**
  257. * AudioAttributes
  258. */
  259. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  260. private AudioAttributes mAudioAttributes;
  261. private boolean mIsSubmixFullVolume = false;
  262. /**
  263. * The log session id used for metrics.
  264. * {@link LogSessionId#LOG_SESSION_ID_NONE} here means it is not set.
  265. */
  266. @NonNull private LogSessionId mLogSessionId = LogSessionId.LOG_SESSION_ID_NONE;
  267. //---------------------------------------------------------
  268. // Constructor, Finalize
  269. //--------------------
  270. /**
  271. * Class constructor.
  272. * Though some invalid parameters will result in an {@link IllegalArgumentException} exception,
  273. * other errors do not. Thus you should call {@link #getState()} immediately after construction
  274. * to confirm that the object is usable.
  275. * @param audioSource the recording source.
  276. * See {@link MediaRecorder.AudioSource} for the recording source definitions.
  277. * @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only
  278. * rate that is guaranteed to work on all devices, but other rates such as 22050,
  279. * 16000, and 11025 may work on some devices.
  280. * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value
  281. * which is usually the sample rate of the source.
  282. * {@link #getSampleRate()} can be used to retrieve the actual sample rate chosen.
  283. * @param channelConfig describes the configuration of the audio channels.
  284. * See {@link AudioFormat#CHANNEL_IN_MONO} and
  285. * {@link AudioFormat#CHANNEL_IN_STEREO}. {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
  286. * to work on all devices.
  287. * @param audioFormat the format in which the audio data is to be returned.
  288. * See {@link AudioFormat#ENCODING_PCM_8BIT}, {@link AudioFormat#ENCODING_PCM_16BIT},
  289. * and {@link AudioFormat#ENCODING_PCM_FLOAT}.
  290. * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
  291. * to during the recording. New audio data can be read from this buffer in smaller chunks
  292. * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
  293. * required buffer size for the successful creation of an AudioRecord instance. Using values
  294. * smaller than getMinBufferSize() will result in an initialization failure.
  295. * @throws java.lang.IllegalArgumentException
  296. */
  297. @RequiresPermission(android.Manifest.permission.RECORD_AUDIO)
  298. public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
  299. int bufferSizeInBytes)
  300. throws IllegalArgumentException {
  301. this((new AudioAttributes.Builder())
  302. .setInternalCapturePreset(audioSource)
  303. .build(),
  304. (new AudioFormat.Builder())
  305. .setChannelMask(getChannelMaskFromLegacyConfig(channelConfig,
  306. true/*allow legacy configurations*/))
  307. .setEncoding(audioFormat)
  308. .setSampleRate(sampleRateInHz)
  309. .build(),
  310. bufferSizeInBytes,
  311. AudioManager.AUDIO_SESSION_ID_GENERATE);
  312. }
  313. /**
  314. * @hide
  315. * Class constructor with {@link AudioAttributes} and {@link AudioFormat}.
  316. * @param attributes a non-null {@link AudioAttributes} instance. Use
  317. * {@link AudioAttributes.Builder#setCapturePreset(int)} for configuring the audio
  318. * source for this instance.
  319. * @param format a non-null {@link AudioFormat} instance describing the format of the data
  320. * that will be recorded through this AudioRecord. See {@link AudioFormat.Builder} for
  321. * configuring the audio format parameters such as encoding, channel mask and sample rate.
  322. * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
  323. * to during the recording. New audio data can be read from this buffer in smaller chunks
  324. * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
  325. * required buffer size for the successful creation of an AudioRecord instance. Using values
  326. * smaller than getMinBufferSize() will result in an initialization failure.
  327. * @param sessionId ID of audio session the AudioRecord must be attached to, or
  328. * {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at construction
  329. * time. See also {@link AudioManager#generateAudioSessionId()} to obtain a session ID before
  330. * construction.
  331. * @throws IllegalArgumentException
  332. */
  333. @SystemApi
  334. @RequiresPermission(android.Manifest.permission.RECORD_AUDIO)
  335. public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
  336. int sessionId) throws IllegalArgumentException {
  337. this(attributes, format, bufferSizeInBytes, sessionId,
  338. ActivityThread.currentApplication(), 0 /*maxSharedAudioHistoryMs*/);
  339. }
  340. /**
  341. * @hide
  342. * Class constructor with {@link AudioAttributes} and {@link AudioFormat}.
  343. * @param attributes a non-null {@link AudioAttributes} instance. Use
  344. * {@link AudioAttributes.Builder#setCapturePreset(int)} for configuring the audio
  345. * source for this instance.
  346. * @param format a non-null {@link AudioFormat} instance describing the format of the data
  347. * that will be recorded through this AudioRecord. See {@link AudioFormat.Builder} for
  348. * configuring the audio format parameters such as encoding, channel mask and sample rate.
  349. * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
  350. * to during the recording. New audio data can be read from this buffer in smaller chunks
  351. * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
  352. * required buffer size for the successful creation of an AudioRecord instance. Using values
  353. * smaller than getMinBufferSize() will result in an initialization failure.
  354. * @param sessionId ID of audio session the AudioRecord must be attached to, or
  355. * {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at construction
  356. * time. See also {@link AudioManager#generateAudioSessionId()} to obtain a session ID before
  357. * construction.
  358. * @param context An optional context on whose behalf the recoding is performed.
  359. *
  360. * @throws IllegalArgumentException
  361. */
  362. private AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
  363. int sessionId, @Nullable Context context,
  364. int maxSharedAudioHistoryMs) throws IllegalArgumentException {
  365. mRecordingState = RECORDSTATE_STOPPED;
  366. if (attributes == null) {
  367. throw new IllegalArgumentException("Illegal null AudioAttributes");
  368. }
  369. if (format == null) {
  370. throw new IllegalArgumentException("Illegal null AudioFormat");
  371. }
  372. // remember which looper is associated with the AudioRecord instanciation
  373. if ((mInitializationLooper = Looper.myLooper()) == null) {
  374. mInitializationLooper = Looper.getMainLooper();
  375. }
  376. // is this AudioRecord using REMOTE_SUBMIX at full volume?
  377. if (attributes.getCapturePreset() == MediaRecorder.AudioSource.REMOTE_SUBMIX) {
  378. final AudioAttributes.Builder filteredAttr = new AudioAttributes.Builder();
  379. final Iterator<String> tagsIter = attributes.getTags().iterator();
  380. while (tagsIter.hasNext()) {
  381. final String tag = tagsIter.next();
  382. if (tag.equalsIgnoreCase(SUBMIX_FIXED_VOLUME)) {
  383. mIsSubmixFullVolume = true;
  384. Log.v(TAG, "Will record from REMOTE_SUBMIX at full fixed volume");
  385. } else { // SUBMIX_FIXED_VOLUME: is not to be propagated to the native layers
  386. filteredAttr.addTag(tag);
  387. }
  388. }
  389. filteredAttr.setInternalCapturePreset(attributes.getCapturePreset());
  390. mAudioAttributes = filteredAttr.build();
  391. } else {
  392. mAudioAttributes = attributes;
  393. }
  394. int rate = format.getSampleRate();
  395. if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
  396. rate = 0;
  397. }
  398. int encoding = AudioFormat.ENCODING_DEFAULT;
  399. if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0)
  400. {
  401. encoding = format.getEncoding();
  402. }
  403. audioParamCheck(attributes.getCapturePreset(), rate, encoding);
  404. if ((format.getPropertySetMask()
  405. & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) {
  406. mChannelIndexMask = format.getChannelIndexMask();
  407. mChannelCount = format.getChannelCount();
  408. }
  409. if ((format.getPropertySetMask()
  410. & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0) {
  411. mChannelMask = getChannelMaskFromLegacyConfig(format.getChannelMask(), false);
  412. mChannelCount = format.getChannelCount();
  413. } else if (mChannelIndexMask == 0) {
  414. mChannelMask = getChannelMaskFromLegacyConfig(AudioFormat.CHANNEL_IN_DEFAULT, false);
  415. mChannelCount = AudioFormat.channelCountFromInChannelMask(mChannelMask);
  416. }
  417. audioBuffSizeCheck(bufferSizeInBytes);
  418. AttributionSource attributionSource = (context != null)
  419. ? context.getAttributionSource() : AttributionSource.myAttributionSource();
  420. if (attributionSource.getPackageName() == null) {
  421. // Command line utility
  422. attributionSource = attributionSource.withPackageName("uid:" + Binder.getCallingUid());
  423. }
  424. int[] sampleRate = new int[] {mSampleRate};
  425. int[] session = new int[1];
  426. session[0] = sessionId;
  427. //TODO: update native initialization when information about hardware init failure
  428. // due to capture device already open is available.
  429. try (ScopedParcelState attributionSourceState = attributionSource.asScopedParcelState()) {
  430. int initResult = native_setup(new WeakReference<AudioRecord>(this), mAudioAttributes,
  431. sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
  432. mNativeBufferSizeInBytes, session, attributionSourceState.getParcel(),
  433. 0 /*nativeRecordInJavaObj*/, maxSharedAudioHistoryMs);
  434. if (initResult != SUCCESS) {
  435. loge("Error code " + initResult + " when initializing native AudioRecord object.");
  436. return; // with mState == STATE_UNINITIALIZED
  437. }
  438. }
  439. mSampleRate = sampleRate[0];
  440. mSessionId = session[0];
  441. mState = STATE_INITIALIZED;
  442. }
  443. /**
  444. * A constructor which explicitly connects a Native (C++) AudioRecord. For use by
  445. * the AudioRecordRoutingProxy subclass.
  446. * @param nativeRecordInJavaObj A C/C++ pointer to a native AudioRecord
  447. * (associated with an OpenSL ES recorder). Note: the caller must ensure a correct
  448. * value here as no error checking is or can be done.
  449. */
  450. /*package*/ AudioRecord(long nativeRecordInJavaObj) {
  451. mNativeRecorderInJavaObj = 0;
  452. mNativeCallbackCookie = 0;
  453. mNativeDeviceCallback = 0;
  454. // other initialization...
  455. if (nativeRecordInJavaObj != 0) {
  456. deferred_connect(nativeRecordInJavaObj);
  457. } else {
  458. mState = STATE_UNINITIALIZED;
  459. }
  460. }
  461. /**
  462. * Sets an {@link AudioPolicy} to automatically unregister when the record is released.
  463. *
  464. * <p>This is to prevent users of the audio capture API from having to manually unregister the
  465. * policy that was used to create the record.
  466. */
  467. private void unregisterAudioPolicyOnRelease(AudioPolicy audioPolicy) {
  468. mAudioCapturePolicy = audioPolicy;
  469. }
  470. /**
  471. * @hide
  472. */
  473. /* package */ void deferred_connect(long nativeRecordInJavaObj) {
  474. if (mState != STATE_INITIALIZED) {
  475. int[] session = {0};
  476. int[] rates = {0};
  477. //TODO: update native initialization when information about hardware init failure
  478. // due to capture device already open is available.
  479. // Note that for this native_setup, we are providing an already created/initialized
  480. // *Native* AudioRecord, so the attributes parameters to native_setup() are ignored.
  481. final int initResult;
  482. try (ScopedParcelState attributionSourceState = AttributionSource.myAttributionSource()
  483. .asScopedParcelState()) {
  484. initResult = native_setup(new WeakReference<>(this),
  485. null /*mAudioAttributes*/,
  486. rates /*mSampleRates*/,
  487. 0 /*mChannelMask*/,
  488. 0 /*mChannelIndexMask*/,
  489. 0 /*mAudioFormat*/,
  490. 0 /*mNativeBufferSizeInBytes*/,
  491. session,
  492. attributionSourceState.getParcel(),
  493. nativeRecordInJavaObj,
  494. 0);
  495. }
  496. if (initResult != SUCCESS) {
  497. loge("Error code "+initResult+" when initializing native AudioRecord object.");
  498. return; // with mState == STATE_UNINITIALIZED
  499. }
  500. mSessionId = session[0];
  501. mState = STATE_INITIALIZED;
  502. }
  503. }
  504. /** @hide */
  505. public AudioAttributes getAudioAttributes() {
  506. return mAudioAttributes;
  507. }
  508. /**
  509. * Builder class for {@link AudioRecord} objects.
  510. * Use this class to configure and create an <code>AudioRecord</code> instance. By setting the
  511. * recording source and audio format parameters, you indicate which of
  512. * those vary from the default behavior on the device.
  513. * <p> Here is an example where <code>Builder</code> is used to specify all {@link AudioFormat}
  514. * parameters, to be used by a new <code>AudioRecord</code> instance:
  515. *
  516. * <pre class="prettyprint">
  517. * AudioRecord recorder = new AudioRecord.Builder()
  518. * .setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION)
  519. * .setAudioFormat(new AudioFormat.Builder()
  520. * .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
  521. * .setSampleRate(32000)
  522. * .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
  523. * .build())
  524. * .setBufferSizeInBytes(2*minBuffSize)
  525. * .build();
  526. * </pre>
  527. * <p>
  528. * If the audio source is not set with {@link #setAudioSource(int)},
  529. * {@link MediaRecorder.AudioSource#DEFAULT} is used.
  530. * <br>If the audio format is not specified or is incomplete, its channel configuration will be
  531. * {@link AudioFormat#CHANNEL_IN_MONO}, and the encoding will be
  532. * {@link AudioFormat#ENCODING_PCM_16BIT}.
  533. * The sample rate will depend on the device actually selected for capture and can be queried
  534. * with {@link #getSampleRate()} method.
  535. * <br>If the buffer size is not specified with {@link #setBufferSizeInBytes(int)},
  536. * the minimum buffer size for the source is used.
  537. */
  538. public static class Builder {
  539. private static final String ERROR_MESSAGE_SOURCE_MISMATCH =
  540. "Cannot both set audio source and set playback capture config";
  541. private AudioPlaybackCaptureConfiguration mAudioPlaybackCaptureConfiguration;
  542. private AudioAttributes mAttributes;
  543. private AudioFormat mFormat;
  544. private Context mContext;
  545. private int mBufferSizeInBytes;
  546. private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
  547. private int mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT;
  548. private int mMaxSharedAudioHistoryMs = 0;
  549. private static final int PRIVACY_SENSITIVE_DEFAULT = -1;
  550. private static final int PRIVACY_SENSITIVE_DISABLED = 0;
  551. private static final int PRIVACY_SENSITIVE_ENABLED = 1;
  552. /**
  553. * Constructs a new Builder with the default values as described above.
  554. */
  555. public Builder() {
  556. }
  557. /**
  558. * @param source the audio source.
  559. * See {@link MediaRecorder.AudioSource} for the supported audio source definitions.
  560. * @return the same Builder instance.
  561. * @throws IllegalArgumentException
  562. */
  563. public Builder setAudioSource(@Source int source) throws IllegalArgumentException {
  564. Preconditions.checkState(
  565. mAudioPlaybackCaptureConfiguration == null,
  566. ERROR_MESSAGE_SOURCE_MISMATCH);
  567. if ( (source < MediaRecorder.AudioSource.DEFAULT) ||
  568. (source > MediaRecorder.getAudioSourceMax()) ) {
  569. throw new IllegalArgumentException("Invalid audio source " + source);
  570. }
  571. mAttributes = new AudioAttributes.Builder()
  572. .setInternalCapturePreset(source)
  573. .build();
  574. return this;
  575. }
  576. /**
  577. * Sets the context the record belongs to. This context will be used to pull information,
  578. * such as {@link android.content.AttributionSource}, which will be associated with
  579. * the AudioRecord. However, the context itself will not be retained by the AudioRecord.
  580. * @param context a non-null {@link Context} instance
  581. * @return the same Builder instance.
  582. */
  583. public @NonNull Builder setContext(@NonNull Context context) {
  584. Objects.requireNonNull(context);
  585. // keep reference, we only copy the data when building
  586. mContext = context;
  587. return this;
  588. }
  589. /**
  590. * @hide
  591. * To be only used by system components. Allows specifying non-public capture presets
  592. * @param attributes a non-null {@link AudioAttributes} instance that contains the capture
  593. * preset to be used.
  594. * @return the same Builder instance.
  595. * @throws IllegalArgumentException
  596. */
  597. @SystemApi
  598. public Builder setAudioAttributes(@NonNull AudioAttributes attributes)
  599. throws IllegalArgumentException {
  600. if (attributes == null) {
  601. throw new IllegalArgumentException("Illegal null AudioAttributes argument");
  602. }
  603. if (attributes.getCapturePreset() == MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID) {
  604. throw new IllegalArgumentException(
  605. "No valid capture preset in AudioAttributes argument");
  606. }
  607. // keep reference, we only copy the data when building
  608. mAttributes = attributes;
  609. return this;
  610. }
  611. /**
  612. * Sets the format of the audio data to be captured.
  613. * @param format a non-null {@link AudioFormat} instance
  614. * @return the same Builder instance.
  615. * @throws IllegalArgumentException
  616. */
  617. public Builder setAudioFormat(@NonNull AudioFormat format) throws IllegalArgumentException {
  618. if (format == null) {
  619. throw new IllegalArgumentException("Illegal null AudioFormat argument");
  620. }
  621. // keep reference, we only copy the data when building
  622. mFormat = format;
  623. return this;
  624. }
  625. /**
  626. * Sets the total size (in bytes) of the buffer where audio data is written
  627. * during the recording. New audio data can be read from this buffer in smaller chunks
  628. * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
  629. * required buffer size for the successful creation of an AudioRecord instance.
  630. * Since bufferSizeInBytes may be internally increased to accommodate the source
  631. * requirements, use {@link #getBufferSizeInFrames()} to determine the actual buffer size
  632. * in frames.
  633. * @param bufferSizeInBytes a value strictly greater than 0
  634. * @return the same Builder instance.
  635. * @throws IllegalArgumentException
  636. */
  637. public Builder setBufferSizeInBytes(int bufferSizeInBytes) throws IllegalArgumentException {
  638. if (bufferSizeInBytes <= 0) {
  639. throw new IllegalArgumentException("Invalid buffer size " + bufferSizeInBytes);
  640. }
  641. mBufferSizeInBytes = bufferSizeInBytes;
  642. return this;
  643. }
  644. /**
  645. * Sets the {@link AudioRecord} to record audio played by other apps.
  646. *
  647. * @param config Defines what apps to record audio from (i.e., via either their uid or
  648. * the type of audio).
  649. * @throws IllegalStateException if called in conjunction with {@link #setAudioSource(int)}.
  650. * @throws NullPointerException if {@code config} is null.
  651. */
  652. public @NonNull Builder setAudioPlaybackCaptureConfig(
  653. @NonNull AudioPlaybackCaptureConfiguration config) {
  654. Preconditions.checkNotNull(
  655. config, "Illegal null AudioPlaybackCaptureConfiguration argument");
  656. Preconditions.checkState(
  657. mAttributes == null,
  658. ERROR_MESSAGE_SOURCE_MISMATCH);
  659. mAudioPlaybackCaptureConfiguration = config;
  660. return this;
  661. }
  662. /**
  663. * Indicates that this capture request is privacy sensitive and that
  664. * any concurrent capture is not permitted.
  665. * <p>
  666. * The default is not privacy sensitive except when the audio source set with
  667. * {@link #setAudioSource(int)} is {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION} or
  668. * {@link MediaRecorder.AudioSource#CAMCORDER}.
  669. * <p>
  670. * Always takes precedence over default from audio source when set explicitly.
  671. * <p>
  672. * Using this API is only permitted when the audio source is one of:
  673. * <ul>
  674. * <li>{@link MediaRecorder.AudioSource#MIC}</li>
  675. * <li>{@link MediaRecorder.AudioSource#CAMCORDER}</li>
  676. * <li>{@link MediaRecorder.AudioSource#VOICE_RECOGNITION}</li>
  677. * <li>{@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}</li>
  678. * <li>{@link MediaRecorder.AudioSource#UNPROCESSED}</li>
  679. * <li>{@link MediaRecorder.AudioSource#VOICE_PERFORMANCE}</li>
  680. * </ul>
  681. * Invoking {@link #build()} will throw an UnsupportedOperationException if this
  682. * condition is not met.
  683. * @param privacySensitive True if capture from this AudioRecord must be marked as privacy
  684. * sensitive, false otherwise.
  685. */
  686. public @NonNull Builder setPrivacySensitive(boolean privacySensitive) {
  687. mPrivacySensitive =
  688. privacySensitive ? PRIVACY_SENSITIVE_ENABLED : PRIVACY_SENSITIVE_DISABLED;
  689. return this;
  690. }
  691. /**
  692. * @hide
  693. * To be only used by system components.
  694. * @param sessionId ID of audio session the AudioRecord must be attached to, or
  695. * {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at
  696. * construction time.
  697. * @return the same Builder instance.
  698. * @throws IllegalArgumentException
  699. */
  700. @SystemApi
  701. public Builder setSessionId(int sessionId) throws IllegalArgumentException {
  702. if (sessionId < 0) {
  703. throw new IllegalArgumentException("Invalid session ID " + sessionId);
  704. }
  705. // Do not override a session ID previously set with setSharedAudioEvent()
  706. if (mSessionId == AudioManager.AUDIO_SESSION_ID_GENERATE) {
  707. mSessionId = sessionId;
  708. } else {
  709. Log.e(TAG, "setSessionId() called twice or after setSharedAudioEvent()");
  710. }
  711. return this;
  712. }
  713. private @NonNull AudioRecord buildAudioPlaybackCaptureRecord() {
  714. AudioMix audioMix = mAudioPlaybackCaptureConfiguration.createAudioMix(mFormat);
  715. MediaProjection projection = mAudioPlaybackCaptureConfiguration.getMediaProjection();
  716. AudioPolicy audioPolicy = new AudioPolicy.Builder(/*context=*/ null)
  717. .setMediaProjection(projection)
  718. .addMix(audioMix).build();
  719. int error = AudioManager.registerAudioPolicyStatic(audioPolicy);
  720. if (error != 0) {
  721. throw new UnsupportedOperationException("Error: could not register audio policy");
  722. }
  723. AudioRecord record = audioPolicy.createAudioRecordSink(audioMix);
  724. if (record == null) {
  725. throw new UnsupportedOperationException("Cannot create AudioRecord");
  726. }
  727. record.unregisterAudioPolicyOnRelease(audioPolicy);
  728. return record;
  729. }
  730. /**
  731. * @hide
  732. * Specifies the maximum duration in the past of the this AudioRecord's capture buffer
  733. * that can be shared with another app by calling
  734. * {@link AudioRecord#shareAudioHistory(String, long)}.
  735. * @param maxSharedAudioHistoryMillis the maximum duration that will be available
  736. * in milliseconds.
  737. * @return the same Builder instance.
  738. * @throws IllegalArgumentException
  739. *
  740. */
  741. @SystemApi
  742. @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD)
  743. public @NonNull Builder setMaxSharedAudioHistoryMillis(long maxSharedAudioHistoryMillis)
  744. throws IllegalArgumentException {
  745. if (maxSharedAudioHistoryMillis <= 0
  746. || maxSharedAudioHistoryMillis > MAX_SHARED_AUDIO_HISTORY_MS) {
  747. throw new IllegalArgumentException("Illegal maxSharedAudioHistoryMillis argument");
  748. }
  749. mMaxSharedAudioHistoryMs = (int) maxSharedAudioHistoryMillis;
  750. return this;
  751. }
  752. /**
  753. * @hide
  754. * Indicates that this AudioRecord will use the audio history shared by another app's
  755. * AudioRecord. See {@link AudioRecord#shareAudioHistory(String, long)}.
  756. * The audio session ID set with {@link AudioRecord.Builder#setSessionId(int)} will be
  757. * ignored if this method is used.
  758. * @param event The {@link MediaSyncEvent} provided by the app sharing its audio history
  759. * with this AudioRecord.
  760. * @return the same Builder instance.
  761. * @throws IllegalArgumentException
  762. */
  763. @SystemApi
  764. public @NonNull Builder setSharedAudioEvent(@NonNull MediaSyncEvent event)
  765. throws IllegalArgumentException {
  766. Objects.requireNonNull(event);
  767. if (event.getType() != MediaSyncEvent.SYNC_EVENT_SHARE_AUDIO_HISTORY) {
  768. throw new IllegalArgumentException(
  769. "Invalid event type " + event.getType());
  770. }
  771. if (event.getAudioSessionId() == AudioSystem.AUDIO_SESSION_ALLOCATE) {
  772. throw new IllegalArgumentException(
  773. "Invalid session ID " + event.getAudioSessionId());
  774. }
  775. // This prevails over a session ID set with setSessionId()
  776. mSessionId = event.getAudioSessionId();
  777. return this;
  778. }
  779. /**
  780. * @return a new {@link AudioRecord} instance successfully initialized with all
  781. * the parameters set on this <code>Builder</code>.
  782. * @throws UnsupportedOperationException if the parameters set on the <code>Builder</code>
  783. * were incompatible, or if they are not supported by the device,
  784. * or if the device was not available.
  785. */
  786. @RequiresPermission(android.Manifest.permission.RECORD_AUDIO)
  787. public AudioRecord build() throws UnsupportedOperationException {
  788. if (mAudioPlaybackCaptureConfiguration != null) {
  789. return buildAudioPlaybackCaptureRecord();
  790. }
  791. if (mFormat == null) {
  792. mFormat = new AudioFormat.Builder()
  793. .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
  794. .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
  795. .build();
  796. } else {
  797. if (mFormat.getEncoding() == AudioFormat.ENCODING_INVALID) {
  798. mFormat = new AudioFormat.Builder(mFormat)
  799. .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
  800. .build();
  801. }
  802. if (mFormat.getChannelMask() == AudioFormat.CHANNEL_INVALID
  803. && mFormat.getChannelIndexMask() == AudioFormat.CHANNEL_INVALID) {
  804. mFormat = new AudioFormat.Builder(mFormat)
  805. .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
  806. .build();
  807. }
  808. }
  809. if (mAttributes == null) {
  810. mAttributes = new AudioAttributes.Builder()
  811. .setInternalCapturePreset(MediaRecorder.AudioSource.DEFAULT)
  812. .build();
  813. }
  814. // If mPrivacySensitive is default, the privacy flag is already set
  815. // according to audio source in audio attributes.
  816. if (mPrivacySensitive != PRIVACY_SENSITIVE_DEFAULT) {
  817. int source = mAttributes.getCapturePreset();
  818. if (source == MediaRecorder.AudioSource.REMOTE_SUBMIX
  819. || source == MediaRecorder.AudioSource.RADIO_TUNER
  820. || source == MediaRecorder.AudioSource.VOICE_DOWNLINK
  821. || source == MediaRecorder.AudioSource.VOICE_UPLINK
  822. || source == MediaRecorder.AudioSource.VOICE_CALL
  823. || source == MediaRecorder.AudioSource.ECHO_REFERENCE) {
  824. throw new UnsupportedOperationException(
  825. "Cannot request private capture with source: " + source);
  826. }
  827. mAttributes = new AudioAttributes.Builder(mAttributes)
  828. .setInternalCapturePreset(source)
  829. .setPrivacySensitive(mPrivacySensitive == PRIVACY_SENSITIVE_ENABLED)
  830. .build();
  831. }
  832. try {
  833. // If the buffer size is not specified,
  834. // use a single frame for the buffer size and let the
  835. // native code figure out the minimum buffer size.
  836. if (mBufferSizeInBytes == 0) {
  837. mBufferSizeInBytes = mFormat.getChannelCount()
  838. * mFormat.getBytesPerSample(mFormat.getEncoding());
  839. }
  840. final AudioRecord record = new AudioRecord(
  841. mAttributes, mFormat, mBufferSizeInBytes, mSessionId, mContext,
  842. mMaxSharedAudioHistoryMs);
  843. if (record.getState() == STATE_UNINITIALIZED) {
  844. // release is not necessary
  845. throw new UnsupportedOperationException("Cannot create AudioRecord");
  846. }
  847. return record;
  848. } catch (IllegalArgumentException e) {
  849. throw new UnsupportedOperationException(e.getMessage());
  850. }
  851. }
  852. }
  853. // Convenience method for the constructor's parameter checks.
  854. // This, getChannelMaskFromLegacyConfig and audioBuffSizeCheck are where constructor
  855. // IllegalArgumentException-s are thrown
  856. private static int getChannelMaskFromLegacyConfig(int inChannelConfig,
  857. boolean allowLegacyConfig) {
  858. int mask;
  859. switch (inChannelConfig) {
  860. case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
  861. case AudioFormat.CHANNEL_IN_MONO:
  862. case AudioFormat.CHANNEL_CONFIGURATION_MONO:
  863. mask = AudioFormat.CHANNEL_IN_MONO;
  864. break;
  865. case AudioFormat.CHANNEL_IN_STEREO:
  866. case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
  867. mask = AudioFormat.CHANNEL_IN_STEREO;
  868. break;
  869. case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
  870. mask = inChannelConfig;
  871. break;
  872. default:
  873. throw new IllegalArgumentException("Unsupported channel configuration.");
  874. }
  875. if (!allowLegacyConfig && ((inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_MONO)
  876. || (inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_STEREO))) {
  877. // only happens with the constructor that uses AudioAttributes and AudioFormat
  878. throw new IllegalArgumentException("Unsupported deprecated configuration.");
  879. }
  880. return mask;
  881. }
  882. // postconditions:
  883. // mRecordSource is valid
  884. // mAudioFormat is valid
  885. // mSampleRate is valid
  886. private void audioParamCheck(int audioSource, int sampleRateInHz, int audioFormat)
  887. throws IllegalArgumentException {
  888. //--------------
  889. // audio source
  890. if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) ||
  891. ((audioSource > MediaRecorder.getAudioSourceMax()) &&
  892. (audioSource != MediaRecorder.AudioSource.RADIO_TUNER) &&
  893. (audioSource != MediaRecorder.AudioSource.ECHO_REFERENCE) &&
  894. (audioSource != MediaRecorder.AudioSource.HOTWORD)) ) {
  895. throw new IllegalArgumentException("Invalid audio source " + audioSource);
  896. }
  897. mRecordSource = audioSource;
  898. //--------------
  899. // sample rate
  900. if ((sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN ||
  901. sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) &&
  902. sampleRateInHz != AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
  903. throw new IllegalArgumentException(sampleRateInHz
  904. + "Hz is not a supported sample rate.");
  905. }
  906. mSampleRate = sampleRateInHz;
  907. //--------------
  908. // audio format
  909. switch (audioFormat) {
  910. case AudioFormat.ENCODING_DEFAULT:
  911. mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
  912. break;
  913. case AudioFormat.ENCODING_PCM_24BIT_PACKED:
  914. case AudioFormat.ENCODING_PCM_32BIT:
  915. case AudioFormat.ENCODING_PCM_FLOAT:
  916. case AudioFormat.ENCODING_PCM_16BIT:
  917. case AudioFormat.ENCODING_PCM_8BIT:
  918. mAudioFormat = audioFormat;
  919. break;
  920. default:
  921. throw new IllegalArgumentException("Unsupported sample encoding " + audioFormat
  922. + ". Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT,"
  923. + " ENCODING_PCM_24BIT_PACKED, ENCODING_PCM_32BIT,"
  924. + " or ENCODING_PCM_FLOAT.");
  925. }
  926. }
  927. // Convenience method for the contructor's audio buffer size check.
  928. // preconditions:
  929. // mChannelCount is valid
  930. // mAudioFormat is AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT,
  931. // or AudioFormat.ENCODING_PCM_FLOAT
  932. // postcondition:
  933. // mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
  934. private void audioBuffSizeCheck(int audioBufferSize) throws IllegalArgumentException {
  935. // NB: this section is only valid with PCM data.
  936. // To update when supporting compressed formats
  937. int frameSizeInBytes = mChannelCount
  938. * (AudioFormat.getBytesPerSample(mAudioFormat));
  939. if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
  940. throw new IllegalArgumentException("Invalid audio buffer size " + audioBufferSize
  941. + " (frame size " + frameSizeInBytes + ")");
  942. }
  943. mNativeBufferSizeInBytes = audioBufferSize;
  944. }
  945. /**
  946. * Releases the native AudioRecord resources.
  947. * The object can no longer be used and the reference should be set to null
  948. * after a call to release()
  949. */
  950. public void release() {
  951. try {
  952. stop();
  953. } catch(IllegalStateException ise) {
  954. // don't raise an exception, we're releasing the resources.
  955. }
  956. if (mAudioCapturePolicy != null) {
  957. AudioManager.unregisterAudioPolicyAsyncStatic(mAudioCapturePolicy);
  958. mAudioCapturePolicy = null;
  959. }
  960. native_release();
  961. mState = STATE_UNINITIALIZED;
  962. }
  963. @Override
  964. protected void finalize() {
  965. // will cause stop() to be called, and if appropriate, will handle fixed volume recording
  966. release();
  967. }
  968. //--------------------------------------------------------------------------
  969. // Getters
  970. //--------------------
  971. /**
  972. * Returns the configured audio sink sample rate in Hz.
  973. * The sink sample rate never changes after construction.
  974. * If the constructor had a specific sample rate, then the sink sample rate is that value.
  975. * If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED},
  976. * then the sink sample rate is a route-dependent default value based on the source [sic].
  977. */
  978. public int getSampleRate() {
  979. return mSampleRate;
  980. }
  981. /**
  982. * Returns the audio recording source.
  983. * @see MediaRecorder.AudioSource
  984. */
  985. public int getAudioSource() {
  986. return mRecordSource;
  987. }
  988. /**
  989. * Returns the configured audio data encoding. See {@link AudioFormat#ENCODING_PCM_8BIT},
  990. * {@link AudioFormat#ENCODING_PCM_16BIT}, and {@link AudioFormat#ENCODING_PCM_FLOAT}.
  991. */
  992. public int getAudioFormat() {
  993. return mAudioFormat;
  994. }
  995. /**
  996. * Returns the configured channel position mask.
  997. * <p> See {@link AudioFormat#CHANNEL_IN_MONO}
  998. * and {@link AudioFormat#CHANNEL_IN_STEREO}.
  999. * This method may return {@link AudioFormat#CHANNEL_INVALID} if
  1000. * a channel index mask is used.
  1001. * Consider {@link #getFormat()} instead, to obtain an {@link AudioFormat},
  1002. * which contains both the channel position mask and the channel index mask.
  1003. */
  1004. public int getChannelConfiguration() {
  1005. return mChannelMask;
  1006. }
  1007. /**
  1008. * Returns the configured <code>AudioRecord</code> format.
  1009. * @return an {@link AudioFormat} containing the
  1010. * <code>AudioRecord</code> parameters at the time of configuration.
  1011. */
  1012. public @NonNull AudioFormat getFormat() {
  1013. AudioFormat.Builder builder = new AudioFormat.Builder()
  1014. .setSampleRate(mSampleRate)
  1015. .setEncoding(mAudioFormat);
  1016. if (mChannelMask != AudioFormat.CHANNEL_INVALID) {
  1017. builder.setChannelMask(mChannelMask);
  1018. }
  1019. if (mChannelIndexMask != AudioFormat.CHANNEL_INVALID /* 0 */) {
  1020. builder.setChannelIndexMask(mChannelIndexMask);
  1021. }
  1022. return builder.build();
  1023. }
  1024. /**
  1025. * Returns the configured number of channels.
  1026. */
  1027. public int getChannelCount() {
  1028. return mChannelCount;
  1029. }
  1030. /**
  1031. * Returns the state of the AudioRecord instance. This is useful after the
  1032. * AudioRecord instance has been created to check if it was initialized
  1033. * properly. This ensures that the appropriate hardware resources have been
  1034. * acquired.
  1035. * @see AudioRecord#STATE_INITIALIZED
  1036. * @see AudioRecord#STATE_UNINITIALIZED
  1037. */
  1038. public int getState() {
  1039. return mState;
  1040. }
  1041. /**
  1042. * Returns…