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