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 17package android.media; 18 19import java.lang.ref.WeakReference; 20import java.nio.ByteBuffer; 21import java.util.Iterator; 22 23import android.os.Binder; 24import android.os.Handler; 25import android.os.IBinder; 26import android.os.Looper; 27import android.os.Message; 28import android.os.RemoteException; 29import android.os.ServiceManager; 30import android.util.Log; 31 32/** 33 * The AudioRecord class manages the audio resources for Java applications 34 * to record audio from the audio input hardware of the platform. This is 35 * achieved by "pulling" (reading) the data from the AudioRecord object. The 36 * application is responsible for polling the AudioRecord object in time using one of 37 * the following three methods: {@link #read(byte[],int, int)}, {@link #read(short[], int, int)} 38 * or {@link #read(ByteBuffer, int)}. The choice of which method to use will be based 39 * on the audio data storage format that is the most convenient for the user of AudioRecord. 40 * <p>Upon creation, an AudioRecord object initializes its associated audio buffer that it will 41 * fill with the new audio data. The size of this buffer, specified during the construction, 42 * determines how long an AudioRecord can record before "over-running" data that has not 43 * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to 44 * the total recording buffer size. 45 */ 46public class AudioRecord 47{ 48 //--------------------------------------------------------- 49 // Constants 50 //-------------------- 51 /** 52 * indicates AudioRecord state is not successfully initialized. 53 */ 54 public static final int STATE_UNINITIALIZED = 0; 55 /** 56 * indicates AudioRecord state is ready to be used 57 */ 58 public static final int STATE_INITIALIZED = 1; 59 60 /** 61 * indicates AudioRecord recording state is not recording 62 */ 63 public static final int RECORDSTATE_STOPPED = 1; // matches SL_RECORDSTATE_STOPPED 64 /** 65 * indicates AudioRecord recording state is recording 66 */ 67 public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING 68 69 /** 70 * Denotes a successful operation. 71 */ 72 public static final int SUCCESS = AudioSystem.SUCCESS; 73 /** 74 * Denotes a generic operation failure. 75 */ 76 public static final int ERROR = AudioSystem.ERROR; 77 /** 78 * Denotes a failure due to the use of an invalid value. 79 */ 80 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE; 81 /** 82 * Denotes a failure due to the improper use of a method. 83 */ 84 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION; 85 86 // Error codes: 87 // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp 88 private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT = -16; 89 private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK = -17; 90 private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT = -18; 91 private static final int AUDIORECORD_ERROR_SETUP_INVALIDSOURCE = -19; 92 private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED = -20; 93 94 // Events: 95 // to keep in sync with frameworks/av/include/media/AudioRecord.h 96 /** 97 * Event id denotes when record head has reached a previously set marker. 98 */ 99 private static final int NATIVE_EVENT_MARKER = 2; 100 /** 101 * Event id denotes when previously set update period has elapsed during recording. 102 */ 103 private static final int NATIVE_EVENT_NEW_POS = 3; 104 105 private final static String TAG = "android.media.AudioRecord"; 106 107 /** @hide */ 108 public final static String SUBMIX_FIXED_VOLUME = "fixedVolume"; 109 110 //--------------------------------------------------------- 111 // Used exclusively by native code 112 //-------------------- 113 /** 114 * Accessed by native methods: provides access to C++ AudioRecord object 115 */ 116 @SuppressWarnings("unused") 117 private long mNativeRecorderInJavaObj; 118 119 /** 120 * Accessed by native methods: provides access to the callback data. 121 */ 122 @SuppressWarnings("unused") 123 private long mNativeCallbackCookie; 124 125 126 //--------------------------------------------------------- 127 // Member variables 128 //-------------------- 129 /** 130 * The audio data sampling rate in Hz. 131 */ 132 private int mSampleRate; 133 /** 134 * The number of input audio channels (1 is mono, 2 is stereo) 135 */ 136 private int mChannelCount; 137 /** 138 * The audio channel mask 139 */ 140 private int mChannelMask; 141 /** 142 * The encoding of the audio samples. 143 * @see AudioFormat#ENCODING_PCM_8BIT 144 * @see AudioFormat#ENCODING_PCM_16BIT 145 */ 146 private int mAudioFormat; 147 /** 148 * Where the audio data is recorded from. 149 */ 150 private int mRecordSource; 151 /** 152 * Indicates the state of the AudioRecord instance. 153 */ 154 private int mState = STATE_UNINITIALIZED; 155 /** 156 * Indicates the recording state of the AudioRecord instance. 157 */ 158 private int mRecordingState = RECORDSTATE_STOPPED; 159 /** 160 * Lock to make sure mRecordingState updates are reflecting the actual state of the object. 161 */ 162 private final Object mRecordingStateLock = new Object(); 163 /** 164 * The listener the AudioRecord notifies when the record position reaches a marker 165 * or for periodic updates during the progression of the record head. 166 * @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener) 167 * @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler) 168 */ 169 private OnRecordPositionUpdateListener mPositionListener = null; 170 /** 171 * Lock to protect position listener updates against event notifications 172 */ 173 private final Object mPositionListenerLock = new Object(); 174 /** 175 * Handler for marker events coming from the native code 176 */ 177 private NativeEventHandler mEventHandler = null; 178 /** 179 * Looper associated with the thread that creates the AudioRecord instance 180 */ 181 private Looper mInitializationLooper = null; 182 /** 183 * Size of the native audio buffer. 184 */ 185 private int mNativeBufferSizeInBytes = 0; 186 /** 187 * Audio session ID 188 */ 189 private int mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE; 190 /** 191 * AudioAttributes 192 */ 193 private AudioAttributes mAudioAttributes; 194 private boolean mIsSubmixFullVolume = false; 195 196 //--------------------------------------------------------- 197 // Constructor, Finalize 198 //-------------------- 199 /** 200 * Class constructor. 201 * Though some invalid parameters will result in an {@link IllegalArgumentException} exception, 202 * other errors do not. Thus you should call {@link #getState()} immediately after construction 203 * to confirm that the object is usable. 204 * @param audioSource the recording source (also referred to as capture preset). 205 * See {@link MediaRecorder.AudioSource} for the capture preset definitions. 206 * @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only 207 * rate that is guaranteed to work on all devices, but other rates such as 22050, 208 * 16000, and 11025 may work on some devices. 209 * @param channelConfig describes the configuration of the audio channels. 210 * See {@link AudioFormat#CHANNEL_IN_MONO} and 211 * {@link AudioFormat#CHANNEL_IN_STEREO}. {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed 212 * to work on all devices. 213 * @param audioFormat the format in which the audio data is represented. 214 * See {@link AudioFormat#ENCODING_PCM_16BIT} and 215 * {@link AudioFormat#ENCODING_PCM_8BIT} 216 * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written 217 * to during the recording. New audio data can be read from this buffer in smaller chunks 218 * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum 219 * required buffer size for the successful creation of an AudioRecord instance. Using values 220 * smaller than getMinBufferSize() will result in an initialization failure. 221 * @throws java.lang.IllegalArgumentException 222 */ 223 public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, 224 int bufferSizeInBytes) 225 throws IllegalArgumentException { 226 this((new AudioAttributes.Builder()) 227 .setInternalCapturePreset(audioSource) 228 .build(), 229 (new AudioFormat.Builder()) 230 .setChannelMask(getChannelMaskFromLegacyConfig(channelConfig, 231 true/*allow legacy configurations*/)) 232 .setEncoding(audioFormat) 233 .setSampleRate(sampleRateInHz) 234 .build(), 235 bufferSizeInBytes, 236 AudioManager.AUDIO_SESSION_ID_GENERATE); 237 } 238 239 /** 240 * @hide 241 * CANDIDATE FOR PUBLIC API 242 * Class constructor with {@link AudioAttributes} and {@link AudioFormat}. 243 * @param attributes a non-null {@link AudioAttributes} instance. Use 244 * {@link AudioAttributes.Builder#setCapturePreset(int)} for configuring the capture 245 * preset for this instance. 246 * @param format a non-null {@link AudioFormat} instance describing the format of the data 247 * that will be recorded through this AudioRecord. See {@link AudioFormat.Builder} for 248 * configuring the audio format parameters such as encoding, channel mask and sample rate. 249 * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written 250 * to during the recording. New audio data can be read from this buffer in smaller chunks 251 * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum 252 * required buffer size for the successful creation of an AudioRecord instance. Using values 253 * smaller than getMinBufferSize() will result in an initialization failure. 254 * @param sessionId ID of audio session the AudioRecord must be attached to, or 255 * {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at construction 256 * time. See also {@link AudioManager#generateAudioSessionId()} to obtain a session ID before 257 * construction. 258 * @throws IllegalArgumentException 259 */ 260 public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, 261 int sessionId) throws IllegalArgumentException { 262 mRecordingState = RECORDSTATE_STOPPED; 263 264 if (attributes == null) { 265 throw new IllegalArgumentException("Illegal null AudioAttributes"); 266 } 267 if (format == null) { 268 throw new IllegalArgumentException("Illegal null AudioFormat"); 269 } 270 271 // remember which looper is associated with the AudioRecord instanciation 272 if ((mInitializationLooper = Looper.myLooper()) == null) { 273 mInitializationLooper = Looper.getMainLooper(); 274 } 275 276 // is this AudioRecord using REMOTE_SUBMIX at full volume? 277 if (attributes.getCapturePreset() == MediaRecorder.AudioSource.REMOTE_SUBMIX) { 278 final AudioAttributes.Builder filteredAttr = new AudioAttributes.Builder(); 279 final Iterator<String> tagsIter = attributes.getTags().iterator(); 280 while (tagsIter.hasNext()) { 281 final String tag = tagsIter.next(); 282 if (tag.equalsIgnoreCase(SUBMIX_FIXED_VOLUME)) { 283 mIsSubmixFullVolume = true; 284 Log.v(TAG, "Will record from REMOTE_SUBMIX at full fixed volume"); 285 } else { // SUBMIX_FIXED_VOLUME: is not to be propagated to the native layers 286 filteredAttr.addTag(tag); 287 } 288 } 289 filteredAttr.setInternalCapturePreset(attributes.getCapturePreset()); 290 mAudioAttributes = filteredAttr.build(); 291 } else { 292 mAudioAttributes = attributes; 293 } 294 295 int rate = 0; 296 if ((format.getPropertySetMask() 297 & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0) 298 { 299 rate = format.getSampleRate(); 300 } else { 301 rate = AudioSystem.getPrimaryOutputSamplingRate(); 302 if (rate <= 0) { 303 rate = 44100; 304 } 305 } 306 307 int encoding = AudioFormat.ENCODING_DEFAULT; 308 if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0) 309 { 310 encoding = format.getEncoding(); 311 } 312 313 audioParamCheck(attributes.getCapturePreset(), rate, encoding); 314 315 mChannelCount = AudioFormat.channelCountFromInChannelMask(format.getChannelMask()); 316 mChannelMask = getChannelMaskFromLegacyConfig(format.getChannelMask(), false); 317 318 audioBuffSizeCheck(bufferSizeInBytes); 319 320 int[] session = new int[1]; 321 session[0] = sessionId; 322 //TODO: update native initialization when information about hardware init failure 323 // due to capture device already open is available. 324 int initResult = native_setup( new WeakReference<AudioRecord>(this), 325 mAudioAttributes, mSampleRate, mChannelMask, mAudioFormat, mNativeBufferSizeInBytes, 326 session); 327 if (initResult != SUCCESS) { 328 loge("Error code "+initResult+" when initializing native AudioRecord object."); 329 return; // with mState == STATE_UNINITIALIZED 330 } 331 332 mSessionId = session[0]; 333 334 mState = STATE_INITIALIZED; 335 } 336 337 // Convenience method for the constructor's parameter checks. 338 // This, getChannelMaskFromLegacyConfig and audioBuffSizeCheck are where constructor 339 // IllegalArgumentException-s are thrown 340 private static int getChannelMaskFromLegacyConfig(int inChannelConfig, 341 boolean allowLegacyConfig) { 342 int mask; 343 switch (inChannelConfig) { 344 case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT 345 case AudioFormat.CHANNEL_IN_MONO: 346 case AudioFormat.CHANNEL_CONFIGURATION_MONO: 347 mask = AudioFormat.CHANNEL_IN_MONO; 348 break; 349 case AudioFormat.CHANNEL_IN_STEREO: 350 case AudioFormat.CHANNEL_CONFIGURATION_STEREO: 351 mask = AudioFormat.CHANNEL_IN_STEREO; 352 break; 353 case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK): 354 mask = inChannelConfig; 355 break; 356 default: 357 throw new IllegalArgumentException("Unsupported channel configuration."); 358 } 359 360 if (!allowLegacyConfig && ((inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_MONO) 361 || (inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_STEREO))) { 362 // only happens with the constructor that uses AudioAttributes and AudioFormat 363 throw new IllegalArgumentException("Unsupported deprecated configuration."); 364 } 365 366 return mask; 367 } 368 // postconditions: 369 // mRecordSource is valid 370 // mAudioFormat is valid 371 // mSampleRate is valid 372 private void audioParamCheck(int audioSource, int sampleRateInHz, int audioFormat) 373 throws IllegalArgumentException { 374 375 //-------------- 376 // audio source 377 if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) || 378 ((audioSource > MediaRecorder.getAudioSourceMax()) && 379 (audioSource != MediaRecorder.AudioSource.FM_TUNER) && 380 (audioSource != MediaRecorder.AudioSource.HOTWORD)) ) { 381 throw new IllegalArgumentException("Invalid audio source."); 382 } 383 mRecordSource = audioSource; 384 385 //-------------- 386 // sample rate 387 if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) { 388 throw new IllegalArgumentException(sampleRateInHz 389 + "Hz is not a supported sample rate."); 390 } 391 mSampleRate = sampleRateInHz; 392 393 //-------------- 394 // audio format 395 switch (audioFormat) { 396 case AudioFormat.ENCODING_DEFAULT: 397 mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; 398 break; 399 case AudioFormat.ENCODING_PCM_16BIT: 400 case AudioFormat.ENCODING_PCM_8BIT: 401 mAudioFormat = audioFormat; 402 break; 403 default: 404 throw new IllegalArgumentException("Unsupported sample encoding." 405 + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT."); 406 } 407 } 408 409 410 // Convenience method for the contructor's audio buffer size check. 411 // preconditions: 412 // mChannelCount is valid 413 // mAudioFormat is AudioFormat.ENCODING_PCM_8BIT OR AudioFormat.ENCODING_PCM_16BIT 414 // postcondition: 415 // mNativeBufferSizeInBytes is valid (multiple of frame size, positive) 416 private void audioBuffSizeCheck(int audioBufferSize) throws IllegalArgumentException { 417 // NB: this section is only valid with PCM data. 418 // To update when supporting compressed formats 419 int frameSizeInBytes = mChannelCount 420 * (AudioFormat.getBytesPerSample(mAudioFormat)); 421 if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) { 422 throw new IllegalArgumentException("Invalid audio buffer size."); 423 } 424 425 mNativeBufferSizeInBytes = audioBufferSize; 426 } 427 428 429 430 /** 431 * Releases the native AudioRecord resources. 432 * The object can no longer be used and the reference should be set to null 433 * after a call to release() 434 */ 435 public void release() { 436 try { 437 stop(); 438 } catch(IllegalStateException ise) { 439 // don't raise an exception, we're releasing the resources. 440 } 441 native_release(); 442 mState = STATE_UNINITIALIZED; 443 } 444 445 446 @Override 447 protected void finalize() { 448 // will cause stop() to be called, and if appropriate, will handle fixed volume recording 449 release(); 450 } 451 452 453 //-------------------------------------------------------------------------- 454 // Getters 455 //-------------------- 456 /** 457 * Returns the configured audio data sample rate in Hz 458 */ 459 public int getSampleRate() { 460 return mSampleRate; 461 } 462 463 /** 464 * Returns the audio recording source. 465 * @see MediaRecorder.AudioSource 466 */ 467 public int getAudioSource() { 468 return mRecordSource; 469 } 470 471 /** 472 * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT} 473 * and {@link AudioFormat#ENCODING_PCM_8BIT}. 474 */ 475 public int getAudioFormat() { 476 return mAudioFormat; 477 } 478 479 /** 480 * Returns the configured channel configuration. 481 * See {@link AudioFormat#CHANNEL_IN_MONO} 482 * and {@link AudioFormat#CHANNEL_IN_STEREO}. 483 */ 484 public int getChannelConfiguration() { 485 return mChannelMask; 486 } 487 488 /** 489 * Returns the configured number of channels. 490 */ 491 public int getChannelCount() { 492 return mChannelCount; 493 } 494 495 /** 496 * Returns the state of the AudioRecord instance. This is useful after the 497 * AudioRecord instance has been created to check if it was initialized 498 * properly. This ensures that the appropriate hardware resources have been 499 * acquired. 500 * @see AudioRecord#STATE_INITIALIZED 501 * @see AudioRecord#STATE_UNINITIALIZED 502 */ 503 public int getState() { 504 return mState; 505 } 506 507 /** 508 * Returns the recording state of the AudioRecord instance. 509 * @see AudioRecord#RECORDSTATE_STOPPED 510 * @see AudioRecord#RECORDSTATE_RECORDING 511 */ 512 public int getRecordingState() { 513 synchronized (mRecordingStateLock) { 514 return mRecordingState; 515 } 516 } 517 518 /** 519 * Returns the notification marker position expressed in frames. 520 */ 521 public int getNotificationMarkerPosition() { 522 return native_get_marker_pos(); 523 } 524 525 /** 526 * Returns the notification update period expressed in frames. 527 */ 528 public int getPositionNotificationPeriod() { 529 return native_get_pos_update_period(); 530 } 531 532 /** 533 * Returns the minimum buffer size required for the successful creation of an AudioRecord 534 * object, in byte units. 535 * Note that this size doesn't guarantee a smooth recording under load, and higher values 536 * should be chosen according to the expected frequency at which the AudioRecord instance 537 * will be polled for new data. 538 * See {@link #AudioRecord(int, int, int, int, int)} for more information on valid 539 * configuration values. 540 * @param sampleRateInHz the sample rate expressed in Hertz. 541 * @param channelConfig describes the configuration of the audio channels. 542 * See {@link AudioFormat#CHANNEL_IN_MONO} and 543 * {@link AudioFormat#CHANNEL_IN_STEREO} 544 * @param audioFormat the format in which the audio data is represented. 545 * See {@link AudioFormat#ENCODING_PCM_16BIT}. 546 * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the 547 * hardware, or an invalid parameter was passed, 548 * or {@link #ERROR} if the implementation was unable to query the hardware for its 549 * input properties, 550 * or the minimum buffer size expressed in bytes. 551 * @see #AudioRecord(int, int, int, int, int) 552 */ 553 static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { 554 int channelCount = 0; 555 switch (channelConfig) { 556 case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT 557 case AudioFormat.CHANNEL_IN_MONO: 558 case AudioFormat.CHANNEL_CONFIGURATION_MONO: 559 channelCount = 1; 560 break; 561 case AudioFormat.CHANNEL_IN_STEREO: 562 case AudioFormat.CHANNEL_CONFIGURATION_STEREO: 563 case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK): 564 channelCount = 2; 565 break; 566 case AudioFormat.CHANNEL_INVALID: 567 default: 568 loge("getMinBufferSize(): Invalid channel configuration."); 569 return ERROR_BAD_VALUE; 570 } 571 572 // PCM_8BIT is not supported at the moment 573 if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) { 574 loge("getMinBufferSize(): Invalid audio format."); 575 return ERROR_BAD_VALUE; 576 } 577 578 int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat); 579 if (size == 0) { 580 return ERROR_BAD_VALUE; 581 } 582 else if (size == -1) { 583 return ERROR; 584 } 585 else { 586 return size; 587 } 588 } 589 590 /** 591 * Returns the audio session ID. 592 * 593 * @return the ID of the audio session this AudioRecord belongs to. 594 */ 595 public int getAudioSessionId() { 596 return mSessionId; 597 } 598 599 //--------------------------------------------------------- 600 // Transport control methods 601 //-------------------- 602 /** 603 * Starts recording from the AudioRecord instance. 604 * @throws IllegalStateException 605 */ 606 public void startRecording() 607 throws IllegalStateException { 608 if (mState != STATE_INITIALIZED) { 609 throw new IllegalStateException("startRecording() called on an " 610 + "uninitialized AudioRecord."); 611 } 612 613 // start recording 614 synchronized(mRecordingStateLock) { 615 if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) { 616 handleFullVolumeRec(true); 617 mRecordingState = RECORDSTATE_RECORDING; 618 } 619 } 620 } 621 622 /** 623 * Starts recording from the AudioRecord instance when the specified synchronization event 624 * occurs on the specified audio session. 625 * @throws IllegalStateException 626 * @param syncEvent event that triggers the capture. 627 * @see MediaSyncEvent 628 */ 629 public void startRecording(MediaSyncEvent syncEvent) 630 throws IllegalStateException { 631 if (mState != STATE_INITIALIZED) { 632 throw new IllegalStateException("startRecording() called on an " 633 + "uninitialized AudioRecord."); 634 } 635 636 // start recording 637 synchronized(mRecordingStateLock) { 638 if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) { 639 handleFullVolumeRec(true); 640 mRecordingState = RECORDSTATE_RECORDING; 641 } 642 } 643 } 644 645 /** 646 * Stops recording. 647 * @throws IllegalStateException 648 */ 649 public void stop() 650 throws IllegalStateException { 651 if (mState != STATE_INITIALIZED) { 652 throw new IllegalStateException("stop() called on an uninitialized AudioRecord."); 653 } 654 655 // stop recording 656 synchronized(mRecordingStateLock) { 657 handleFullVolumeRec(false); 658 native_stop(); 659 mRecordingState = RECORDSTATE_STOPPED; 660 } 661 } 662 663 private final IBinder mICallBack = new Binder(); 664 private void handleFullVolumeRec(boolean starting) { 665 if (!mIsSubmixFullVolume) { 666 return; 667 } 668 final IBinder b = ServiceManager.getService(android.content.Context.AUDIO_SERVICE); 669 final IAudioService ias = IAudioService.Stub.asInterface(b); 670 try { 671 ias.forceRemoteSubmixFullVolume(starting, mICallBack); 672 } catch (RemoteException e) { 673 Log.e(TAG, "Error talking to AudioService when handling full submix volume", e); 674 } 675 } 676 677 //--------------------------------------------------------- 678 // Audio data supply 679 //-------------------- 680 /** 681 * Reads audio data from the audio hardware for recording into a buffer. 682 * @param audioData the array to which the recorded audio data is written. 683 * @param offsetInBytes index in audioData from which the data is written expressed in bytes. 684 * @param sizeInBytes the number of requested bytes. 685 * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION} 686 * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if 687 * the parameters don't resolve to valid data and indexes. 688 * The number of bytes will not exceed sizeInBytes. 689 */ 690 public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) { 691 if (mState != STATE_INITIALIZED) { 692 return ERROR_INVALID_OPERATION; 693 } 694 695 if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0) 696 || (offsetInBytes + sizeInBytes < 0) // detect integer overflow 697 || (offsetInBytes + sizeInBytes > audioData.length)) { 698 return ERROR_BAD_VALUE; 699 } 700 701 return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes); 702 } 703 704 705 /** 706 * Reads audio data from the audio hardware for recording into a buffer. 707 * @param audioData the array to which the recorded audio data is written. 708 * @param offsetInShorts index in audioData from which the data is written expressed in shorts. 709 * @param sizeInShorts the number of requested shorts. 710 * @return the number of shorts that were read or or {@link #ERROR_INVALID_OPERATION} 711 * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if 712 * the parameters don't resolve to valid data and indexes. 713 * The number of shorts will not exceed sizeInShorts. 714 */ 715 public int read(short[] audioData, int offsetInShorts, int sizeInShorts) { 716 if (mState != STATE_INITIALIZED) { 717 return ERROR_INVALID_OPERATION; 718 } 719 720 if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0) 721 || (offsetInShorts + sizeInShorts < 0) // detect integer overflow 722 || (offsetInShorts + sizeInShorts > audioData.length)) { 723 return ERROR_BAD_VALUE; 724 } 725 726 return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts); 727 } 728 729 730 /** 731 * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer 732 * is not a direct buffer, this method will always return 0. 733 * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is 734 * unchanged after a call to this method. 735 * @param audioBuffer the direct buffer to which the recorded audio data is written. 736 * @param sizeInBytes the number of requested bytes. 737 * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION} 738 * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if 739 * the parameters don't resolve to valid data and indexes. 740 * The number of bytes will not exceed sizeInBytes. 741 */ 742 public int read(ByteBuffer audioBuffer, int sizeInBytes) { 743 if (mState != STATE_INITIALIZED) { 744 return ERROR_INVALID_OPERATION; 745 } 746 747 if ( (audioBuffer == null) || (sizeInBytes < 0) ) { 748 return ERROR_BAD_VALUE; 749 } 750 751 return native_read_in_direct_buffer(audioBuffer, sizeInBytes); 752 } 753 754 755 //-------------------------------------------------------------------------- 756 // Initialization / configuration 757 //-------------------- 758 /** 759 * Sets the listener the AudioRecord notifies when a previously set marker is reached or 760 * for each periodic record head position update. 761 * @param listener 762 */ 763 public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener) { 764 setRecordPositionUpdateListener(listener, null); 765 } 766 767 /** 768 * Sets the listener the AudioRecord notifies when a previously set marker is reached or 769 * for each periodic record head position update. 770 * Use this method to receive AudioRecord events in the Handler associated with another 771 * thread than the one in which you created the AudioTrack instance. 772 * @param listener 773 * @param handler the Handler that will receive the event notification messages. 774 */ 775 public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, 776 Handler handler) { 777 synchronized (mPositionListenerLock) { 778 779 mPositionListener = listener; 780 781 if (listener != null) { 782 if (handler != null) { 783 mEventHandler = new NativeEventHandler(this, handler.getLooper()); 784 } else { 785 // no given handler, use the looper the AudioRecord was created in 786 mEventHandler = new NativeEventHandler(this, mInitializationLooper); 787 } 788 } else { 789 mEventHandler = null; 790 } 791 } 792 793 } 794 795 796 /** 797 * Sets the marker position at which the listener is called, if set with 798 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or 799 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}. 800 * @param markerInFrames marker position expressed in frames 801 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, 802 * {@link #ERROR_INVALID_OPERATION} 803 */ 804 public int setNotificationMarkerPosition(int markerInFrames) { 805 if (mState == STATE_UNINITIALIZED) { 806 return ERROR_INVALID_OPERATION; 807 } 808 return native_set_marker_pos(markerInFrames); 809 } 810 811 812 /** 813 * Sets the period at which the listener is called, if set with 814 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or 815 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}. 816 * It is possible for notifications to be lost if the period is too small. 817 * @param periodInFrames update period expressed in frames 818 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION} 819 */ 820 public int setPositionNotificationPeriod(int periodInFrames) { 821 if (mState == STATE_UNINITIALIZED) { 822 return ERROR_INVALID_OPERATION; 823 } 824 return native_set_pos_update_period(periodInFrames); 825 } 826 827 828 //--------------------------------------------------------- 829 // Interface definitions 830 //-------------------- 831 /** 832 * Interface definition for a callback to be invoked when an AudioRecord has 833 * reached a notification marker set by {@link AudioRecord#setNotificationMarkerPosition(int)} 834 * or for periodic updates on the progress of the record head, as set by 835 * {@link AudioRecord#setPositionNotificationPeriod(int)}. 836 */ 837 public interface OnRecordPositionUpdateListener { 838 /** 839 * Called on the listener to notify it that the previously set marker has been reached 840 * by the recording head. 841 */ 842 void onMarkerReached(AudioRecord recorder); 843 844 /** 845 * Called on the listener to periodically notify it that the record head has reached 846 * a multiple of the notification period. 847 */ 848 void onPeriodicNotification(AudioRecord recorder); 849 } 850 851 852 853 //--------------------------------------------------------- 854 // Inner classes 855 //-------------------- 856 857 /** 858 * Helper class to handle the forwarding of native events to the appropriate listener 859 * (potentially) handled in a different thread 860 */ 861 private class NativeEventHandler extends Handler { 862 863 private final AudioRecord mAudioRecord; 864 865 NativeEventHandler(AudioRecord recorder, Looper looper) { 866 super(looper); 867 mAudioRecord = recorder; 868 } 869 870 @Override 871 public void handleMessage(Message msg) { 872 OnRecordPositionUpdateListener listener = null; 873 synchronized (mPositionListenerLock) { 874 listener = mAudioRecord.mPositionListener; 875 } 876 877 switch (msg.what) { 878 case NATIVE_EVENT_MARKER: 879 if (listener != null) { 880 listener.onMarkerReached(mAudioRecord); 881 } 882 break; 883 case NATIVE_EVENT_NEW_POS: 884 if (listener != null) { 885 listener.onPeriodicNotification(mAudioRecord); 886 } 887 break; 888 default: 889 loge("Unknown native event type: " + msg.what); 890 break; 891 } 892 } 893 }; 894 895 896 //--------------------------------------------------------- 897 // Java methods called from the native side 898 //-------------------- 899 @SuppressWarnings("unused") 900 private static void postEventFromNative(Object audiorecord_ref, 901 int what, int arg1, int arg2, Object obj) { 902 //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2); 903 AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get(); 904 if (recorder == null) { 905 return; 906 } 907 908 if (recorder.mEventHandler != null) { 909 Message m = 910 recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj); 911 recorder.mEventHandler.sendMessage(m); 912 } 913 914 } 915 916 917 //--------------------------------------------------------- 918 // Native methods called from the Java side 919 //-------------------- 920 921 private native final int native_setup(Object audiorecord_this, 922 Object /*AudioAttributes*/ attributes, 923 int sampleRate, int channelMask, int audioFormat, 924 int buffSizeInBytes, int[] sessionId); 925 926 // TODO remove: implementation calls directly into implementation of native_release() 927 private native final void native_finalize(); 928 929 private native final void native_release(); 930 931 private native final int native_start(int syncEvent, int sessionId); 932 933 private native final void native_stop(); 934 935 private native final int native_read_in_byte_array(byte[] audioData, 936 int offsetInBytes, int sizeInBytes); 937 938 private native final int native_read_in_short_array(short[] audioData, 939 int offsetInShorts, int sizeInShorts); 940 941 private native final int native_read_in_direct_buffer(Object jBuffer, int sizeInBytes); 942 943 private native final int native_set_marker_pos(int marker); 944 private native final int native_get_marker_pos(); 945 946 private native final int native_set_pos_update_period(int updatePeriod); 947 private native final int native_get_pos_update_period(); 948 949 static private native final int native_get_min_buff_size( 950 int sampleRateInHz, int channelCount, int audioFormat); 951 952 953 //--------------------------------------------------------- 954 // Utility methods 955 //------------------ 956 957 private static void logd(String msg) { 958 Log.d(TAG, msg); 959 } 960 961 private static void loge(String msg) { 962 Log.e(TAG, msg); 963 } 964 965} 966