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