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