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