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