AudioRecord.java revision a553c25b33c99b345cf1c8688f8df0ed8df14e5a
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.io.OutputStream; 21import java.io.IOException; 22import java.lang.IllegalArgumentException; 23import java.lang.IllegalStateException; 24import java.lang.Thread; 25import java.nio.ByteBuffer; 26 27import android.os.Handler; 28import android.os.Looper; 29import android.os.Message; 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 // Error codes: 70 // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp 71 /** 72 * Denotes a successful operation. 73 */ 74 public static final int SUCCESS = 0; 75 /** 76 * Denotes a generic operation failure. 77 */ 78 public static final int ERROR = -1; 79 /** 80 * Denotes a failure due to the use of an invalid value. 81 */ 82 public static final int ERROR_BAD_VALUE = -2; 83 /** 84 * Denotes a failure due to the improper use of a method. 85 */ 86 public static final int ERROR_INVALID_OPERATION = -3; 87 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/base/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 = "AudioRecord-Java"; 106 107 108 //--------------------------------------------------------- 109 // Used exclusively by native code 110 //-------------------- 111 /** 112 * Accessed by native methods: provides access to C++ AudioRecord object 113 */ 114 @SuppressWarnings("unused") 115 private int mNativeRecorderInJavaObj; 116 117 /** 118 * Accessed by native methods: provides access to the callback data. 119 */ 120 @SuppressWarnings("unused") 121 private int mNativeCallbackCookie; 122 123 124 //--------------------------------------------------------- 125 // Member variables 126 //-------------------- 127 /** 128 * The audio data sampling rate in Hz. 129 */ 130 private int mSampleRate = 22050; 131 /** 132 * The number of input audio channels (1 is mono, 2 is stereo) 133 */ 134 private int mChannelCount = 1; 135 /** 136 * The current audio channel configuration 137 */ 138 private int mChannelConfiguration = AudioFormat.CHANNEL_IN_MONO; 139 /** 140 * The encoding of the audio samples. 141 * @see AudioFormat#ENCODING_PCM_8BIT 142 * @see AudioFormat#ENCODING_PCM_16BIT 143 */ 144 private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; 145 /** 146 * Where the audio data is recorded from. 147 */ 148 private int mRecordSource = MediaRecorder.AudioSource.DEFAULT; 149 /** 150 * Indicates the state of the AudioRecord instance. 151 */ 152 private int mState = STATE_UNINITIALIZED; 153 /** 154 * Indicates the recording state of the AudioRecord instance. 155 */ 156 private int mRecordingState = RECORDSTATE_STOPPED; 157 /** 158 * Lock to make sure mRecordingState updates are reflecting the actual state of the object. 159 */ 160 private Object mRecordingStateLock = new Object(); 161 /** 162 * The listener the AudioRecord notifies when the record position reaches a marker 163 * or for periodic updates during the progression of the record head. 164 * @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener) 165 * @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler) 166 */ 167 private OnRecordPositionUpdateListener mPositionListener = null; 168 /** 169 * Lock to protect position listener updates against event notifications 170 */ 171 private final Object mPositionListenerLock = new Object(); 172 /** 173 * Handler for marker events coming from the native code 174 */ 175 private NativeEventHandler mEventHandler = null; 176 /** 177 * Looper associated with the thread that creates the AudioRecord instance 178 */ 179 private Looper mInitializationLooper = null; 180 /** 181 * Size of the native audio buffer. 182 */ 183 private int mNativeBufferSizeInBytes = 0; 184 185 186 //--------------------------------------------------------- 187 // Constructor, Finalize 188 //-------------------- 189 /** 190 * Class constructor. 191 * @param audioSource the recording source. See {@link MediaRecorder.AudioSource} for 192 * recording source definitions. 193 * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but 194 * not limited to) 44100, 22050 and 11025. 195 * @param channelConfig describes the configuration of the audio channels. 196 * See {@link AudioFormat#CHANNEL_IN_MONO} and 197 * {@link AudioFormat#CHANNEL_IN_STEREO} 198 * @param audioFormat the format in which the audio data is represented. 199 * See {@link AudioFormat#ENCODING_PCM_16BIT} and 200 * {@link AudioFormat#ENCODING_PCM_8BIT} 201 * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written 202 * to during the recording. New audio data can be read from this buffer in smaller chunks 203 * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum 204 * required buffer size for the successful creation of an AudioRecord instance. Using values 205 * smaller than getMinBufferSize() will result in an initialization failure. 206 * @throws java.lang.IllegalArgumentException 207 */ 208 public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, 209 int bufferSizeInBytes) 210 throws IllegalArgumentException { 211 mState = STATE_UNINITIALIZED; 212 mRecordingState = RECORDSTATE_STOPPED; 213 214 // remember which looper is associated with the AudioRecord instanciation 215 if ((mInitializationLooper = Looper.myLooper()) == null) { 216 mInitializationLooper = Looper.getMainLooper(); 217 } 218 219 audioParamCheck(audioSource, sampleRateInHz, channelConfig, audioFormat); 220 221 audioBuffSizeCheck(bufferSizeInBytes); 222 223 // native initialization 224 //TODO: update native initialization when information about hardware init failure 225 // due to capture device already open is available. 226 int initResult = native_setup( new WeakReference<AudioRecord>(this), 227 mRecordSource, mSampleRate, mChannelCount, mAudioFormat, mNativeBufferSizeInBytes); 228 if (initResult != SUCCESS) { 229 loge("Error code "+initResult+" when initializing native AudioRecord object."); 230 return; // with mState == STATE_UNINITIALIZED 231 } 232 233 mState = STATE_INITIALIZED; 234 } 235 236 237 // Convenience method for the constructor's parameter checks. 238 // This is where constructor IllegalArgumentException-s are thrown 239 // postconditions: 240 // mRecordSource is valid 241 // mChannelCount is valid 242 // mAudioFormat is valid 243 // mSampleRate is valid 244 private void audioParamCheck(int audioSource, int sampleRateInHz, 245 int channelConfig, int audioFormat) { 246 247 //-------------- 248 // audio source 249 if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) || 250 (audioSource > MediaRecorder.getAudioSourceMax()) ) { 251 throw (new IllegalArgumentException("Invalid audio source.")); 252 } else { 253 mRecordSource = audioSource; 254 } 255 256 //-------------- 257 // sample rate 258 if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) { 259 throw (new IllegalArgumentException(sampleRateInHz 260 + "Hz is not a supported sample rate.")); 261 } else { 262 mSampleRate = sampleRateInHz; 263 } 264 265 //-------------- 266 // channel config 267 switch (channelConfig) { 268 case AudioFormat.CHANNEL_IN_DEFAULT: 269 case AudioFormat.CHANNEL_IN_MONO: 270 mChannelCount = 1; 271 mChannelConfiguration = AudioFormat.CHANNEL_IN_MONO; 272 break; 273 case AudioFormat.CHANNEL_IN_STEREO: 274 mChannelCount = 2; 275 mChannelConfiguration = AudioFormat.CHANNEL_IN_STEREO; 276 break; 277 default: 278 mChannelCount = 0; 279 mChannelConfiguration = AudioFormat.CHANNEL_INVALID; 280 throw (new IllegalArgumentException("Unsupported channel configuration.")); 281 } 282 283 //-------------- 284 // audio format 285 switch (audioFormat) { 286 case AudioFormat.ENCODING_DEFAULT: 287 mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; 288 break; 289 case AudioFormat.ENCODING_PCM_16BIT: 290 case AudioFormat.ENCODING_PCM_8BIT: 291 mAudioFormat = audioFormat; 292 break; 293 default: 294 mAudioFormat = AudioFormat.ENCODING_INVALID; 295 throw (new IllegalArgumentException("Unsupported sample encoding." 296 + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT.")); 297 } 298 } 299 300 301 // Convenience method for the contructor's audio buffer size check. 302 // preconditions: 303 // mChannelCount is valid 304 // mAudioFormat is AudioFormat.ENCODING_PCM_8BIT OR AudioFormat.ENCODING_PCM_16BIT 305 // postcondition: 306 // mNativeBufferSizeInBytes is valid (multiple of frame size, positive) 307 private void audioBuffSizeCheck(int audioBufferSize) { 308 // NB: this section is only valid with PCM data. 309 // To update when supporting compressed formats 310 int frameSizeInBytes = mChannelCount 311 * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2); 312 if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) { 313 throw (new IllegalArgumentException("Invalid audio buffer size.")); 314 } 315 316 mNativeBufferSizeInBytes = audioBufferSize; 317 } 318 319 320 321 /** 322 * Releases the native AudioRecord resources. 323 * The object can no longer be used and the reference should be set to null 324 * after a call to release() 325 */ 326 public void release() { 327 try { 328 stop(); 329 } catch(IllegalStateException ise) { 330 // don't raise an exception, we're releasing the resources. 331 } 332 native_release(); 333 mState = STATE_UNINITIALIZED; 334 } 335 336 337 @Override 338 protected void finalize() { 339 native_finalize(); 340 } 341 342 343 //-------------------------------------------------------------------------- 344 // Getters 345 //-------------------- 346 /** 347 * Returns the configured audio data sample rate in Hz 348 */ 349 public int getSampleRate() { 350 return mSampleRate; 351 } 352 353 /** 354 * Returns the audio recording source. 355 * @see MediaRecorder.AudioSource 356 */ 357 public int getAudioSource() { 358 return mRecordSource; 359 } 360 361 /** 362 * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT} 363 * and {@link AudioFormat#ENCODING_PCM_8BIT}. 364 */ 365 public int getAudioFormat() { 366 return mAudioFormat; 367 } 368 369 /** 370 * Returns the configured channel configuration. 371 * See {@link AudioFormat#CHANNEL_IN_MONO} 372 * and {@link AudioFormat#CHANNEL_IN_STEREO}. 373 */ 374 public int getChannelConfiguration() { 375 return mChannelConfiguration; 376 } 377 378 /** 379 * Returns the configured number of channels. 380 */ 381 public int getChannelCount() { 382 return mChannelCount; 383 } 384 385 /** 386 * Returns the state of the AudioRecord instance. This is useful after the 387 * AudioRecord instance has been created to check if it was initialized 388 * properly. This ensures that the appropriate hardware resources have been 389 * acquired. 390 * @see AudioRecord#STATE_INITIALIZED 391 * @see AudioRecord#STATE_UNINITIALIZED 392 */ 393 public int getState() { 394 return mState; 395 } 396 397 /** 398 * Returns the recording state of the AudioRecord instance. 399 * @see AudioRecord#RECORDSTATE_STOPPED 400 * @see AudioRecord#RECORDSTATE_RECORDING 401 */ 402 public int getRecordingState() { 403 return mRecordingState; 404 } 405 406 /** 407 * Returns the notification marker position expressed in frames. 408 */ 409 public int getNotificationMarkerPosition() { 410 return native_get_marker_pos(); 411 } 412 413 /** 414 * Returns the notification update period expressed in frames. 415 */ 416 public int getPositionNotificationPeriod() { 417 return native_get_pos_update_period(); 418 } 419 420 /** 421 * Returns the minimum buffer size required for the successful creation of an AudioRecord 422 * object. 423 * Note that this size doesn't guarantee a smooth recording under load, and higher values 424 * should be chosen according to the expected frequency at which the AudioRecord instance 425 * will be polled for new data. 426 * @param sampleRateInHz the sample rate expressed in Hertz. 427 * @param channelConfig describes the configuration of the audio channels. 428 * See {@link AudioFormat#CHANNEL_IN_MONO} and 429 * {@link AudioFormat#CHANNEL_IN_STEREO} 430 * @param audioFormat the format in which the audio data is represented. 431 * See {@link AudioFormat#ENCODING_PCM_16BIT}. 432 * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the 433 * hardware, or an invalid parameter was passed, 434 * or {@link #ERROR} if the implementation was unable to query the hardware for its 435 * output properties, 436 * or the minimum buffer size expressed in bytes. 437 */ 438 static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { 439 int channelCount = 0; 440 switch(channelConfig) { 441 case AudioFormat.CHANNEL_IN_DEFAULT: 442 case AudioFormat.CHANNEL_IN_MONO: 443 channelCount = 1; 444 break; 445 case AudioFormat.CHANNEL_IN_STEREO: 446 channelCount = 2; 447 break; 448 case AudioFormat.CHANNEL_INVALID: 449 default: 450 loge("getMinBufferSize(): Invalid channel configuration."); 451 return AudioRecord.ERROR_BAD_VALUE; 452 } 453 454 // PCM_8BIT is not supported at the moment 455 if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) { 456 loge("getMinBufferSize(): Invalid audio format."); 457 return AudioRecord.ERROR_BAD_VALUE; 458 } 459 460 int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat); 461 if (size == 0) { 462 return AudioRecord.ERROR_BAD_VALUE; 463 } 464 else if (size == -1) { 465 return AudioRecord.ERROR; 466 } 467 else { 468 return size; 469 } 470 } 471 472 473 //--------------------------------------------------------- 474 // Transport control methods 475 //-------------------- 476 /** 477 * Starts recording from the AudioRecord instance. 478 * @throws IllegalStateException 479 */ 480 public void startRecording() 481 throws IllegalStateException { 482 if (mState != STATE_INITIALIZED) { 483 throw(new IllegalStateException("startRecording() called on an " 484 +"uninitialized AudioRecord.")); 485 } 486 487 // start recording 488 synchronized(mRecordingStateLock) { 489 native_start(); 490 mRecordingState = RECORDSTATE_RECORDING; 491 } 492 } 493 494 495 496 /** 497 * Stops recording. 498 * @throws IllegalStateException 499 */ 500 public void stop() 501 throws IllegalStateException { 502 if (mState != STATE_INITIALIZED) { 503 throw(new IllegalStateException("stop() called on an uninitialized AudioRecord.")); 504 } 505 506 // stop recording 507 synchronized(mRecordingStateLock) { 508 native_stop(); 509 mRecordingState = RECORDSTATE_STOPPED; 510 } 511 } 512 513 514 //--------------------------------------------------------- 515 // Audio data supply 516 //-------------------- 517 /** 518 * Reads audio data from the audio hardware for recording into a buffer. 519 * @param audioData the array to which the recorded audio data is written. 520 * @param offsetInBytes index in audioData from which the data is written expressed in bytes. 521 * @param sizeInBytes the number of requested bytes. 522 * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION} 523 * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if 524 * the parameters don't resolve to valid data and indexes. 525 * The number of bytes will not exceed sizeInBytes. 526 */ 527 public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) { 528 if (mState != STATE_INITIALIZED) { 529 return ERROR_INVALID_OPERATION; 530 } 531 532 if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0) 533 || (offsetInBytes + sizeInBytes > audioData.length)) { 534 return ERROR_BAD_VALUE; 535 } 536 537 return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes); 538 } 539 540 541 /** 542 * Reads audio data from the audio hardware for recording into a buffer. 543 * @param audioData the array to which the recorded audio data is written. 544 * @param offsetInShorts index in audioData from which the data is written expressed in shorts. 545 * @param sizeInShorts the number of requested shorts. 546 * @return the number of shorts that were read or or {@link #ERROR_INVALID_OPERATION} 547 * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if 548 * the parameters don't resolve to valid data and indexes. 549 * The number of shorts will not exceed sizeInShorts. 550 */ 551 public int read(short[] audioData, int offsetInShorts, int sizeInShorts) { 552 if (mState != STATE_INITIALIZED) { 553 return ERROR_INVALID_OPERATION; 554 } 555 556 if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0) 557 || (offsetInShorts + sizeInShorts > audioData.length)) { 558 return ERROR_BAD_VALUE; 559 } 560 561 return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts); 562 } 563 564 565 /** 566 * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer 567 * is not a direct buffer, this method will always return 0. 568 * @param audioBuffer the direct buffer to which the recorded audio data is written. 569 * @param sizeInBytes the number of requested bytes. 570 * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION} 571 * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if 572 * the parameters don't resolve to valid data and indexes. 573 * The number of bytes will not exceed sizeInBytes. 574 */ 575 public int read(ByteBuffer audioBuffer, int sizeInBytes) { 576 if (mState != STATE_INITIALIZED) { 577 return ERROR_INVALID_OPERATION; 578 } 579 580 if ( (audioBuffer == null) || (sizeInBytes < 0) ) { 581 return ERROR_BAD_VALUE; 582 } 583 584 return native_read_in_direct_buffer(audioBuffer, sizeInBytes); 585 } 586 587 588 //-------------------------------------------------------------------------- 589 // Initialization / configuration 590 //-------------------- 591 /** 592 * Sets the listener the AudioRecord notifies when a previously set marker is reached or 593 * for each periodic record head position update. 594 * @param listener 595 */ 596 public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener) { 597 setRecordPositionUpdateListener(listener, null); 598 } 599 600 /** 601 * Sets the listener the AudioRecord notifies when a previously set marker is reached or 602 * for each periodic record head position update. 603 * Use this method to receive AudioRecord events in the Handler associated with another 604 * thread than the one in which you created the AudioTrack instance. 605 * @param listener 606 * @param handler the Handler that will receive the event notification messages. 607 */ 608 public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, 609 Handler handler) { 610 synchronized (mPositionListenerLock) { 611 612 mPositionListener = listener; 613 614 if (listener != null) { 615 if (handler != null) { 616 mEventHandler = new NativeEventHandler(this, handler.getLooper()); 617 } else { 618 // no given handler, use the looper the AudioRecord was created in 619 mEventHandler = new NativeEventHandler(this, mInitializationLooper); 620 } 621 } else { 622 mEventHandler = null; 623 } 624 } 625 626 } 627 628 629 /** 630 * Sets the marker position at which the listener is called, if set with 631 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or 632 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}. 633 * @param markerInFrames marker position expressed in frames 634 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, 635 * {@link #ERROR_INVALID_OPERATION} 636 */ 637 public int setNotificationMarkerPosition(int markerInFrames) { 638 return native_set_marker_pos(markerInFrames); 639 } 640 641 642 /** 643 * Sets the period at which the listener is called, if set with 644 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or 645 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}. 646 * @param periodInFrames update period expressed in frames 647 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION} 648 */ 649 public int setPositionNotificationPeriod(int periodInFrames) { 650 return native_set_pos_update_period(periodInFrames); 651 } 652 653 654 //--------------------------------------------------------- 655 // Interface definitions 656 //-------------------- 657 /** 658 * Interface definition for a callback to be invoked when an AudioRecord has 659 * reached a notification marker set by {@link AudioRecord#setNotificationMarkerPosition(int)} 660 * or for periodic updates on the progress of the record head, as set by 661 * {@link AudioRecord#setPositionNotificationPeriod(int)}. 662 */ 663 public interface OnRecordPositionUpdateListener { 664 /** 665 * Called on the listener to notify it that the previously set marker has been reached 666 * by the recording head. 667 */ 668 void onMarkerReached(AudioRecord recorder); 669 670 /** 671 * Called on the listener to periodically notify it that the record head has reached 672 * a multiple of the notification period. 673 */ 674 void onPeriodicNotification(AudioRecord recorder); 675 } 676 677 678 679 //--------------------------------------------------------- 680 // Inner classes 681 //-------------------- 682 683 /** 684 * Helper class to handle the forwarding of native events to the appropriate listener 685 * (potentially) handled in a different thread 686 */ 687 private class NativeEventHandler extends Handler { 688 689 private final AudioRecord mAudioRecord; 690 691 NativeEventHandler(AudioRecord recorder, Looper looper) { 692 super(looper); 693 mAudioRecord = recorder; 694 } 695 696 @Override 697 public void handleMessage(Message msg) { 698 OnRecordPositionUpdateListener listener = null; 699 synchronized (mPositionListenerLock) { 700 listener = mAudioRecord.mPositionListener; 701 } 702 703 switch(msg.what) { 704 case NATIVE_EVENT_MARKER: 705 if (listener != null) { 706 listener.onMarkerReached(mAudioRecord); 707 } 708 break; 709 case NATIVE_EVENT_NEW_POS: 710 if (listener != null) { 711 listener.onPeriodicNotification(mAudioRecord); 712 } 713 break; 714 default: 715 Log.e(TAG, "[ android.media.AudioRecord.NativeEventHandler ] " + 716 "Unknown event type: " + msg.what); 717 break; 718 } 719 } 720 }; 721 722 723 //--------------------------------------------------------- 724 // Java methods called from the native side 725 //-------------------- 726 @SuppressWarnings("unused") 727 private static void postEventFromNative(Object audiorecord_ref, 728 int what, int arg1, int arg2, Object obj) { 729 //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2); 730 AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get(); 731 if (recorder == null) { 732 return; 733 } 734 735 if (recorder.mEventHandler != null) { 736 Message m = 737 recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj); 738 recorder.mEventHandler.sendMessage(m); 739 } 740 741 } 742 743 744 //--------------------------------------------------------- 745 // Native methods called from the Java side 746 //-------------------- 747 748 private native final int native_setup(Object audiorecord_this, 749 int recordSource, int sampleRate, int nbChannels, int audioFormat, int buffSizeInBytes); 750 751 private native final void native_finalize(); 752 753 private native final void native_release(); 754 755 private native final void native_start(); 756 757 private native final void native_stop(); 758 759 private native final int native_read_in_byte_array(byte[] audioData, 760 int offsetInBytes, int sizeInBytes); 761 762 private native final int native_read_in_short_array(short[] audioData, 763 int offsetInShorts, int sizeInShorts); 764 765 private native final int native_read_in_direct_buffer(Object jBuffer, int sizeInBytes); 766 767 private native final int native_set_marker_pos(int marker); 768 private native final int native_get_marker_pos(); 769 770 private native final int native_set_pos_update_period(int updatePeriod); 771 private native final int native_get_pos_update_period(); 772 773 static private native final int native_get_min_buff_size( 774 int sampleRateInHz, int channelCount, int audioFormat); 775 776 777 //--------------------------------------------------------- 778 // Utility methods 779 //------------------ 780 781 private static void logd(String msg) { 782 Log.d(TAG, "[ android.media.AudioRecord ] " + msg); 783 } 784 785 private static void loge(String msg) { 786 Log.e(TAG, "[ android.media.AudioRecord ] " + msg); 787 } 788 789} 790 791