AudioTrack.java revision 3026a023b8979b7ddcb3fe97bbc45531c89fda92
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media;
18
19import java.lang.ref.WeakReference;
20import java.lang.IllegalArgumentException;
21import java.lang.IllegalStateException;
22
23import android.os.Handler;
24import android.os.Looper;
25import android.os.Message;
26import android.media.AudioManager;
27import 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 */
61public 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     */
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
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)
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     */
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
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     */
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     */
428    static public float getMaxVolume() {
429        return AudioTrack.VOLUME_MAX;
430    }
431
432    /**
433     * Returns the configured audio data sample rate in Hz
434     */
435    public int getSampleRate() {
436        return mSampleRate;
437    }
438
439    /**
440     * Returns the current playback rate in Hz.
441     */
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     */
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     */
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     */
470    public int getChannelConfiguration() {
471        return mChannelConfiguration;
472    }
473
474    /**
475     * Returns the configured number of channels.
476     */
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     */
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     */
500    public int getPlayState() {
501        return mPlayState;
502    }
503
504    /**
505     *  Returns the native frame count used by the hardware.
506     */
507    protected int getNativeFrameCount() {
508        return native_get_native_frame_count();
509    }
510
511    /**
512     * Returns marker position expressed in frames.
513     */
514    public int getNotificationMarkerPosition() {
515        return native_get_marker_pos();
516    }
517
518    /**
519     * Returns the notification update period expressed in frames.
520     */
521    public int getPositionNotificationPeriod() {
522        return native_get_pos_update_period();
523    }
524
525    /**
526     * Returns the playback head position expressed in frames
527     */
528    public int getPlaybackHeadPosition() {
529        return native_get_position();
530    }
531
532    /**
533     *  Returns the hardware output sample rate
534     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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
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
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     */
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         */
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         */
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
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
982        Handler getHandler() {
983            return mHandler;
984        }
985    }
986
987
988    //---------------------------------------------------------
989    // Java methods called from the native side
990    //--------------------
991    @SuppressWarnings("unused")
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
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
1017    private native final void native_finalize();
1018
1019    private native final void native_release();
1020
1021    private native final void native_start();
1022
1023    private native final void native_stop();
1024
1025    private native final void native_pause();
1026
1027    private native final void native_flush();
1028
1029    private native final int native_write_byte(byte[] audioData,
1030                                               int offsetInBytes, int sizeInBytes, int format);
1031
1032    private native final int native_write_short(short[] audioData,
1033                                                int offsetInShorts, int sizeInShorts, int format);
1034
1035    private native final int native_reload_static();
1036
1037    private native final int native_get_native_frame_count();
1038
1039    private native final void native_setVolume(float leftVolume, float rightVolume);
1040
1041    private native final int native_set_playback_rate(int sampleRateInHz);
1042    private native final int native_get_playback_rate();
1043
1044    private native final int native_set_marker_pos(int marker);
1045    private native final int native_get_marker_pos();
1046
1047    private native final int native_set_pos_update_period(int updatePeriod);
1048    private native final int native_get_pos_update_period();
1049
1050    private native final int native_set_position(int position);
1051    private native final int native_get_position();
1052
1053    private native final int native_set_loop(int start, int end, int loopCount);
1054
1055    static private native final int native_get_output_sample_rate(int streamType);
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
1064    private static void logd(String msg) {
1065        Log.d(TAG, "[ android.media.AudioTrack ] " + msg);
1066    }
1067
1068    private static void loge(String msg) {
1069        Log.e(TAG, "[ android.media.AudioTrack ] " + msg);
1070    }
1071
1072}
1073