• 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.annotation.Retention;
20 import java.lang.annotation.RetentionPolicy;
21 import java.lang.ref.WeakReference;
22 import java.nio.ByteBuffer;
23 import java.util.Collection;
24 import java.util.Iterator;
25 
26 import android.annotation.IntDef;
27 import android.annotation.NonNull;
28 import android.annotation.SystemApi;
29 import android.app.ActivityThread;
30 import android.os.Binder;
31 import android.os.Handler;
32 import android.os.IBinder;
33 import android.os.Looper;
34 import android.os.Message;
35 import android.os.RemoteException;
36 import android.os.ServiceManager;
37 import android.util.ArrayMap;
38 import android.util.Log;
39 
40 /**
41  * The AudioRecord class manages the audio resources for Java applications
42  * to record audio from the audio input hardware of the platform. This is
43  * achieved by "pulling" (reading) the data from the AudioRecord object. The
44  * application is responsible for polling the AudioRecord object in time using one of
45  * the following three methods:  {@link #read(byte[],int, int)}, {@link #read(short[], int, int)}
46  * or {@link #read(ByteBuffer, int)}. The choice of which method to use will be based
47  * on the audio data storage format that is the most convenient for the user of AudioRecord.
48  * <p>Upon creation, an AudioRecord object initializes its associated audio buffer that it will
49  * fill with the new audio data. The size of this buffer, specified during the construction,
50  * determines how long an AudioRecord can record before "over-running" data that has not
51  * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
52  * the total recording buffer size.
53  */
54 public class AudioRecord
55 {
56     //---------------------------------------------------------
57     // Constants
58     //--------------------
59 
60     /** Minimum value for sample rate */
61     private static final int SAMPLE_RATE_HZ_MIN = 4000;
62     /** Maximum value for sample rate */
63     private static final int SAMPLE_RATE_HZ_MAX = 192000;
64 
65     /**
66      *  indicates AudioRecord state is not successfully initialized.
67      */
68     public static final int STATE_UNINITIALIZED = 0;
69     /**
70      *  indicates AudioRecord state is ready to be used
71      */
72     public static final int STATE_INITIALIZED   = 1;
73 
74     /**
75      * indicates AudioRecord recording state is not recording
76      */
77     public static final int RECORDSTATE_STOPPED = 1;  // matches SL_RECORDSTATE_STOPPED
78     /**
79      * indicates AudioRecord recording state is recording
80      */
81     public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING
82 
83     /**
84      * Denotes a successful operation.
85      */
86     public  static final int SUCCESS                               = AudioSystem.SUCCESS;
87     /**
88      * Denotes a generic operation failure.
89      */
90     public  static final int ERROR                                 = AudioSystem.ERROR;
91     /**
92      * Denotes a failure due to the use of an invalid value.
93      */
94     public  static final int ERROR_BAD_VALUE                       = AudioSystem.BAD_VALUE;
95     /**
96      * Denotes a failure due to the improper use of a method.
97      */
98     public  static final int ERROR_INVALID_OPERATION               = AudioSystem.INVALID_OPERATION;
99 
100     // Error codes:
101     // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp
102     private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      = -16;
103     private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK  = -17;
104     private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       = -18;
105     private static final int AUDIORECORD_ERROR_SETUP_INVALIDSOURCE       = -19;
106     private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    = -20;
107 
108     // Events:
109     // to keep in sync with frameworks/av/include/media/AudioRecord.h
110     /**
111      * Event id denotes when record head has reached a previously set marker.
112      */
113     private static final int NATIVE_EVENT_MARKER  = 2;
114     /**
115      * Event id denotes when previously set update period has elapsed during recording.
116      */
117     private static final int NATIVE_EVENT_NEW_POS = 3;
118 
119     private final static String TAG = "android.media.AudioRecord";
120 
121     /** @hide */
122     public final static String SUBMIX_FIXED_VOLUME = "fixedVolume";
123 
124     /** @hide */
125     @IntDef({
126         READ_BLOCKING,
127         READ_NON_BLOCKING
128     })
129     @Retention(RetentionPolicy.SOURCE)
130     public @interface ReadMode {}
131 
132     /**
133      * The read mode indicating the read operation will block until all data
134      * requested has been read.
135      */
136     public final static int READ_BLOCKING = 0;
137 
138     /**
139      * The read mode indicating the read operation will return immediately after
140      * reading as much audio data as possible without blocking.
141      */
142     public final static int READ_NON_BLOCKING = 1;
143 
144     //---------------------------------------------------------
145     // Used exclusively by native code
146     //--------------------
147     /**
148      * Accessed by native methods: provides access to C++ AudioRecord object
149      */
150     @SuppressWarnings("unused")
151     private long mNativeRecorderInJavaObj;
152 
153     /**
154      * Accessed by native methods: provides access to the callback data.
155      */
156     @SuppressWarnings("unused")
157     private long mNativeCallbackCookie;
158 
159     /**
160      * Accessed by native methods: provides access to the JNIDeviceCallback instance.
161      */
162     @SuppressWarnings("unused")
163     private long mNativeDeviceCallback;
164 
165 
166     //---------------------------------------------------------
167     // Member variables
168     //--------------------
169     /**
170      * The audio data sampling rate in Hz.
171      */
172     private int mSampleRate;
173     /**
174      * The number of input audio channels (1 is mono, 2 is stereo)
175      */
176     private int mChannelCount;
177     /**
178      * The audio channel position mask
179      */
180     private int mChannelMask;
181     /**
182      * The audio channel index mask
183      */
184     private int mChannelIndexMask;
185     /**
186      * The encoding of the audio samples.
187      * @see AudioFormat#ENCODING_PCM_8BIT
188      * @see AudioFormat#ENCODING_PCM_16BIT
189      * @see AudioFormat#ENCODING_PCM_FLOAT
190      */
191     private int mAudioFormat;
192     /**
193      * Where the audio data is recorded from.
194      */
195     private int mRecordSource;
196     /**
197      * Indicates the state of the AudioRecord instance.
198      */
199     private int mState = STATE_UNINITIALIZED;
200     /**
201      * Indicates the recording state of the AudioRecord instance.
202      */
203     private int mRecordingState = RECORDSTATE_STOPPED;
204     /**
205      * Lock to make sure mRecordingState updates are reflecting the actual state of the object.
206      */
207     private final Object mRecordingStateLock = new Object();
208     /**
209      * The listener the AudioRecord notifies when the record position reaches a marker
210      * or for periodic updates during the progression of the record head.
211      *  @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)
212      *  @see #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)
213      */
214     private OnRecordPositionUpdateListener mPositionListener = null;
215     /**
216      * Lock to protect position listener updates against event notifications
217      */
218     private final Object mPositionListenerLock = new Object();
219     /**
220      * Handler for marker events coming from the native code
221      */
222     private NativeEventHandler mEventHandler = null;
223     /**
224      * Looper associated with the thread that creates the AudioRecord instance
225      */
226     private Looper mInitializationLooper = null;
227     /**
228      * Size of the native audio buffer.
229      */
230     private int mNativeBufferSizeInBytes = 0;
231     /**
232      * Audio session ID
233      */
234     private int mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE;
235     /**
236      * AudioAttributes
237      */
238     private AudioAttributes mAudioAttributes;
239     private boolean mIsSubmixFullVolume = false;
240 
241     //---------------------------------------------------------
242     // Constructor, Finalize
243     //--------------------
244     /**
245      * Class constructor.
246      * Though some invalid parameters will result in an {@link IllegalArgumentException} exception,
247      * other errors do not.  Thus you should call {@link #getState()} immediately after construction
248      * to confirm that the object is usable.
249      * @param audioSource the recording source.
250      *   See {@link MediaRecorder.AudioSource} for the recording source definitions.
251      * @param sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only
252      *   rate that is guaranteed to work on all devices, but other rates such as 22050,
253      *   16000, and 11025 may work on some devices.
254      * @param channelConfig describes the configuration of the audio channels.
255      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
256      *   {@link AudioFormat#CHANNEL_IN_STEREO}.  {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
257      *   to work on all devices.
258      * @param audioFormat the format in which the audio data is to be returned.
259      *   See {@link AudioFormat#ENCODING_PCM_8BIT}, {@link AudioFormat#ENCODING_PCM_16BIT},
260      *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
261      * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
262      *   to during the recording. New audio data can be read from this buffer in smaller chunks
263      *   than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
264      *   required buffer size for the successful creation of an AudioRecord instance. Using values
265      *   smaller than getMinBufferSize() will result in an initialization failure.
266      * @throws java.lang.IllegalArgumentException
267      */
AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)268     public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
269             int bufferSizeInBytes)
270     throws IllegalArgumentException {
271         this((new AudioAttributes.Builder())
272                     .setInternalCapturePreset(audioSource)
273                     .build(),
274                 (new AudioFormat.Builder())
275                     .setChannelMask(getChannelMaskFromLegacyConfig(channelConfig,
276                                         true/*allow legacy configurations*/))
277                     .setEncoding(audioFormat)
278                     .setSampleRate(sampleRateInHz)
279                     .build(),
280                 bufferSizeInBytes,
281                 AudioManager.AUDIO_SESSION_ID_GENERATE);
282     }
283 
284     /**
285      * @hide
286      * Class constructor with {@link AudioAttributes} and {@link AudioFormat}.
287      * @param attributes a non-null {@link AudioAttributes} instance. Use
288      *     {@link AudioAttributes.Builder#setAudioSource(int)} for configuring the audio
289      *     source for this instance.
290      * @param format a non-null {@link AudioFormat} instance describing the format of the data
291      *     that will be recorded through this AudioRecord. See {@link AudioFormat.Builder} for
292      *     configuring the audio format parameters such as encoding, channel mask and sample rate.
293      * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
294      *   to during the recording. New audio data can be read from this buffer in smaller chunks
295      *   than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
296      *   required buffer size for the successful creation of an AudioRecord instance. Using values
297      *   smaller than getMinBufferSize() will result in an initialization failure.
298      * @param sessionId ID of audio session the AudioRecord must be attached to, or
299      *   {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at construction
300      *   time. See also {@link AudioManager#generateAudioSessionId()} to obtain a session ID before
301      *   construction.
302      * @throws IllegalArgumentException
303      */
304     @SystemApi
AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes, int sessionId)305     public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
306             int sessionId) throws IllegalArgumentException {
307         mRecordingState = RECORDSTATE_STOPPED;
308 
309         if (attributes == null) {
310             throw new IllegalArgumentException("Illegal null AudioAttributes");
311         }
312         if (format == null) {
313             throw new IllegalArgumentException("Illegal null AudioFormat");
314         }
315 
316         // remember which looper is associated with the AudioRecord instanciation
317         if ((mInitializationLooper = Looper.myLooper()) == null) {
318             mInitializationLooper = Looper.getMainLooper();
319         }
320 
321         // is this AudioRecord using REMOTE_SUBMIX at full volume?
322         if (attributes.getCapturePreset() == MediaRecorder.AudioSource.REMOTE_SUBMIX) {
323             final AudioAttributes.Builder filteredAttr = new AudioAttributes.Builder();
324             final Iterator<String> tagsIter = attributes.getTags().iterator();
325             while (tagsIter.hasNext()) {
326                 final String tag = tagsIter.next();
327                 if (tag.equalsIgnoreCase(SUBMIX_FIXED_VOLUME)) {
328                     mIsSubmixFullVolume = true;
329                     Log.v(TAG, "Will record from REMOTE_SUBMIX at full fixed volume");
330                 } else { // SUBMIX_FIXED_VOLUME: is not to be propagated to the native layers
331                     filteredAttr.addTag(tag);
332                 }
333             }
334             filteredAttr.setInternalCapturePreset(attributes.getCapturePreset());
335             mAudioAttributes = filteredAttr.build();
336         } else {
337             mAudioAttributes = attributes;
338         }
339 
340         int rate = 0;
341         if ((format.getPropertySetMask()
342                 & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0)
343         {
344             rate = format.getSampleRate();
345         } else {
346             rate = AudioSystem.getPrimaryOutputSamplingRate();
347             if (rate <= 0) {
348                 rate = 44100;
349             }
350         }
351 
352         int encoding = AudioFormat.ENCODING_DEFAULT;
353         if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0)
354         {
355             encoding = format.getEncoding();
356         }
357 
358         audioParamCheck(attributes.getCapturePreset(), rate, encoding);
359 
360         if ((format.getPropertySetMask()
361                 & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) {
362             mChannelIndexMask = format.getChannelIndexMask();
363             mChannelCount = format.getChannelCount();
364         }
365         if ((format.getPropertySetMask()
366                 & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0) {
367             mChannelMask = getChannelMaskFromLegacyConfig(format.getChannelMask(), false);
368             mChannelCount = format.getChannelCount();
369         } else if (mChannelIndexMask == 0) {
370             mChannelMask = getChannelMaskFromLegacyConfig(AudioFormat.CHANNEL_IN_DEFAULT, false);
371             mChannelCount =  AudioFormat.channelCountFromInChannelMask(mChannelMask);
372         }
373 
374         audioBuffSizeCheck(bufferSizeInBytes);
375 
376         int[] session = new int[1];
377         session[0] = sessionId;
378         //TODO: update native initialization when information about hardware init failure
379         //      due to capture device already open is available.
380         int initResult = native_setup( new WeakReference<AudioRecord>(this),
381                 mAudioAttributes, mSampleRate, mChannelMask, mChannelIndexMask,
382                 mAudioFormat, mNativeBufferSizeInBytes,
383                 session, ActivityThread.currentOpPackageName());
384         if (initResult != SUCCESS) {
385             loge("Error code "+initResult+" when initializing native AudioRecord object.");
386             return; // with mState == STATE_UNINITIALIZED
387         }
388 
389         mSessionId = session[0];
390 
391         mState = STATE_INITIALIZED;
392     }
393 
394     /**
395      * Builder class for {@link AudioRecord} objects.
396      * Use this class to configure and create an <code>AudioRecord</code> instance. By setting the
397      * recording source and audio format parameters, you indicate which of
398      * those vary from the default behavior on the device.
399      * <p> Here is an example where <code>Builder</code> is used to specify all {@link AudioFormat}
400      * parameters, to be used by a new <code>AudioRecord</code> instance:
401      *
402      * <pre class="prettyprint">
403      * AudioRecord recorder = new AudioRecord.Builder()
404      *         .setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION)
405      *         .setAudioFormat(new AudioFormat.Builder()
406      *                 .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
407      *                 .setSampleRate(32000)
408      *                 .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
409      *                 .build())
410      *         .setBufferSize(2*minBuffSize)
411      *         .build();
412      * </pre>
413      * <p>
414      * If the audio source is not set with {@link #setAudioSource(int)},
415      * {@link MediaRecorder.AudioSource#DEFAULT} is used.
416      * <br>If the audio format is not specified or is incomplete, its sample rate will be the
417      * default output sample rate of the device (see
418      * {@link AudioManager#PROPERTY_OUTPUT_SAMPLE_RATE}), its channel configuration will be
419      * {@link AudioFormat#CHANNEL_IN_MONO}, and the encoding will be
420      * {@link AudioFormat#ENCODING_PCM_16BIT}.
421      * <br>If the buffer size is not specified with {@link #setBufferSizeInBytes(int)},
422      * the minimum buffer size for the source is used.
423      */
424     public static class Builder {
425         private AudioAttributes mAttributes;
426         private AudioFormat mFormat;
427         private int mBufferSizeInBytes;
428         private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
429 
430         /**
431          * Constructs a new Builder with the default values as described above.
432          */
Builder()433         public Builder() {
434         }
435 
436         /**
437          * @param source the audio source.
438          * See {@link MediaRecorder.AudioSource} for the supported audio source definitions.
439          * @return the same Builder instance.
440          * @throws IllegalArgumentException
441          */
setAudioSource(int source)442         public Builder setAudioSource(int source) throws IllegalArgumentException {
443             if ( (source < MediaRecorder.AudioSource.DEFAULT) ||
444                     (source > MediaRecorder.getAudioSourceMax()) ) {
445                 throw new IllegalArgumentException("Invalid audio source " + source);
446             }
447             mAttributes = new AudioAttributes.Builder()
448                     .setInternalCapturePreset(source)
449                     .build();
450             return this;
451         }
452 
453         /**
454          * @hide
455          * To be only used by system components. Allows specifying non-public capture presets
456          * @param attributes a non-null {@link AudioAttributes} instance that contains the capture
457          *     preset to be used.
458          * @return the same Builder instance.
459          * @throws IllegalArgumentException
460          */
461         @SystemApi
setAudioAttributes(@onNull AudioAttributes attributes)462         public Builder setAudioAttributes(@NonNull AudioAttributes attributes)
463                 throws IllegalArgumentException {
464             if (attributes == null) {
465                 throw new IllegalArgumentException("Illegal null AudioAttributes argument");
466             }
467             if (attributes.getCapturePreset() == MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID) {
468                 throw new IllegalArgumentException(
469                         "No valid capture preset in AudioAttributes argument");
470             }
471             // keep reference, we only copy the data when building
472             mAttributes = attributes;
473             return this;
474         }
475 
476         /**
477          * Sets the format of the audio data to be captured.
478          * @param format a non-null {@link AudioFormat} instance
479          * @return the same Builder instance.
480          * @throws IllegalArgumentException
481          */
setAudioFormat(@onNull AudioFormat format)482         public Builder setAudioFormat(@NonNull AudioFormat format) throws IllegalArgumentException {
483             if (format == null) {
484                 throw new IllegalArgumentException("Illegal null AudioFormat argument");
485             }
486             // keep reference, we only copy the data when building
487             mFormat = format;
488             return this;
489         }
490 
491         /**
492          * Sets the total size (in bytes) of the buffer where audio data is written
493          * during the recording. New audio data can be read from this buffer in smaller chunks
494          * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
495          * required buffer size for the successful creation of an AudioRecord instance.
496          * Since bufferSizeInBytes may be internally increased to accommodate the source
497          * requirements, use {@link #getBufferSizeInFrames()} to determine the actual buffer size
498          * in frames.
499          * @param bufferSizeInBytes a value strictly greater than 0
500          * @return the same Builder instance.
501          * @throws IllegalArgumentException
502          */
setBufferSizeInBytes(int bufferSizeInBytes)503         public Builder setBufferSizeInBytes(int bufferSizeInBytes) throws IllegalArgumentException {
504             if (bufferSizeInBytes <= 0) {
505                 throw new IllegalArgumentException("Invalid buffer size " + bufferSizeInBytes);
506             }
507             mBufferSizeInBytes = bufferSizeInBytes;
508             return this;
509         }
510 
511         /**
512          * @hide
513          * To be only used by system components.
514          * @param sessionId ID of audio session the AudioRecord must be attached to, or
515          *     {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at
516          *     construction time.
517          * @return the same Builder instance.
518          * @throws IllegalArgumentException
519          */
520         @SystemApi
setSessionId(int sessionId)521         public Builder setSessionId(int sessionId) throws IllegalArgumentException {
522             if (sessionId < 0) {
523                 throw new IllegalArgumentException("Invalid session ID " + sessionId);
524             }
525             mSessionId = sessionId;
526             return this;
527         }
528 
529         /**
530          * @return a new {@link AudioRecord} instance successfully initialized with all
531          *     the parameters set on this <code>Builder</code>.
532          * @throws UnsupportedOperationException if the parameters set on the <code>Builder</code>
533          *     were incompatible, or if they are not supported by the device,
534          *     or if the device was not available.
535          */
build()536         public AudioRecord build() throws UnsupportedOperationException {
537             if (mFormat == null) {
538                 mFormat = new AudioFormat.Builder()
539                         .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
540                         .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
541                         .build();
542             } else {
543                 if (mFormat.getEncoding() == AudioFormat.ENCODING_INVALID) {
544                     mFormat = new AudioFormat.Builder(mFormat)
545                             .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
546                             .build();
547                 }
548                 if (mFormat.getChannelMask() == AudioFormat.CHANNEL_INVALID
549                         && mFormat.getChannelIndexMask() == AudioFormat.CHANNEL_INVALID) {
550                     mFormat = new AudioFormat.Builder(mFormat)
551                             .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
552                             .build();
553                 }
554             }
555             if (mAttributes == null) {
556                 mAttributes = new AudioAttributes.Builder()
557                         .setInternalCapturePreset(MediaRecorder.AudioSource.DEFAULT)
558                         .build();
559             }
560             try {
561                 // If the buffer size is not specified,
562                 // use a single frame for the buffer size and let the
563                 // native code figure out the minimum buffer size.
564                 if (mBufferSizeInBytes == 0) {
565                     mBufferSizeInBytes = mFormat.getChannelCount()
566                             * mFormat.getBytesPerSample(mFormat.getEncoding());
567                 }
568                 final AudioRecord record = new AudioRecord(
569                         mAttributes, mFormat, mBufferSizeInBytes, mSessionId);
570                 if (record.getState() == STATE_UNINITIALIZED) {
571                     // release is not necessary
572                     throw new UnsupportedOperationException("Cannot create AudioRecord");
573                 }
574                 return record;
575             } catch (IllegalArgumentException e) {
576                 throw new UnsupportedOperationException(e.getMessage());
577             }
578         }
579     }
580 
581     // Convenience method for the constructor's parameter checks.
582     // This, getChannelMaskFromLegacyConfig and audioBuffSizeCheck are where constructor
583     // IllegalArgumentException-s are thrown
getChannelMaskFromLegacyConfig(int inChannelConfig, boolean allowLegacyConfig)584     private static int getChannelMaskFromLegacyConfig(int inChannelConfig,
585             boolean allowLegacyConfig) {
586         int mask;
587         switch (inChannelConfig) {
588         case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
589         case AudioFormat.CHANNEL_IN_MONO:
590         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
591             mask = AudioFormat.CHANNEL_IN_MONO;
592             break;
593         case AudioFormat.CHANNEL_IN_STEREO:
594         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
595             mask = AudioFormat.CHANNEL_IN_STEREO;
596             break;
597         case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
598             mask = inChannelConfig;
599             break;
600         default:
601             throw new IllegalArgumentException("Unsupported channel configuration.");
602         }
603 
604         if (!allowLegacyConfig && ((inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_MONO)
605                 || (inChannelConfig == AudioFormat.CHANNEL_CONFIGURATION_STEREO))) {
606             // only happens with the constructor that uses AudioAttributes and AudioFormat
607             throw new IllegalArgumentException("Unsupported deprecated configuration.");
608         }
609 
610         return mask;
611     }
612     // postconditions:
613     //    mRecordSource is valid
614     //    mAudioFormat is valid
615     //    mSampleRate is valid
audioParamCheck(int audioSource, int sampleRateInHz, int audioFormat)616     private void audioParamCheck(int audioSource, int sampleRateInHz, int audioFormat)
617             throws IllegalArgumentException {
618 
619         //--------------
620         // audio source
621         if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) ||
622              ((audioSource > MediaRecorder.getAudioSourceMax()) &&
623               (audioSource != MediaRecorder.AudioSource.RADIO_TUNER) &&
624               (audioSource != MediaRecorder.AudioSource.HOTWORD)) )  {
625             throw new IllegalArgumentException("Invalid audio source.");
626         }
627         mRecordSource = audioSource;
628 
629         //--------------
630         // sample rate
631         if ((sampleRateInHz < SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > SAMPLE_RATE_HZ_MAX)) {
632             throw new IllegalArgumentException(sampleRateInHz
633                     + "Hz is not a supported sample rate.");
634         }
635         mSampleRate = sampleRateInHz;
636 
637         //--------------
638         // audio format
639         switch (audioFormat) {
640         case AudioFormat.ENCODING_DEFAULT:
641             mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
642             break;
643         case AudioFormat.ENCODING_PCM_FLOAT:
644         case AudioFormat.ENCODING_PCM_16BIT:
645         case AudioFormat.ENCODING_PCM_8BIT:
646             mAudioFormat = audioFormat;
647             break;
648         default:
649             throw new IllegalArgumentException("Unsupported sample encoding."
650                     + " Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, or ENCODING_PCM_FLOAT.");
651         }
652     }
653 
654 
655     // Convenience method for the contructor's audio buffer size check.
656     // preconditions:
657     //    mChannelCount is valid
658     //    mAudioFormat is AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT,
659     //                 or AudioFormat.ENCODING_PCM_FLOAT
660     // postcondition:
661     //    mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
audioBuffSizeCheck(int audioBufferSize)662     private void audioBuffSizeCheck(int audioBufferSize) throws IllegalArgumentException {
663         // NB: this section is only valid with PCM data.
664         // To update when supporting compressed formats
665         int frameSizeInBytes = mChannelCount
666             * (AudioFormat.getBytesPerSample(mAudioFormat));
667         if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
668             throw new IllegalArgumentException("Invalid audio buffer size.");
669         }
670 
671         mNativeBufferSizeInBytes = audioBufferSize;
672     }
673 
674 
675 
676     /**
677      * Releases the native AudioRecord resources.
678      * The object can no longer be used and the reference should be set to null
679      * after a call to release()
680      */
release()681     public void release() {
682         try {
683             stop();
684         } catch(IllegalStateException ise) {
685             // don't raise an exception, we're releasing the resources.
686         }
687         native_release();
688         mState = STATE_UNINITIALIZED;
689     }
690 
691 
692     @Override
finalize()693     protected void finalize() {
694         // will cause stop() to be called, and if appropriate, will handle fixed volume recording
695         release();
696     }
697 
698 
699     //--------------------------------------------------------------------------
700     // Getters
701     //--------------------
702     /**
703      * Returns the configured audio data sample rate in Hz
704      */
getSampleRate()705     public int getSampleRate() {
706         return mSampleRate;
707     }
708 
709     /**
710      * Returns the audio recording source.
711      * @see MediaRecorder.AudioSource
712      */
getAudioSource()713     public int getAudioSource() {
714         return mRecordSource;
715     }
716 
717     /**
718      * Returns the configured audio data encoding. See {@link AudioFormat#ENCODING_PCM_8BIT},
719      * {@link AudioFormat#ENCODING_PCM_16BIT}, and {@link AudioFormat#ENCODING_PCM_FLOAT}.
720      */
getAudioFormat()721     public int getAudioFormat() {
722         return mAudioFormat;
723     }
724 
725     /**
726      * Returns the configured channel position mask.
727      * <p> See {@link AudioFormat#CHANNEL_IN_MONO}
728      * and {@link AudioFormat#CHANNEL_IN_STEREO}.
729      * This method may return {@link AudioFormat#CHANNEL_INVALID} if
730      * a channel index mask is used.
731      * Consider {@link #getFormat()} instead, to obtain an {@link AudioFormat},
732      * which contains both the channel position mask and the channel index mask.
733      */
getChannelConfiguration()734     public int getChannelConfiguration() {
735         return mChannelMask;
736     }
737 
738     /**
739      * Returns the configured <code>AudioRecord</code> format.
740      * @return an {@link AudioFormat} containing the
741      * <code>AudioRecord</code> parameters at the time of configuration.
742      */
getFormat()743     public @NonNull AudioFormat getFormat() {
744         AudioFormat.Builder builder = new AudioFormat.Builder()
745             .setSampleRate(mSampleRate)
746             .setEncoding(mAudioFormat);
747         if (mChannelMask != AudioFormat.CHANNEL_INVALID) {
748             builder.setChannelMask(mChannelMask);
749         }
750         if (mChannelIndexMask != AudioFormat.CHANNEL_INVALID  /* 0 */) {
751             builder.setChannelIndexMask(mChannelIndexMask);
752         }
753         return builder.build();
754     }
755 
756     /**
757      * Returns the configured number of channels.
758      */
getChannelCount()759     public int getChannelCount() {
760         return mChannelCount;
761     }
762 
763     /**
764      * Returns the state of the AudioRecord instance. This is useful after the
765      * AudioRecord instance has been created to check if it was initialized
766      * properly. This ensures that the appropriate hardware resources have been
767      * acquired.
768      * @see AudioRecord#STATE_INITIALIZED
769      * @see AudioRecord#STATE_UNINITIALIZED
770      */
getState()771     public int getState() {
772         return mState;
773     }
774 
775     /**
776      * Returns the recording state of the AudioRecord instance.
777      * @see AudioRecord#RECORDSTATE_STOPPED
778      * @see AudioRecord#RECORDSTATE_RECORDING
779      */
getRecordingState()780     public int getRecordingState() {
781         synchronized (mRecordingStateLock) {
782             return mRecordingState;
783         }
784     }
785 
786     /**
787      *  Returns the frame count of the native <code>AudioRecord</code> buffer.
788      *  This is greater than or equal to the bufferSizeInBytes converted to frame units
789      *  specified in the <code>AudioRecord</code> constructor or Builder.
790      *  The native frame count may be enlarged to accommodate the requirements of the
791      *  source on creation or if the <code>AudioRecord</code>
792      *  is subsequently rerouted.
793      *  @return current size in frames of the <code>AudioRecord</code> buffer.
794      *  @throws IllegalStateException
795      */
getBufferSizeInFrames()796     public int getBufferSizeInFrames() {
797         return native_get_buffer_size_in_frames();
798     }
799 
800     /**
801      * Returns the notification marker position expressed in frames.
802      */
getNotificationMarkerPosition()803     public int getNotificationMarkerPosition() {
804         return native_get_marker_pos();
805     }
806 
807     /**
808      * Returns the notification update period expressed in frames.
809      */
getPositionNotificationPeriod()810     public int getPositionNotificationPeriod() {
811         return native_get_pos_update_period();
812     }
813 
814     /**
815      * Returns the minimum buffer size required for the successful creation of an AudioRecord
816      * object, in byte units.
817      * Note that this size doesn't guarantee a smooth recording under load, and higher values
818      * should be chosen according to the expected frequency at which the AudioRecord instance
819      * will be polled for new data.
820      * See {@link #AudioRecord(int, int, int, int, int)} for more information on valid
821      * configuration values.
822      * @param sampleRateInHz the sample rate expressed in Hertz.
823      * @param channelConfig describes the configuration of the audio channels.
824      *   See {@link AudioFormat#CHANNEL_IN_MONO} and
825      *   {@link AudioFormat#CHANNEL_IN_STEREO}
826      * @param audioFormat the format in which the audio data is represented.
827      *   See {@link AudioFormat#ENCODING_PCM_16BIT}.
828      * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the
829      *  hardware, or an invalid parameter was passed,
830      *  or {@link #ERROR} if the implementation was unable to query the hardware for its
831      *  input properties,
832      *   or the minimum buffer size expressed in bytes.
833      * @see #AudioRecord(int, int, int, int, int)
834      */
getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)835     static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
836         int channelCount = 0;
837         switch (channelConfig) {
838         case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
839         case AudioFormat.CHANNEL_IN_MONO:
840         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
841             channelCount = 1;
842             break;
843         case AudioFormat.CHANNEL_IN_STEREO:
844         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
845         case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
846             channelCount = 2;
847             break;
848         case AudioFormat.CHANNEL_INVALID:
849         default:
850             loge("getMinBufferSize(): Invalid channel configuration.");
851             return ERROR_BAD_VALUE;
852         }
853 
854         int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
855         if (size == 0) {
856             return ERROR_BAD_VALUE;
857         }
858         else if (size == -1) {
859             return ERROR;
860         }
861         else {
862             return size;
863         }
864     }
865 
866     /**
867      * Returns the audio session ID.
868      *
869      * @return the ID of the audio session this AudioRecord belongs to.
870      */
getAudioSessionId()871     public int getAudioSessionId() {
872         return mSessionId;
873     }
874 
875     //---------------------------------------------------------
876     // Transport control methods
877     //--------------------
878     /**
879      * Starts recording from the AudioRecord instance.
880      * @throws IllegalStateException
881      */
startRecording()882     public void startRecording()
883     throws IllegalStateException {
884         if (mState != STATE_INITIALIZED) {
885             throw new IllegalStateException("startRecording() called on an "
886                     + "uninitialized AudioRecord.");
887         }
888 
889         // start recording
890         synchronized(mRecordingStateLock) {
891             if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) {
892                 handleFullVolumeRec(true);
893                 mRecordingState = RECORDSTATE_RECORDING;
894             }
895         }
896     }
897 
898     /**
899      * Starts recording from the AudioRecord instance when the specified synchronization event
900      * occurs on the specified audio session.
901      * @throws IllegalStateException
902      * @param syncEvent event that triggers the capture.
903      * @see MediaSyncEvent
904      */
startRecording(MediaSyncEvent syncEvent)905     public void startRecording(MediaSyncEvent syncEvent)
906     throws IllegalStateException {
907         if (mState != STATE_INITIALIZED) {
908             throw new IllegalStateException("startRecording() called on an "
909                     + "uninitialized AudioRecord.");
910         }
911 
912         // start recording
913         synchronized(mRecordingStateLock) {
914             if (native_start(syncEvent.getType(), syncEvent.getAudioSessionId()) == SUCCESS) {
915                 handleFullVolumeRec(true);
916                 mRecordingState = RECORDSTATE_RECORDING;
917             }
918         }
919     }
920 
921     /**
922      * Stops recording.
923      * @throws IllegalStateException
924      */
stop()925     public void stop()
926     throws IllegalStateException {
927         if (mState != STATE_INITIALIZED) {
928             throw new IllegalStateException("stop() called on an uninitialized AudioRecord.");
929         }
930 
931         // stop recording
932         synchronized(mRecordingStateLock) {
933             handleFullVolumeRec(false);
934             native_stop();
935             mRecordingState = RECORDSTATE_STOPPED;
936         }
937     }
938 
939     private final IBinder mICallBack = new Binder();
handleFullVolumeRec(boolean starting)940     private void handleFullVolumeRec(boolean starting) {
941         if (!mIsSubmixFullVolume) {
942             return;
943         }
944         final IBinder b = ServiceManager.getService(android.content.Context.AUDIO_SERVICE);
945         final IAudioService ias = IAudioService.Stub.asInterface(b);
946         try {
947             ias.forceRemoteSubmixFullVolume(starting, mICallBack);
948         } catch (RemoteException e) {
949             Log.e(TAG, "Error talking to AudioService when handling full submix volume", e);
950         }
951     }
952 
953     //---------------------------------------------------------
954     // Audio data supply
955     //--------------------
956     /**
957      * Reads audio data from the audio hardware for recording into a byte array.
958      * The format specified in the AudioRecord constructor should be
959      * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
960      * @param audioData the array to which the recorded audio data is written.
961      * @param offsetInBytes index in audioData from which the data is written expressed in bytes.
962      * @param sizeInBytes the number of requested bytes.
963      * @return the number of bytes that were read or {@link #ERROR_INVALID_OPERATION}
964      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
965      *    the parameters don't resolve to valid data and indexes.
966      *    The number of bytes will not exceed sizeInBytes.
967      */
read(@onNull byte[] audioData, int offsetInBytes, int sizeInBytes)968     public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) {
969         return read(audioData, offsetInBytes, sizeInBytes, READ_BLOCKING);
970     }
971 
972     /**
973      * Reads audio data from the audio hardware for recording into a byte array.
974      * The format specified in the AudioRecord constructor should be
975      * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
976      * @param audioData the array to which the recorded audio data is written.
977      * @param offsetInBytes index in audioData from which the data is written expressed in bytes.
978      * @param sizeInBytes the number of requested bytes.
979      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
980      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
981      *     is read.
982      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
983      *     reading as much audio data as possible without blocking.
984      * @return the number of bytes that were read or {@link #ERROR_INVALID_OPERATION}
985      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
986      *    the parameters don't resolve to valid data and indexes.
987      *    The number of bytes will not exceed sizeInBytes.
988      */
read(@onNull byte[] audioData, int offsetInBytes, int sizeInBytes, @ReadMode int readMode)989     public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
990             @ReadMode int readMode) {
991         if (mState != STATE_INITIALIZED  || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
992             return ERROR_INVALID_OPERATION;
993         }
994 
995         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
996             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
997             return ERROR_BAD_VALUE;
998         }
999 
1000         if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
1001                 || (offsetInBytes + sizeInBytes < 0)  // detect integer overflow
1002                 || (offsetInBytes + sizeInBytes > audioData.length)) {
1003             return ERROR_BAD_VALUE;
1004         }
1005 
1006         return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes,
1007                 readMode == READ_BLOCKING);
1008     }
1009 
1010     /**
1011      * Reads audio data from the audio hardware for recording into a short array.
1012      * The format specified in the AudioRecord constructor should be
1013      * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
1014      * @param audioData the array to which the recorded audio data is written.
1015      * @param offsetInShorts index in audioData from which the data is written expressed in shorts.
1016      * @param sizeInShorts the number of requested shorts.
1017      * @return the number of shorts that were read or {@link #ERROR_INVALID_OPERATION}
1018      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
1019      *    the parameters don't resolve to valid data and indexes.
1020      *    The number of shorts will not exceed sizeInShorts.
1021      */
read(@onNull short[] audioData, int offsetInShorts, int sizeInShorts)1022     public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) {
1023         return read(audioData, offsetInShorts, sizeInShorts, READ_BLOCKING);
1024     }
1025 
1026     /**
1027      * Reads audio data from the audio hardware for recording into a short array.
1028      * The format specified in the AudioRecord constructor should be
1029      * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
1030      * @param audioData the array to which the recorded audio data is written.
1031      * @param offsetInShorts index in audioData from which the data is written expressed in shorts.
1032      * @param sizeInShorts the number of requested shorts.
1033      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1034      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1035      *     is read.
1036      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1037      *     reading as much audio data as possible without blocking.
1038      * @return the number of shorts that were read or {@link #ERROR_INVALID_OPERATION}
1039      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
1040      *    the parameters don't resolve to valid data and indexes.
1041      *    The number of shorts will not exceed sizeInShorts.
1042      */
read(@onNull short[] audioData, int offsetInShorts, int sizeInShorts, @ReadMode int readMode)1043     public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
1044             @ReadMode int readMode) {
1045         if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
1046             return ERROR_INVALID_OPERATION;
1047         }
1048 
1049         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1050             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1051             return ERROR_BAD_VALUE;
1052         }
1053 
1054         if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
1055                 || (offsetInShorts + sizeInShorts < 0)  // detect integer overflow
1056                 || (offsetInShorts + sizeInShorts > audioData.length)) {
1057             return ERROR_BAD_VALUE;
1058         }
1059 
1060         return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts,
1061                 readMode == READ_BLOCKING);
1062     }
1063 
1064     /**
1065      * Reads audio data from the audio hardware for recording into a float array.
1066      * The format specified in the AudioRecord constructor should be
1067      * {@link AudioFormat#ENCODING_PCM_FLOAT} to correspond to the data in the array.
1068      * @param audioData the array to which the recorded audio data is written.
1069      * @param offsetInFloats index in audioData from which the data is written.
1070      * @param sizeInFloats the number of requested floats.
1071      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1072      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1073      *     is read.
1074      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1075      *     reading as much audio data as possible without blocking.
1076      * @return the number of floats that were read or {@link #ERROR_INVALID_OPERATION}
1077      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
1078      *    the parameters don't resolve to valid data and indexes.
1079      *    The number of floats will not exceed sizeInFloats.
1080      */
read(@onNull float[] audioData, int offsetInFloats, int sizeInFloats, @ReadMode int readMode)1081     public int read(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
1082             @ReadMode int readMode) {
1083         if (mState == STATE_UNINITIALIZED) {
1084             Log.e(TAG, "AudioRecord.read() called in invalid state STATE_UNINITIALIZED");
1085             return ERROR_INVALID_OPERATION;
1086         }
1087 
1088         if (mAudioFormat != AudioFormat.ENCODING_PCM_FLOAT) {
1089             Log.e(TAG, "AudioRecord.read(float[] ...) requires format ENCODING_PCM_FLOAT");
1090             return ERROR_INVALID_OPERATION;
1091         }
1092 
1093         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1094             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1095             return ERROR_BAD_VALUE;
1096         }
1097 
1098         if ((audioData == null) || (offsetInFloats < 0) || (sizeInFloats < 0)
1099                 || (offsetInFloats + sizeInFloats < 0)  // detect integer overflow
1100                 || (offsetInFloats + sizeInFloats > audioData.length)) {
1101             return ERROR_BAD_VALUE;
1102         }
1103 
1104         return native_read_in_float_array(audioData, offsetInFloats, sizeInFloats,
1105                 readMode == READ_BLOCKING);
1106     }
1107 
1108     /**
1109      * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
1110      * is not a direct buffer, this method will always return 0.
1111      * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
1112      * unchanged after a call to this method.
1113      * The representation of the data in the buffer will depend on the format specified in
1114      * the AudioRecord constructor, and will be native endian.
1115      * @param audioBuffer the direct buffer to which the recorded audio data is written.
1116      * @param sizeInBytes the number of requested bytes. It is recommended but not enforced
1117      *    that the number of bytes requested be a multiple of the frame size (sample size in
1118      *    bytes multiplied by the channel count).
1119      * @return the number of bytes that were read or {@link #ERROR_INVALID_OPERATION}
1120      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
1121      *    the parameters don't resolve to valid data and indexes.
1122      *    The number of bytes will not exceed sizeInBytes.
1123      *    The number of bytes read will truncated to be a multiple of the frame size.
1124      */
read(@onNull ByteBuffer audioBuffer, int sizeInBytes)1125     public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes) {
1126         return read(audioBuffer, sizeInBytes, READ_BLOCKING);
1127     }
1128 
1129     /**
1130      * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
1131      * is not a direct buffer, this method will always return 0.
1132      * Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
1133      * unchanged after a call to this method.
1134      * The representation of the data in the buffer will depend on the format specified in
1135      * the AudioRecord constructor, and will be native endian.
1136      * @param audioBuffer the direct buffer to which the recorded audio data is written.
1137      * @param sizeInBytes the number of requested bytes. It is recommended but not enforced
1138      *    that the number of bytes requested be a multiple of the frame size (sample size in
1139      *    bytes multiplied by the channel count).
1140      * @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
1141      *     <br>With {@link #READ_BLOCKING}, the read will block until all the requested data
1142      *     is read.
1143      *     <br>With {@link #READ_NON_BLOCKING}, the read will return immediately after
1144      *     reading as much audio data as possible without blocking.
1145      * @return the number of bytes that were read or {@link #ERROR_INVALID_OPERATION}
1146      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
1147      *    the parameters don't resolve to valid data and indexes.
1148      *    The number of bytes will not exceed sizeInBytes.
1149      *    The number of bytes read will truncated to be a multiple of the frame size.
1150      */
read(@onNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode)1151     public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode) {
1152         if (mState != STATE_INITIALIZED) {
1153             return ERROR_INVALID_OPERATION;
1154         }
1155 
1156         if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
1157             Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
1158             return ERROR_BAD_VALUE;
1159         }
1160 
1161         if ( (audioBuffer == null) || (sizeInBytes < 0) ) {
1162             return ERROR_BAD_VALUE;
1163         }
1164 
1165         return native_read_in_direct_buffer(audioBuffer, sizeInBytes, readMode == READ_BLOCKING);
1166     }
1167 
1168     //--------------------------------------------------------------------------
1169     // Initialization / configuration
1170     //--------------------
1171     /**
1172      * Sets the listener the AudioRecord notifies when a previously set marker is reached or
1173      * for each periodic record head position update.
1174      * @param listener
1175      */
setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener)1176     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener) {
1177         setRecordPositionUpdateListener(listener, null);
1178     }
1179 
1180     /**
1181      * Sets the listener the AudioRecord notifies when a previously set marker is reached or
1182      * for each periodic record head position update.
1183      * Use this method to receive AudioRecord events in the Handler associated with another
1184      * thread than the one in which you created the AudioRecord instance.
1185      * @param listener
1186      * @param handler the Handler that will receive the event notification messages.
1187      */
setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener, Handler handler)1188     public void setRecordPositionUpdateListener(OnRecordPositionUpdateListener listener,
1189                                                     Handler handler) {
1190         synchronized (mPositionListenerLock) {
1191 
1192             mPositionListener = listener;
1193 
1194             if (listener != null) {
1195                 if (handler != null) {
1196                     mEventHandler = new NativeEventHandler(this, handler.getLooper());
1197                 } else {
1198                     // no given handler, use the looper the AudioRecord was created in
1199                     mEventHandler = new NativeEventHandler(this, mInitializationLooper);
1200                 }
1201             } else {
1202                 mEventHandler = null;
1203             }
1204         }
1205 
1206     }
1207 
1208 
1209     /**
1210      * Sets the marker position at which the listener is called, if set with
1211      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
1212      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
1213      * @param markerInFrames marker position expressed in frames
1214      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
1215      *  {@link #ERROR_INVALID_OPERATION}
1216      */
setNotificationMarkerPosition(int markerInFrames)1217     public int setNotificationMarkerPosition(int markerInFrames) {
1218         if (mState == STATE_UNINITIALIZED) {
1219             return ERROR_INVALID_OPERATION;
1220         }
1221         return native_set_marker_pos(markerInFrames);
1222     }
1223 
1224 
1225     //--------------------------------------------------------------------------
1226     // (Re)Routing Info
1227     //--------------------
1228     /**
1229      * Defines the interface by which applications can receive notifications of routing
1230      * changes for the associated {@link AudioRecord}.
1231      */
1232     public interface OnRoutingChangedListener {
1233         /**
1234          * Called when the routing of an AudioRecord changes from either and explicit or
1235          * policy rerouting. Use {@link #getRoutedDevice()} to retrieve the newly routed-from
1236          * device.
1237          */
onRoutingChanged(AudioRecord audioRecord)1238         public void onRoutingChanged(AudioRecord audioRecord);
1239     }
1240 
1241     /**
1242      * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord.
1243      * Note: The query is only valid if the AudioRecord is currently recording. If it is not,
1244      * <code>getRoutedDevice()</code> will return null.
1245      */
getRoutedDevice()1246     public AudioDeviceInfo getRoutedDevice() {
1247         int deviceId = native_getRoutedDeviceId();
1248         if (deviceId == 0) {
1249             return null;
1250         }
1251         AudioDeviceInfo[] devices =
1252                 AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
1253         for (int i = 0; i < devices.length; i++) {
1254             if (devices[i].getId() == deviceId) {
1255                 return devices[i];
1256             }
1257         }
1258         return null;
1259     }
1260 
1261     /**
1262      * The list of AudioRecord.OnRoutingChangedListener interface added (with
1263      * {@link AudioRecord#addOnRoutingChangedListener(OnRoutingChangedListener,android.os.Handler)}
1264      * by an app to receive (re)routing notifications.
1265      */
1266     private ArrayMap<OnRoutingChangedListener, NativeRoutingEventHandlerDelegate>
1267         mRoutingChangeListeners =
1268             new ArrayMap<OnRoutingChangedListener, NativeRoutingEventHandlerDelegate>();
1269 
1270     /**
1271      * Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes
1272      * on this AudioRecord.
1273      * @param listener The {@link OnRoutingChangedListener} interface to receive notifications
1274      * of rerouting events.
1275      * @param handler  Specifies the {@link Handler} object for the thread on which to execute
1276      * the callback. If <code>null</code>, the {@link Handler} associated with the main
1277      * {@link Looper} will be used.
1278      */
addOnRoutingChangedListener(OnRoutingChangedListener listener, android.os.Handler handler)1279     public void addOnRoutingChangedListener(OnRoutingChangedListener listener,
1280             android.os.Handler handler) {
1281         if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
1282             synchronized (mRoutingChangeListeners) {
1283                 if (mRoutingChangeListeners.size() == 0) {
1284                     native_enableDeviceCallback();
1285                 }
1286                 mRoutingChangeListeners.put(
1287                     listener, new NativeRoutingEventHandlerDelegate(this, listener,
1288                             handler != null ? handler : new Handler(mInitializationLooper)));
1289             }
1290         }
1291     }
1292 
1293     /**
1294      * Removes an {@link OnRoutingChangedListener} which has been previously added
1295      * to receive rerouting notifications.
1296      * @param listener The previously added {@link OnRoutingChangedListener} interface to remove.
1297      */
removeOnRoutingChangedListener(OnRoutingChangedListener listener)1298     public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) {
1299         synchronized (mRoutingChangeListeners) {
1300             if (mRoutingChangeListeners.containsKey(listener)) {
1301                 mRoutingChangeListeners.remove(listener);
1302                 if (mRoutingChangeListeners.size() == 0) {
1303                     native_disableDeviceCallback();
1304                 }
1305             }
1306         }
1307     }
1308 
1309     /**
1310      * Helper class to handle the forwarding of native events to the appropriate listener
1311      * (potentially) handled in a different thread
1312      */
1313     private class NativeRoutingEventHandlerDelegate {
1314         private final Handler mHandler;
1315 
NativeRoutingEventHandlerDelegate(final AudioRecord record, final OnRoutingChangedListener listener, Handler handler)1316         NativeRoutingEventHandlerDelegate(final AudioRecord record,
1317                                    final OnRoutingChangedListener listener,
1318                                    Handler handler) {
1319             // find the looper for our new event handler
1320             Looper looper;
1321             if (handler != null) {
1322                 looper = handler.getLooper();
1323             } else {
1324                 // no given handler, use the looper the AudioRecord was created in
1325                 looper = mInitializationLooper;
1326             }
1327 
1328             // construct the event handler with this looper
1329             if (looper != null) {
1330                 // implement the event handler delegate
1331                 mHandler = new Handler(looper) {
1332                     @Override
1333                     public void handleMessage(Message msg) {
1334                         if (record == null) {
1335                             return;
1336                         }
1337                         switch(msg.what) {
1338                         case AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
1339                             if (listener != null) {
1340                                 listener.onRoutingChanged(record);
1341                             }
1342                             break;
1343                         default:
1344                             loge("Unknown native event type: " + msg.what);
1345                             break;
1346                         }
1347                     }
1348                 };
1349             } else {
1350                 mHandler = null;
1351             }
1352         }
1353 
getHandler()1354         Handler getHandler() {
1355             return mHandler;
1356         }
1357     }
1358     /**
1359      * Sends device list change notification to all listeners.
1360      */
broadcastRoutingChange()1361     private void broadcastRoutingChange() {
1362         Collection<NativeRoutingEventHandlerDelegate> values;
1363         synchronized (mRoutingChangeListeners) {
1364             values = mRoutingChangeListeners.values();
1365         }
1366         AudioManager.resetAudioPortGeneration();
1367         for(NativeRoutingEventHandlerDelegate delegate : values) {
1368             Handler handler = delegate.getHandler();
1369             if (handler != null) {
1370                 handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
1371             }
1372         }
1373     }
1374 
1375     /**
1376      * Sets the period at which the listener is called, if set with
1377      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener)} or
1378      * {@link #setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler)}.
1379      * It is possible for notifications to be lost if the period is too small.
1380      * @param periodInFrames update period expressed in frames
1381      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
1382      */
setPositionNotificationPeriod(int periodInFrames)1383     public int setPositionNotificationPeriod(int periodInFrames) {
1384         if (mState == STATE_UNINITIALIZED) {
1385             return ERROR_INVALID_OPERATION;
1386         }
1387         return native_set_pos_update_period(periodInFrames);
1388     }
1389 
1390     //--------------------------------------------------------------------------
1391     // Explicit Routing
1392     //--------------------
1393     private AudioDeviceInfo mPreferredDevice = null;
1394 
1395     /**
1396      * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
1397      * the input to this AudioRecord.
1398      * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio source.
1399      *  If deviceInfo is null, default routing is restored.
1400      * @return true if successful, false if the specified {@link AudioDeviceInfo} is non-null and
1401      * does not correspond to a valid audio input device.
1402      */
setPreferredDevice(AudioDeviceInfo deviceInfo)1403     public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
1404         // Do some validation....
1405         if (deviceInfo != null && !deviceInfo.isSource()) {
1406             return false;
1407         }
1408 
1409         int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
1410         boolean status = native_setInputDevice(preferredDeviceId);
1411         if (status == true) {
1412             synchronized (this) {
1413                 mPreferredDevice = deviceInfo;
1414             }
1415         }
1416         return status;
1417     }
1418 
1419     /**
1420      * Returns the selected input specified by {@link #setPreferredDevice}. Note that this
1421      * is not guarenteed to correspond to the actual device being used for recording.
1422      */
getPreferredDevice()1423     public AudioDeviceInfo getPreferredDevice() {
1424         synchronized (this) {
1425             return mPreferredDevice;
1426         }
1427     }
1428 
1429     //---------------------------------------------------------
1430     // Interface definitions
1431     //--------------------
1432     /**
1433      * Interface definition for a callback to be invoked when an AudioRecord has
1434      * reached a notification marker set by {@link AudioRecord#setNotificationMarkerPosition(int)}
1435      * or for periodic updates on the progress of the record head, as set by
1436      * {@link AudioRecord#setPositionNotificationPeriod(int)}.
1437      */
1438     public interface OnRecordPositionUpdateListener  {
1439         /**
1440          * Called on the listener to notify it that the previously set marker has been reached
1441          * by the recording head.
1442          */
onMarkerReached(AudioRecord recorder)1443         void onMarkerReached(AudioRecord recorder);
1444 
1445         /**
1446          * Called on the listener to periodically notify it that the record head has reached
1447          * a multiple of the notification period.
1448          */
onPeriodicNotification(AudioRecord recorder)1449         void onPeriodicNotification(AudioRecord recorder);
1450     }
1451 
1452 
1453 
1454     //---------------------------------------------------------
1455     // Inner classes
1456     //--------------------
1457 
1458     /**
1459      * Helper class to handle the forwarding of native events to the appropriate listener
1460      * (potentially) handled in a different thread
1461      */
1462     private class NativeEventHandler extends Handler {
1463 
1464         private final AudioRecord mAudioRecord;
1465 
NativeEventHandler(AudioRecord recorder, Looper looper)1466         NativeEventHandler(AudioRecord recorder, Looper looper) {
1467             super(looper);
1468             mAudioRecord = recorder;
1469         }
1470 
1471         @Override
handleMessage(Message msg)1472         public void handleMessage(Message msg) {
1473             OnRecordPositionUpdateListener listener = null;
1474             synchronized (mPositionListenerLock) {
1475                 listener = mAudioRecord.mPositionListener;
1476             }
1477 
1478             switch (msg.what) {
1479             case NATIVE_EVENT_MARKER:
1480                 if (listener != null) {
1481                     listener.onMarkerReached(mAudioRecord);
1482                 }
1483                 break;
1484             case NATIVE_EVENT_NEW_POS:
1485                 if (listener != null) {
1486                     listener.onPeriodicNotification(mAudioRecord);
1487                 }
1488                 break;
1489             default:
1490                 loge("Unknown native event type: " + msg.what);
1491                 break;
1492             }
1493         }
1494     };
1495 
1496 
1497     //---------------------------------------------------------
1498     // Java methods called from the native side
1499     //--------------------
1500     @SuppressWarnings("unused")
postEventFromNative(Object audiorecord_ref, int what, int arg1, int arg2, Object obj)1501     private static void postEventFromNative(Object audiorecord_ref,
1502             int what, int arg1, int arg2, Object obj) {
1503         //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
1504         AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get();
1505         if (recorder == null) {
1506             return;
1507         }
1508 
1509         if (what == AudioSystem.NATIVE_EVENT_ROUTING_CHANGE) {
1510             recorder.broadcastRoutingChange();
1511             return;
1512         }
1513 
1514         if (recorder.mEventHandler != null) {
1515             Message m =
1516                 recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj);
1517             recorder.mEventHandler.sendMessage(m);
1518         }
1519 
1520     }
1521 
1522 
1523     //---------------------------------------------------------
1524     // Native methods called from the Java side
1525     //--------------------
1526 
native_setup(Object audiorecord_this, Object attributes, int sampleRate, int channelMask, int channelIndexMask, int audioFormat, int buffSizeInBytes, int[] sessionId, String opPackageName)1527     private native final int native_setup(Object audiorecord_this,
1528             Object /*AudioAttributes*/ attributes,
1529             int sampleRate, int channelMask, int channelIndexMask, int audioFormat,
1530             int buffSizeInBytes, int[] sessionId, String opPackageName);
1531 
1532     // TODO remove: implementation calls directly into implementation of native_release()
native_finalize()1533     private native final void native_finalize();
1534 
native_release()1535     private native final void native_release();
1536 
native_start(int syncEvent, int sessionId)1537     private native final int native_start(int syncEvent, int sessionId);
1538 
native_stop()1539     private native final void native_stop();
1540 
native_read_in_byte_array(byte[] audioData, int offsetInBytes, int sizeInBytes, boolean isBlocking)1541     private native final int native_read_in_byte_array(byte[] audioData,
1542             int offsetInBytes, int sizeInBytes, boolean isBlocking);
1543 
native_read_in_short_array(short[] audioData, int offsetInShorts, int sizeInShorts, boolean isBlocking)1544     private native final int native_read_in_short_array(short[] audioData,
1545             int offsetInShorts, int sizeInShorts, boolean isBlocking);
1546 
native_read_in_float_array(float[] audioData, int offsetInFloats, int sizeInFloats, boolean isBlocking)1547     private native final int native_read_in_float_array(float[] audioData,
1548             int offsetInFloats, int sizeInFloats, boolean isBlocking);
1549 
native_read_in_direct_buffer(Object jBuffer, int sizeInBytes, boolean isBlocking)1550     private native final int native_read_in_direct_buffer(Object jBuffer,
1551             int sizeInBytes, boolean isBlocking);
1552 
native_get_buffer_size_in_frames()1553     private native final int native_get_buffer_size_in_frames();
1554 
native_set_marker_pos(int marker)1555     private native final int native_set_marker_pos(int marker);
native_get_marker_pos()1556     private native final int native_get_marker_pos();
1557 
native_set_pos_update_period(int updatePeriod)1558     private native final int native_set_pos_update_period(int updatePeriod);
native_get_pos_update_period()1559     private native final int native_get_pos_update_period();
1560 
native_get_min_buff_size( int sampleRateInHz, int channelCount, int audioFormat)1561     static private native final int native_get_min_buff_size(
1562             int sampleRateInHz, int channelCount, int audioFormat);
1563 
native_setInputDevice(int deviceId)1564     private native final boolean native_setInputDevice(int deviceId);
native_getRoutedDeviceId()1565     private native final int native_getRoutedDeviceId();
native_enableDeviceCallback()1566     private native final void native_enableDeviceCallback();
native_disableDeviceCallback()1567     private native final void native_disableDeviceCallback();
1568 
1569     //---------------------------------------------------------
1570     // Utility methods
1571     //------------------
1572 
logd(String msg)1573     private static void logd(String msg) {
1574         Log.d(TAG, msg);
1575     }
1576 
loge(String msg)1577     private static void loge(String msg) {
1578         Log.e(TAG, msg);
1579     }
1580 }
1581