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