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