• 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.lang.IllegalArgumentException;
21 import java.lang.IllegalStateException;
22 
23 import android.os.Handler;
24 import android.os.Looper;
25 import android.os.Message;
26 import android.media.AudioManager;
27 import android.util.Log;
28 
29 
30 /**
31  * The AudioTrack class manages and plays a single audio resource for Java applications.
32  * It allows to stream PCM audio buffers to the audio hardware for playback. This is
33  * achieved by "pushing" the data to the AudioTrack object using one of the
34  *  {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods.
35  *
36  * <p>An AudioTrack instance can operate under two modes: static or streaming.<br>
37  * In Streaming mode, the application writes a continuous stream of data to the AudioTrack, using
38  * one of the write() methods. These are blocking and return when the data has been transferred
39  * from the Java layer to the native layer and queued for playback. The streaming mode
40  *  is most useful when playing blocks of audio data that for instance are:
41  * <ul>
42  *   <li>too big to fit in memory because of the duration of the sound to play,</li>
43  *   <li>too big to fit in memory because of the characteristics of the audio data
44  *         (high sampling rate, bits per sample ...)</li>
45  *   <li>received or generated while previously queued audio is playing.</li>
46  * </ul>
47  * The static mode is to be chosen when dealing with short sounds that fit in memory and
48  * that need to be played with the smallest latency possible. AudioTrack instances in static mode
49  * can play the sound without the need to transfer the audio data from Java to native layer
50  * each time the sound is to be played. The static mode will therefore be preferred for UI and
51  * game sounds that are played often, and with the smallest overhead possible.
52  *
53  * <p>Upon creation, an AudioTrack object initializes its associated audio buffer.
54  * The size of this buffer, specified during the construction, determines how long an AudioTrack
55  * can play before running out of data.<br>
56  * For an AudioTrack using the static mode, this size is the maximum size of the sound that can
57  * be played from it.<br>
58  * For the streaming mode, data will be written to the hardware in chunks of
59  * sizes inferior to the total buffer size.
60  */
61 public class AudioTrack
62 {
63     //---------------------------------------------------------
64     // Constants
65     //--------------------
66     /** Minimum value for a channel volume */
67     private static final float VOLUME_MIN = 0.0f;
68     /** Maximum value for a channel volume */
69     private static final float VOLUME_MAX = 1.0f;
70 
71     /** indicates AudioTrack state is stopped */
72     public static final int PLAYSTATE_STOPPED = 1;  // matches SL_PLAYSTATE_STOPPED
73     /** indicates AudioTrack state is paused */
74     public static final int PLAYSTATE_PAUSED  = 2;  // matches SL_PLAYSTATE_PAUSED
75     /** indicates AudioTrack state is playing */
76     public static final int PLAYSTATE_PLAYING = 3;  // matches SL_PLAYSTATE_PLAYING
77 
78     /**
79      * Creation mode where audio data is transferred from Java to the native layer
80      * only once before the audio starts playing.
81      */
82     public static final int MODE_STATIC = 0;
83     /**
84      * Creation mode where audio data is streamed from Java to the native layer
85      * as the audio is playing.
86      */
87     public static final int MODE_STREAM = 1;
88 
89     /**
90      * State of an AudioTrack that was not successfully initialized upon creation.
91      */
92     public static final int STATE_UNINITIALIZED = 0;
93     /**
94      * State of an AudioTrack that is ready to be used.
95      */
96     public static final int STATE_INITIALIZED   = 1;
97     /**
98      * State of a successfully initialized AudioTrack that uses static data,
99      * but that hasn't received that data yet.
100      */
101     public static final int STATE_NO_STATIC_DATA = 2;
102 
103     // Error codes:
104     // to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp
105     /**
106      * Denotes a successful operation.
107      */
108     public  static final int SUCCESS                               = 0;
109     /**
110      * Denotes a generic operation failure.
111      */
112     public  static final int ERROR                                 = -1;
113     /**
114      * Denotes a failure due to the use of an invalid value.
115      */
116     public  static final int ERROR_BAD_VALUE                       = -2;
117     /**
118      * Denotes a failure due to the improper use of a method.
119      */
120     public  static final int ERROR_INVALID_OPERATION               = -3;
121 
122     private static final int ERROR_NATIVESETUP_AUDIOSYSTEM         = -16;
123     private static final int ERROR_NATIVESETUP_INVALIDCHANNELMASK  = -17;
124     private static final int ERROR_NATIVESETUP_INVALIDFORMAT       = -18;
125     private static final int ERROR_NATIVESETUP_INVALIDSTREAMTYPE   = -19;
126     private static final int ERROR_NATIVESETUP_NATIVEINITFAILED    = -20;
127 
128     // Events:
129     // to keep in sync with frameworks/base/include/media/AudioTrack.h
130     /**
131      * Event id denotes when playback head has reached a previously set marker.
132      */
133     private static final int NATIVE_EVENT_MARKER  = 3;
134     /**
135      * Event id denotes when previously set update period has elapsed during playback.
136      */
137     private static final int NATIVE_EVENT_NEW_POS = 4;
138 
139     private final static String TAG = "AudioTrack-Java";
140 
141 
142     //--------------------------------------------------------------------------
143     // Member variables
144     //--------------------
145     /**
146      * Indicates the state of the AudioTrack instance.
147      */
148     private int mState = STATE_UNINITIALIZED;
149     /**
150      * Indicates the play state of the AudioTrack instance.
151      */
152     private int mPlayState = PLAYSTATE_STOPPED;
153     /**
154      * Lock to make sure mPlayState updates are reflecting the actual state of the object.
155      */
156     private final Object mPlayStateLock = new Object();
157     /**
158      * The listener the AudioTrack notifies when the playback position reaches a marker
159      * or for periodic updates during the progression of the playback head.
160      *  @see #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener)
161      */
162     private OnPlaybackPositionUpdateListener mPositionListener = null;
163     /**
164      * Lock to protect event listener updates against event notifications.
165      */
166     private final Object mPositionListenerLock = new Object();
167     /**
168      * Size of the native audio buffer.
169      */
170     private int mNativeBufferSizeInBytes = 0;
171     /**
172      * Handler for marker events coming from the native code.
173      */
174     private NativeEventHandlerDelegate mEventHandlerDelegate = null;
175     /**
176      * Looper associated with the thread that creates the AudioTrack instance.
177      */
178     private Looper mInitializationLooper = null;
179     /**
180      * The audio data sampling rate in Hz.
181      */
182     private int mSampleRate = 22050;
183     /**
184      * The number of audio output channels (1 is mono, 2 is stereo).
185      */
186     private int mChannelCount = 1;
187     /**
188      * The audio channel mask.
189      */
190     private int mChannels = AudioFormat.CHANNEL_OUT_MONO;
191 
192     /**
193      * The type of the audio stream to play. See
194      *   {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
195      *   {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and
196      *   {@link AudioManager#STREAM_ALARM}
197      */
198     private int mStreamType = AudioManager.STREAM_MUSIC;
199     /**
200      * The way audio is consumed by the hardware, streaming or static.
201      */
202     private int mDataLoadMode = MODE_STREAM;
203     /**
204      * The current audio channel configuration.
205      */
206     private int mChannelConfiguration = AudioFormat.CHANNEL_OUT_MONO;
207     /**
208      * The encoding of the audio samples.
209      * @see AudioFormat#ENCODING_PCM_8BIT
210      * @see AudioFormat#ENCODING_PCM_16BIT
211      */
212     private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
213 
214 
215     //--------------------------------
216     // Used exclusively by native code
217     //--------------------
218     /**
219      * Accessed by native methods: provides access to C++ AudioTrack object.
220      */
221     @SuppressWarnings("unused")
222     private int mNativeTrackInJavaObj;
223     /**
224      * Accessed by native methods: provides access to the JNI data (i.e. resources used by
225      * the native AudioTrack object, but not stored in it).
226      */
227     @SuppressWarnings("unused")
228     private int mJniData;
229 
230 
231     //--------------------------------------------------------------------------
232     // Constructor, Finalize
233     //--------------------
234     /**
235      * Class constructor.
236      * @param streamType the type of the audio stream. See
237      *   {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
238      *   {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and
239      *   {@link AudioManager#STREAM_ALARM}
240      * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but
241      *   not limited to) 44100, 22050 and 11025.
242      * @param channelConfig describes the configuration of the audio channels.
243      *   See {@link AudioFormat#CHANNEL_OUT_MONO} and
244      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
245      * @param audioFormat the format in which the audio data is represented.
246      *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
247      *   {@link AudioFormat#ENCODING_PCM_8BIT}
248      * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read
249      *   from for playback. If using the AudioTrack in streaming mode, you can write data into
250      *   this buffer in smaller chunks than this size. If using the AudioTrack in static mode,
251      *   this is the maximum size of the sound that will be played for this instance.
252      *   See {@link #getMinBufferSize(int, int, int)} to determine the minimum required buffer size
253      *   for the successful creation of an AudioTrack instance in streaming mode. Using values
254      *   smaller than getMinBufferSize() will result in an initialization failure.
255      * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}
256      * @throws java.lang.IllegalArgumentException
257      */
AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)258     public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
259             int bufferSizeInBytes, int mode)
260     throws IllegalArgumentException {
261         mState = STATE_UNINITIALIZED;
262 
263         // remember which looper is associated with the AudioTrack instanciation
264         if ((mInitializationLooper = Looper.myLooper()) == null) {
265             mInitializationLooper = Looper.getMainLooper();
266         }
267 
268         audioParamCheck(streamType, sampleRateInHz, channelConfig, audioFormat, mode);
269 
270         audioBuffSizeCheck(bufferSizeInBytes);
271 
272         // native initialization
273         int initResult = native_setup(new WeakReference<AudioTrack>(this),
274                 mStreamType, mSampleRate, mChannels, mAudioFormat,
275                 mNativeBufferSizeInBytes, mDataLoadMode);
276         if (initResult != SUCCESS) {
277             loge("Error code "+initResult+" when initializing AudioTrack.");
278             return; // with mState == STATE_UNINITIALIZED
279         }
280 
281         if (mDataLoadMode == MODE_STATIC) {
282             mState = STATE_NO_STATIC_DATA;
283         } else {
284             mState = STATE_INITIALIZED;
285         }
286     }
287 
288 
289     // Convenience method for the constructor's parameter checks.
290     // This is where constructor IllegalArgumentException-s are thrown
291     // postconditions:
292     //    mStreamType is valid
293     //    mChannelCount is valid
294     //    mChannels is valid
295     //    mAudioFormat is valid
296     //    mSampleRate is valid
297     //    mDataLoadMode is valid
audioParamCheck(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int mode)298     private void audioParamCheck(int streamType, int sampleRateInHz,
299                                  int channelConfig, int audioFormat, int mode) {
300 
301         //--------------
302         // stream type
303         if( (streamType != AudioManager.STREAM_ALARM) && (streamType != AudioManager.STREAM_MUSIC)
304            && (streamType != AudioManager.STREAM_RING) && (streamType != AudioManager.STREAM_SYSTEM)
305            && (streamType != AudioManager.STREAM_VOICE_CALL)
306            && (streamType != AudioManager.STREAM_NOTIFICATION)
307            && (streamType != AudioManager.STREAM_BLUETOOTH_SCO)
308            && (streamType != AudioManager.STREAM_DTMF)) {
309             throw (new IllegalArgumentException("Invalid stream type."));
310         } else {
311             mStreamType = streamType;
312         }
313 
314         //--------------
315         // sample rate
316         if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
317             throw (new IllegalArgumentException(sampleRateInHz
318                     + "Hz is not a supported sample rate."));
319         } else {
320             mSampleRate = sampleRateInHz;
321         }
322 
323         //--------------
324         // channel config
325         mChannelConfiguration = channelConfig;
326 
327         switch (channelConfig) {
328         case AudioFormat.CHANNEL_OUT_DEFAULT: //AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
329         case AudioFormat.CHANNEL_OUT_MONO:
330         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
331             mChannelCount = 1;
332             mChannels = AudioFormat.CHANNEL_OUT_MONO;
333             break;
334         case AudioFormat.CHANNEL_OUT_STEREO:
335         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
336             mChannelCount = 2;
337             mChannels = AudioFormat.CHANNEL_OUT_STEREO;
338             break;
339         default:
340             mChannelCount = 0;
341             mChannels = AudioFormat.CHANNEL_INVALID;
342             mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_INVALID;
343             throw(new IllegalArgumentException("Unsupported channel configuration."));
344         }
345 
346         //--------------
347         // audio format
348         switch (audioFormat) {
349         case AudioFormat.ENCODING_DEFAULT:
350             mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
351             break;
352         case AudioFormat.ENCODING_PCM_16BIT:
353         case AudioFormat.ENCODING_PCM_8BIT:
354             mAudioFormat = audioFormat;
355             break;
356         default:
357             mAudioFormat = AudioFormat.ENCODING_INVALID;
358             throw(new IllegalArgumentException("Unsupported sample encoding."
359                 + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT."));
360         }
361 
362         //--------------
363         // audio load mode
364         if ( (mode != MODE_STREAM) && (mode != MODE_STATIC) ) {
365             throw(new IllegalArgumentException("Invalid mode."));
366         } else {
367             mDataLoadMode = mode;
368         }
369     }
370 
371 
372     // Convenience method for the contructor's audio buffer size check.
373     // preconditions:
374     //    mChannelCount is valid
375     //    mAudioFormat is valid
376     // postcondition:
377     //    mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
audioBuffSizeCheck(int audioBufferSize)378     private void audioBuffSizeCheck(int audioBufferSize) {
379         // NB: this section is only valid with PCM data.
380         //     To update when supporting compressed formats
381         int frameSizeInBytes = mChannelCount
382                 * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
383         if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
384             throw (new IllegalArgumentException("Invalid audio buffer size."));
385         }
386 
387         mNativeBufferSizeInBytes = audioBufferSize;
388     }
389 
390 
391     /**
392      * Releases the native AudioTrack resources.
393      */
release()394     public void release() {
395         // even though native_release() stops the native AudioTrack, we need to stop
396         // AudioTrack subclasses too.
397         try {
398             stop();
399         } catch(IllegalStateException ise) {
400             // don't raise an exception, we're releasing the resources.
401         }
402         native_release();
403         mState = STATE_UNINITIALIZED;
404     }
405 
406     @Override
finalize()407     protected void finalize() {
408         native_finalize();
409     }
410 
411     //--------------------------------------------------------------------------
412     // Getters
413     //--------------------
414     /**
415      * Returns the minimum valid volume value. Volume values set under this one will
416      * be clamped at this value.
417      * @return the minimum volume expressed as a linear attenuation.
418      */
getMinVolume()419     static public float getMinVolume() {
420         return AudioTrack.VOLUME_MIN;
421     }
422 
423     /**
424      * Returns the maximum valid volume value. Volume values set above this one will
425      * be clamped at this value.
426      * @return the maximum volume expressed as a linear attenuation.
427      */
getMaxVolume()428     static public float getMaxVolume() {
429         return AudioTrack.VOLUME_MAX;
430     }
431 
432     /**
433      * Returns the configured audio data sample rate in Hz
434      */
getSampleRate()435     public int getSampleRate() {
436         return mSampleRate;
437     }
438 
439     /**
440      * Returns the current playback rate in Hz.
441      */
getPlaybackRate()442     public int getPlaybackRate() {
443         return native_get_playback_rate();
444     }
445 
446     /**
447      * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT}
448      * and {@link AudioFormat#ENCODING_PCM_8BIT}.
449      */
getAudioFormat()450     public int getAudioFormat() {
451         return mAudioFormat;
452     }
453 
454     /**
455      * Returns the type of audio stream this AudioTrack is configured for.
456      * Compare the result against {@link AudioManager#STREAM_VOICE_CALL},
457      * {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING},
458      * {@link AudioManager#STREAM_MUSIC} or {@link AudioManager#STREAM_ALARM}
459      */
getStreamType()460     public int getStreamType() {
461         return mStreamType;
462     }
463 
464     /**
465      * Returns the configured channel configuration.
466 
467      * See {@link AudioFormat#CHANNEL_OUT_MONO}
468      * and {@link AudioFormat#CHANNEL_OUT_STEREO}.
469      */
getChannelConfiguration()470     public int getChannelConfiguration() {
471         return mChannelConfiguration;
472     }
473 
474     /**
475      * Returns the configured number of channels.
476      */
getChannelCount()477     public int getChannelCount() {
478         return mChannelCount;
479     }
480 
481     /**
482      * Returns the state of the AudioTrack instance. This is useful after the
483      * AudioTrack instance has been created to check if it was initialized
484      * properly. This ensures that the appropriate hardware resources have been
485      * acquired.
486      * @see #STATE_INITIALIZED
487      * @see #STATE_NO_STATIC_DATA
488      * @see #STATE_UNINITIALIZED
489      */
getState()490     public int getState() {
491         return mState;
492     }
493 
494     /**
495      * Returns the playback state of the AudioTrack instance.
496      * @see #PLAYSTATE_STOPPED
497      * @see #PLAYSTATE_PAUSED
498      * @see #PLAYSTATE_PLAYING
499      */
getPlayState()500     public int getPlayState() {
501         return mPlayState;
502     }
503 
504     /**
505      *  Returns the native frame count used by the hardware.
506      */
getNativeFrameCount()507     protected int getNativeFrameCount() {
508         return native_get_native_frame_count();
509     }
510 
511     /**
512      * Returns marker position expressed in frames.
513      */
getNotificationMarkerPosition()514     public int getNotificationMarkerPosition() {
515         return native_get_marker_pos();
516     }
517 
518     /**
519      * Returns the notification update period expressed in frames.
520      */
getPositionNotificationPeriod()521     public int getPositionNotificationPeriod() {
522         return native_get_pos_update_period();
523     }
524 
525     /**
526      * Returns the playback head position expressed in frames
527      */
getPlaybackHeadPosition()528     public int getPlaybackHeadPosition() {
529         return native_get_position();
530     }
531 
532     /**
533      *  Returns the hardware output sample rate
534      */
getNativeOutputSampleRate(int streamType)535     static public int getNativeOutputSampleRate(int streamType) {
536         return native_get_output_sample_rate(streamType);
537     }
538 
539     /**
540      * Returns the minimum buffer size required for the successful creation of an AudioTrack
541      * object to be created in the {@link #MODE_STREAM} mode. Note that this size doesn't
542      * guarantee a smooth playback under load, and higher values should be chosen according to
543      * the expected frequency at which the buffer will be refilled with additional data to play.
544      * @param sampleRateInHz the sample rate expressed in Hertz.
545      * @param channelConfig describes the configuration of the audio channels.
546      *   See {@link AudioFormat#CHANNEL_OUT_MONO} and
547      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
548      * @param audioFormat the format in which the audio data is represented.
549      *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
550      *   {@link AudioFormat#ENCODING_PCM_8BIT}
551      * @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed,
552      *   or {@link #ERROR} if the implementation was unable to query the hardware for its output
553      *     properties,
554      *   or the minimum buffer size expressed in bytes.
555      */
getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)556     static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
557         int channelCount = 0;
558         switch(channelConfig) {
559         case AudioFormat.CHANNEL_OUT_MONO:
560         case AudioFormat.CHANNEL_CONFIGURATION_MONO:
561             channelCount = 1;
562             break;
563         case AudioFormat.CHANNEL_OUT_STEREO:
564         case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
565             channelCount = 2;
566             break;
567         default:
568             loge("getMinBufferSize(): Invalid channel configuration.");
569             return AudioTrack.ERROR_BAD_VALUE;
570         }
571 
572         if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
573             && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {
574             loge("getMinBufferSize(): Invalid audio format.");
575             return AudioTrack.ERROR_BAD_VALUE;
576         }
577 
578         if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
579             loge("getMinBufferSize(): " + sampleRateInHz +"Hz is not a supported sample rate.");
580             return AudioTrack.ERROR_BAD_VALUE;
581         }
582 
583         int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
584         if ((size == -1) || (size == 0)) {
585             loge("getMinBufferSize(): error querying hardware");
586             return AudioTrack.ERROR;
587         }
588         else {
589             return size;
590         }
591     }
592 
593 
594     //--------------------------------------------------------------------------
595     // Initialization / configuration
596     //--------------------
597     /**
598      * Sets the listener the AudioTrack notifies when a previously set marker is reached or
599      * for each periodic playback head position update.
600      * Notifications will be received in the same thread as the one in which the AudioTrack
601      * instance was created.
602      * @param listener
603      */
setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener)604     public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener) {
605         setPlaybackPositionUpdateListener(listener, null);
606     }
607 
608     /**
609      * Sets the listener the AudioTrack notifies when a previously set marker is reached or
610      * for each periodic playback head position update.
611      * Use this method to receive AudioTrack events in the Handler associated with another
612      * thread than the one in which you created the AudioTrack instance.
613      * @param listener
614      * @param handler the Handler that will receive the event notification messages.
615      */
setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener, Handler handler)616     public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener,
617                                                     Handler handler) {
618         synchronized (mPositionListenerLock) {
619             mPositionListener = listener;
620         }
621         if (listener != null) {
622             mEventHandlerDelegate = new NativeEventHandlerDelegate(this, handler);
623         }
624 
625     }
626 
627 
628 
629      /**
630      * Sets the specified left/right output volume values on the AudioTrack. Values are clamped
631      * to the ({@link #getMinVolume()}, {@link #getMaxVolume()}) interval if outside this range.
632      * @param leftVolume output attenuation for the left channel. A value of 0.0f is silence,
633      *      a value of 1.0f is no attenuation.
634      * @param rightVolume output attenuation for the right channel
635      * @return error code or success, see {@link #SUCCESS},
636      *    {@link #ERROR_INVALID_OPERATION}
637      */
setStereoVolume(float leftVolume, float rightVolume)638     public int setStereoVolume(float leftVolume, float rightVolume) {
639         if (mState != STATE_INITIALIZED) {
640             return ERROR_INVALID_OPERATION;
641         }
642 
643         // clamp the volumes
644         if (leftVolume < getMinVolume()) {
645             leftVolume = getMinVolume();
646         }
647         if (leftVolume > getMaxVolume()) {
648             leftVolume = getMaxVolume();
649         }
650         if (rightVolume < getMinVolume()) {
651             rightVolume = getMinVolume();
652         }
653         if (rightVolume > getMaxVolume()) {
654             rightVolume = getMaxVolume();
655         }
656 
657         native_setVolume(leftVolume, rightVolume);
658 
659         return SUCCESS;
660     }
661 
662 
663     /**
664      * Sets the playback sample rate for this track. This sets the sampling rate at which
665      * the audio data will be consumed and played back, not the original sampling rate of the
666      * content. Setting it to half the sample rate of the content will cause the playback to
667      * last twice as long, but will also result in a negative pitch shift.
668      * The valid sample rate range if from 1Hz to twice the value returned by
669      * {@link #getNativeOutputSampleRate(int)}.
670      * @param sampleRateInHz the sample rate expressed in Hz
671      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
672      *    {@link #ERROR_INVALID_OPERATION}
673      */
setPlaybackRate(int sampleRateInHz)674     public int setPlaybackRate(int sampleRateInHz) {
675         if (mState != STATE_INITIALIZED) {
676             return ERROR_INVALID_OPERATION;
677         }
678         if (sampleRateInHz <= 0) {
679             return ERROR_BAD_VALUE;
680         }
681         return native_set_playback_rate(sampleRateInHz);
682     }
683 
684 
685     /**
686      * Sets the position of the notification marker.
687      * @param markerInFrames marker in frames
688      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
689      *  {@link #ERROR_INVALID_OPERATION}
690      */
setNotificationMarkerPosition(int markerInFrames)691     public int setNotificationMarkerPosition(int markerInFrames) {
692         if (mState != STATE_INITIALIZED) {
693             return ERROR_INVALID_OPERATION;
694         }
695         return native_set_marker_pos(markerInFrames);
696     }
697 
698 
699     /**
700      * Sets the period for the periodic notification event.
701      * @param periodInFrames update period expressed in frames
702      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
703      */
setPositionNotificationPeriod(int periodInFrames)704     public int setPositionNotificationPeriod(int periodInFrames) {
705         if (mState != STATE_INITIALIZED) {
706             return ERROR_INVALID_OPERATION;
707         }
708         return native_set_pos_update_period(periodInFrames);
709     }
710 
711 
712     /**
713      * Sets the playback head position. The track must be stopped for the position to be changed.
714      * @param positionInFrames playback head position expressed in frames
715      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
716      *    {@link #ERROR_INVALID_OPERATION}
717      */
setPlaybackHeadPosition(int positionInFrames)718     public int setPlaybackHeadPosition(int positionInFrames) {
719         synchronized(mPlayStateLock) {
720             if ((mPlayState == PLAYSTATE_STOPPED) || (mPlayState == PLAYSTATE_PAUSED)) {
721                 return native_set_position(positionInFrames);
722             } else {
723                 return ERROR_INVALID_OPERATION;
724             }
725         }
726     }
727 
728     /**
729      * Sets the loop points and the loop count. The loop can be infinite.
730      * @param startInFrames loop start marker expressed in frames
731      * @param endInFrames loop end marker expressed in frames
732      * @param loopCount the number of times the loop is looped.
733      *    A value of -1 means infinite looping.
734      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
735      *    {@link #ERROR_INVALID_OPERATION}
736      */
setLoopPoints(int startInFrames, int endInFrames, int loopCount)737     public int setLoopPoints(int startInFrames, int endInFrames, int loopCount) {
738         if (mDataLoadMode == MODE_STREAM) {
739             return ERROR_INVALID_OPERATION;
740         }
741         return native_set_loop(startInFrames, endInFrames, loopCount);
742     }
743 
744     /**
745      * Sets the initialization state of the instance. To be used in an AudioTrack subclass
746      * constructor to set a subclass-specific post-initialization state.
747      * @param state the state of the AudioTrack instance
748      */
setState(int state)749     protected void setState(int state) {
750         mState = state;
751     }
752 
753 
754     //---------------------------------------------------------
755     // Transport control methods
756     //--------------------
757     /**
758      * Starts playing an AudioTrack.
759      * @throws IllegalStateException
760      */
play()761     public void play()
762     throws IllegalStateException {
763         if (mState != STATE_INITIALIZED) {
764             throw(new IllegalStateException("play() called on uninitialized AudioTrack."));
765         }
766 
767         synchronized(mPlayStateLock) {
768             native_start();
769             mPlayState = PLAYSTATE_PLAYING;
770         }
771     }
772 
773     /**
774      * Stops playing the audio data.
775      * @throws IllegalStateException
776      */
stop()777     public void stop()
778     throws IllegalStateException {
779         if (mState != STATE_INITIALIZED) {
780             throw(new IllegalStateException("stop() called on uninitialized AudioTrack."));
781         }
782 
783         // stop playing
784         synchronized(mPlayStateLock) {
785             native_stop();
786             mPlayState = PLAYSTATE_STOPPED;
787         }
788     }
789 
790     /**
791      * Pauses the playback of the audio data.
792      * @throws IllegalStateException
793      */
pause()794     public void pause()
795     throws IllegalStateException {
796         if (mState != STATE_INITIALIZED) {
797             throw(new IllegalStateException("pause() called on uninitialized AudioTrack."));
798         }
799         //logd("pause()");
800 
801         // pause playback
802         synchronized(mPlayStateLock) {
803             native_pause();
804             mPlayState = PLAYSTATE_PAUSED;
805         }
806     }
807 
808 
809     //---------------------------------------------------------
810     // Audio data supply
811     //--------------------
812 
813     /**
814      * Flushes the audio data currently queued for playback.
815      */
816 
flush()817     public void flush() {
818         if (mState == STATE_INITIALIZED) {
819             // flush the data in native layer
820             native_flush();
821         }
822 
823     }
824 
825     /**
826      * Writes the audio data to the audio hardware for playback.
827      * @param audioData the array that holds the data to play.
828      * @param offsetInBytes the offset expressed in bytes in audioData where the data to play
829      *    starts.
830      * @param sizeInBytes the number of bytes to read in audioData after the offset.
831      * @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION}
832      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
833      *    the parameters don't resolve to valid data and indexes.
834      */
835 
write(byte[] audioData,int offsetInBytes, int sizeInBytes)836     public int write(byte[] audioData,int offsetInBytes, int sizeInBytes) {
837         if ((mDataLoadMode == MODE_STATIC)
838                 && (mState == STATE_NO_STATIC_DATA)
839                 && (sizeInBytes > 0)) {
840             mState = STATE_INITIALIZED;
841         }
842 
843         if (mState != STATE_INITIALIZED) {
844             return ERROR_INVALID_OPERATION;
845         }
846 
847         if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
848                 || (offsetInBytes + sizeInBytes > audioData.length)) {
849             return ERROR_BAD_VALUE;
850         }
851 
852         return native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat);
853     }
854 
855 
856     /**
857      * Writes the audio data to the audio hardware for playback.
858      * @param audioData the array that holds the data to play.
859      * @param offsetInShorts the offset expressed in shorts in audioData where the data to play
860      *     starts.
861      * @param sizeInShorts the number of bytes to read in audioData after the offset.
862      * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION}
863       *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
864       *    the parameters don't resolve to valid data and indexes.
865      */
866 
write(short[] audioData, int offsetInShorts, int sizeInShorts)867     public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
868         if ((mDataLoadMode == MODE_STATIC)
869                 && (mState == STATE_NO_STATIC_DATA)
870                 && (sizeInShorts > 0)) {
871             mState = STATE_INITIALIZED;
872         }
873 
874         if (mState != STATE_INITIALIZED) {
875             return ERROR_INVALID_OPERATION;
876         }
877 
878         if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
879                 || (offsetInShorts + sizeInShorts > audioData.length)) {
880             return ERROR_BAD_VALUE;
881         }
882 
883         return native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);
884     }
885 
886 
887     /**
888      * Notifies the native resource to reuse the audio data already loaded in the native
889      * layer. This call is only valid with AudioTrack instances that don't use the streaming
890      * model.
891      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
892      *  {@link #ERROR_INVALID_OPERATION}
893      */
reloadStaticData()894     public int reloadStaticData() {
895         if (mDataLoadMode == MODE_STREAM) {
896             return ERROR_INVALID_OPERATION;
897         }
898         return native_reload_static();
899     }
900 
901 
902     //---------------------------------------------------------
903     // Interface definitions
904     //--------------------
905     /**
906      * Interface definition for a callback to be invoked when the playback head position of
907      * an AudioTrack has reached a notification marker or has increased by a certain period.
908      */
909     public interface OnPlaybackPositionUpdateListener  {
910         /**
911          * Called on the listener to notify it that the previously set marker has been reached
912          * by the playback head.
913          */
onMarkerReached(AudioTrack track)914         void onMarkerReached(AudioTrack track);
915 
916         /**
917          * Called on the listener to periodically notify it that the playback head has reached
918          * a multiple of the notification period.
919          */
onPeriodicNotification(AudioTrack track)920         void onPeriodicNotification(AudioTrack track);
921     }
922 
923 
924     //---------------------------------------------------------
925     // Inner classes
926     //--------------------
927     /**
928      * Helper class to handle the forwarding of native events to the appropriate listener
929      * (potentially) handled in a different thread
930      */
931     private class NativeEventHandlerDelegate {
932         private final AudioTrack mAudioTrack;
933         private final Handler mHandler;
934 
NativeEventHandlerDelegate(AudioTrack track, Handler handler)935         NativeEventHandlerDelegate(AudioTrack track, Handler handler) {
936             mAudioTrack = track;
937             // find the looper for our new event handler
938             Looper looper;
939             if (handler != null) {
940                 looper = handler.getLooper();
941             } else {
942                 // no given handler, use the looper the AudioTrack was created in
943                 looper = mInitializationLooper;
944             }
945 
946             // construct the event handler with this looper
947             if (looper != null) {
948                 // implement the event handler delegate
949                 mHandler = new Handler(looper) {
950                     @Override
951                     public void handleMessage(Message msg) {
952                         if (mAudioTrack == null) {
953                             return;
954                         }
955                         OnPlaybackPositionUpdateListener listener = null;
956                         synchronized (mPositionListenerLock) {
957                             listener = mAudioTrack.mPositionListener;
958                         }
959                         switch(msg.what) {
960                         case NATIVE_EVENT_MARKER:
961                             if (listener != null) {
962                                 listener.onMarkerReached(mAudioTrack);
963                             }
964                             break;
965                         case NATIVE_EVENT_NEW_POS:
966                             if (listener != null) {
967                                 listener.onPeriodicNotification(mAudioTrack);
968                             }
969                             break;
970                         default:
971                             Log.e(TAG, "[ android.media.AudioTrack.NativeEventHandler ] " +
972                                     "Unknown event type: " + msg.what);
973                             break;
974                         }
975                     }
976                 };
977             } else {
978                 mHandler = null;
979             }
980         }
981 
getHandler()982         Handler getHandler() {
983             return mHandler;
984         }
985     }
986 
987 
988     //---------------------------------------------------------
989     // Java methods called from the native side
990     //--------------------
991     @SuppressWarnings("unused")
postEventFromNative(Object audiotrack_ref, int what, int arg1, int arg2, Object obj)992     private static void postEventFromNative(Object audiotrack_ref,
993             int what, int arg1, int arg2, Object obj) {
994         //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
995         AudioTrack track = (AudioTrack)((WeakReference)audiotrack_ref).get();
996         if (track == null) {
997             return;
998         }
999 
1000         if (track.mEventHandlerDelegate != null) {
1001             Message m =
1002                 track.mEventHandlerDelegate.getHandler().obtainMessage(what, arg1, arg2, obj);
1003             track.mEventHandlerDelegate.getHandler().sendMessage(m);
1004         }
1005 
1006     }
1007 
1008 
1009     //---------------------------------------------------------
1010     // Native methods called from the Java side
1011     //--------------------
1012 
native_setup(Object audiotrack_this, int streamType, int sampleRate, int nbChannels, int audioFormat, int buffSizeInBytes, int mode)1013     private native final int native_setup(Object audiotrack_this,
1014             int streamType, int sampleRate, int nbChannels, int audioFormat,
1015             int buffSizeInBytes, int mode);
1016 
native_finalize()1017     private native final void native_finalize();
1018 
native_release()1019     private native final void native_release();
1020 
native_start()1021     private native final void native_start();
1022 
native_stop()1023     private native final void native_stop();
1024 
native_pause()1025     private native final void native_pause();
1026 
native_flush()1027     private native final void native_flush();
1028 
native_write_byte(byte[] audioData, int offsetInBytes, int sizeInBytes, int format)1029     private native final int native_write_byte(byte[] audioData,
1030                                                int offsetInBytes, int sizeInBytes, int format);
1031 
native_write_short(short[] audioData, int offsetInShorts, int sizeInShorts, int format)1032     private native final int native_write_short(short[] audioData,
1033                                                 int offsetInShorts, int sizeInShorts, int format);
1034 
native_reload_static()1035     private native final int native_reload_static();
1036 
native_get_native_frame_count()1037     private native final int native_get_native_frame_count();
1038 
native_setVolume(float leftVolume, float rightVolume)1039     private native final void native_setVolume(float leftVolume, float rightVolume);
1040 
native_set_playback_rate(int sampleRateInHz)1041     private native final int native_set_playback_rate(int sampleRateInHz);
native_get_playback_rate()1042     private native final int native_get_playback_rate();
1043 
native_set_marker_pos(int marker)1044     private native final int native_set_marker_pos(int marker);
native_get_marker_pos()1045     private native final int native_get_marker_pos();
1046 
native_set_pos_update_period(int updatePeriod)1047     private native final int native_set_pos_update_period(int updatePeriod);
native_get_pos_update_period()1048     private native final int native_get_pos_update_period();
1049 
native_set_position(int position)1050     private native final int native_set_position(int position);
native_get_position()1051     private native final int native_get_position();
1052 
native_set_loop(int start, int end, int loopCount)1053     private native final int native_set_loop(int start, int end, int loopCount);
1054 
native_get_output_sample_rate(int streamType)1055     static private native final int native_get_output_sample_rate(int streamType);
native_get_min_buff_size( int sampleRateInHz, int channelConfig, int audioFormat)1056     static private native final int native_get_min_buff_size(
1057             int sampleRateInHz, int channelConfig, int audioFormat);
1058 
1059 
1060     //---------------------------------------------------------
1061     // Utility methods
1062     //------------------
1063 
logd(String msg)1064     private static void logd(String msg) {
1065         Log.d(TAG, "[ android.media.AudioTrack ] " + msg);
1066     }
1067 
loge(String msg)1068     private static void loge(String msg) {
1069         Log.e(TAG, "[ android.media.AudioTrack ] " + msg);
1070     }
1071 
1072 }
1073