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 java.io.IOException; 20 import java.lang.annotation.Retention; 21 import java.lang.annotation.RetentionPolicy; 22 import java.lang.ref.WeakReference; 23 import java.nio.ByteBuffer; 24 import java.util.Collection; 25 import java.util.Iterator; 26 import java.util.ArrayList; 27 import java.util.List; 28 29 import android.annotation.IntDef; 30 import android.annotation.NonNull; 31 import android.annotation.SystemApi; 32 import android.app.ActivityThread; 33 import android.os.Binder; 34 import android.os.Handler; 35 import android.os.IBinder; 36 import android.os.Looper; 37 import android.os.Message; 38 import android.os.PersistableBundle; 39 import android.os.RemoteException; 40 import android.os.ServiceManager; 41 import android.text.TextUtils; 42 import android.util.ArrayMap; 43 import android.util.Log; 44 import android.util.Pair; 45 46 import com.android.internal.annotations.GuardedBy; 47 48 /** 49 * The AudioRecord class manages the audio resources for Java applications 50 * to record audio from the audio input hardware of the platform. This is 51 * achieved by "pulling" (reading) the data from the AudioRecord object. The 52 * application is responsible for polling the AudioRecord object in time using one of 53 * the following three methods: {@link #read(byte[],int, int)}, {@link #read(short[], int, int)} 54 * or {@link #read(ByteBuffer, int)}. The choice of which method to use will be based 55 * on the audio data storage format that is the most convenient for the user of AudioRecord. 56 * <p>Upon creation, an AudioRecord object initializes its associated audio buffer that it will 57 * fill with the new audio data. The size of this buffer, specified during the construction, 58 * determines how long an AudioRecord can record before "over-running" data that has not 59 * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to 60 * the total recording buffer size. 61 */ 62 public class AudioRecord implements AudioRouting 63 { 64 //--------------------------------------------------------- 65 // Constants 66 //-------------------- 67 68 69 /** 70 * indicates AudioRecord state is not successfully initialized. 71 */ 72 public static final int STATE_UNINITIALIZED = 0; 73 /** 74 * indicates AudioRecord state is ready to be used 75 */ 76 public static final int STATE_INITIALIZED = 1; 77 78 /** 79 * indicates AudioRecord recording state is not recording 80 */ 81 public static final int RECORDSTATE_STOPPED = 1; // matches SL_RECORDSTATE_STOPPED 82 /** 83 * indicates AudioRecord recording state is recording 84 */ 85 public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING 86 87 /** 88 * Denotes a successful operation. 89 */ 90 public static final int SUCCESS = AudioSystem.SUCCESS; 91 /** 92 * Denotes a generic operation failure. 93 */ 94 public static final int ERROR = AudioSystem.ERROR; 95 /** 96 * Denotes a failure due to the use of an invalid value. 97 */ 98 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE; 99 /** 100 * Denotes a failure due to the improper use of a method. 101 */ 102 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION; 103 /** 104 * An error code indicating that the object reporting it is no longer valid and needs to 105 * be recreated. 106 */ 107 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT; 108 109 // Error codes: 110 // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp 111 private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT = -16; 112 private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK = -17; 113 private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT = -18; 114 private static final int AUDIORECORD_ERROR_SETUP_INVALIDSOURCE = -19; 115 private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED = -20; 116 117 // Events: 118 // to keep in sync with frameworks/av/include/media/AudioRecord.h 119 /** 120 * Event id denotes when record head has reached a previously set marker. 121 */ 122 private static final int NATIVE_EVENT_MARKER = 2; 123 /** 124 * Event id denotes when previously set update period has elapsed during recording. 125 */ 126 private static final int NATIVE_EVENT_NEW_POS = 3; 127 128 private final static String TAG = "android.media.AudioRecord"; 129 130 /** @hide */ 131 public final static String SUBMIX_FIXED_VOLUME = "fixedVolume"; 132 133 /** @hide */ 134 @IntDef({ 135 READ_BLOCKING, 136 READ_NON_BLOCKING 137 }) 138 @Retention(RetentionPolicy.SOURCE) 139 public @interface ReadMode {} 140 141 /** 142 * The read mode indicating the read operation will block until all data 143 * requested has been read. 144 */ 145 public final static int READ_BLOCKING = 0; 146 147 /** 148 * The read mode indicating the read operation will return immediately after 149 * reading as much audio data as possible without blocking. 150 */ 151 public final static int READ_NON_BLOCKING = 1; 152 153 //--------------------------------------------------------- 154 // Used exclusively by native code 155 //-------------------- 156 /** 157 * Accessed by native methods: provides access to C++ AudioRecord object 158 */ 159 @SuppressWarnings("unused") 160 private long mNativeRecorderInJavaObj; 161 162 /** 163 * Accessed by native methods: provides access to the callback data. 164 */ 165 @SuppressWarnings("unused") 166 private long mNativeCallbackCookie; 167 168 /** 169 * Accessed by native methods: provides access to the JNIDeviceCallback instance. 170 */ 171 @SuppressWarnings("unused") 172 private long mNativeDeviceCallback; 173 174 175 //--------------------------------------------------------- 176 // Member variables 177 //-------------------- 178 /** 179 * The audio data sampling rate in Hz. 180 * Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}. 181 */ 182 private int mSampleRate; // initialized by all constructors via audioParamCheck() 183 /** 184 * The number of input audio channels (1 is mono, 2 is stereo) 185 */ 186 private int mChannelCount; 187 /** 188 * The audio channel position mask 189 */ 190 private int mChannelMask; 191 /** 192 * The audio channel index mask 193 */ 194 private int mChannelIndexMask; 195 /** 196 * The encoding of the audio samples. 197 * @see AudioFormat#ENCODING_PCM_8BIT 198 * @see AudioFormat#ENCODING_PCM_16BIT 199 * @see AudioFormat#ENCODING_PCM_FLOAT 200 */ 201 private int mAudioFormat; 202 /** 203 * Where the audio data is recorded from. 204 */ 205 private int mRecordSource; 206 /** 207 * Indicates the state of the AudioRecord instance. 208 */ 209 private int mState = STATE_UNINITIALIZED; 210 /** 211 * Indicates the recording state of the AudioRecord instance. 212 */ 213 private int mRecordingState = RECORDSTATE_STOPPED; 214 /** 215 * Lock to make sure mRecordingState updates are reflecting the actual state of the object. 216 */ 217 private final Object mRecordingStateLock = new Object(); 218 /** 219 * The listener the AudioRecord notifies when the record position reaches a marker 220 * or for periodic updates during the progression of the record head. 221 * @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener) 222 * @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler) 223 */ 224 private OnRecordPositionUpdateListener mPositionListener = null; 225 /** 226 * Lock to protect position listener updates against event notifications 227 */ 228 private final Object mPositionListenerLock = new Object(); 229 /** 230 * Handler for marker events coming from the native code 231 */ 232 private NativeEventHandler mEventHandler = null; 233 /** 234 * Looper associated with the thread that creates the AudioRecord instance 235 */ 236 private Looper mInitializationLooper = null; 237 /** 238 * Size of the native audio buffer. 239 */ 240 private int mNativeBufferSizeInBytes = 0; 241 /** 242 * Audio session ID 243 */ 244 private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE; 245 /** 246 * AudioAttributes 247 */ 248 private AudioAttributes mAudioAttributes; 249 private boolean mIsSubmixFullVolume = false; 250 251 //--------------------------------------------------------- 252 // Constructor, Finalize 253 //-------------------- 254 /** 255 * Class constructor. 256 * Though some invalid parameters will result in an {@link IllegalArgumentException} exception, 257 * other errors do not. Thus you should call {@link #getState()} immediately after construction 258 * to confirm that the object is usable. 259 * @param audioSource the recording source. 260 * See {@link MediaRecorder.AudioSource} for the recording source definitions. 261 * @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only 262 * rate that is guaranteed to work on all devices, but other rates such as 22050, 263 * 16000, and 11025 may work on some devices. 264 * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} means to use a route-dependent value 265 * which is usually the sample rate of the source. 266 * {@link #getSampleRate()} can be used to retrieve the actual sample rate chosen. 267 * @param channelConfig describes the configuration of the audio channels. 268 * See {@link AudioFormat#CHANNEL_IN_MONO} and 269 * {@link AudioFormat#CHANNEL_IN_STEREO}. {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed 270 * to work on all devices. 271 * @param audioFormat the format in which the audio data is to be returned. 272 * See {@link AudioFormat#ENCODING_PCM_8BIT}, {@link AudioFormat#ENCODING_PCM_16BIT}, 273 * and {@link AudioFormat#ENCODING_PCM_FLOAT}. 274 * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written 275 * to during the recording. New audio data can be read from this buffer in smaller chunks 276 * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum 277 * required buffer size for the successful creation of an AudioRecord instance. Using values 278 * smaller than getMinBufferSize() will result in an initialization failure. 279 * @throws java.lang.IllegalArgumentException 280 */ AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)281 public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, 282 int bufferSizeInBytes) 283 throws IllegalArgumentException { 284 this((new AudioAttributes.Builder()) 285 .setInternalCapturePreset(audioSource) 286 .build(), 287 (new AudioFormat.Builder()) 288 .setChannelMask(getChannelMaskFromLegacyConfig(channelConfig, 289 true/*allow legacy configurations*/)) 290 .setEncoding(audioFormat) 291 .setSampleRate(sampleRateInHz) 292 .build(), 293 bufferSizeInBytes, 294 AudioManager.AUDIO_SESSION_ID_GENERATE); 295 } 296 297 /** 298 * @hide 299 * Class constructor with {@link AudioAttributes} and {@link AudioFormat}. 300 * @param attributes a non-null {@link AudioAttributes} instance. Use 301 * {@link AudioAttributes.Builder#setAudioSource(int)} for configuring the audio 302 * source for this instance. 303 * @param format a non-null {@link AudioFormat} instance describing the format of the data 304 * that will be recorded through this AudioRecord. See {@link AudioFormat.Builder} for 305 * configuring the audio format parameters such as encoding, channel mask and sample rate. 306 * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written 307 * to during the recording. New audio data can be read from this buffer in smaller chunks 308 * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum 309 * required buffer size for the successful creation of an AudioRecord instance. Using values 310 * smaller than getMinBufferSize() will result in an initialization failure. 311 * @param sessionId ID of audio session the AudioRecord must be attached to, or 312 * {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at construction 313 * time. See also {@link AudioManager#generateAudioSessionId()} to obtain a session ID before 314 * construction. 315 * @throws IllegalArgumentException 316 */ 317 @SystemApi AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, int sessionId)318 public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, 319 int sessionId) throws IllegalArgumentException { 320 mRecordingState = RECORDSTATE_STOPPED; 321 322 if (attributes == null) { 323 throw new IllegalArgumentException("Illegal null AudioAttributes"); 324 } 325 if (format == null) { 326 throw new IllegalArgumentException("Illegal null AudioFormat"); 327 } 328 329 // remember which looper is associated with the AudioRecord instanciation 330 if ((mInitializationLooper = Looper.myLooper()) == null) { 331 mInitializationLooper = Looper.getMainLooper(); 332 } 333 334 // is this AudioRecord using REMOTE_SUBMIX at full volume? 335 if (attributes.getCapturePreset() == MediaRecorder.AudioSource.REMOTE_SUBMIX) { 336 final AudioAttributes.Builder filteredAttr = new AudioAttributes.Builder(); 337 final Iterator<String> tagsIter = attributes.getTags().iterator(); 338 while (tagsIter.hasNext()) { 339 final String tag = tagsIter.next(); 340 if (tag.equalsIgnoreCase(SUBMIX_FIXED_VOLUME)) { 341 mIsSubmixFullVolume = true; 342 Log.v(TAG, "Will record from REMOTE_SUBMIX at full fixed volume"); 343 } else { // SUBMIX_FIXED_VOLUME: is not to be propagated to the native layers 344 filteredAttr.addTag(tag); 345 } 346 } 347 filteredAttr.setInternalCapturePreset(attributes.getCapturePreset()); 348 mAudioAttributes = filteredAttr.build(); 349 } else { 350 mAudioAttributes = attributes; 351 } 352 353 int rate = format.getSampleRate(); 354 if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) { 355 rate = 0; 356 } 357 358 int encoding = AudioFormat.ENCODING_DEFAULT; 359 if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0) 360 { 361 encoding = format.getEncoding(); 362 } 363 364 audioParamCheck(attributes.getCapturePreset(), rate, encoding); 365 366 if ((format.getPropertySetMask() 367 & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) { 368 mChannelIndexMask = format.getChannelIndexMask(); 369 mChannelCount = format.getChannelCount(); 370 } 371 if ((format.getPropertySetMask() 372 & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0) { 373 mChannelMask = getChannelMaskFromLegacyConfig(format.getChannelMask(), false); 374 mChannelCount = format.getChannelCount(); 375 } else if (mChannelIndexMask == 0) { 376 mChannelMask = getChannelMaskFromLegacyConfig(AudioFormat.CHANNEL_IN_DEFAULT, false); 377 mChannelCount = AudioFormat.channelCountFromInChannelMask(mChannelMask); 378 } 379 380 audioBuffSizeCheck(bufferSizeInBytes); 381 382 int[] sampleRate = new int[] {mSampleRate}; 383 int[] session = new int[1]; 384 session[0] = sessionId; 385 //TODO: update native initialization when information about hardware init failure 386 // due to capture device already open is available. 387 int initResult = native_setup( new WeakReference<AudioRecord>(this), 388 mAudioAttributes, sampleRate, mChannelMask, mChannelIndexMask, 389 mAudioFormat, mNativeBufferSizeInBytes, 390 session, ActivityThread.currentOpPackageName(), 0 /*nativeRecordInJavaObj*/); 391 if (initResult != SUCCESS) { 392 loge("Error code "+initResult+" when initializing native AudioRecord object."); 393 return; // with mState == STATE_UNINITIALIZED 394 } 395 396 mSampleRate = sampleRate[0]; 397 mSessionId = session[0]; 398 399 mState = STATE_INITIALIZED; 400 } 401 402 /** 403 * A constructor which explicitly connects a Native (C++) AudioRecord. For use by 404 * the AudioRecordRoutingProxy subclass. 405 * @param nativeRecordInJavaObj A C/C++ pointer to a native AudioRecord 406 * (associated with an OpenSL ES recorder). Note: the caller must ensure a correct 407 * value here as no error checking is or can be done. 408 */ AudioRecord(long nativeRecordInJavaObj)409 /*package*/ AudioRecord(long nativeRecordInJavaObj) { 410 mNativeRecorderInJavaObj = 0; 411 mNativeCallbackCookie = 0; 412 mNativeDeviceCallback = 0; 413 414 // other initialization... 415 if (nativeRecordInJavaObj != 0) { 416 deferred_connect(nativeRecordInJavaObj); 417 } else { 418 mState = STATE_UNINITIALIZED; 419 } 420 } 421 422 /** 423 * @hide 424 */ deferred_connect(long nativeRecordInJavaObj)425 /* package */ void deferred_connect(long nativeRecordInJavaObj) { 426 if (mState != STATE_INITIALIZED) { 427 int[] session = { 0 }; 428 int[] rates = { 0 }; 429 //TODO: update native initialization when information about hardware init failure 430 // due to capture device already open is available. 431 // Note that for this native_setup, we are providing an already created/initialized 432 // *Native* AudioRecord, so the attributes parameters to native_setup() are ignored. 433 int initResult = native_setup(new WeakReference<AudioRecord>(this), 434 null /*mAudioAttributes*/, 435 rates /*mSampleRates*/, 436 0 /*mChannelMask*/, 437 0 /*mChannelIndexMask*/, 438 0 /*mAudioFormat*/, 439 0 /*mNativeBufferSizeInBytes*/, 440 session, 441 ActivityThread.currentOpPackageName(), 442 nativeRecordInJavaObj); 443 if (initResult != SUCCESS) { 444 loge("Error code "+initResult+" when initializing native AudioRecord object."); 445 return; // with mState == STATE_UNINITIALIZED 446 } 447 448 mSessionId = session[0]; 449 450 mState = STATE_INITIALIZED; 451 } 452 } 453 454 /** 455 * Builder class for {@link AudioRecord} objects. 456 * Use this class to configure and create an <code>AudioRecord</code> instance. By setting the 457 * recording source and audio format parameters, you indicate which of 458 * those vary from the default behavior on the device. 459 * <p> Here is an example where <code>Builder</code> is used to specify all {@link AudioFormat} 460 * parameters, to be used by a new <code>AudioRecord</code> instance: 461 * 462 * <pre class="prettyprint"> 463 * AudioRecord recorder = new AudioRecord.Builder() 464 * .setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION) 465 * .setAudioFormat(new AudioFormat.Builder() 466 * .setEncoding(AudioFormat.ENCODING_PCM_16BIT) 467 * .setSampleRate(32000) 468 * .setChannelMask(AudioFormat.CHANNEL_IN_MONO) 469 * .build()) 470 * .setBufferSize(2*minBuffSize) 471 * .build(); 472 * </pre> 473 * <p> 474 * If the audio source is not set with {@link #setAudioSource(int)}, 475 * {@link MediaRecorder.AudioSource#DEFAULT} is used. 476 * <br>If the audio format is not specified or is incomplete, its channel configuration will be 477 * {@link AudioFormat#CHANNEL_IN_MONO}, and the encoding will be 478 * {@link AudioFormat#ENCODING_PCM_16BIT}. 479 * The sample rate will depend on the device actually selected for capture and can be queried 480 * with {@link #getSampleRate()} method. 481 * <br>If the buffer size is not specified with {@link #setBufferSizeInBytes(int)}, 482 * the minimum buffer size for the source is used. 483 */ 484 public static class Builder { 485 private AudioAttributes mAttributes; 486 private AudioFormat mFormat; 487 private int mBufferSizeInBytes; 488 private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE; 489 490 /** 491 * Constructs a new Builder with the default values as described above. 492 */ Builder()493 public Builder() { 494 } 495 496 /** 497 * @param source the audio source. 498 * See {@link MediaRecorder.AudioSource} for the supported audio source definitions. 499 * @return the same Builder instance. 500 * @throws IllegalArgumentException 501 */ setAudioSource(int source)502 public Builder setAudioSource(int source) throws IllegalArgumentException { 503 if ( (source < MediaRecorder.AudioSource.DEFAULT) || 504 (source > MediaRecorder.getAudioSourceMax()) ) { 505 throw new IllegalArgumentException("Invalid audio source " + source); 506 } 507 mAttributes = new AudioAttributes.Builder() 508 .setInternalCapturePreset(source) 509 .build(); 510 return this; 511 } 512 513 /** 514 * @hide 515 * To be only used by system components. Allows specifying non-public capture presets 516 * @param attributes a non-null {@link AudioAttributes} instance that contains the capture 517 * preset to be used. 518 * @return the same Builder instance. 519 * @throws IllegalArgumentException 520 */ 521 @SystemApi setAudioAttributes(@onNull AudioAttributes attributes)522 public Builder setAudioAttributes(@NonNull AudioAttributes attributes) 523 throws IllegalArgumentException { 524 if (attributes == null) { 525 throw new IllegalArgumentException("Illegal null AudioAttributes argument"); 526 } 527 if (attributes.getCapturePreset() == MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID) { 528 throw new IllegalArgumentException( 529 "No valid capture preset in AudioAttributes argument"); 530 } 531 // keep reference, we only copy the data when building 532 mAttributes = attributes; 533 return this; 534 } 535 536 /** 537 * Sets the format of the audio data to be captured. 538 * @param format a non-null {@link AudioFormat} instance 539 * @return the same Builder instance. 540 * @throws IllegalArgumentException 541 */ setAudioFormat(@onNull AudioFormat format)542 public Builder setAudioFormat(@NonNull AudioFormat format) throws IllegalArgumentException { 543 if (format == null) { 544 throw new IllegalArgumentException("Illegal null AudioFormat argument"); 545 } 546 // keep reference, we only copy the data when building 547 mFormat = format; 548 return this; 549 } 550 551 /** 552 * Sets the total size (in bytes) of the buffer where audio data is written 553 * during the recording. New audio data can be read from this buffer in smaller chunks 554 * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum 555 * required buffer size for the successful creation of an AudioRecord instance. 556 * Since bufferSizeInBytes may be internally increased to accommodate the source 557 * requirements, use {@link #getBufferSizeInFrames()} to determine the actual buffer size 558 * in frames. 559 * @param bufferSizeInBytes a value strictly greater than 0 560 * @return the same Builder instance. 561 * @throws IllegalArgumentException 562 */ setBufferSizeInBytes(int bufferSizeInBytes)563 public Builder setBufferSizeInBytes(int bufferSizeInBytes) throws IllegalArgumentException { 564 if (bufferSizeInBytes <= 0) { 565 throw new IllegalArgumentException("Invalid buffer size " + bufferSizeInBytes); 566 } 567 mBufferSizeInBytes = bufferSizeInBytes; 568 return this; 569 } 570 571 /** 572 * @hide 573 * To be only used by system components. 574 * @param sessionId ID of audio session the AudioRecord must be attached to, or 575 * {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at 576 * construction time. 577 * @return the same Builder instance. 578 * @throws IllegalArgumentException 579 */ 580 @SystemApi setSessionId(int sessionId)581 public Builder setSessionId(int sessionId) throws IllegalArgumentException { 582 if (sessionId < 0) { 583 throw new IllegalArgumentException("Invalid session ID " + sessionId); 584 } 585 mSessionId = sessionId; 586 return this; 587 } 588 589 /** 590 * @return a new {@link AudioRecord} instance successfully initialized with all 591 * the parameters set on this <code>Builder</code>. 592 * @throws UnsupportedOperationException if the parameters set on the <code>Builder</code> 593 * were incompatible, or if they are not supported by the device, 594 * or if the device was not available. 595 */ build()596 public AudioRecord build() throws UnsupportedOperationException { 597 if (mFormat == null) { 598 mFormat = new AudioFormat.Builder() 599 .setEncoding(AudioFormat.ENCODING_PCM_16BIT) 600 .setChannelMask(AudioFormat.CHANNEL_IN_MONO) 601 .build(); 602 } else { 603 if (mFormat.getEncoding() == AudioFormat.ENCODING_INVALID) { 604 mFormat = new AudioFormat.Builder(mFormat) 605 .setEncoding(AudioFormat.ENCODING_PCM_16BIT) 606 .build(); 607 } 608 if (mFormat.getChannelMask() == AudioFormat.CHANNEL_INVALID 609 && mFormat.getChannelIndexMask() == AudioFormat.CHANNEL_INVALID) { 610 mFormat = new AudioFormat.Builder(mFormat) 611 .setChannelMask(AudioFormat.CHANNEL_IN_MONO) 612 .build(); 613 } 614 } 615 if (mAttributes == null) { 616 mAttributes = new AudioAttributes.Builder() 617 .setInternalCapturePreset(MediaRecorder.AudioSource.DEFAULT) 618 .build(); 619 } 620 try { 621 // If the buffer size is not specified, 622 // use a single frame for the buffer size and let the 623 // native code figure out the minimum buffer size. 624 if (mBufferSizeInBytes == 0) { 625 mBufferSizeInBytes = mFormat.getChannelCount() 626 * mFormat.getBytesPerSample(mFormat.getEncoding()); 627 } 628 final AudioRecord record = new AudioRecord( 629 mAttributes, mFormat, mBufferSizeInBytes, mSessionId); 630 if (record.getState() == STATE_UNINITIALIZED) { 631 // release is not necessary 632 throw new UnsupportedOperationException("Cannot create AudioRecord"); 633 } 634 return record; 635 } catch (IllegalArgumentException e) { 636 throw new UnsupportedOperationException(e.getMessage()); 637 } 638 } 639 } 640 641 // Convenience method for the constructor's parameter checks. 642 // This, getChannelMaskFromLegacyConfig and audioBuffSizeCheck are where constructor 643 // IllegalArgumentException-s are thrown getChannelMaskFromLegacyConfig(int inChannelConfig, boolean allowLegacyConfig)644 private static int getChannelMaskFromLegacyConfig(int inChannelConfig, 645 boolean allowLegacyConfig) { 646 int mask; 647 switch (inChannelConfig) { 648 case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT 649 case AudioFormat.CHANNEL_IN_MONO: 650 case AudioFormat.CHANNEL_CONFIGURATION_MONO: 651 mask = AudioFormat.CHANNEL_IN_MONO; 652 break; 653 case AudioFormat.CHANNEL_IN_STEREO: 654 case AudioFormat.CHANNEL_CONFIGURATION_STEREO: 655 mask = AudioFormat.CHANNEL_IN_STEREO; 656 break; 657 case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK): 658 mask = inChannelConfig; 659 break; 660 default: 661 throw new IllegalArgumentException("Unsupported channel configuration."); 662 } 663 664 if (!allowLegacyConfig && ((inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_MONO) 665 || (inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_STEREO))) { 666 // only happens with the constructor that uses AudioAttributes and AudioFormat 667 throw new IllegalArgumentException("Unsupported deprecated configuration."); 668 } 669 670 return mask; 671 } 672 673 // postconditions: 674 // mRecordSource is valid 675 // mAudioFormat is valid 676 // mSampleRate is valid audioParamCheck(int audioSource, int sampleRateInHz, int audioFormat)677 private void audioParamCheck(int audioSource, int sampleRateInHz, int audioFormat) 678 throws IllegalArgumentException { 679 680 //-------------- 681 // audio source 682 if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) || 683 ((audioSource > MediaRecorder.getAudioSourceMax()) && 684 (audioSource != MediaRecorder.AudioSource.RADIO_TUNER) && 685 (audioSource != MediaRecorder.AudioSource.HOTWORD)) ) { 686 throw new IllegalArgumentException("Invalid audio source " + audioSource); 687 } 688 mRecordSource = audioSource; 689 690 //-------------- 691 // sample rate 692 if ((sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN || 693 sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) && 694 sampleRateInHz != AudioFormat.SAMPLE_RATE_UNSPECIFIED) { 695 throw new IllegalArgumentException(sampleRateInHz 696 + "Hz is not a supported sample rate."); 697 } 698 mSampleRate = sampleRateInHz; 699 700 //-------------- 701 // audio format 702 switch (audioFormat) { 703 case AudioFormat.ENCODING_DEFAULT: 704 mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; 705 break; 706 case AudioFormat.ENCODING_PCM_FLOAT: 707 case AudioFormat.ENCODING_PCM_16BIT: 708 case AudioFormat.ENCODING_PCM_8BIT: 709 mAudioFormat = audioFormat; 710 break; 711 default: 712 throw new IllegalArgumentException("Unsupported sample encoding " + audioFormat 713 + ". Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, or ENCODING_PCM_FLOAT."); 714 } 715 } 716 717 718 // Convenience method for the contructor's audio buffer size check. 719 // preconditions: 720 // mChannelCount is valid 721 // mAudioFormat is AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT, 722 // or AudioFormat.ENCODING_PCM_FLOAT 723 // postcondition: 724 // mNativeBufferSizeInBytes is valid (multiple of frame size, positive) audioBuffSizeCheck(int audioBufferSize)725 private void audioBuffSizeCheck(int audioBufferSize) throws IllegalArgumentException { 726 // NB: this section is only valid with PCM data. 727 // To update when supporting compressed formats 728 int frameSizeInBytes = mChannelCount 729 * (AudioFormat.getBytesPerSample(mAudioFormat)); 730 if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) { 731 throw new IllegalArgumentException("Invalid audio buffer size " + audioBufferSize 732 + " (frame size " + frameSizeInBytes + ")"); 733 } 734 735 mNativeBufferSizeInBytes = audioBufferSize; 736 } 737 738 739 740 /** 741 * Releases the native AudioRecord resources. 742 * The object can no longer be used and the reference should be set to null 743 * after a call to release() 744 */ release()745 public void release() { 746 try { 747 stop(); 748 } catch(IllegalStateException ise) { 749 // don't raise an exception, we're releasing the resources. 750 } 751 native_release(); 752 mState = STATE_UNINITIALIZED; 753 } 754 755 756 @Override finalize()757 protected void finalize() { 758 // will cause stop() to be called, and if appropriate, will handle fixed volume recording 759 release(); 760 } 761 762 763 //-------------------------------------------------------------------------- 764 // Getters 765 //-------------------- 766 /** 767 * Returns the configured audio sink sample rate in Hz. 768 * The sink sample rate never changes after construction. 769 * If the constructor had a specific sample rate, then the sink sample rate is that value. 770 * If the constructor had {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}, 771 * then the sink sample rate is a route-dependent default value based on the source [sic]. 772 */ getSampleRate()773 public int getSampleRate() { 774 return mSampleRate; 775 } 776 777 /** 778 * Returns the audio recording source. 779 * @see MediaRecorder.AudioSource 780 */ getAudioSource()781 public int getAudioSource() { 782 return mRecordSource; 783 } 784 785 /** 786 * Returns the configured audio data encoding. See {@link AudioFormat#ENCODING_PCM_8BIT}, 787 * {@link AudioFormat#ENCODING_PCM_16BIT}, and {@link AudioFormat#ENCODING_PCM_FLOAT}. 788 */ getAudioFormat()789 public int getAudioFormat() { 790 return mAudioFormat; 791 } 792 793 /** 794 * Returns the configured channel position mask. 795 * <p> See {@link AudioFormat#CHANNEL_IN_MONO} 796 * and {@link AudioFormat#CHANNEL_IN_STEREO}. 797 * This method may return {@link AudioFormat#CHANNEL_INVALID} if 798 * a channel index mask is used. 799 * Consider {@link #getFormat()} instead, to obtain an {@link AudioFormat}, 800 * which contains both the channel position mask and the channel index mask. 801 */ getChannelConfiguration()802 public int getChannelConfiguration() { 803 return mChannelMask; 804 } 805 806 /** 807 * Returns the configured <code>AudioRecord</code> format. 808 * @return an {@link AudioFormat} containing the 809 * <code>AudioRecord</code> parameters at the time of configuration. 810 */ getFormat()811 public @NonNull AudioFormat getFormat() { 812 AudioFormat.Builder builder = new AudioFormat.Builder() 813 .setSampleRate(mSampleRate) 814 .setEncoding(mAudioFormat); 815 if (mChannelMask != AudioFormat.CHANNEL_INVALID) { 816 builder.setChannelMask(mChannelMask); 817 } 818 if (mChannelIndexMask != AudioFormat.CHANNEL_INVALID /* 0 */) { 819 builder.setChannelIndexMask(mChannelIndexMask); 820 } 821 return builder.build(); 822 } 823 824 /** 825 * Returns the configured number of channels. 826 */ getChannelCount()827 public int getChannelCount() { 828 return mChannelCount; 829 } 830 831 /** 832 * Returns the state of the AudioRecord instance. This is useful after the 833 * AudioRecord instance has been created to check if it was initialized 834 * properly. This ensures that the appropriate hardware resources have been 835 * acquired. 836 * @see AudioRecord#STATE_INITIALIZED 837 * @see AudioRecord#STATE_UNINITIALIZED 838 */ getState()839 public int getState() { 840 return mState; 841 } 842 843 /** 844 * Returns the recording state of the AudioRecord instance. 845 * @see AudioRecord#RECORDSTATE_STOPPED 846 * @see AudioRecord#RECORDSTATE_RECORDING 847 */ getRecordingState()848 public int getRecordingState() { 849 synchronized (mRecordingStateLock) { 850 return mRecordingState; 851 } 852 } 853 854 /** 855 * Returns the frame count of the native <code>AudioRecord</code> buffer. 856 * This is greater than or equal to the bufferSizeInBytes converted to frame units 857 * specified in the <code>AudioRecord</code> constructor or Builder. 858 * The native frame count may be enlarged to accommodate the requirements of the 859 * source on creation or if the <code>AudioRecord</code> 860 * is subsequently rerouted. 861 * @return current size in frames of the <code>AudioRecord</code> buffer. 862 * @throws IllegalStateException 863 */ getBufferSizeInFrames()864 public int getBufferSizeInFrames() { 865 return native_get_buffer_size_in_frames(); 866 } 867 868 /** 869 * Returns the notification marker position expressed in frames. 870 */ getNotificationMarkerPosition()871 public int getNotificationMarkerPosition() { 872 return native_get_marker_pos(); 873 } 874 875 /** 876 * Returns the notification update period expressed in frames. 877 */ getPositionNotificationPeriod()878 public int getPositionNotificationPeriod() { 879 return native_get_pos_update_period(); 880 } 881 882 /** 883 * Poll for an {@link AudioTimestamp} on demand. 884 * <p> 885 * The AudioTimestamp reflects the frame delivery information at 886 * the earliest point available in the capture pipeline. 887 * <p> 888 * Calling {@link #startRecording()} following a {@link #stop()} will reset 889 * the frame count to 0. 890 * 891 * @param outTimestamp a caller provided non-null AudioTimestamp instance, 892 * which is updated with the AudioRecord frame delivery information upon success. 893 * @param timebase one of 894 * {@link AudioTimestamp#TIMEBASE_BOOTTIME AudioTimestamp.TIMEBASE_BOOTTIME} or 895 * {@link AudioTimestamp#TIMEBASE_MONOTONIC AudioTimestamp.TIMEBASE_MONOTONIC}, 896 * used to select the clock for the AudioTimestamp time. 897 * @return {@link #SUCCESS} if a timestamp is available, 898 * or {@link #ERROR_INVALID_OPERATION} if a timestamp not available. 899 */ getTimestamp(@onNull AudioTimestamp outTimestamp, @AudioTimestamp.Timebase int timebase)900 public int getTimestamp(@NonNull AudioTimestamp outTimestamp, 901 @AudioTimestamp.Timebase int timebase) 902 { 903 if (outTimestamp == null || 904 (timebase != AudioTimestamp.TIMEBASE_BOOTTIME 905 && timebase != AudioTimestamp.TIMEBASE_MONOTONIC)) { 906 throw new IllegalArgumentException(); 907 } 908 return native_get_timestamp(outTimestamp, timebase); 909 } 910 911 /** 912 * Returns the minimum buffer size required for the successful creation of an AudioRecord 913 * object, in byte units. 914 * Note that this size doesn't guarantee a smooth recording under load, and higher values 915 * should be chosen according to the expected frequency at which the AudioRecord instance 916 * will be polled for new data. 917 * See {@link #AudioRecord(int, int, int, int, int)} for more information on valid 918 * configuration values. 919 * @param sampleRateInHz the sample rate expressed in Hertz. 920 * {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED} is not permitted. 921 * @param channelConfig describes the configuration of the audio channels. 922 * See {@link AudioFormat#CHANNEL_IN_MONO} and 923 * {@link AudioFormat#CHANNEL_IN_STEREO} 924 * @param audioFormat the format in which the audio data is represented. 925 * See {@link AudioFormat#ENCODING_PCM_16BIT}. 926 * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the 927 * hardware, or an invalid parameter was passed, 928 * or {@link #ERROR} if the implementation was unable to query the hardware for its 929 * input properties, 930 * or the minimum buffer size expressed in bytes. 931 * @see #AudioRecord(int, int, int, int, int) 932 */ getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)933 static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { 934 int channelCount = 0; 935 switch (channelConfig) { 936 case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT 937 case AudioFormat.CHANNEL_IN_MONO: 938 case AudioFormat.CHANNEL_CONFIGURATION_MONO: 939 channelCount = 1; 940 break; 941 case AudioFormat.CHANNEL_IN_STEREO: 942 case AudioFormat.CHANNEL_CONFIGURATION_STEREO: 943 case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK): 944 channelCount = 2; 945 break; 946 case AudioFormat.CHANNEL_INVALID: 947 default: 948 loge("getMinBufferSize(): Invalid channel configuration."); 949 return ERROR_BAD_VALUE; 950 } 951 952 int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat); 953 if (size == 0) { 954 return ERROR_BAD_VALUE; 955 } 956 else if (size == -1) { 957 return ERROR; 958 } 959 else { 960 return size; 961 } 962 } 963 964 /** 965 * Returns the audio session ID. 966 * 967 * @return the ID of the audio session this AudioRecord belongs to. 968 */ getAudioSessionId()969 public int getAudioSessionId() { 970 return mSessionId; 971 } 972 973 //--------------------------------------------------------- 974 // Transport control methods 975 //-------------------- 976 /** 977 * Starts recording from the AudioRecord instance. 978 * @throws IllegalStateException 979 */ startRecording()980 public void startRecording() 981 throws IllegalStateException { 982 if (mState != STATE_INITIALIZED) { 983 throw new IllegalStateException("startRecording() called on an " 984 + "uninitialized AudioRecord."); 985 } 986 987 // start recording 988 synchronized(mRecordingStateLock) { 989 if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) { 990 handleFullVolumeRec(true); 991 mRecordingState = RECORDSTATE_RECORDING; 992 } 993 } 994 } 995 996 /** 997 * Starts recording from the AudioRecord instance when the specified synchronization event 998 * occurs on the specified audio session. 999 * @throws IllegalStateException 1000 * @param syncEvent event that triggers the capture. 1001 * @see MediaSyncEvent 1002 */ startRecording(MediaSyncEvent syncEvent)1003 public void startRecording(MediaSyncEvent syncEvent) 1004 throws IllegalStateException { 1005 if (mState != STATE_INITIALIZED) { 1006 throw new IllegalStateException("startRecording() called on an " 1007 + "uninitialized AudioRecord."); 1008 } 1009 1010 // start recording 1011 synchronized(mRecordingStateLock) { 1012 if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) { 1013 handleFullVolumeRec(true); 1014 mRecordingState = RECORDSTATE_RECORDING; 1015 } 1016 } 1017 } 1018 1019 /** 1020 * Stops recording. 1021 * @throws IllegalStateException 1022 */ stop()1023 public void stop() 1024 throws IllegalStateException { 1025 if (mState != STATE_INITIALIZED) { 1026 throw new IllegalStateException("stop() called on an uninitialized AudioRecord."); 1027 } 1028 1029 // stop recording 1030 synchronized(mRecordingStateLock) { 1031 handleFullVolumeRec(false); 1032 native_stop(); 1033 mRecordingState = RECORDSTATE_STOPPED; 1034 } 1035 } 1036 1037 private final IBinder mICallBack = new Binder(); handleFullVolumeRec(boolean starting)1038 private void handleFullVolumeRec(boolean starting) { 1039 if (!mIsSubmixFullVolume) { 1040 return; 1041 } 1042 final IBinder b = ServiceManager.getService(android.content.Context.AUDIO_SERVICE); 1043 final IAudioService ias = IAudioService.Stub.asInterface(b); 1044 try { 1045 ias.forceRemoteSubmixFullVolume(starting, mICallBack); 1046 } catch (RemoteException e) { 1047 Log.e(TAG, "Error talking to AudioService when handling full submix volume", e); 1048 } 1049 } 1050 1051 //--------------------------------------------------------- 1052 // Audio data supply 1053 //-------------------- 1054 /** 1055 * Reads audio data from the audio hardware for recording into a byte array. 1056 * The format specified in the AudioRecord constructor should be 1057 * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array. 1058 * @param audioData the array to which the recorded audio data is written. 1059 * @param offsetInBytes index in audioData from which the data is written expressed in bytes. 1060 * @param sizeInBytes the number of requested bytes. 1061 * @return zero or the positive number of bytes that were read, or one of the following 1062 * error codes. The number of bytes will not exceed sizeInBytes. 1063 * <ul> 1064 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1065 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1066 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1067 * needs to be recreated. The dead object error code is not returned if some data was 1068 * successfully transferred. In this case, the error is returned at the next read()</li> 1069 * <li>{@link #ERROR} in case of other error</li> 1070 * </ul> 1071 */ read(@onNull byte[] audioData, int offsetInBytes, int sizeInBytes)1072 public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) { 1073 return read(audioData, offsetInBytes, sizeInBytes, READ_BLOCKING); 1074 } 1075 1076 /** 1077 * Reads audio data from the audio hardware for recording into a byte array. 1078 * The format specified in the AudioRecord constructor should be 1079 * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array. 1080 * The format can be {@link AudioFormat#ENCODING_PCM_16BIT}, but this is deprecated. 1081 * @param audioData the array to which the recorded audio data is written. 1082 * @param offsetInBytes index in audioData to which the data is written expressed in bytes. 1083 * Must not be negative, or cause the data access to go out of bounds of the array. 1084 * @param sizeInBytes the number of requested bytes. 1085 * Must not be negative, or cause the data access to go out of bounds of the array. 1086 * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}. 1087 * <br>With {@link #READ_BLOCKING}, the read will block until all the requested data 1088 * is read. 1089 * <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after 1090 * reading as much audio data as possible without blocking. 1091 * @return zero or the positive number of bytes that were read, or one of the following 1092 * error codes. The number of bytes will be a multiple of the frame size in bytes 1093 * not to exceed sizeInBytes. 1094 * <ul> 1095 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1096 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1097 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1098 * needs to be recreated. The dead object error code is not returned if some data was 1099 * successfully transferred. In this case, the error is returned at the next read()</li> 1100 * <li>{@link #ERROR} in case of other error</li> 1101 * </ul> 1102 */ read(@onNull byte[] audioData, int offsetInBytes, int sizeInBytes, @ReadMode int readMode)1103 public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes, 1104 @ReadMode int readMode) { 1105 if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { 1106 return ERROR_INVALID_OPERATION; 1107 } 1108 1109 if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) { 1110 Log.e(TAG, "AudioRecord.read() called with invalid blocking mode"); 1111 return ERROR_BAD_VALUE; 1112 } 1113 1114 if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0) 1115 || (offsetInBytes + sizeInBytes < 0) // detect integer overflow 1116 || (offsetInBytes + sizeInBytes > audioData.length)) { 1117 return ERROR_BAD_VALUE; 1118 } 1119 1120 return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes, 1121 readMode == READ_BLOCKING); 1122 } 1123 1124 /** 1125 * Reads audio data from the audio hardware for recording into a short array. 1126 * The format specified in the AudioRecord constructor should be 1127 * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array. 1128 * @param audioData the array to which the recorded audio data is written. 1129 * @param offsetInShorts index in audioData to which the data is written expressed in shorts. 1130 * Must not be negative, or cause the data access to go out of bounds of the array. 1131 * @param sizeInShorts the number of requested shorts. 1132 * Must not be negative, or cause the data access to go out of bounds of the array. 1133 * @return zero or the positive number of shorts that were read, or one of the following 1134 * error codes. The number of shorts will be a multiple of the channel count not to exceed 1135 * sizeInShorts. 1136 * <ul> 1137 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1138 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1139 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1140 * needs to be recreated. The dead object error code is not returned if some data was 1141 * successfully transferred. In this case, the error is returned at the next read()</li> 1142 * <li>{@link #ERROR} in case of other error</li> 1143 * </ul> 1144 */ read(@onNull short[] audioData, int offsetInShorts, int sizeInShorts)1145 public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) { 1146 return read(audioData, offsetInShorts, sizeInShorts, READ_BLOCKING); 1147 } 1148 1149 /** 1150 * Reads audio data from the audio hardware for recording into a short array. 1151 * The format specified in the AudioRecord constructor should be 1152 * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array. 1153 * @param audioData the array to which the recorded audio data is written. 1154 * @param offsetInShorts index in audioData from which the data is written expressed in shorts. 1155 * Must not be negative, or cause the data access to go out of bounds of the array. 1156 * @param sizeInShorts the number of requested shorts. 1157 * Must not be negative, or cause the data access to go out of bounds of the array. 1158 * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}. 1159 * <br>With {@link #READ_BLOCKING}, the read will block until all the requested data 1160 * is read. 1161 * <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after 1162 * reading as much audio data as possible without blocking. 1163 * @return zero or the positive number of shorts that were read, or one of the following 1164 * error codes. The number of shorts will be a multiple of the channel count not to exceed 1165 * sizeInShorts. 1166 * <ul> 1167 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1168 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1169 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1170 * needs to be recreated. The dead object error code is not returned if some data was 1171 * successfully transferred. In this case, the error is returned at the next read()</li> 1172 * <li>{@link #ERROR} in case of other error</li> 1173 * </ul> 1174 */ read(@onNull short[] audioData, int offsetInShorts, int sizeInShorts, @ReadMode int readMode)1175 public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts, 1176 @ReadMode int readMode) { 1177 if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { 1178 return ERROR_INVALID_OPERATION; 1179 } 1180 1181 if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) { 1182 Log.e(TAG, "AudioRecord.read() called with invalid blocking mode"); 1183 return ERROR_BAD_VALUE; 1184 } 1185 1186 if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0) 1187 || (offsetInShorts + sizeInShorts < 0) // detect integer overflow 1188 || (offsetInShorts + sizeInShorts > audioData.length)) { 1189 return ERROR_BAD_VALUE; 1190 } 1191 1192 return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts, 1193 readMode == READ_BLOCKING); 1194 } 1195 1196 /** 1197 * Reads audio data from the audio hardware for recording into a float array. 1198 * The format specified in the AudioRecord constructor should be 1199 * {@link AudioFormat#ENCODING_PCM_FLOAT} to correspond to the data in the array. 1200 * @param audioData the array to which the recorded audio data is written. 1201 * @param offsetInFloats index in audioData from which the data is written. 1202 * Must not be negative, or cause the data access to go out of bounds of the array. 1203 * @param sizeInFloats the number of requested floats. 1204 * Must not be negative, or cause the data access to go out of bounds of the array. 1205 * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}. 1206 * <br>With {@link #READ_BLOCKING}, the read will block until all the requested data 1207 * is read. 1208 * <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after 1209 * reading as much audio data as possible without blocking. 1210 * @return zero or the positive number of floats that were read, or one of the following 1211 * error codes. The number of floats will be a multiple of the channel count not to exceed 1212 * sizeInFloats. 1213 * <ul> 1214 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1215 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1216 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1217 * needs to be recreated. The dead object error code is not returned if some data was 1218 * successfully transferred. In this case, the error is returned at the next read()</li> 1219 * <li>{@link #ERROR} in case of other error</li> 1220 * </ul> 1221 */ read(@onNull float[] audioData, int offsetInFloats, int sizeInFloats, @ReadMode int readMode)1222 public int read(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats, 1223 @ReadMode int readMode) { 1224 if (mState == STATE_UNINITIALIZED) { 1225 Log.e(TAG, "AudioRecord.read() called in invalid state STATE_UNINITIALIZED"); 1226 return ERROR_INVALID_OPERATION; 1227 } 1228 1229 if (mAudioFormat != AudioFormat.ENCODING_PCM_FLOAT) { 1230 Log.e(TAG, "AudioRecord.read(float[] ...) requires format ENCODING_PCM_FLOAT"); 1231 return ERROR_INVALID_OPERATION; 1232 } 1233 1234 if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) { 1235 Log.e(TAG, "AudioRecord.read() called with invalid blocking mode"); 1236 return ERROR_BAD_VALUE; 1237 } 1238 1239 if ((audioData == null) || (offsetInFloats < 0) || (sizeInFloats < 0) 1240 || (offsetInFloats + sizeInFloats < 0) // detect integer overflow 1241 || (offsetInFloats + sizeInFloats > audioData.length)) { 1242 return ERROR_BAD_VALUE; 1243 } 1244 1245 return native_read_in_float_array(audioData, offsetInFloats, sizeInFloats, 1246 readMode == READ_BLOCKING); 1247 } 1248 1249 /** 1250 * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer 1251 * is not a direct buffer, this method will always return 0. 1252 * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is 1253 * unchanged after a call to this method. 1254 * The representation of the data in the buffer will depend on the format specified in 1255 * the AudioRecord constructor, and will be native endian. 1256 * @param audioBuffer the direct buffer to which the recorded audio data is written. 1257 * Data is written to audioBuffer.position(). 1258 * @param sizeInBytes the number of requested bytes. It is recommended but not enforced 1259 * that the number of bytes requested be a multiple of the frame size (sample size in 1260 * bytes multiplied by the channel count). 1261 * @return zero or the positive number of bytes that were read, or one of the following 1262 * error codes. The number of bytes will not exceed sizeInBytes and will be truncated to be 1263 * a multiple of the frame size. 1264 * <ul> 1265 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1266 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1267 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1268 * needs to be recreated. The dead object error code is not returned if some data was 1269 * successfully transferred. In this case, the error is returned at the next read()</li> 1270 * <li>{@link #ERROR} in case of other error</li> 1271 * </ul> 1272 */ read(@onNull ByteBuffer audioBuffer, int sizeInBytes)1273 public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes) { 1274 return read(audioBuffer, sizeInBytes, READ_BLOCKING); 1275 } 1276 1277 /** 1278 * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer 1279 * is not a direct buffer, this method will always return 0. 1280 * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is 1281 * unchanged after a call to this method. 1282 * The representation of the data in the buffer will depend on the format specified in 1283 * the AudioRecord constructor, and will be native endian. 1284 * @param audioBuffer the direct buffer to which the recorded audio data is written. 1285 * Data is written to audioBuffer.position(). 1286 * @param sizeInBytes the number of requested bytes. It is recommended but not enforced 1287 * that the number of bytes requested be a multiple of the frame size (sample size in 1288 * bytes multiplied by the channel count). 1289 * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}. 1290 * <br>With {@link #READ_BLOCKING}, the read will block until all the requested data 1291 * is read. 1292 * <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after 1293 * reading as much audio data as possible without blocking. 1294 * @return zero or the positive number of bytes that were read, or one of the following 1295 * error codes. The number of bytes will not exceed sizeInBytes and will be truncated to be 1296 * a multiple of the frame size. 1297 * <ul> 1298 * <li>{@link #ERROR_INVALID_OPERATION} if the object isn't properly initialized</li> 1299 * <li>{@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes</li> 1300 * <li>{@link #ERROR_DEAD_OBJECT} if the object is not valid anymore and 1301 * needs to be recreated. The dead object error code is not returned if some data was 1302 * successfully transferred. In this case, the error is returned at the next read()</li> 1303 * <li>{@link #ERROR} in case of other error</li> 1304 * </ul> 1305 */ read(@onNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode)1306 public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode) { 1307 if (mState != STATE_INITIALIZED) { 1308 return ERROR_INVALID_OPERATION; 1309 } 1310 1311 if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) { 1312 Log.e(TAG, "AudioRecord.read() called with invalid blocking mode"); 1313 return ERROR_BAD_VALUE; 1314 } 1315 1316 if ( (audioBuffer == null) || (sizeInBytes < 0) ) { 1317 return ERROR_BAD_VALUE; 1318 } 1319 1320 return native_read_in_direct_buffer(audioBuffer, sizeInBytes, readMode == READ_BLOCKING); 1321 } 1322 1323 /** 1324 * Return Metrics data about the current AudioTrack instance. 1325 * 1326 * @return a {@link PersistableBundle} containing the set of attributes and values 1327 * available for the media being handled by this instance of AudioRecord 1328 * The attributes are descibed in {@link MetricsConstants}. 1329 * 1330 * Additional vendor-specific fields may also be present in 1331 * the return value. 1332 */ getMetrics()1333 public PersistableBundle getMetrics() { 1334 PersistableBundle bundle = native_getMetrics(); 1335 return bundle; 1336 } 1337 native_getMetrics()1338 private native PersistableBundle native_getMetrics(); 1339 1340 //-------------------------------------------------------------------------- 1341 // Initialization / configuration 1342 //-------------------- 1343 /** 1344 * Sets the listener the AudioRecord notifies when a previously set marker is reached or 1345 * for each periodic record head position update. 1346 * @param listener 1347 */ setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener)1348 public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener) { 1349 setRecordPositionUpdateListener(listener, null); 1350 } 1351 1352 /** 1353 * Sets the listener the AudioRecord notifies when a previously set marker is reached or 1354 * for each periodic record head position update. 1355 * Use this method to receive AudioRecord events in the Handler associated with another 1356 * thread than the one in which you created the AudioRecord instance. 1357 * @param listener 1358 * @param handler the Handler that will receive the event notification messages. 1359 */ setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, Handler handler)1360 public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, 1361 Handler handler) { 1362 synchronized (mPositionListenerLock) { 1363 1364 mPositionListener = listener; 1365 1366 if (listener != null) { 1367 if (handler != null) { 1368 mEventHandler = new NativeEventHandler(this, handler.getLooper()); 1369 } else { 1370 // no given handler, use the looper the AudioRecord was created in 1371 mEventHandler = new NativeEventHandler(this, mInitializationLooper); 1372 } 1373 } else { 1374 mEventHandler = null; 1375 } 1376 } 1377 1378 } 1379 1380 1381 /** 1382 * Sets the marker position at which the listener is called, if set with 1383 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or 1384 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}. 1385 * @param markerInFrames marker position expressed in frames 1386 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, 1387 * {@link #ERROR_INVALID_OPERATION} 1388 */ setNotificationMarkerPosition(int markerInFrames)1389 public int setNotificationMarkerPosition(int markerInFrames) { 1390 if (mState == STATE_UNINITIALIZED) { 1391 return ERROR_INVALID_OPERATION; 1392 } 1393 return native_set_marker_pos(markerInFrames); 1394 } 1395 1396 /** 1397 * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord. 1398 * Note: The query is only valid if the AudioRecord is currently recording. If it is not, 1399 * <code>getRoutedDevice()</code> will return null. 1400 */ 1401 @Override getRoutedDevice()1402 public AudioDeviceInfo getRoutedDevice() { 1403 int deviceId = native_getRoutedDeviceId(); 1404 if (deviceId == 0) { 1405 return null; 1406 } 1407 AudioDeviceInfo[] devices = 1408 AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_INPUTS); 1409 for (int i = 0; i < devices.length; i++) { 1410 if (devices[i].getId() == deviceId) { 1411 return devices[i]; 1412 } 1413 } 1414 return null; 1415 } 1416 1417 /* 1418 * Call BEFORE adding a routing callback handler. 1419 */ 1420 @GuardedBy("mRoutingChangeListeners") testEnableNativeRoutingCallbacksLocked()1421 private void testEnableNativeRoutingCallbacksLocked() { 1422 if (mRoutingChangeListeners.size() == 0) { 1423 native_enableDeviceCallback(); 1424 } 1425 } 1426 1427 /* 1428 * Call AFTER removing a routing callback handler. 1429 */ 1430 @GuardedBy("mRoutingChangeListeners") testDisableNativeRoutingCallbacksLocked()1431 private void testDisableNativeRoutingCallbacksLocked() { 1432 if (mRoutingChangeListeners.size() == 0) { 1433 native_disableDeviceCallback(); 1434 } 1435 } 1436 1437 //-------------------------------------------------------------------------- 1438 // (Re)Routing Info 1439 //-------------------- 1440 /** 1441 * The list of AudioRouting.OnRoutingChangedListener interfaces added (with 1442 * {@link AudioRecord#addOnRoutingChangedListener} by an app to receive 1443 * (re)routing notifications. 1444 */ 1445 @GuardedBy("mRoutingChangeListeners") 1446 private ArrayMap<AudioRouting.OnRoutingChangedListener, 1447 NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>(); 1448 1449 /** 1450 * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of 1451 * routing changes on this AudioRecord. 1452 * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive 1453 * notifications of rerouting events. 1454 * @param handler Specifies the {@link Handler} object for the thread on which to execute 1455 * the callback. If <code>null</code>, the {@link Handler} associated with the main 1456 * {@link Looper} will be used. 1457 */ 1458 @Override addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, android.os.Handler handler)1459 public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, 1460 android.os.Handler handler) { 1461 synchronized (mRoutingChangeListeners) { 1462 if (listener != null && !mRoutingChangeListeners.containsKey(listener)) { 1463 testEnableNativeRoutingCallbacksLocked(); 1464 mRoutingChangeListeners.put( 1465 listener, new NativeRoutingEventHandlerDelegate(this, listener, 1466 handler != null ? handler : new Handler(mInitializationLooper))); 1467 } 1468 } 1469 } 1470 1471 /** 1472 * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added 1473 * to receive rerouting notifications. 1474 * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface 1475 * to remove. 1476 */ 1477 @Override removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener)1478 public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) { 1479 synchronized (mRoutingChangeListeners) { 1480 if (mRoutingChangeListeners.containsKey(listener)) { 1481 mRoutingChangeListeners.remove(listener); 1482 testDisableNativeRoutingCallbacksLocked(); 1483 } 1484 } 1485 } 1486 1487 //-------------------------------------------------------------------------- 1488 // (Re)Routing Info 1489 //-------------------- 1490 /** 1491 * Defines the interface by which applications can receive notifications of 1492 * routing changes for the associated {@link AudioRecord}. 1493 * 1494 * @deprecated users should switch to the general purpose 1495 * {@link AudioRouting.OnRoutingChangedListener} class instead. 1496 */ 1497 @Deprecated 1498 public interface OnRoutingChangedListener extends AudioRouting.OnRoutingChangedListener { 1499 /** 1500 * Called when the routing of an AudioRecord changes from either and 1501 * explicit or policy rerouting. Use {@link #getRoutedDevice()} to 1502 * retrieve the newly routed-from device. 1503 */ onRoutingChanged(AudioRecord audioRecord)1504 public void onRoutingChanged(AudioRecord audioRecord); 1505 1506 @Override onRoutingChanged(AudioRouting router)1507 default public void onRoutingChanged(AudioRouting router) { 1508 if (router instanceof AudioRecord) { 1509 onRoutingChanged((AudioRecord) router); 1510 } 1511 } 1512 } 1513 1514 /** 1515 * Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes 1516 * on this AudioRecord. 1517 * @param listener The {@link OnRoutingChangedListener} interface to receive notifications 1518 * of rerouting events. 1519 * @param handler Specifies the {@link Handler} object for the thread on which to execute 1520 * the callback. If <code>null</code>, the {@link Handler} associated with the main 1521 * {@link Looper} will be used. 1522 * @deprecated users should switch to the general purpose 1523 * {@link AudioRouting.OnRoutingChangedListener} class instead. 1524 */ 1525 @Deprecated addOnRoutingChangedListener(OnRoutingChangedListener listener, android.os.Handler handler)1526 public void addOnRoutingChangedListener(OnRoutingChangedListener listener, 1527 android.os.Handler handler) { 1528 addOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener, handler); 1529 } 1530 1531 /** 1532 * Removes an {@link OnRoutingChangedListener} which has been previously added 1533 * to receive rerouting notifications. 1534 * @param listener The previously added {@link OnRoutingChangedListener} interface to remove. 1535 * @deprecated users should switch to the general purpose 1536 * {@link AudioRouting.OnRoutingChangedListener} class instead. 1537 */ 1538 @Deprecated removeOnRoutingChangedListener(OnRoutingChangedListener listener)1539 public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) { 1540 removeOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener); 1541 } 1542 1543 /** 1544 * Sends device list change notification to all listeners. 1545 */ broadcastRoutingChange()1546 private void broadcastRoutingChange() { 1547 AudioManager.resetAudioPortGeneration(); 1548 synchronized (mRoutingChangeListeners) { 1549 for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) { 1550 delegate.notifyClient(); 1551 } 1552 } 1553 } 1554 1555 /** 1556 * Sets the period at which the listener is called, if set with 1557 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or 1558 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}. 1559 * It is possible for notifications to be lost if the period is too small. 1560 * @param periodInFrames update period expressed in frames 1561 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION} 1562 */ setPositionNotificationPeriod(int periodInFrames)1563 public int setPositionNotificationPeriod(int periodInFrames) { 1564 if (mState == STATE_UNINITIALIZED) { 1565 return ERROR_INVALID_OPERATION; 1566 } 1567 return native_set_pos_update_period(periodInFrames); 1568 } 1569 1570 //-------------------------------------------------------------------------- 1571 // Explicit Routing 1572 //-------------------- 1573 private AudioDeviceInfo mPreferredDevice = null; 1574 1575 /** 1576 * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route 1577 * the input to this AudioRecord. 1578 * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio source. 1579 * If deviceInfo is null, default routing is restored. 1580 * @return true if successful, false if the specified {@link AudioDeviceInfo} is non-null and 1581 * does not correspond to a valid audio input device. 1582 */ 1583 @Override setPreferredDevice(AudioDeviceInfo deviceInfo)1584 public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) { 1585 // Do some validation.... 1586 if (deviceInfo != null && !deviceInfo.isSource()) { 1587 return false; 1588 } 1589 1590 int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0; 1591 boolean status = native_setInputDevice(preferredDeviceId); 1592 if (status == true) { 1593 synchronized (this) { 1594 mPreferredDevice = deviceInfo; 1595 } 1596 } 1597 return status; 1598 } 1599 1600 /** 1601 * Returns the selected input specified by {@link #setPreferredDevice}. Note that this 1602 * is not guarenteed to correspond to the actual device being used for recording. 1603 */ 1604 @Override getPreferredDevice()1605 public AudioDeviceInfo getPreferredDevice() { 1606 synchronized (this) { 1607 return mPreferredDevice; 1608 } 1609 } 1610 1611 //-------------------------------------------------------------------------- 1612 // Microphone information 1613 //-------------------- 1614 /** 1615 * Returns a lists of {@link MicrophoneInfo} representing the active microphones. 1616 * By querying channel mapping for each active microphone, developer can know how 1617 * the microphone is used by each channels or a capture stream. 1618 * Note that the information about the active microphones may change during a recording. 1619 * See {@link AudioManager#registerAudioDeviceCallback} to be notified of changes 1620 * in the audio devices, querying the active microphones then will return the latest 1621 * information. 1622 * 1623 * @return a lists of {@link MicrophoneInfo} representing the active microphones. 1624 * @throws IOException if an error occurs 1625 */ getActiveMicrophones()1626 public List<MicrophoneInfo> getActiveMicrophones() throws IOException { 1627 ArrayList<MicrophoneInfo> activeMicrophones = new ArrayList<>(); 1628 int status = native_get_active_microphones(activeMicrophones); 1629 if (status != AudioManager.SUCCESS) { 1630 if (status != AudioManager.ERROR_INVALID_OPERATION) { 1631 Log.e(TAG, "getActiveMicrophones failed:" + status); 1632 } 1633 Log.i(TAG, "getActiveMicrophones failed, fallback on routed device info"); 1634 } 1635 AudioManager.setPortIdForMicrophones(activeMicrophones); 1636 1637 // Use routed device when there is not information returned by hal. 1638 if (activeMicrophones.size() == 0) { 1639 AudioDeviceInfo device = getRoutedDevice(); 1640 if (device != null) { 1641 MicrophoneInfo microphone = AudioManager.microphoneInfoFromAudioDeviceInfo(device); 1642 ArrayList<Pair<Integer, Integer>> channelMapping = new ArrayList<>(); 1643 for (int i = 0; i < mChannelCount; i++) { 1644 channelMapping.add(new Pair(i, MicrophoneInfo.CHANNEL_MAPPING_DIRECT)); 1645 } 1646 microphone.setChannelMapping(channelMapping); 1647 activeMicrophones.add(microphone); 1648 } 1649 } 1650 return activeMicrophones; 1651 } 1652 1653 //--------------------------------------------------------- 1654 // Interface definitions 1655 //-------------------- 1656 /** 1657 * Interface definition for a callback to be invoked when an AudioRecord has 1658 * reached a notification marker set by {@link AudioRecord#setNotificationMarkerPosition(int)} 1659 * or for periodic updates on the progress of the record head, as set by 1660 * {@link AudioRecord#setPositionNotificationPeriod(int)}. 1661 */ 1662 public interface OnRecordPositionUpdateListener { 1663 /** 1664 * Called on the listener to notify it that the previously set marker has been reached 1665 * by the recording head. 1666 */ onMarkerReached(AudioRecord recorder)1667 void onMarkerReached(AudioRecord recorder); 1668 1669 /** 1670 * Called on the listener to periodically notify it that the record head has reached 1671 * a multiple of the notification period. 1672 */ onPeriodicNotification(AudioRecord recorder)1673 void onPeriodicNotification(AudioRecord recorder); 1674 } 1675 1676 1677 1678 //--------------------------------------------------------- 1679 // Inner classes 1680 //-------------------- 1681 1682 /** 1683 * Helper class to handle the forwarding of native events to the appropriate listener 1684 * (potentially) handled in a different thread 1685 */ 1686 private class NativeEventHandler extends Handler { 1687 private final AudioRecord mAudioRecord; 1688 NativeEventHandler(AudioRecord recorder, Looper looper)1689 NativeEventHandler(AudioRecord recorder, Looper looper) { 1690 super(looper); 1691 mAudioRecord = recorder; 1692 } 1693 1694 @Override handleMessage(Message msg)1695 public void handleMessage(Message msg) { 1696 OnRecordPositionUpdateListener listener = null; 1697 synchronized (mPositionListenerLock) { 1698 listener = mAudioRecord.mPositionListener; 1699 } 1700 1701 switch (msg.what) { 1702 case NATIVE_EVENT_MARKER: 1703 if (listener != null) { 1704 listener.onMarkerReached(mAudioRecord); 1705 } 1706 break; 1707 case NATIVE_EVENT_NEW_POS: 1708 if (listener != null) { 1709 listener.onPeriodicNotification(mAudioRecord); 1710 } 1711 break; 1712 default: 1713 loge("Unknown native event type: " + msg.what); 1714 break; 1715 } 1716 } 1717 } 1718 1719 //--------------------------------------------------------- 1720 // Java methods called from the native side 1721 //-------------------- 1722 @SuppressWarnings("unused") postEventFromNative(Object audiorecord_ref, int what, int arg1, int arg2, Object obj)1723 private static void postEventFromNative(Object audiorecord_ref, 1724 int what, int arg1, int arg2, Object obj) { 1725 //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2); 1726 AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get(); 1727 if (recorder == null) { 1728 return; 1729 } 1730 1731 if (what == AudioSystem.NATIVE_EVENT_ROUTING_CHANGE) { 1732 recorder.broadcastRoutingChange(); 1733 return; 1734 } 1735 1736 if (recorder.mEventHandler != null) { 1737 Message m = 1738 recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj); 1739 recorder.mEventHandler.sendMessage(m); 1740 } 1741 1742 } 1743 1744 1745 //--------------------------------------------------------- 1746 // Native methods called from the Java side 1747 //-------------------- 1748 native_setup(Object audiorecord_this, Object attributes, int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, int buffSizeInBytes, int[] sessionId, String opPackageName, long nativeRecordInJavaObj)1749 private native final int native_setup(Object audiorecord_this, 1750 Object /*AudioAttributes*/ attributes, 1751 int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, 1752 int buffSizeInBytes, int[] sessionId, String opPackageName, 1753 long nativeRecordInJavaObj); 1754 1755 // TODO remove: implementation calls directly into implementation of native_release() native_finalize()1756 private native final void native_finalize(); 1757 1758 /** 1759 * @hide 1760 */ native_release()1761 public native final void native_release(); 1762 native_start(int syncEvent, int sessionId)1763 private native final int native_start(int syncEvent, int sessionId); 1764 native_stop()1765 private native final void native_stop(); 1766 native_read_in_byte_array(byte[] audioData, int offsetInBytes, int sizeInBytes, boolean isBlocking)1767 private native final int native_read_in_byte_array(byte[] audioData, 1768 int offsetInBytes, int sizeInBytes, boolean isBlocking); 1769 native_read_in_short_array(short[] audioData, int offsetInShorts, int sizeInShorts, boolean isBlocking)1770 private native final int native_read_in_short_array(short[] audioData, 1771 int offsetInShorts, int sizeInShorts, boolean isBlocking); 1772 native_read_in_float_array(float[] audioData, int offsetInFloats, int sizeInFloats, boolean isBlocking)1773 private native final int native_read_in_float_array(float[] audioData, 1774 int offsetInFloats, int sizeInFloats, boolean isBlocking); 1775 native_read_in_direct_buffer(Object jBuffer, int sizeInBytes, boolean isBlocking)1776 private native final int native_read_in_direct_buffer(Object jBuffer, 1777 int sizeInBytes, boolean isBlocking); 1778 native_get_buffer_size_in_frames()1779 private native final int native_get_buffer_size_in_frames(); 1780 native_set_marker_pos(int marker)1781 private native final int native_set_marker_pos(int marker); native_get_marker_pos()1782 private native final int native_get_marker_pos(); 1783 native_set_pos_update_period(int updatePeriod)1784 private native final int native_set_pos_update_period(int updatePeriod); native_get_pos_update_period()1785 private native final int native_get_pos_update_period(); 1786 native_get_min_buff_size( int sampleRateInHz, int channelCount, int audioFormat)1787 static private native final int native_get_min_buff_size( 1788 int sampleRateInHz, int channelCount, int audioFormat); 1789 native_setInputDevice(int deviceId)1790 private native final boolean native_setInputDevice(int deviceId); native_getRoutedDeviceId()1791 private native final int native_getRoutedDeviceId(); native_enableDeviceCallback()1792 private native final void native_enableDeviceCallback(); native_disableDeviceCallback()1793 private native final void native_disableDeviceCallback(); 1794 native_get_timestamp(@onNull AudioTimestamp outTimestamp, @AudioTimestamp.Timebase int timebase)1795 private native final int native_get_timestamp(@NonNull AudioTimestamp outTimestamp, 1796 @AudioTimestamp.Timebase int timebase); 1797 native_get_active_microphones( ArrayList<MicrophoneInfo> activeMicrophones)1798 private native final int native_get_active_microphones( 1799 ArrayList<MicrophoneInfo> activeMicrophones); 1800 1801 //--------------------------------------------------------- 1802 // Utility methods 1803 //------------------ 1804 logd(String msg)1805 private static void logd(String msg) { 1806 Log.d(TAG, msg); 1807 } 1808 loge(String msg)1809 private static void loge(String msg) { 1810 Log.e(TAG, msg); 1811 } 1812 1813 public static final class MetricsConstants 1814 { MetricsConstants()1815 private MetricsConstants() {} 1816 1817 /** 1818 * Key to extract the output format being recorded 1819 * from the {@link AudioRecord#getMetrics} return value. 1820 * The value is a String. 1821 */ 1822 public static final String ENCODING = "android.media.audiorecord.encoding"; 1823 1824 /** 1825 * Key to extract the Source Type for this track 1826 * from the {@link AudioRecord#getMetrics} return value. 1827 * The value is a String. 1828 */ 1829 public static final String SOURCE = "android.media.audiorecord.source"; 1830 1831 /** 1832 * Key to extract the estimated latency through the recording pipeline 1833 * from the {@link AudioRecord#getMetrics} return value. 1834 * This is in units of milliseconds. 1835 * The value is an integer. 1836 */ 1837 public static final String LATENCY = "android.media.audiorecord.latency"; 1838 1839 /** 1840 * Key to extract the sink sample rate for this record track in Hz 1841 * from the {@link AudioRecord#getMetrics} return value. 1842 * The value is an integer. 1843 */ 1844 public static final String SAMPLERATE = "android.media.audiorecord.samplerate"; 1845 1846 /** 1847 * Key to extract the number of channels being recorded in this record track 1848 * from the {@link AudioRecord#getMetrics} return value. 1849 * The value is an integer. 1850 */ 1851 public static final String CHANNELS = "android.media.audiorecord.channels"; 1852 1853 } 1854 } 1855