• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.media;
18 
19 import java.lang.ref.WeakReference;
20 import java.nio.ByteBuffer;
21 import java.util.Iterator;
22 
23 import android.os.Binder;
24 import android.os.Handler;
25 import android.os.IBinder;
26 import android.os.Looper;
27 import android.os.Message;
28 import android.os.RemoteException;
29 import android.os.ServiceManager;
30 import 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  */
46 public 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      */
AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)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      */
AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, int sessionId)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
getChannelMaskFromLegacyConfig(int inChannelConfig, boolean allowLegacyConfig)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
audioParamCheck(int audioSource, int sampleRateInHz, int audioFormat)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)
audioBuffSizeCheck(int audioBufferSize)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      */
release()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
finalize()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      */
getSampleRate()459     public int getSampleRate() {
460         return mSampleRate;
461     }
462 
463     /**
464      * Returns the audio recording source.
465      * @see MediaRecorder.AudioSource
466      */
getAudioSource()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      */
getAudioFormat()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      */
getChannelConfiguration()484     public int getChannelConfiguration() {
485         return mChannelMask;
486     }
487 
488     /**
489      * Returns the configured number of channels.
490      */
getChannelCount()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      */
getState()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      */
getRecordingState()512     public int getRecordingState() {
513         synchronized (mRecordingStateLock) {
514             return mRecordingState;
515         }
516     }
517 
518     /**
519      * Returns the notification marker position expressed in frames.
520      */
getNotificationMarkerPosition()521     public int getNotificationMarkerPosition() {
522         return native_get_marker_pos();
523     }
524 
525     /**
526      * Returns the notification update period expressed in frames.
527      */
getPositionNotificationPeriod()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      */
getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)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      */
getAudioSessionId()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      */
startRecording()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      */
startRecording(MediaSyncEvent syncEvent)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      */
stop()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();
handleFullVolumeRec(boolean starting)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      */
read(byte[] audioData, int offsetInBytes, int sizeInBytes)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      */
read(short[] audioData, int offsetInShorts, int sizeInShorts)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      */
read(ByteBuffer audioBuffer, int sizeInBytes)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      */
setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener)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      */
setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, Handler handler)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      */
setNotificationMarkerPosition(int markerInFrames)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      */
setPositionNotificationPeriod(int periodInFrames)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          */
onMarkerReached(AudioRecord recorder)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          */
onPeriodicNotification(AudioRecord recorder)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 
NativeEventHandler(AudioRecord recorder, Looper looper)865         NativeEventHandler(AudioRecord recorder, Looper looper) {
866             super(looper);
867             mAudioRecord = recorder;
868         }
869 
870         @Override
handleMessage(Message msg)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")
postEventFromNative(Object audiorecord_ref, int what, int arg1, int arg2, Object obj)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 
native_setup(Object audiorecord_this, Object attributes, int sampleRate, int channelMask, int audioFormat, int buffSizeInBytes, int[] sessionId)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()
native_finalize()927     private native final void native_finalize();
928 
native_release()929     private native final void native_release();
930 
native_start(int syncEvent, int sessionId)931     private native final int native_start(int syncEvent, int sessionId);
932 
native_stop()933     private native final void native_stop();
934 
native_read_in_byte_array(byte[] audioData, int offsetInBytes, int sizeInBytes)935     private native final int native_read_in_byte_array(byte[] audioData,
936             int offsetInBytes, int sizeInBytes);
937 
native_read_in_short_array(short[] audioData, int offsetInShorts, int sizeInShorts)938     private native final int native_read_in_short_array(short[] audioData,
939             int offsetInShorts, int sizeInShorts);
940 
native_read_in_direct_buffer(Object jBuffer, int sizeInBytes)941     private native final int native_read_in_direct_buffer(Object jBuffer, int sizeInBytes);
942 
native_set_marker_pos(int marker)943     private native final int native_set_marker_pos(int marker);
native_get_marker_pos()944     private native final int native_get_marker_pos();
945 
native_set_pos_update_period(int updatePeriod)946     private native final int native_set_pos_update_period(int updatePeriod);
native_get_pos_update_period()947     private native final int native_get_pos_update_period();
948 
native_get_min_buff_size( int sampleRateInHz, int channelCount, int audioFormat)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 
logd(String msg)957     private static void logd(String msg) {
958         Log.d(TAG, msg);
959     }
960 
loge(String msg)961     private static void loge(String msg) {
962         Log.e(TAG, msg);
963     }
964 
965 }
966