2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.media;
19 import java.lang.ref.WeakReference;
20 import java.io.OutputStream;
21 import java.io.IOException;
22 import java.lang.IllegalArgumentException;
23 import java.lang.IllegalStateException;
24 import java.lang.Thread;
25 import java.nio.ByteBuffer;
27 import android.os.Handler;
28 import android.os.Looper;
29 import android.os.Message;
30 import android.util.Log;
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.
46 public class AudioRecord
48 //---------------------------------------------------------
50 //--------------------
52 * indicates AudioRecord state is not successfully initialized.
54 public static final int STATE_UNINITIALIZED = 0;
56 * indicates AudioRecord state is ready to be used
58 public static final int STATE_INITIALIZED = 1;
61 * indicates AudioRecord recording state is not recording
63 public static final int RECORDSTATE_STOPPED = 1; // matches SL_RECORDSTATE_STOPPED
65 * indicates AudioRecord recording state is recording
67 public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING
70 // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp
72 * Denotes a successful operation.
74 public static final int SUCCESS = 0;
76 * Denotes a generic operation failure.
78 public static final int ERROR = -1;
80 * Denotes a failure due to the use of an invalid value.
82 public static final int ERROR_BAD_VALUE = -2;
84 * Denotes a failure due to the improper use of a method.
86 public static final int ERROR_INVALID_OPERATION = -3;
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;
95 // to keep in sync with frameworks/base/include/media/AudioRecord.h
97 * Event id denotes when record head has reached a previously set marker.
99 private static final int NATIVE_EVENT_MARKER = 2;
101 * Event id denotes when previously set update period has elapsed during recording.
103 private static final int NATIVE_EVENT_NEW_POS = 3;
105 private final static String TAG = "AudioRecord-Java";
108 //---------------------------------------------------------
109 // Used exclusively by native code
110 //--------------------
112 * Accessed by native methods: provides access to C++ AudioRecord object
114 @SuppressWarnings("unused")
115 private int mNativeRecorderInJavaObj;
118 * Accessed by native methods: provides access to the callback data.
120 @SuppressWarnings("unused")
121 private int mNativeCallbackCookie;
124 //---------------------------------------------------------
126 //--------------------
128 * The audio data sampling rate in Hz.
130 private int mSampleRate = 22050;
132 * The number of input audio channels (1 is mono, 2 is stereo)
134 private int mChannelCount = 1;
136 * The audio channel mask
138 private int mChannels = AudioFormat.CHANNEL_IN_MONO;
140 * The current audio channel configuration
142 private int mChannelConfiguration = AudioFormat.CHANNEL_IN_MONO;
144 * The encoding of the audio samples.
145 * @see AudioFormat#ENCODING_PCM_8BIT
146 * @see AudioFormat#ENCODING_PCM_16BIT
148 private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
150 * Where the audio data is recorded from.
152 private int mRecordSource = MediaRecorder.AudioSource.DEFAULT;
154 * Indicates the state of the AudioRecord instance.
156 private int mState = STATE_UNINITIALIZED;
158 * Indicates the recording state of the AudioRecord instance.
160 private int mRecordingState = RECORDSTATE_STOPPED;
162 * Lock to make sure mRecordingState updates are reflecting the actual state of the object.
164 private Object mRecordingStateLock = new Object();
166 * The listener the AudioRecord notifies when the record position reaches a marker
167 * or for periodic updates during the progression of the record head.
168 * @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)
169 * @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)
171 private OnRecordPositionUpdateListener mPositionListener = null;
173 * Lock to protect position listener updates against event notifications
175 private final Object mPositionListenerLock = new Object();
177 * Handler for marker events coming from the native code
179 private NativeEventHandler mEventHandler = null;
181 * Looper associated with the thread that creates the AudioRecord instance
183 private Looper mInitializationLooper = null;
185 * Size of the native audio buffer.
187 private int mNativeBufferSizeInBytes = 0;
190 //---------------------------------------------------------
191 // Constructor, Finalize
192 //--------------------
195 * @param audioSource the recording source. See {@link MediaRecorder.AudioSource} for
196 * recording source definitions.
197 * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but
198 * not limited to) 44100, 22050 and 11025.
199 * @param channelConfig describes the configuration of the audio channels.
200 * See {@link AudioFormat#CHANNEL_IN_MONO} and
201 * {@link AudioFormat#CHANNEL_IN_STEREO}
202 * @param audioFormat the format in which the audio data is represented.
203 * See {@link AudioFormat#ENCODING_PCM_16BIT} and
204 * {@link AudioFormat#ENCODING_PCM_8BIT}
205 * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
206 * to during the recording. New audio data can be read from this buffer in smaller chunks
207 * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
208 * required buffer size for the successful creation of an AudioRecord instance. Using values
209 * smaller than getMinBufferSize() will result in an initialization failure.
210 * @throws java.lang.IllegalArgumentException
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;
218 // remember which looper is associated with the AudioRecord instanciation
219 if ((mInitializationLooper = Looper.myLooper()) == null) {
220 mInitializationLooper = Looper.getMainLooper();
223 audioParamCheck(audioSource, sampleRateInHz, channelConfig, audioFormat);
225 audioBuffSizeCheck(bufferSizeInBytes);
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, mChannels, mAudioFormat, mNativeBufferSizeInBytes);
232 if (initResult != SUCCESS) {
233 loge("Error code "+initResult+" when initializing native AudioRecord object.");
234 return; // with mState == STATE_UNINITIALIZED
237 mState = STATE_INITIALIZED;
241 // Convenience method for the constructor's parameter checks.
242 // This is where constructor IllegalArgumentException-s are thrown
244 // mRecordSource is valid
245 // mChannelCount is valid
246 // mChannels is valid
247 // mAudioFormat is valid
248 // mSampleRate is valid
249 private void audioParamCheck(int audioSource, int sampleRateInHz,
250 int channelConfig, int audioFormat) {
254 if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) ||
255 (audioSource > MediaRecorder.AudioSource.VOICE_COMMUNICATION) ) {
256 //(audioSource > MediaRecorder.getAudioSourceMax()) ) {
257 throw (new IllegalArgumentException("Invalid audio source."));
259 mRecordSource = audioSource;
264 if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
265 throw (new IllegalArgumentException(sampleRateInHz
266 + "Hz is not a supported sample rate."));
268 mSampleRate = sampleRateInHz;
273 mChannelConfiguration = channelConfig;
275 switch (channelConfig) {
276 case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
277 case AudioFormat.CHANNEL_IN_MONO:
278 case AudioFormat.CHANNEL_CONFIGURATION_MONO:
280 mChannels = AudioFormat.CHANNEL_IN_MONO;
282 case AudioFormat.CHANNEL_IN_STEREO:
283 case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
285 mChannels = AudioFormat.CHANNEL_IN_STEREO;
289 mChannels = AudioFormat.CHANNEL_INVALID;
290 mChannelConfiguration = AudioFormat.CHANNEL_INVALID;
291 throw (new IllegalArgumentException("Unsupported channel configuration."));
296 switch (audioFormat) {
297 case AudioFormat.ENCODING_DEFAULT:
298 mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
300 case AudioFormat.ENCODING_PCM_16BIT:
301 case AudioFormat.ENCODING_PCM_8BIT:
302 mAudioFormat = audioFormat;
305 mAudioFormat = AudioFormat.ENCODING_INVALID;
306 throw (new IllegalArgumentException("Unsupported sample encoding."
307 + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT."));
312 // Convenience method for the contructor's audio buffer size check.
314 // mChannelCount is valid
315 // mAudioFormat is AudioFormat.ENCODING_PCM_8BIT OR AudioFormat.ENCODING_PCM_16BIT
317 // mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
318 private void audioBuffSizeCheck(int audioBufferSize) {
319 // NB: this section is only valid with PCM data.
320 // To update when supporting compressed formats
321 int frameSizeInBytes = mChannelCount
322 * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
323 if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
324 throw (new IllegalArgumentException("Invalid audio buffer size."));
327 mNativeBufferSizeInBytes = audioBufferSize;
333 * Releases the native AudioRecord resources.
334 * The object can no longer be used and the reference should be set to null
335 * after a call to release()
337 public void release() {
340 } catch(IllegalStateException ise) {
341 // don't raise an exception, we're releasing the resources.
344 mState = STATE_UNINITIALIZED;
349 protected void finalize() {
354 //--------------------------------------------------------------------------
356 //--------------------
358 * Returns the configured audio data sample rate in Hz
360 public int getSampleRate() {
365 * Returns the audio recording source.
366 * @see MediaRecorder.AudioSource
368 public int getAudioSource() {
369 return mRecordSource;
373 * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT}
374 * and {@link AudioFormat#ENCODING_PCM_8BIT}.
376 public int getAudioFormat() {
381 * Returns the configured channel configuration.
382 * See {@link AudioFormat#CHANNEL_IN_MONO}
383 * and {@link AudioFormat#CHANNEL_IN_STEREO}.
385 public int getChannelConfiguration() {
386 return mChannelConfiguration;
390 * Returns the configured number of channels.
392 public int getChannelCount() {
393 return mChannelCount;
397 * Returns the state of the AudioRecord instance. This is useful after the
398 * AudioRecord instance has been created to check if it was initialized
399 * properly. This ensures that the appropriate hardware resources have been
401 * @see AudioRecord#STATE_INITIALIZED
402 * @see AudioRecord#STATE_UNINITIALIZED
404 public int getState() {
409 * Returns the recording state of the AudioRecord instance.
410 * @see AudioRecord#RECORDSTATE_STOPPED
411 * @see AudioRecord#RECORDSTATE_RECORDING
413 public int getRecordingState() {
414 return mRecordingState;
418 * Returns the notification marker position expressed in frames.
420 public int getNotificationMarkerPosition() {
421 return native_get_marker_pos();
425 * Returns the notification update period expressed in frames.
427 public int getPositionNotificationPeriod() {
428 return native_get_pos_update_period();
432 * Returns the minimum buffer size required for the successful creation of an AudioRecord
434 * Note that this size doesn't guarantee a smooth recording under load, and higher values
435 * should be chosen according to the expected frequency at which the AudioRecord instance
436 * will be polled for new data.
437 * @param sampleRateInHz the sample rate expressed in Hertz.
438 * @param channelConfig describes the configuration of the audio channels.
439 * See {@link AudioFormat#CHANNEL_IN_MONO} and
440 * {@link AudioFormat#CHANNEL_IN_STEREO}
441 * @param audioFormat the format in which the audio data is represented.
442 * See {@link AudioFormat#ENCODING_PCM_16BIT}.
443 * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the
444 * hardware, or an invalid parameter was passed,
445 * or {@link #ERROR} if the implementation was unable to query the hardware for its
447 * or the minimum buffer size expressed in bytes.
449 static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
450 int channelCount = 0;
451 switch(channelConfig) {
452 case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
453 case AudioFormat.CHANNEL_IN_MONO:
454 case AudioFormat.CHANNEL_CONFIGURATION_MONO:
457 case AudioFormat.CHANNEL_IN_STEREO:
458 case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
461 case AudioFormat.CHANNEL_INVALID:
463 loge("getMinBufferSize(): Invalid channel configuration.");
464 return AudioRecord.ERROR_BAD_VALUE;
467 // PCM_8BIT is not supported at the moment
468 if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) {
469 loge("getMinBufferSize(): Invalid audio format.");
470 return AudioRecord.ERROR_BAD_VALUE;
473 int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
475 return AudioRecord.ERROR_BAD_VALUE;
477 else if (size == -1) {
478 return AudioRecord.ERROR;
486 //---------------------------------------------------------
487 // Transport control methods
488 //--------------------
490 * Starts recording from the AudioRecord instance.
491 * @throws IllegalStateException
493 public void startRecording()
494 throws IllegalStateException {
495 if (mState != STATE_INITIALIZED) {
496 throw(new IllegalStateException("startRecording() called on an "
497 +"uninitialized AudioRecord."));
501 synchronized(mRecordingStateLock) {
502 if (native_start() == SUCCESS) {
503 mRecordingState = RECORDSTATE_RECORDING;
512 * @throws IllegalStateException
515 throws IllegalStateException {
516 if (mState != STATE_INITIALIZED) {
517 throw(new IllegalStateException("stop() called on an uninitialized AudioRecord."));
521 synchronized(mRecordingStateLock) {
523 mRecordingState = RECORDSTATE_STOPPED;
528 //---------------------------------------------------------
530 //--------------------
532 * Reads audio data from the audio hardware for recording into a buffer.
533 * @param audioData the array to which the recorded audio data is written.
534 * @param offsetInBytes index in audioData from which the data is written expressed in bytes.
535 * @param sizeInBytes the number of requested bytes.
536 * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
537 * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
538 * the parameters don't resolve to valid data and indexes.
539 * The number of bytes will not exceed sizeInBytes.
541 public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) {
542 if (mState != STATE_INITIALIZED) {
543 return ERROR_INVALID_OPERATION;
546 if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
547 || (offsetInBytes + sizeInBytes > audioData.length)) {
548 return ERROR_BAD_VALUE;
551 return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes);
556 * Reads audio data from the audio hardware for recording into a buffer.
557 * @param audioData the array to which the recorded audio data is written.
558 * @param offsetInShorts index in audioData from which the data is written expressed in shorts.
559 * @param sizeInShorts the number of requested shorts.
560 * @return the number of shorts that were read or or {@link #ERROR_INVALID_OPERATION}
561 * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
562 * the parameters don't resolve to valid data and indexes.
563 * The number of shorts will not exceed sizeInShorts.
565 public int read(short[] audioData, int offsetInShorts, int sizeInShorts) {
566 if (mState != STATE_INITIALIZED) {
567 return ERROR_INVALID_OPERATION;
570 if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
571 || (offsetInShorts + sizeInShorts > audioData.length)) {
572 return ERROR_BAD_VALUE;
575 return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts);
580 * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
581 * is not a direct buffer, this method will always return 0.
582 * @param audioBuffer the direct buffer to which the recorded audio data is written.
583 * @param sizeInBytes the number of requested bytes.
584 * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
585 * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
586 * the parameters don't resolve to valid data and indexes.
587 * The number of bytes will not exceed sizeInBytes.
589 public int read(ByteBuffer audioBuffer, int sizeInBytes) {
590 if (mState != STATE_INITIALIZED) {
591 return ERROR_INVALID_OPERATION;
594 if ( (audioBuffer == null) || (sizeInBytes < 0) ) {
595 return ERROR_BAD_VALUE;
598 return native_read_in_direct_buffer(audioBuffer, sizeInBytes);
602 //--------------------------------------------------------------------------
603 // Initialization / configuration
604 //--------------------
606 * Sets the listener the AudioRecord notifies when a previously set marker is reached or
607 * for each periodic record head position update.
610 public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener) {
611 setRecordPositionUpdateListener(listener, null);
615 * Sets the listener the AudioRecord notifies when a previously set marker is reached or
616 * for each periodic record head position update.
617 * Use this method to receive AudioRecord events in the Handler associated with another
618 * thread than the one in which you created the AudioTrack instance.
620 * @param handler the Handler that will receive the event notification messages.
622 public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener,
624 synchronized (mPositionListenerLock) {
626 mPositionListener = listener;
628 if (listener != null) {
629 if (handler != null) {
630 mEventHandler = new NativeEventHandler(this, handler.getLooper());
632 // no given handler, use the looper the AudioRecord was created in
633 mEventHandler = new NativeEventHandler(this, mInitializationLooper);
636 mEventHandler = null;
644 * Sets the marker position at which the listener is called, if set with
645 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
646 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
647 * @param markerInFrames marker position expressed in frames
648 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
649 * {@link #ERROR_INVALID_OPERATION}
651 public int setNotificationMarkerPosition(int markerInFrames) {
652 return native_set_marker_pos(markerInFrames);
657 * Sets the period at which the listener is called, if set with
658 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
659 * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
660 * @param periodInFrames update period expressed in frames
661 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
663 public int setPositionNotificationPeriod(int periodInFrames) {
664 return native_set_pos_update_period(periodInFrames);
668 //---------------------------------------------------------
669 // Interface definitions
670 //--------------------
672 * Interface definition for a callback to be invoked when an AudioRecord has
673 * reached a notification marker set by {@link AudioRecord#setNotificationMarkerPosition(int)}
674 * or for periodic updates on the progress of the record head, as set by
675 * {@link AudioRecord#setPositionNotificationPeriod(int)}.
677 public interface OnRecordPositionUpdateListener {
679 * Called on the listener to notify it that the previously set marker has been reached
680 * by the recording head.
682 void onMarkerReached(AudioRecord recorder);
685 * Called on the listener to periodically notify it that the record head has reached
686 * a multiple of the notification period.
688 void onPeriodicNotification(AudioRecord recorder);
693 //---------------------------------------------------------
695 //--------------------
698 * Helper class to handle the forwarding of native events to the appropriate listener
699 * (potentially) handled in a different thread
701 private class NativeEventHandler extends Handler {
703 private final AudioRecord mAudioRecord;
705 NativeEventHandler(AudioRecord recorder, Looper looper) {
707 mAudioRecord = recorder;
711 public void handleMessage(Message msg) {
712 OnRecordPositionUpdateListener listener = null;
713 synchronized (mPositionListenerLock) {
714 listener = mAudioRecord.mPositionListener;
718 case NATIVE_EVENT_MARKER:
719 if (listener != null) {
720 listener.onMarkerReached(mAudioRecord);
723 case NATIVE_EVENT_NEW_POS:
724 if (listener != null) {
725 listener.onPeriodicNotification(mAudioRecord);
729 Log.e(TAG, "[ android.media.AudioRecord.NativeEventHandler ] " +
730 "Unknown event type: " + msg.what);
737 //---------------------------------------------------------
738 // Java methods called from the native side
739 //--------------------
740 @SuppressWarnings("unused")
741 private static void postEventFromNative(Object audiorecord_ref,
742 int what, int arg1, int arg2, Object obj) {
743 //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
744 AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get();
745 if (recorder == null) {
749 if (recorder.mEventHandler != null) {
751 recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj);
752 recorder.mEventHandler.sendMessage(m);
758 //---------------------------------------------------------
759 // Native methods called from the Java side
760 //--------------------
762 private native final int native_setup(Object audiorecord_this,
763 int recordSource, int sampleRate, int nbChannels, int audioFormat, int buffSizeInBytes);
765 private native final void native_finalize();
767 private native final void native_release();
769 private native final int native_start();
771 private native final void native_stop();
773 private native final int native_read_in_byte_array(byte[] audioData,
774 int offsetInBytes, int sizeInBytes);
776 private native final int native_read_in_short_array(short[] audioData,
777 int offsetInShorts, int sizeInShorts);
779 private native final int native_read_in_direct_buffer(Object jBuffer, int sizeInBytes);
781 private native final int native_set_marker_pos(int marker);
782 private native final int native_get_marker_pos();
784 private native final int native_set_pos_update_period(int updatePeriod);
785 private native final int native_get_pos_update_period();
787 static private native final int native_get_min_buff_size(
788 int sampleRateInHz, int channelCount, int audioFormat);
791 //---------------------------------------------------------
795 private static void logd(String msg) {
796 Log.d(TAG, "[ android.media.AudioRecord ] " + msg);
799 private static void loge(String msg) {
800 Log.e(TAG, "[ android.media.AudioRecord ] " + msg);