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=*/ null) 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(null).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 mAudioFormat = audioFormat; 1180 break; 1181 default: 1182 throw new IllegalArgumentException("Unsupported sample encoding " + audioFormat 1183 + ". Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT," 1184 + " ENCODING_PCM_24BIT_PACKED, ENCODING_PCM_32BIT," 1185 + " or ENCODING_PCM_FLOAT."); 1186 } 1187 } 1188 1189 1190 // Convenience method for the contructor's audio buffer size check. 1191 // preconditions: 1192 // mChannelCount is valid 1193 // mAudioFormat is AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT, 1194 // or AudioFormat.ENCODING_PCM_FLOAT 1195 // postcondition: 1196 // mNativeBufferSizeInBytes is valid (multiple of frame size, positive) audioBuffSizeCheck(int audioBufferSize)1197 private void audioBuffSizeCheck(int audioBufferSize) throws IllegalArgumentException { 1198 // NB: this section is only valid with PCM data. 1199 // To update when supporting compressed formats 1200 int frameSizeInBytes = mChannelCount 1201 * (AudioFormat.getBytesPerSample(mAudioFormat)); 1202 if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) { 1203 throw new IllegalArgumentException("Invalid audio buffer size " + audioBufferSize 1204 + " (frame size " + frameSizeInBytes + ")"); 1205 } 1206 1207 mNativeBufferSizeInBytes = audioBufferSize; 1208 } 1209 1210 1211 1212 /** 1213 * Releases the native AudioRecord resources. 1214 * The object can no longer be used and the reference should be set to null 1215 * after a call to release() 1216 */ release()1217 public void release() { 1218 try { 1219 stop(); 1220 } catch(IllegalStateException ise) { 1221 // don't raise an exception, we're releasing the resources. 1222 } 1223 if (mAudioCapturePolicy != null) { 1224 AudioManager.unregisterAudioPolicyAsyncStatic(mAudioCapturePolicy); 1225 mAudioCapturePolicy = null; 1226 } 1227 native_release(); 1228 mState = STATE_UNINITIALIZED; 1229 } 1230 1231 1232 @Override finalize()1233 protected void finalize() { 1234 // will cause stop() to be called, and if appropriate, will handle fixed volume recording 1235 release(); 1236 } 1237 1238 1239 //-------------------------------------------------------------------------- 1240 // Getters 1241 //-------------------- 1242 /** 1243 * Returns the configured audio sink sample rate in Hz. 1244 * The sink sample rate never changes after construction. 1245 * If the constructor had a specific sample rate, then the sink sample rate is that value. 1246 * If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}, 1247 * then the sink sample rate is a route-dependent default value based on the source [sic]. 1248 */ getSampleRate()1249 public int getSampleRate() { 1250 return mSampleRate; 1251 } 1252 1253 /** 1254 * Returns the audio recording source. 1255 * @see MediaRecorder.AudioSource 1256 */ getAudioSource()1257 public int getAudioSource() { 1258 return mRecordSource; 1259 } 1260 1261 /** 1262 * Returns the configured audio data encoding. See {@link AudioFormat#ENCODING_PCM_8BIT}, 1263 * {@link AudioFormat#ENCODING_PCM_16BIT}, and {@link AudioFormat#ENCODING_PCM_FLOAT}. 1264 */ getAudioFormat()1265 public int getAudioFormat() { 1266 return mAudioFormat; 1267 } 1268 1269 /** 1270 * Returns the configured channel position mask. 1271 * <p> See {@link AudioFormat#CHANNEL_IN_MONO} 1272 * and {@link AudioFormat#CHANNEL_IN_STEREO}. 1273 * This method may return {@link AudioFormat#CHANNEL_INVALID} if 1274 * a channel index mask is used. 1275 * Consider {@link #getFormat()} instead, to obtain an {@link AudioFormat}, 1276 * which contains both the channel position mask and the channel index mask. 1277 */ getChannelConfiguration()1278 public int getChannelConfiguration() { 1279 return mChannelMask; 1280 } 1281 1282 /** 1283 * Returns the configured <code>AudioRecord</code> format. 1284 * @return an {@link AudioFormat} containing the 1285 * <code>AudioRecord</code> parameters at the time of configuration. 1286 */ getFormat()1287 public @NonNull AudioFormat getFormat() { 1288 AudioFormat.Builder builder = new AudioFormat.Builder() 1289 .setSampleRate(mSampleRate) 1290 .setEncoding(mAudioFormat); 1291 if (mChannelMask != AudioFormat.CHANNEL_INVALID) { 1292 builder.setChannelMask(mChannelMask); 1293 } 1294 if (mChannelIndexMask != AudioFormat.CHANNEL_INVALID /* 0 */) { 1295 builder.setChannelIndexMask(mChannelIndexMask); 1296 } 1297 return builder.build(); 1298 } 1299 1300 /** 1301 * Returns the configured number of channels. 1302 */ getChannelCount()1303 public int getChannelCount() { 1304 return mChannelCount; 1305 } 1306 1307 /** 1308 * Returns the state of the AudioRecord instance. This is useful after the 1309 * AudioRecord instance has been created to check if it was initialized 1310 * properly. This ensures that the appropriate hardware resources have been 1311 * acquired. 1312 * @see AudioRecord#STATE_INITIALIZED 1313 * @see AudioRecord#STATE_UNINITIALIZED 1314 */ getState()1315 public int getState() { 1316 return mState; 1317 } 1318 1319 /** 1320 * Returns the recording state of the AudioRecord instance. 1321 * @see AudioRecord#RECORDSTATE_STOPPED 1322 * @see AudioRecord#RECORDSTATE_RECORDING 1323 */ getRecordingState()1324 public int getRecordingState() { 1325 synchronized (mRecordingStateLock) { 1326 return mRecordingState; 1327 } 1328 } 1329 1330 /** 1331 * Returns the frame count of the native <code>AudioRecord</code> buffer. 1332 * This is greater than or equal to the bufferSizeInBytes converted to frame units 1333 * specified in the <code>AudioRecord</code> constructor or Builder. 1334 * The native frame count may be enlarged to accommodate the requirements of the 1335 * source on creation or if the <code>AudioRecord</code> 1336 * is subsequently rerouted. 1337 * @return current size in frames of the <code>AudioRecord</code> buffer. 1338 * @throws IllegalStateException 1339 */ getBufferSizeInFrames()1340 public int getBufferSizeInFrames() { 1341 return native_get_buffer_size_in_frames(); 1342 } 1343 1344 /** 1345 * Returns the notification marker position expressed in frames. 1346 */ getNotificationMarkerPosition()1347 public int getNotificationMarkerPosition() { 1348 return native_get_marker_pos(); 1349 } 1350 1351 /** 1352 * Returns the notification update period expressed in frames. 1353 */ getPositionNotificationPeriod()1354 public int getPositionNotificationPeriod() { 1355 return native_get_pos_update_period(); 1356 } 1357 1358 /** 1359 * Poll for an {@link AudioTimestamp} on demand. 1360 * <p> 1361 * The AudioTimestamp reflects the frame delivery information at 1362 * the earliest point available in the capture pipeline. 1363 * <p> 1364 * Calling {@link #startRecording()} following a {@link #stop()} will reset 1365 * the frame count to 0. 1366 * 1367 * @param outTimestamp a caller provided non-null AudioTimestamp instance, 1368 * which is updated with the AudioRecord frame delivery information upon success. 1369 * @param timebase one of 1370 * {@link AudioTimestamp#TIMEBASE_BOOTTIME AudioTimestamp.TIMEBASE_BOOTTIME} or 1371 * {@link AudioTimestamp#TIMEBASE_MONOTONIC AudioTimestamp.TIMEBASE_MONOTONIC}, 1372 * used to select the clock for the AudioTimestamp time. 1373 * @return {@link #SUCCESS} if a timestamp is available, 1374 * or {@link #ERROR_INVALID_OPERATION} if a timestamp not available. 1375 */ getTimestamp(@onNull AudioTimestamp outTimestamp, @AudioTimestamp.Timebase int timebase)1376 public int getTimestamp(@NonNull AudioTimestamp outTimestamp, 1377 @AudioTimestamp.Timebase int timebase) 1378 { 1379 if (outTimestamp == null || 1380 (timebase != AudioTimestamp.TIMEBASE_BOOTTIME 1381 && timebase != AudioTimestamp.TIMEBASE_MONOTONIC)) { 1382 throw new IllegalArgumentException(); 1383 } 1384 return native_get_timestamp(outTimestamp, timebase); 1385 } 1386 1387 /** 1388 * Returns the minimum buffer size required for the successful creation of an AudioRecord 1389 * object, in byte units. 1390 * Note that this size doesn't guarantee a smooth recording under load, and higher values 1391 * should be chosen according to the expected frequency at which the AudioRecord instance 1392 * will be polled for new data. 1393 * See {@link #AudioRecord(int, int, int, int, int)} for more information on valid 1394 * configuration values. 1395 * @param sampleRateInHz the sample rate expressed in Hertz. 1396 * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted. 1397 * @param channelConfig describes the configuration of the audio channels. 1398 * See {@link AudioFormat#CHANNEL_IN_MONO} and 1399 * {@link AudioFormat#CHANNEL_IN_STEREO} 1400 * @param audioFormat the format in which the audio data is represented. 1401 * See {@link AudioFormat#ENCODING_PCM_16BIT}. 1402 * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the 1403 * hardware, or an invalid parameter was passed, 1404 * or {@link #ERROR} if the implementation was unable to query the hardware for its 1405 * input properties, 1406 * or the minimum buffer size expressed in bytes. 1407 * @see #AudioRecord(int, int, int, int, int) 1408 */ getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)1409 static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { 1410 int channelCount = 0; 1411 switch (channelConfig) { 1412 case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT 1413 case AudioFormat.CHANNEL_IN_MONO: 1414 case AudioFormat.CHANNEL_CONFIGURATION_MONO: 1415 channelCount = 1; 1416 break; 1417 case AudioFormat.CHANNEL_IN_STEREO: 1418 case AudioFormat.CHANNEL_CONFIGURATION_STEREO: 1419 case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK): 1420 channelCount = 2; 1421 break; 1422 case AudioFormat.CHANNEL_INVALID: 1423 default: 1424 loge("getMinBufferSize(): Invalid channel configuration."); 1425 return ERROR_BAD_VALUE; 1426 } 1427 1428 int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat); 1429 if (size == 0) { 1430 return ERROR_BAD_VALUE; 1431 } 1432 else if (size == -1) { 1433 return ERROR; 1434 } 1435 else { 1436 return size; 1437 } 1438 } 1439 1440 /** 1441 * Returns the audio session ID. 1442 * 1443 * @return the ID of the audio session this AudioRecord belongs to. 1444 */ getAudioSessionId()1445 public int getAudioSessionId() { 1446 return mSessionId; 1447 } 1448 1449 /** 1450 * Returns whether this AudioRecord is marked as privacy sensitive or not. 1451 * <p> 1452 * See {@link Builder#setPrivacySensitive(boolean)} 1453 * <p> 1454 * @return true if privacy sensitive, false otherwise 1455 */ isPrivacySensitive()1456 public boolean isPrivacySensitive() { 1457 return (mAudioAttributes.getAllFlags() & AudioAttributes.FLAG_CAPTURE_PRIVATE) != 0; 1458 } 1459 1460 /** 1461 * @hide 1462 * Returns whether the AudioRecord object produces the same type of audio content that 1463 * the hotword recognition model consumes. 1464 * <br> If {@link isHotwordLookbackStream(boolean)} is true, this will return false 1465 * <br> See {@link Builder#setRequestHotwordStream(boolean)} 1466 * @return true if AudioRecord produces hotword content, false otherwise 1467 **/ 1468 @SystemApi isHotwordStream()1469 public boolean isHotwordStream() { 1470 return ((mHalInputFlags & (1 << AudioInputFlags.HOTWORD_TAP)) != 0 && 1471 (mHalInputFlags & (1 << AudioInputFlags.HW_LOOKBACK)) == 0); 1472 } 1473 1474 /** 1475 * @hide 1476 * Returns whether the AudioRecord object produces the same type of audio content that 1477 * the hotword recognition model consumes, and includes capture content from prior to 1478 * stream open. 1479 * <br> See {@link Builder#setRequestHotwordLookbackStream(boolean)} 1480 * @return true if AudioRecord produces hotword capture content from 1481 * prior to stream open, false otherwise 1482 **/ 1483 @SystemApi isHotwordLookbackStream()1484 public boolean isHotwordLookbackStream() { 1485 return ((mHalInputFlags & (1 << AudioInputFlags.HW_LOOKBACK)) != 0); 1486 } 1487 1488 1489 //--------------------------------------------------------- 1490 // Transport control methods 1491 //-------------------- 1492 /** 1493 * Starts recording from the AudioRecord instance. 1494 * @throws IllegalStateException 1495 */ startRecording()1496 public void startRecording() 1497 throws IllegalStateException { 1498 if (mState != STATE_INITIALIZED) { 1499 throw new IllegalStateException("startRecording() called on an " 1500 + "uninitialized AudioRecord."); 1501 } 1502 1503 // start recording 1504 synchronized(mRecordingStateLock) { 1505 if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) { 1506 handleFullVolumeRec(true); 1507 mRecordingState = RECORDSTATE_RECORDING; 1508 } 1509 } 1510 } 1511 1512 /** 1513 * Starts recording from the AudioRecord instance when the specified synchronization event 1514 * occurs on the specified audio session. 1515 * @throws IllegalStateException 1516 * @param syncEvent event that triggers the capture. 1517 * @see MediaSyncEvent 1518 */ startRecording(MediaSyncEvent syncEvent)1519 public void startRecording(MediaSyncEvent syncEvent) 1520 throws IllegalStateException { 1521 if (mState != STATE_INITIALIZED) { 1522 throw new IllegalStateException("startRecording() called on an " 1523 + "uninitialized AudioRecord."); 1524 } 1525 1526 // start recording 1527 synchronized(mRecordingStateLock) { 1528 if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) { 1529 handleFullVolumeRec(true); 1530 mRecordingState = RECORDSTATE_RECORDING; 1531 } 1532 } 1533 } 1534 1535 /** 1536 * Stops recording. 1537 * @throws IllegalStateException 1538 */ stop()1539 public void stop() 1540 throws IllegalStateException { 1541 if (mState != STATE_INITIALIZED) { 1542 throw new IllegalStateException("stop() called on an uninitialized AudioRecord."); 1543 } 1544 1545 // stop recording 1546 synchronized(mRecordingStateLock) { 1547 handleFullVolumeRec(false); 1548 native_stop(); 1549 mRecordingState = RECORDSTATE_STOPPED; 1550 } 1551 } 1552 1553 private final IBinder mICallBack = new Binder(); handleFullVolumeRec(boolean starting)1554 private void handleFullVolumeRec(boolean starting) { 1555 if (!mIsSubmixFullVolume) { 1556 return; 1557 } 1558 final IBinder b = ServiceManager.getService(android.content.Context.AUDIO_SERVICE); 1559 final IAudioService ias = IAudioService.Stub.asInterface(b); 1560 try { 1561 ias.forceRemoteSubmixFullVolume(starting, mICallBack); 1562 } catch (RemoteException e) { 1563 Log.e(TAG, "Error talking to AudioService when handling full submix volume", e); 1564 } 1565 } 1566 1567 //--------------------------------------------------------- 1568 // Audio data supply 1569 //-------------------- 1570 /** 1571 * Reads audio data from the audio hardware for recording into a byte array. 1572 * The format specified in the AudioRecord constructor should be 1573 * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array. 1574 * @param audioData the array to which the recorded audio data is written. 1575 * @param offsetInBytes index in audioData from which the data is written expressed in bytes. 1576 * @param sizeInBytes the number of requested bytes. 1577 * @return zero or the positive number of bytes that were read, or one of the following 1578 * error codes. The number of bytes will not exceed sizeInBytes. 1579 * <ul> 1580 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1581 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1582 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1583 * needs to be recreated. The dead object error code is not returned if some data was 1584 * successfully transferred. In this case, the error is returned at the next read()</li> 1585 * <li>{@link #ERROR} in case of other error</li> 1586 * </ul> 1587 */ read(@onNull byte[] audioData, int offsetInBytes, int sizeInBytes)1588 public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) { 1589 return read(audioData, offsetInBytes, sizeInBytes, READ_BLOCKING); 1590 } 1591 1592 /** 1593 * Reads audio data from the audio hardware for recording into a byte array. 1594 * The format specified in the AudioRecord constructor should be 1595 * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array. 1596 * The format can be {@link AudioFormat#ENCODING_PCM_16BIT}, but this is deprecated. 1597 * @param audioData the array to which the recorded audio data is written. 1598 * @param offsetInBytes index in audioData to which the data is written expressed in bytes. 1599 * Must not be negative, or cause the data access to go out of bounds of the array. 1600 * @param sizeInBytes the number of requested bytes. 1601 * Must not be negative, or cause the data access to go out of bounds of the array. 1602 * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}. 1603 * <br>With {@link #READ_BLOCKING}, the read will block until all the requested data 1604 * is read. 1605 * <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after 1606 * reading as much audio data as possible without blocking. 1607 * @return zero or the positive number of bytes that were read, or one of the following 1608 * error codes. The number of bytes will be a multiple of the frame size in bytes 1609 * not to exceed sizeInBytes. 1610 * <ul> 1611 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1612 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1613 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1614 * needs to be recreated. The dead object error code is not returned if some data was 1615 * successfully transferred. In this case, the error is returned at the next read()</li> 1616 * <li>{@link #ERROR} in case of other error</li> 1617 * </ul> 1618 */ read(@onNull byte[] audioData, int offsetInBytes, int sizeInBytes, @ReadMode int readMode)1619 public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes, 1620 @ReadMode int readMode) { 1621 // Note: we allow reads of extended integers into a byte array. 1622 if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { 1623 return ERROR_INVALID_OPERATION; 1624 } 1625 1626 if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) { 1627 Log.e(TAG, "AudioRecord.read() called with invalid blocking mode"); 1628 return ERROR_BAD_VALUE; 1629 } 1630 1631 if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0) 1632 || (offsetInBytes + sizeInBytes < 0) // detect integer overflow 1633 || (offsetInBytes + sizeInBytes > audioData.length)) { 1634 return ERROR_BAD_VALUE; 1635 } 1636 1637 return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes, 1638 readMode == READ_BLOCKING); 1639 } 1640 1641 /** 1642 * Reads audio data from the audio hardware for recording into a short array. 1643 * The format specified in the AudioRecord constructor should be 1644 * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array. 1645 * @param audioData the array to which the recorded audio data is written. 1646 * @param offsetInShorts index in audioData to which the data is written expressed in shorts. 1647 * Must not be negative, or cause the data access to go out of bounds of the array. 1648 * @param sizeInShorts the number of requested shorts. 1649 * Must not be negative, or cause the data access to go out of bounds of the array. 1650 * @return zero or the positive number of shorts that were read, or one of the following 1651 * error codes. The number of shorts will be a multiple of the channel count not to exceed 1652 * sizeInShorts. 1653 * <ul> 1654 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1655 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1656 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1657 * needs to be recreated. The dead object error code is not returned if some data was 1658 * successfully transferred. In this case, the error is returned at the next read()</li> 1659 * <li>{@link #ERROR} in case of other error</li> 1660 * </ul> 1661 */ read(@onNull short[] audioData, int offsetInShorts, int sizeInShorts)1662 public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) { 1663 return read(audioData, offsetInShorts, sizeInShorts, READ_BLOCKING); 1664 } 1665 1666 /** 1667 * Reads audio data from the audio hardware for recording into a short array. 1668 * The format specified in the AudioRecord constructor should be 1669 * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array. 1670 * @param audioData the array to which the recorded audio data is written. 1671 * @param offsetInShorts index in audioData from which the data is written expressed in shorts. 1672 * Must not be negative, or cause the data access to go out of bounds of the array. 1673 * @param sizeInShorts the number of requested shorts. 1674 * Must not be negative, or cause the data access to go out of bounds of the array. 1675 * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}. 1676 * <br>With {@link #READ_BLOCKING}, the read will block until all the requested data 1677 * is read. 1678 * <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after 1679 * reading as much audio data as possible without blocking. 1680 * @return zero or the positive number of shorts that were read, or one of the following 1681 * error codes. The number of shorts will be a multiple of the channel count not to exceed 1682 * sizeInShorts. 1683 * <ul> 1684 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1685 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1686 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1687 * needs to be recreated. The dead object error code is not returned if some data was 1688 * successfully transferred. In this case, the error is returned at the next read()</li> 1689 * <li>{@link #ERROR} in case of other error</li> 1690 * </ul> 1691 */ read(@onNull short[] audioData, int offsetInShorts, int sizeInShorts, @ReadMode int readMode)1692 public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts, 1693 @ReadMode int readMode) { 1694 if (mState != STATE_INITIALIZED 1695 || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT 1696 // use ByteBuffer instead for later encodings 1697 || mAudioFormat > AudioFormat.ENCODING_LEGACY_SHORT_ARRAY_THRESHOLD) { 1698 return ERROR_INVALID_OPERATION; 1699 } 1700 1701 if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) { 1702 Log.e(TAG, "AudioRecord.read() called with invalid blocking mode"); 1703 return ERROR_BAD_VALUE; 1704 } 1705 1706 if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0) 1707 || (offsetInShorts + sizeInShorts < 0) // detect integer overflow 1708 || (offsetInShorts + sizeInShorts > audioData.length)) { 1709 return ERROR_BAD_VALUE; 1710 } 1711 return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts, 1712 readMode == READ_BLOCKING); 1713 } 1714 1715 /** 1716 * Reads audio data from the audio hardware for recording into a float array. 1717 * The format specified in the AudioRecord constructor should be 1718 * {@link AudioFormat#ENCODING_PCM_FLOAT} to correspond to the data in the array. 1719 * @param audioData the array to which the recorded audio data is written. 1720 * @param offsetInFloats index in audioData from which the data is written. 1721 * Must not be negative, or cause the data access to go out of bounds of the array. 1722 * @param sizeInFloats the number of requested floats. 1723 * Must not be negative, or cause the data access to go out of bounds of the array. 1724 * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}. 1725 * <br>With {@link #READ_BLOCKING}, the read will block until all the requested data 1726 * is read. 1727 * <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after 1728 * reading as much audio data as possible without blocking. 1729 * @return zero or the positive number of floats that were read, or one of the following 1730 * error codes. The number of floats will be a multiple of the channel count not to exceed 1731 * sizeInFloats. 1732 * <ul> 1733 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1734 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1735 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1736 * needs to be recreated. The dead object error code is not returned if some data was 1737 * successfully transferred. In this case, the error is returned at the next read()</li> 1738 * <li>{@link #ERROR} in case of other error</li> 1739 * </ul> 1740 */ read(@onNull float[] audioData, int offsetInFloats, int sizeInFloats, @ReadMode int readMode)1741 public int read(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats, 1742 @ReadMode int readMode) { 1743 if (mState == STATE_UNINITIALIZED) { 1744 Log.e(TAG, "AudioRecord.read() called in invalid state STATE_UNINITIALIZED"); 1745 return ERROR_INVALID_OPERATION; 1746 } 1747 1748 if (mAudioFormat != AudioFormat.ENCODING_PCM_FLOAT) { 1749 Log.e(TAG, "AudioRecord.read(float[] ...) requires format ENCODING_PCM_FLOAT"); 1750 return ERROR_INVALID_OPERATION; 1751 } 1752 1753 if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) { 1754 Log.e(TAG, "AudioRecord.read() called with invalid blocking mode"); 1755 return ERROR_BAD_VALUE; 1756 } 1757 1758 if ((audioData == null) || (offsetInFloats < 0) || (sizeInFloats < 0) 1759 || (offsetInFloats + sizeInFloats < 0) // detect integer overflow 1760 || (offsetInFloats + sizeInFloats > audioData.length)) { 1761 return ERROR_BAD_VALUE; 1762 } 1763 1764 return native_read_in_float_array(audioData, offsetInFloats, sizeInFloats, 1765 readMode == READ_BLOCKING); 1766 } 1767 1768 /** 1769 * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer 1770 * is not a direct buffer, this method will always return 0. 1771 * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is 1772 * unchanged after a call to this method. 1773 * The representation of the data in the buffer will depend on the format specified in 1774 * the AudioRecord constructor, and will be native endian. 1775 * @param audioBuffer the direct buffer to which the recorded audio data is written. 1776 * Data is written to audioBuffer.position(). 1777 * @param sizeInBytes the number of requested bytes. It is recommended but not enforced 1778 * that the number of bytes requested be a multiple of the frame size (sample size in 1779 * bytes multiplied by the channel count). 1780 * @return zero or the positive number of bytes that were read, or one of the following 1781 * error codes. The number of bytes will not exceed sizeInBytes and will be truncated to be 1782 * a multiple of the frame size. 1783 * <ul> 1784 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1785 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1786 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1787 * needs to be recreated. The dead object error code is not returned if some data was 1788 * successfully transferred. In this case, the error is returned at the next read()</li> 1789 * <li>{@link #ERROR} in case of other error</li> 1790 * </ul> 1791 */ read(@onNull ByteBuffer audioBuffer, int sizeInBytes)1792 public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes) { 1793 return read(audioBuffer, sizeInBytes, READ_BLOCKING); 1794 } 1795 1796 /** 1797 * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer 1798 * is not a direct buffer, this method will always return 0. 1799 * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is 1800 * unchanged after a call to this method. 1801 * The representation of the data in the buffer will depend on the format specified in 1802 * the AudioRecord constructor, and will be native endian. 1803 * @param audioBuffer the direct buffer to which the recorded audio data is written. 1804 * Data is written to audioBuffer.position(). 1805 * @param sizeInBytes the number of requested bytes. It is recommended but not enforced 1806 * that the number of bytes requested be a multiple of the frame size (sample size in 1807 * bytes multiplied by the channel count). 1808 * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}. 1809 * <br>With {@link #READ_BLOCKING}, the read will block until all the requested data 1810 * is read. 1811 * <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after 1812 * reading as much audio data as possible without blocking. 1813 * @return zero or the positive number of bytes that were read, or one of the following 1814 * error codes. The number of bytes will not exceed sizeInBytes and will be truncated to be 1815 * a multiple of the frame size. 1816 * <ul> 1817 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1818 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1819 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1820 * needs to be recreated. The dead object error code is not returned if some data was 1821 * successfully transferred. In this case, the error is returned at the next read()</li> 1822 * <li>{@link #ERROR} in case of other error</li> 1823 * </ul> 1824 */ read(@onNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode)1825 public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode) { 1826 if (mState != STATE_INITIALIZED) { 1827 return ERROR_INVALID_OPERATION; 1828 } 1829 1830 if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) { 1831 Log.e(TAG, "AudioRecord.read() called with invalid blocking mode"); 1832 return ERROR_BAD_VALUE; 1833 } 1834 1835 if ( (audioBuffer == null) || (sizeInBytes < 0) ) { 1836 return ERROR_BAD_VALUE; 1837 } 1838 1839 return native_read_in_direct_buffer(audioBuffer, sizeInBytes, readMode == READ_BLOCKING); 1840 } 1841 1842 /** 1843 * Return Metrics data about the current AudioTrack instance. 1844 * 1845 * @return a {@link PersistableBundle} containing the set of attributes and values 1846 * available for the media being handled by this instance of AudioRecord 1847 * The attributes are descibed in {@link MetricsConstants}. 1848 * 1849 * Additional vendor-specific fields may also be present in 1850 * the return value. 1851 */ getMetrics()1852 public PersistableBundle getMetrics() { 1853 PersistableBundle bundle = native_getMetrics(); 1854 return bundle; 1855 } 1856 native_getMetrics()1857 private native PersistableBundle native_getMetrics(); 1858 1859 //-------------------------------------------------------------------------- 1860 // Initialization / configuration 1861 //-------------------- 1862 /** 1863 * Sets the listener the AudioRecord notifies when a previously set marker is reached or 1864 * for each periodic record head position update. 1865 * @param listener 1866 */ setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener)1867 public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener) { 1868 setRecordPositionUpdateListener(listener, null); 1869 } 1870 1871 /** 1872 * Sets the listener the AudioRecord notifies when a previously set marker is reached or 1873 * for each periodic record head position update. 1874 * Use this method to receive AudioRecord events in the Handler associated with another 1875 * thread than the one in which you created the AudioRecord instance. 1876 * @param listener 1877 * @param handler the Handler that will receive the event notification messages. 1878 */ setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, Handler handler)1879 public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, 1880 Handler handler) { 1881 synchronized (mPositionListenerLock) { 1882 1883 mPositionListener = listener; 1884 1885 if (listener != null) { 1886 if (handler != null) { 1887 mEventHandler = new NativeEventHandler(this, handler.getLooper()); 1888 } else { 1889 // no given handler, use the looper the AudioRecord was created in 1890 mEventHandler = new NativeEventHandler(this, mInitializationLooper); 1891 } 1892 } else { 1893 mEventHandler = null; 1894 } 1895 } 1896 1897 } 1898 1899 1900 /** 1901 * Sets the marker position at which the listener is called, if set with 1902 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or 1903 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}. 1904 * @param markerInFrames marker position expressed in frames 1905 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, 1906 * {@link #ERROR_INVALID_OPERATION} 1907 */ setNotificationMarkerPosition(int markerInFrames)1908 public int setNotificationMarkerPosition(int markerInFrames) { 1909 if (mState == STATE_UNINITIALIZED) { 1910 return ERROR_INVALID_OPERATION; 1911 } 1912 return native_set_marker_pos(markerInFrames); 1913 } 1914 1915 /** 1916 * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord. 1917 * Note: The query is only valid if the AudioRecord is currently recording. If it is not, 1918 * <code>getRoutedDevice()</code> will return null. 1919 */ 1920 @Override getRoutedDevice()1921 public AudioDeviceInfo getRoutedDevice() { 1922 int deviceId = native_getRoutedDeviceId(); 1923 if (deviceId == 0) { 1924 return null; 1925 } 1926 return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_INPUTS); 1927 } 1928 1929 /** 1930 * Must match the native definition in frameworks/av/service/audioflinger/Audioflinger.h. 1931 */ 1932 private static final long MAX_SHARED_AUDIO_HISTORY_MS = 5000; 1933 1934 /** 1935 * @hide 1936 * returns the maximum duration in milliseconds of the audio history that can be requested 1937 * to be made available to other clients using the same session with 1938 * {@Link Builder#setMaxSharedAudioHistory(long)}. 1939 */ 1940 @SystemApi getMaxSharedAudioHistoryMillis()1941 public static long getMaxSharedAudioHistoryMillis() { 1942 return MAX_SHARED_AUDIO_HISTORY_MS; 1943 } 1944 1945 /** 1946 * @hide 1947 * 1948 * A privileged app with permission CAPTURE_AUDIO_HOTWORD can share part of its recent 1949 * capture history on a given AudioRecord with the following steps: 1950 * 1) Specify the maximum time in the past that will be available for other apps by calling 1951 * {@link Builder#setMaxSharedAudioHistoryMillis(long)} when creating the AudioRecord. 1952 * 2) Start recording and determine where the other app should start capturing in the past. 1953 * 3) Call this method with the package name of the app the history will be shared with and 1954 * the intended start time for this app's capture relative to this AudioRecord's start time. 1955 * 4) Communicate the {@link MediaSyncEvent} returned by this method to the other app. 1956 * 5) The other app will use the MediaSyncEvent when creating its AudioRecord with 1957 * {@link Builder#setSharedAudioEvent(MediaSyncEvent). 1958 * 6) Only after the other app has started capturing can this app stop capturing and 1959 * release its AudioRecord. 1960 * This method is intended to be called only once: if called multiple times, only the last 1961 * request will be honored. 1962 * The implementation is "best effort": if the specified start time if too far in the past 1963 * compared to the max available history specified, the start time will be adjusted to the 1964 * start of the available history. 1965 * @param sharedPackage the package the history will be shared with 1966 * @param startFromMillis the start time, relative to the initial start time of this 1967 * AudioRecord, at which the other AudioRecord will start. 1968 * @return a {@link MediaSyncEvent} to be communicated to the app this AudioRecord's audio 1969 * history will be shared with. 1970 * @throws IllegalArgumentException 1971 * @throws SecurityException 1972 */ 1973 @SystemApi 1974 @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD) shareAudioHistory(@onNull String sharedPackage, @IntRange(from = 0) long startFromMillis)1975 @NonNull public MediaSyncEvent shareAudioHistory(@NonNull String sharedPackage, 1976 @IntRange(from = 0) long startFromMillis) { 1977 Objects.requireNonNull(sharedPackage); 1978 if (startFromMillis < 0) { 1979 throw new IllegalArgumentException("Illegal negative sharedAudioHistoryMs argument"); 1980 } 1981 int status = native_shareAudioHistory(sharedPackage, startFromMillis); 1982 if (status == AudioSystem.BAD_VALUE) { 1983 throw new IllegalArgumentException("Illegal sharedAudioHistoryMs argument"); 1984 } else if (status == AudioSystem.PERMISSION_DENIED) { 1985 throw new SecurityException("permission CAPTURE_AUDIO_HOTWORD required"); 1986 } 1987 MediaSyncEvent event = 1988 MediaSyncEvent.createEvent(MediaSyncEvent.SYNC_EVENT_SHARE_AUDIO_HISTORY); 1989 event.setAudioSessionId(mSessionId); 1990 return event; 1991 } 1992 1993 /* 1994 * Call BEFORE adding a routing callback handler. 1995 */ 1996 @GuardedBy("mRoutingChangeListeners") testEnableNativeRoutingCallbacksLocked()1997 private void testEnableNativeRoutingCallbacksLocked() { 1998 if (mRoutingChangeListeners.size() == 0) { 1999 native_enableDeviceCallback(); 2000 } 2001 } 2002 2003 /* 2004 * Call AFTER removing a routing callback handler. 2005 */ 2006 @GuardedBy("mRoutingChangeListeners") testDisableNativeRoutingCallbacksLocked()2007 private void testDisableNativeRoutingCallbacksLocked() { 2008 if (mRoutingChangeListeners.size() == 0) { 2009 native_disableDeviceCallback(); 2010 } 2011 } 2012 2013 //-------------------------------------------------------------------------- 2014 // (Re)Routing Info 2015 //-------------------- 2016 /** 2017 * The list of AudioRouting.OnRoutingChangedListener interfaces added (with 2018 * {@link AudioRecord#addOnRoutingChangedListener} by an app to receive 2019 * (re)routing notifications. 2020 */ 2021 @GuardedBy("mRoutingChangeListeners") 2022 private ArrayMap<AudioRouting.OnRoutingChangedListener, 2023 NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>(); 2024 2025 /** 2026 * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of 2027 * routing changes on this AudioRecord. 2028 * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive 2029 * notifications of rerouting events. 2030 * @param handler Specifies the {@link Handler} object for the thread on which to execute 2031 * the callback. If <code>null</code>, the {@link Handler} associated with the main 2032 * {@link Looper} will be used. 2033 */ 2034 @Override addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, android.os.Handler handler)2035 public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, 2036 android.os.Handler handler) { 2037 synchronized (mRoutingChangeListeners) { 2038 if (listener != null && !mRoutingChangeListeners.containsKey(listener)) { 2039 testEnableNativeRoutingCallbacksLocked(); 2040 mRoutingChangeListeners.put( 2041 listener, new NativeRoutingEventHandlerDelegate(this, listener, 2042 handler != null ? handler : new Handler(mInitializationLooper))); 2043 } 2044 } 2045 } 2046 2047 /** 2048 * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added 2049 * to receive rerouting notifications. 2050 * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface 2051 * to remove. 2052 */ 2053 @Override removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener)2054 public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) { 2055 synchronized (mRoutingChangeListeners) { 2056 if (mRoutingChangeListeners.containsKey(listener)) { 2057 mRoutingChangeListeners.remove(listener); 2058 testDisableNativeRoutingCallbacksLocked(); 2059 } 2060 } 2061 } 2062 2063 //-------------------------------------------------------------------------- 2064 // (Re)Routing Info 2065 //-------------------- 2066 /** 2067 * Defines the interface by which applications can receive notifications of 2068 * routing changes for the associated {@link AudioRecord}. 2069 * 2070 * @deprecated users should switch to the general purpose 2071 * {@link AudioRouting.OnRoutingChangedListener} class instead. 2072 */ 2073 @Deprecated 2074 public interface OnRoutingChangedListener extends AudioRouting.OnRoutingChangedListener { 2075 /** 2076 * Called when the routing of an AudioRecord changes from either and 2077 * explicit or policy rerouting. Use {@link #getRoutedDevice()} to 2078 * retrieve the newly routed-from device. 2079 */ onRoutingChanged(AudioRecord audioRecord)2080 public void onRoutingChanged(AudioRecord audioRecord); 2081 2082 @Override onRoutingChanged(AudioRouting router)2083 default public void onRoutingChanged(AudioRouting router) { 2084 if (router instanceof AudioRecord) { 2085 onRoutingChanged((AudioRecord) router); 2086 } 2087 } 2088 } 2089 2090 /** 2091 * Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes 2092 * on this AudioRecord. 2093 * @param listener The {@link OnRoutingChangedListener} interface to receive notifications 2094 * of rerouting events. 2095 * @param handler Specifies the {@link Handler} object for the thread on which to execute 2096 * the callback. If <code>null</code>, the {@link Handler} associated with the main 2097 * {@link Looper} will be used. 2098 * @deprecated users should switch to the general purpose 2099 * {@link AudioRouting.OnRoutingChangedListener} class instead. 2100 */ 2101 @Deprecated addOnRoutingChangedListener(OnRoutingChangedListener listener, android.os.Handler handler)2102 public void addOnRoutingChangedListener(OnRoutingChangedListener listener, 2103 android.os.Handler handler) { 2104 addOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener, handler); 2105 } 2106 2107 /** 2108 * Removes an {@link OnRoutingChangedListener} which has been previously added 2109 * to receive rerouting notifications. 2110 * @param listener The previously added {@link OnRoutingChangedListener} interface to remove. 2111 * @deprecated users should switch to the general purpose 2112 * {@link AudioRouting.OnRoutingChangedListener} class instead. 2113 */ 2114 @Deprecated removeOnRoutingChangedListener(OnRoutingChangedListener listener)2115 public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) { 2116 removeOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener); 2117 } 2118 2119 /** 2120 * Sends device list change notification to all listeners. 2121 */ broadcastRoutingChange()2122 private void broadcastRoutingChange() { 2123 AudioManager.resetAudioPortGeneration(); 2124 synchronized (mRoutingChangeListeners) { 2125 for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) { 2126 delegate.notifyClient(); 2127 } 2128 } 2129 } 2130 2131 /** 2132 * Sets the period at which the listener is called, if set with 2133 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or 2134 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}. 2135 * It is possible for notifications to be lost if the period is too small. 2136 * @param periodInFrames update period expressed in frames 2137 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION} 2138 */ setPositionNotificationPeriod(int periodInFrames)2139 public int setPositionNotificationPeriod(int periodInFrames) { 2140 if (mState == STATE_UNINITIALIZED) { 2141 return ERROR_INVALID_OPERATION; 2142 } 2143 return native_set_pos_update_period(periodInFrames); 2144 } 2145 2146 //-------------------------------------------------------------------------- 2147 // Explicit Routing 2148 //-------------------- 2149 private AudioDeviceInfo mPreferredDevice = null; 2150 2151 /** 2152 * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route 2153 * the input to this AudioRecord. 2154 * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio source. 2155 * If deviceInfo is null, default routing is restored. 2156 * @return true if successful, false if the specified {@link AudioDeviceInfo} is non-null and 2157 * does not correspond to a valid audio input device. 2158 */ 2159 @Override setPreferredDevice(AudioDeviceInfo deviceInfo)2160 public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) { 2161 // Do some validation.... 2162 if (deviceInfo != null && !deviceInfo.isSource()) { 2163 return false; 2164 } 2165 2166 int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0; 2167 boolean status = native_setInputDevice(preferredDeviceId); 2168 if (status == true) { 2169 synchronized (this) { 2170 mPreferredDevice = deviceInfo; 2171 } 2172 } 2173 return status; 2174 } 2175 2176 /** 2177 * Returns the selected input specified by {@link #setPreferredDevice}. Note that this 2178 * is not guarenteed to correspond to the actual device being used for recording. 2179 */ 2180 @Override getPreferredDevice()2181 public AudioDeviceInfo getPreferredDevice() { 2182 synchronized (this) { 2183 return mPreferredDevice; 2184 } 2185 } 2186 2187 //-------------------------------------------------------------------------- 2188 // Microphone information 2189 //-------------------- 2190 /** 2191 * Returns a lists of {@link MicrophoneInfo} representing the active microphones. 2192 * By querying channel mapping for each active microphone, developer can know how 2193 * the microphone is used by each channels or a capture stream. 2194 * Note that the information about the active microphones may change during a recording. 2195 * See {@link AudioManager#registerAudioDeviceCallback} to be notified of changes 2196 * in the audio devices, querying the active microphones then will return the latest 2197 * information. 2198 * 2199 * @return a lists of {@link MicrophoneInfo} representing the active microphones. 2200 * @throws IOException if an error occurs 2201 */ getActiveMicrophones()2202 public List<MicrophoneInfo> getActiveMicrophones() throws IOException { 2203 ArrayList<MicrophoneInfo> activeMicrophones = new ArrayList<>(); 2204 int status = native_get_active_microphones(activeMicrophones); 2205 if (status != AudioManager.SUCCESS) { 2206 if (status != AudioManager.ERROR_INVALID_OPERATION) { 2207 Log.e(TAG, "getActiveMicrophones failed:" + status); 2208 } 2209 Log.i(TAG, "getActiveMicrophones failed, fallback on routed device info"); 2210 } 2211 AudioManager.setPortIdForMicrophones(activeMicrophones); 2212 2213 // Use routed device when there is not information returned by hal. 2214 if (activeMicrophones.size() == 0) { 2215 AudioDeviceInfo device = getRoutedDevice(); 2216 if (device != null) { 2217 MicrophoneInfo microphone = AudioManager.microphoneInfoFromAudioDeviceInfo(device); 2218 ArrayList<Pair<Integer, Integer>> channelMapping = new ArrayList<>(); 2219 for (int i = 0; i < mChannelCount; i++) { 2220 channelMapping.add(new Pair(i, MicrophoneInfo.CHANNEL_MAPPING_DIRECT)); 2221 } 2222 microphone.setChannelMapping(channelMapping); 2223 activeMicrophones.add(microphone); 2224 } 2225 } 2226 return activeMicrophones; 2227 } 2228 2229 //-------------------------------------------------------------------------- 2230 // Implementation of AudioRecordingMonitor interface 2231 //-------------------- 2232 2233 AudioRecordingMonitorImpl mRecordingInfoImpl = 2234 new AudioRecordingMonitorImpl((AudioRecordingMonitorClient) this); 2235 2236 /** 2237 * Register a callback to be notified of audio capture changes via a 2238 * {@link AudioManager.AudioRecordingCallback}. A callback is received when the capture path 2239 * configuration changes (pre-processing, format, sampling rate...) or capture is 2240 * silenced/unsilenced by the system. 2241 * @param executor {@link Executor} to handle the callbacks. 2242 * @param cb non-null callback to register 2243 */ registerAudioRecordingCallback(@onNull @allbackExecutor Executor executor, @NonNull AudioManager.AudioRecordingCallback cb)2244 public void registerAudioRecordingCallback(@NonNull @CallbackExecutor Executor executor, 2245 @NonNull AudioManager.AudioRecordingCallback cb) { 2246 mRecordingInfoImpl.registerAudioRecordingCallback(executor, cb); 2247 } 2248 2249 /** 2250 * Unregister an audio recording callback previously registered with 2251 * {@link #registerAudioRecordingCallback(Executor, AudioManager.AudioRecordingCallback)}. 2252 * @param cb non-null callback to unregister 2253 */ unregisterAudioRecordingCallback(@onNull AudioManager.AudioRecordingCallback cb)2254 public void unregisterAudioRecordingCallback(@NonNull AudioManager.AudioRecordingCallback cb) { 2255 mRecordingInfoImpl.unregisterAudioRecordingCallback(cb); 2256 } 2257 2258 /** 2259 * Returns the current active audio recording for this audio recorder. 2260 * @return a valid {@link AudioRecordingConfiguration} if this recorder is active 2261 * or null otherwise. 2262 * @see AudioRecordingConfiguration 2263 */ getActiveRecordingConfiguration()2264 public @Nullable AudioRecordingConfiguration getActiveRecordingConfiguration() { 2265 return mRecordingInfoImpl.getActiveRecordingConfiguration(); 2266 } 2267 2268 //--------------------------------------------------------- 2269 // Implementation of AudioRecordingMonitorClient interface 2270 //-------------------- 2271 /** 2272 * @hide 2273 */ getPortId()2274 public int getPortId() { 2275 if (mNativeAudioRecordHandle == 0) { 2276 return 0; 2277 } 2278 try { 2279 return native_getPortId(); 2280 } catch (IllegalStateException e) { 2281 return 0; 2282 } 2283 } 2284 2285 //-------------------------------------------------------------------------- 2286 // MicrophoneDirection 2287 //-------------------- 2288 /** 2289 * Specifies the logical microphone (for processing). Applications can use this to specify 2290 * which side of the device to optimize capture from. Typically used in conjunction with 2291 * the camera capturing video. 2292 * 2293 * @return true if sucessful. 2294 */ setPreferredMicrophoneDirection(@irectionMode int direction)2295 public boolean setPreferredMicrophoneDirection(@DirectionMode int direction) { 2296 return native_set_preferred_microphone_direction(direction) == AudioSystem.SUCCESS; 2297 } 2298 2299 /** 2300 * Specifies the zoom factor (i.e. the field dimension) for the selected microphone 2301 * (for processing). The selected microphone is determined by the use-case for the stream. 2302 * 2303 * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle), 2304 * though 0 (no zoom) to 1 (maximum zoom). 2305 * @return true if sucessful. 2306 */ setPreferredMicrophoneFieldDimension( @loatRangefrom = -1.0, to = 1.0) float zoom)2307 public boolean setPreferredMicrophoneFieldDimension( 2308 @FloatRange(from = -1.0, to = 1.0) float zoom) { 2309 Preconditions.checkArgument( 2310 zoom >= -1 && zoom <= 1, "Argument must fall between -1 & 1 (inclusive)"); 2311 return native_set_preferred_microphone_field_dimension(zoom) == AudioSystem.SUCCESS; 2312 } 2313 2314 /** 2315 * Sets a {@link LogSessionId} instance to this AudioRecord for metrics collection. 2316 * 2317 * @param logSessionId a {@link LogSessionId} instance which is used to 2318 * identify this object to the metrics service. Proper generated 2319 * Ids must be obtained from the Java metrics service and should 2320 * be considered opaque. Use 2321 * {@link LogSessionId#LOG_SESSION_ID_NONE} to remove the 2322 * logSessionId association. 2323 * @throws IllegalStateException if AudioRecord not initialized. 2324 */ setLogSessionId(@onNull LogSessionId logSessionId)2325 public void setLogSessionId(@NonNull LogSessionId logSessionId) { 2326 Objects.requireNonNull(logSessionId); 2327 if (mState == STATE_UNINITIALIZED) { 2328 throw new IllegalStateException("AudioRecord not initialized"); 2329 } 2330 String stringId = logSessionId.getStringId(); 2331 native_setLogSessionId(stringId); 2332 mLogSessionId = logSessionId; 2333 } 2334 2335 /** 2336 * Returns the {@link LogSessionId}. 2337 */ 2338 @NonNull getLogSessionId()2339 public LogSessionId getLogSessionId() { 2340 return mLogSessionId; 2341 } 2342 2343 //--------------------------------------------------------- 2344 // Interface definitions 2345 //-------------------- 2346 /** 2347 * Interface definition for a callback to be invoked when an AudioRecord has 2348 * reached a notification marker set by {@link AudioRecord#setNotificationMarkerPosition(int)} 2349 * or for periodic updates on the progress of the record head, as set by 2350 * {@link AudioRecord#setPositionNotificationPeriod(int)}. 2351 */ 2352 public interface OnRecordPositionUpdateListener { 2353 /** 2354 * Called on the listener to notify it that the previously set marker has been reached 2355 * by the recording head. 2356 */ onMarkerReached(AudioRecord recorder)2357 void onMarkerReached(AudioRecord recorder); 2358 2359 /** 2360 * Called on the listener to periodically notify it that the record head has reached 2361 * a multiple of the notification period. 2362 */ onPeriodicNotification(AudioRecord recorder)2363 void onPeriodicNotification(AudioRecord recorder); 2364 } 2365 2366 2367 2368 //--------------------------------------------------------- 2369 // Inner classes 2370 //-------------------- 2371 2372 /** 2373 * Helper class to handle the forwarding of native events to the appropriate listener 2374 * (potentially) handled in a different thread 2375 */ 2376 private class NativeEventHandler extends Handler { 2377 private final AudioRecord mAudioRecord; 2378 NativeEventHandler(AudioRecord recorder, Looper looper)2379 NativeEventHandler(AudioRecord recorder, Looper looper) { 2380 super(looper); 2381 mAudioRecord = recorder; 2382 } 2383 2384 @Override handleMessage(Message msg)2385 public void handleMessage(Message msg) { 2386 OnRecordPositionUpdateListener listener = null; 2387 synchronized (mPositionListenerLock) { 2388 listener = mAudioRecord.mPositionListener; 2389 } 2390 2391 switch (msg.what) { 2392 case NATIVE_EVENT_MARKER: 2393 if (listener != null) { 2394 listener.onMarkerReached(mAudioRecord); 2395 } 2396 break; 2397 case NATIVE_EVENT_NEW_POS: 2398 if (listener != null) { 2399 listener.onPeriodicNotification(mAudioRecord); 2400 } 2401 break; 2402 default: 2403 loge("Unknown native event type: " + msg.what); 2404 break; 2405 } 2406 } 2407 } 2408 2409 //--------------------------------------------------------- 2410 // Java methods called from the native side 2411 //-------------------- 2412 @SuppressWarnings("unused") 2413 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) postEventFromNative(Object audiorecord_ref, int what, int arg1, int arg2, Object obj)2414 private static void postEventFromNative(Object audiorecord_ref, 2415 int what, int arg1, int arg2, Object obj) { 2416 //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2); 2417 AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get(); 2418 if (recorder == null) { 2419 return; 2420 } 2421 2422 if (what == AudioSystem.NATIVE_EVENT_ROUTING_CHANGE) { 2423 recorder.broadcastRoutingChange(); 2424 return; 2425 } 2426 2427 if (recorder.mEventHandler != null) { 2428 Message m = 2429 recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj); 2430 recorder.mEventHandler.sendMessage(m); 2431 } 2432 2433 } 2434 2435 2436 //--------------------------------------------------------- 2437 // Native methods called from the Java side 2438 //-------------------- 2439 2440 /** 2441 * @deprecated Use native_setup that takes an {@link AttributionSource} object 2442 * @return 2443 */ 2444 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, 2445 publicAlternatives = "{@code AudioRecord.Builder}") 2446 @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)2447 private int native_setup(Object audiorecordThis, 2448 Object /*AudioAttributes*/ attributes, 2449 int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, 2450 int buffSizeInBytes, int[] sessionId, String opPackageName, 2451 long nativeRecordInJavaObj, int halInputFlags) { 2452 AttributionSource attributionSource = AttributionSource.myAttributionSource() 2453 .withPackageName(opPackageName); 2454 try (ScopedParcelState attributionSourceState = attributionSource.asScopedParcelState()) { 2455 return native_setup(audiorecordThis, attributes, sampleRate, channelMask, 2456 channelIndexMask, audioFormat, buffSizeInBytes, sessionId, 2457 attributionSourceState.getParcel(), nativeRecordInJavaObj, 0, halInputFlags); 2458 } 2459 } 2460 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)2461 private native int native_setup(Object audiorecordThis, 2462 Object /*AudioAttributes*/ attributes, 2463 int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, 2464 int buffSizeInBytes, int[] sessionId, @NonNull Parcel attributionSource, 2465 long nativeRecordInJavaObj, int maxSharedAudioHistoryMs, int halInputFlags); 2466 2467 // TODO remove: implementation calls directly into implementation of native_release() native_finalize()2468 private native void native_finalize(); 2469 2470 /** 2471 * @hide 2472 */ 2473 @UnsupportedAppUsage native_release()2474 public native final void native_release(); 2475 native_start(int syncEvent, int sessionId)2476 private native final int native_start(int syncEvent, int sessionId); 2477 native_stop()2478 private native final void native_stop(); 2479 native_read_in_byte_array(byte[] audioData, int offsetInBytes, int sizeInBytes, boolean isBlocking)2480 private native final int native_read_in_byte_array(byte[] audioData, 2481 int offsetInBytes, int sizeInBytes, boolean isBlocking); 2482 native_read_in_short_array(short[] audioData, int offsetInShorts, int sizeInShorts, boolean isBlocking)2483 private native final int native_read_in_short_array(short[] audioData, 2484 int offsetInShorts, int sizeInShorts, boolean isBlocking); 2485 native_read_in_float_array(float[] audioData, int offsetInFloats, int sizeInFloats, boolean isBlocking)2486 private native final int native_read_in_float_array(float[] audioData, 2487 int offsetInFloats, int sizeInFloats, boolean isBlocking); 2488 native_read_in_direct_buffer(Object jBuffer, int sizeInBytes, boolean isBlocking)2489 private native final int native_read_in_direct_buffer(Object jBuffer, 2490 int sizeInBytes, boolean isBlocking); 2491 native_get_buffer_size_in_frames()2492 private native final int native_get_buffer_size_in_frames(); 2493 native_set_marker_pos(int marker)2494 private native final int native_set_marker_pos(int marker); native_get_marker_pos()2495 private native final int native_get_marker_pos(); 2496 native_set_pos_update_period(int updatePeriod)2497 private native final int native_set_pos_update_period(int updatePeriod); native_get_pos_update_period()2498 private native final int native_get_pos_update_period(); 2499 native_get_min_buff_size( int sampleRateInHz, int channelCount, int audioFormat)2500 static private native final int native_get_min_buff_size( 2501 int sampleRateInHz, int channelCount, int audioFormat); 2502 native_setInputDevice(int deviceId)2503 private native final boolean native_setInputDevice(int deviceId); native_getRoutedDeviceId()2504 private native final int native_getRoutedDeviceId(); native_enableDeviceCallback()2505 private native final void native_enableDeviceCallback(); native_disableDeviceCallback()2506 private native final void native_disableDeviceCallback(); 2507 native_get_timestamp(@onNull AudioTimestamp outTimestamp, @AudioTimestamp.Timebase int timebase)2508 private native final int native_get_timestamp(@NonNull AudioTimestamp outTimestamp, 2509 @AudioTimestamp.Timebase int timebase); 2510 native_get_active_microphones( ArrayList<MicrophoneInfo> activeMicrophones)2511 private native final int native_get_active_microphones( 2512 ArrayList<MicrophoneInfo> activeMicrophones); 2513 2514 /** 2515 * @throws IllegalStateException 2516 */ native_getPortId()2517 private native int native_getPortId(); 2518 native_set_preferred_microphone_direction(int direction)2519 private native int native_set_preferred_microphone_direction(int direction); native_set_preferred_microphone_field_dimension(float zoom)2520 private native int native_set_preferred_microphone_field_dimension(float zoom); 2521 native_setLogSessionId(@ullable String logSessionId)2522 private native void native_setLogSessionId(@Nullable String logSessionId); 2523 native_shareAudioHistory(@onNull String sharedPackage, long startFromMs)2524 private native int native_shareAudioHistory(@NonNull String sharedPackage, long startFromMs); 2525 2526 //--------------------------------------------------------- 2527 // Utility methods 2528 //------------------ 2529 logd(String msg)2530 private static void logd(String msg) { 2531 Log.d(TAG, msg); 2532 } 2533 loge(String msg)2534 private static void loge(String msg) { 2535 Log.e(TAG, msg); 2536 } 2537 2538 public static final class MetricsConstants 2539 { MetricsConstants()2540 private MetricsConstants() {} 2541 2542 // MM_PREFIX is slightly different than TAG, used to avoid cut-n-paste errors. 2543 private static final String MM_PREFIX = "android.media.audiorecord."; 2544 2545 /** 2546 * Key to extract the audio data encoding for this track 2547 * from the {@link AudioRecord#getMetrics} return value. 2548 * The value is a {@code String}. 2549 */ 2550 public static final String ENCODING = MM_PREFIX + "encoding"; 2551 2552 /** 2553 * Key to extract the source type for this track 2554 * from the {@link AudioRecord#getMetrics} return value. 2555 * The value is a {@code String}. 2556 */ 2557 public static final String SOURCE = MM_PREFIX + "source"; 2558 2559 /** 2560 * Key to extract the estimated latency through the recording pipeline 2561 * from the {@link AudioRecord#getMetrics} return value. 2562 * This is in units of milliseconds. 2563 * The value is an {@code int}. 2564 * @deprecated Not properly supported in the past. 2565 */ 2566 @Deprecated 2567 public static final String LATENCY = MM_PREFIX + "latency"; 2568 2569 /** 2570 * Key to extract the sink sample rate for this record track in Hz 2571 * from the {@link AudioRecord#getMetrics} return value. 2572 * The value is an {@code int}. 2573 */ 2574 public static final String SAMPLERATE = MM_PREFIX + "samplerate"; 2575 2576 /** 2577 * Key to extract the number of channels being recorded in this record track 2578 * from the {@link AudioRecord#getMetrics} return value. 2579 * The value is an {@code int}. 2580 */ 2581 public static final String CHANNELS = MM_PREFIX + "channels"; 2582 2583 /** 2584 * Use for testing only. Do not expose. 2585 * The native channel mask. 2586 * The value is a {@code long}. 2587 * @hide 2588 */ 2589 @TestApi 2590 public static final String CHANNEL_MASK = MM_PREFIX + "channelMask"; 2591 2592 2593 /** 2594 * Use for testing only. Do not expose. 2595 * The port id of this input port in audioserver. 2596 * The value is an {@code int}. 2597 * @hide 2598 */ 2599 @TestApi 2600 public static final String PORT_ID = MM_PREFIX + "portId"; 2601 2602 /** 2603 * Use for testing only. Do not expose. 2604 * The buffer frameCount. 2605 * The value is an {@code int}. 2606 * @hide 2607 */ 2608 @TestApi 2609 public static final String FRAME_COUNT = MM_PREFIX + "frameCount"; 2610 2611 /** 2612 * Use for testing only. Do not expose. 2613 * The actual record track attributes used. 2614 * The value is a {@code String}. 2615 * @hide 2616 */ 2617 @TestApi 2618 public static final String ATTRIBUTES = MM_PREFIX + "attributes"; 2619 2620 /** 2621 * Use for testing only. Do not expose. 2622 * The buffer frameCount 2623 * The value is a {@code double}. 2624 * @hide 2625 */ 2626 @TestApi 2627 public static final String DURATION_MS = MM_PREFIX + "durationMs"; 2628 2629 /** 2630 * Use for testing only. Do not expose. 2631 * The number of times the record track has started 2632 * The value is a {@code long}. 2633 * @hide 2634 */ 2635 @TestApi 2636 public static final String START_COUNT = MM_PREFIX + "startCount"; 2637 } 2638 } 2639