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