AudioTrack.java revision da996f390e17e16f2dfa60e972e7ebc4f868f37e
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 previously set marker is reached.
157     *  @see #setMarkerReachedListener(OnMarkerReachedListener)
158     */
159    private OnMarkerReachedListener mMarkerListener = null;
160    /**
161     * Lock to protect marker listener updates against event notifications
162     */
163    private final Object mMarkerListenerLock = new Object();
164    /**
165     * The listener the AudioTrack notifies periodically during playback.
166     *  @see #setPeriodicNotificationListener(OnPeriodicNotificationListener)
167     */
168    private OnPeriodicNotificationListener mPeriodicListener = null;
169    /**
170     * Lock to protect periodic listener updates against event notifications
171     */
172    private final Object mPeriodicListenerLock = new Object();
173    /**
174     * Size of the native audio buffer.
175     */
176    private int mNativeBufferSizeInBytes = 0;
177    /**
178     * Handler for events coming from the native code
179     */
180    private NativeEventHandler mNativeEventHandler = null;
181    /**
182     * The audio data sampling rate in Hz.
183     */
184    private int mSampleRate = 22050;
185    /**
186     * The number of input audio channels (1 is mono, 2 is stereo)
187     */
188    private int mChannelCount = 1;
189    /**
190     * The type of the audio stream to play. See
191     *   {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
192     *   {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and
193     *   {@link AudioManager#STREAM_ALARM}
194     */
195    private int mStreamType = AudioManager.STREAM_MUSIC;
196    /**
197     * The way audio is consumed by the hardware, streaming or static.
198     */
199    private int mDataLoadMode = MODE_STREAM;
200    /**
201     * The current audio channel configuration
202     */
203    private int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
204    /**
205     * The encoding of the audio samples.
206     * @see AudioFormat#ENCODING_PCM_8BIT
207     * @see AudioFormat#ENCODING_PCM_16BIT
208     */
209    private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
210
211
212    //--------------------------------
213    // Used exclusively by native code
214    //--------------------
215    /**
216     * Accessed by native methods: provides access to C++ AudioTrack object
217     */
218    @SuppressWarnings("unused")
219    private int mNativeTrackInJavaObj;
220    /**
221     * Accessed by native methods: provides access to the JNI data (i.e. resources used by
222     * the native AudioTrack object, but not stored in it).
223     */
224    @SuppressWarnings("unused")
225    private int mJniData;
226
227
228    //--------------------------------------------------------------------------
229    // Constructor, Finalize
230    //--------------------
231    /**
232     * Class constructor.
233     * @param streamType the type of the audio stream. See
234
235     *   {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
236     *   {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and
237     *   {@link AudioManager#STREAM_ALARM}
238     * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but
239     *   not limited to) 44100, 22050 and 11025.
240     * @param channelConfig describes the configuration of the audio channels.
241
242     *   See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
243     *   {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
244
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     * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}
253     * @throws java.lang.IllegalArgumentException
254     */
255    public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
256            int bufferSizeInBytes, int mode)
257    throws IllegalArgumentException {
258        mState = STATE_UNINITIALIZED;
259
260        audioParamCheck(streamType, sampleRateInHz, channelConfig, audioFormat, mode);
261
262        audioBuffSizeCheck(bufferSizeInBytes);
263
264        // native initialization
265        int initResult = native_setup(new WeakReference<AudioTrack>(this),
266                mStreamType, mSampleRate, mChannelCount, mAudioFormat,
267                mNativeBufferSizeInBytes, mDataLoadMode);
268        if (initResult != SUCCESS) {
269            loge("Error code "+initResult+" when initializing AudioTrack.");
270            return; // with mState == STATE_UNINITIALIZED
271        }
272
273        if (mDataLoadMode == MODE_STATIC) {
274            mState = STATE_NO_STATIC_DATA;
275        } else {
276            mState = STATE_INITIALIZED;
277        }
278    }
279
280
281    // Convenience method for the constructor's parameter checks.
282    // This is where constructor IllegalArgumentException-s are thrown
283    // postconditions:
284    //    mStreamType is valid
285    //    mChannelCount is valid
286    //    mAudioFormat is valid
287    //    mSampleRate is valid
288    //    mDataLoadMode is valid
289    private void audioParamCheck(int streamType, int sampleRateInHz,
290                                 int channelConfig, int audioFormat, int mode) {
291
292        //--------------
293        // stream type
294        if( (streamType != AudioManager.STREAM_ALARM) && (streamType != AudioManager.STREAM_MUSIC)
295           && (streamType != AudioManager.STREAM_RING) && (streamType != AudioManager.STREAM_SYSTEM)
296           && (streamType != AudioManager.STREAM_VOICE_CALL)
297           && (streamType != AudioManager.STREAM_NOTIFICATION)
298           && (streamType != AudioManager.STREAM_BLUETOOTH_SCO)) {
299            throw (new IllegalArgumentException("Invalid stream type."));
300        } else {
301            mStreamType = streamType;
302        }
303
304        //--------------
305        // sample rate
306        if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
307            throw (new IllegalArgumentException(sampleRateInHz
308                    + "Hz is not a supported sample rate."));
309        } else {
310            mSampleRate = sampleRateInHz;
311        }
312
313        //--------------
314        // channel config
315        switch (channelConfig) {
316        case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT:
317        case AudioFormat.CHANNEL_CONFIGURATION_MONO:
318            mChannelCount = 1;
319            mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
320            break;
321        case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
322            mChannelCount = 2;
323            mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
324            break;
325        default:
326            mChannelCount = 0;
327            mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_INVALID;
328            throw(new IllegalArgumentException("Unsupported channel configuration."));
329        }
330
331        //--------------
332        // audio format
333        switch (audioFormat) {
334        case AudioFormat.ENCODING_DEFAULT:
335            mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
336            break;
337        case AudioFormat.ENCODING_PCM_16BIT:
338        case AudioFormat.ENCODING_PCM_8BIT:
339            mAudioFormat = audioFormat;
340            break;
341        default:
342            mAudioFormat = AudioFormat.ENCODING_INVALID;
343            throw(new IllegalArgumentException("Unsupported sample encoding."
344                + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT."));
345        }
346
347        //--------------
348        // audio load mode
349        if ( (mode != MODE_STREAM) && (mode != MODE_STATIC) ) {
350            throw(new IllegalArgumentException("Invalid mode."));
351        } else {
352            mDataLoadMode = mode;
353        }
354    }
355
356
357    // Convenience method for the contructor's audio buffer size check.
358    // preconditions:
359    //    mChannelCount is valid
360    //    mAudioFormat is valid
361    // postcondition:
362    //    mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
363    private void audioBuffSizeCheck(int audioBufferSize) {
364        // NB: this section is only valid with PCM data.
365        //     To update when supporting compressed formats
366        int frameSizeInBytes = mChannelCount
367                * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
368        if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
369            throw (new IllegalArgumentException("Invalid audio buffer size."));
370        }
371
372        mNativeBufferSizeInBytes = audioBufferSize;
373    }
374
375
376    // Convenience method for the creation of the native event handler
377    // It is called only when a non-null event listener is set.
378    // precondition:
379    //    mNativeEventHandler is null
380    private void createNativeEventHandler() {
381        Looper looper;
382        if ((looper = Looper.myLooper()) != null) {
383            mNativeEventHandler = new NativeEventHandler(this, looper);
384        } else if ((looper = Looper.getMainLooper()) != null) {
385            mNativeEventHandler = new NativeEventHandler(this, looper);
386        } else {
387            mNativeEventHandler = null;
388        }
389    }
390
391
392    /**
393     * Releases the native AudioTrack resources.
394     */
395    public void release() {
396        // even though native_release() stops the native AudioTrack, we need to stop
397        // AudioTrack subclasses too.
398        try {
399            stop();
400        } catch(IllegalStateException ise) {
401            // don't raise an exception, we're releasing the resources.
402        }
403        native_release();
404        mState = STATE_UNINITIALIZED;
405    }
406
407    @Override
408    protected void finalize() {
409        native_finalize();
410    }
411
412    //--------------------------------------------------------------------------
413    // Getters
414    //--------------------
415    /**
416     * Returns the minimum valid volume value. Volume values set under this one will
417     * be clamped at this value.
418     * @return the minimum volume expressed as a linear attenuation.
419     */
420    static public float getMinVolume() {
421        return AudioTrack.VOLUME_MIN;
422    }
423
424    /**
425     * Returns the maximum valid volume value. Volume values set above this one will
426     * be clamped at this value.
427     * @return the maximum volume expressed as a linear attenuation.
428     */
429    static public float getMaxVolume() {
430        return AudioTrack.VOLUME_MAX;
431    }
432
433    /**
434     * Returns the configured audio data sample rate in Hz
435     */
436    public int getSampleRate() {
437        return mSampleRate;
438    }
439
440    /**
441     * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT}
442     * and {@link AudioFormat#ENCODING_PCM_8BIT}.
443     */
444    public int getAudioFormat() {
445        return mAudioFormat;
446    }
447
448    /**
449     * Returns the type of audio stream this AudioTrack is configured for.
450     * Compare the result against {@link AudioManager#STREAM_VOICE_CALL},
451     * {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING},
452     * {@link AudioManager#STREAM_MUSIC} or {@link AudioManager#STREAM_ALARM}
453     */
454    public int getStreamType() {
455        return mStreamType;
456    }
457
458    /**
459     * Returns the configured channel configuration.
460
461     * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO}
462     * and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}.
463     */
464    public int getChannelConfiguration() {
465        return mChannelConfiguration;
466    }
467
468    /**
469     * Returns the configured number of channels.
470     */
471    public int getChannelCount() {
472        return mChannelCount;
473    }
474
475    /**
476     * Returns the state of the AudioTrack instance. This is useful after the
477     * AudioTrack instance has been created to check if it was initialized
478     * properly. This ensures that the appropriate hardware resources have been
479     * acquired.
480     */
481    public int getState() {
482        return mState;
483    }
484
485    /**
486     * Returns the playback state of the AudioTrack instance.
487     * @see #PLAYSTATE_STOPPED
488     * @see #PLAYSTATE_PAUSED
489     * @see #PLAYSTATE_PLAYING
490     */
491    public int getPlayState() {
492        return mPlayState;
493    }
494
495    /**
496     *  Returns the native frame count used by the hardware
497     */
498    protected int getNativeFrameCount() {
499        return native_get_native_frame_count();
500    }
501
502    /**
503     * @return marker position in frames
504     */
505    public int getNotificationMarkerPosition() {
506        return native_get_marker_pos();
507    }
508
509    /**
510     * @return update period in frames
511     */
512    public int getPositionNotificationPeriod() {
513        return native_get_pos_update_period();
514    }
515
516    /**
517     * @return playback head position in frames
518     */
519    public int getPlaybackHeadPosition() {
520        return native_get_position();
521    }
522
523    /**
524     *  Returns the hardware output sample rate
525     */
526    static public int getNativeOutputSampleRate() {
527        return native_get_output_sample_rate();
528    }
529
530    /**
531     * {@hide}
532     * Returns the minimum buffer size required for the successful creation of an AudioTrack
533     * object to be created in the {@link #MODE_STREAM} mode.
534     * @param sampleRateInHz the sample rate expressed in Hertz.
535     * @param channelConfig describes the configuration of the audio channels.
536     *   See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
537     *   {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
538     * @param audioFormat the format in which the audio data is represented.
539     *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
540     *   {@link AudioFormat#ENCODING_PCM_8BIT}
541     * @return -1 if an invalid parameter was passed or if the implementation was unable to
542     *   query the hardware for its output properties, or the minimum buffer size expressed
543     *   in number of bytes.
544     */
545    static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
546        int channelCount = 0;
547        switch(channelConfig) {
548        case AudioFormat.CHANNEL_CONFIGURATION_MONO:
549            channelCount = 1;
550            break;
551        case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
552            channelCount = 2;
553            break;
554        default:
555            loge("getMinBufferSize(): Invalid channel configuration.");
556            return -1;
557        }
558
559        if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
560            && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {
561            loge("getMinBufferSize(): Invalid audio format.");
562            return -1;
563        }
564
565        return native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
566    }
567
568
569    //--------------------------------------------------------------------------
570    // Initialization / configuration
571    //--------------------
572    /**
573     * Sets the listener the AudioTrack notifies when a previously set marker is reached.
574     * @param listener
575     */
576    public void setMarkerReachedListener(OnMarkerReachedListener listener) {
577        synchronized (mMarkerListenerLock) {
578            mMarkerListener = listener;
579        }
580        if ((listener != null) && (mNativeEventHandler == null)) {
581            createNativeEventHandler();
582        }
583    }
584
585
586    /**
587     * Sets the listener the AudioTrack notifies periodically during playback.
588     * @param listener
589     */
590    public void setPeriodicNotificationListener(OnPeriodicNotificationListener listener) {
591        synchronized (mPeriodicListenerLock) {
592            mPeriodicListener = listener;
593        }
594        if ((listener != null) && (mNativeEventHandler == null)) {
595            createNativeEventHandler();
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()}). 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},
644     *    {@link #ERROR_INVALID_OPERATION}
645     */
646    public int setPlaybackRate(int sampleRateInHz) {
647        if (mState != STATE_INITIALIZED) {
648            return ERROR_INVALID_OPERATION;
649        }
650        native_set_playback_rate(sampleRateInHz);
651        return SUCCESS;
652    }
653
654
655    /**
656     *
657     * @param markerInFrames marker in frames
658     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
659     *  {@link #ERROR_INVALID_OPERATION}
660     */
661    public int setNotificationMarkerPosition(int markerInFrames) {
662        if (mState != STATE_INITIALIZED) {
663            return ERROR_INVALID_OPERATION;
664        }
665        return native_set_marker_pos(markerInFrames);
666    }
667
668
669    /**
670     * @param periodInFrames update period in frames
671     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
672     */
673    public int setPositionNotificationPeriod(int periodInFrames) {
674        if (mState != STATE_INITIALIZED) {
675            return ERROR_INVALID_OPERATION;
676        }
677        return native_set_pos_update_period(periodInFrames);
678    }
679
680
681    /**
682     * Sets the playback head position. The track must be stopped for the position to be changed.
683     * @param positionInFrames playback head position in frames
684     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
685     *    {@link #ERROR_INVALID_OPERATION}
686     */
687    public int setPlaybackHeadPosition(int positionInFrames) {
688        synchronized(mPlayStateLock) {
689            if(mPlayState == PLAYSTATE_STOPPED) {
690                return native_set_position(positionInFrames);
691            } else {
692                return ERROR_INVALID_OPERATION;
693            }
694        }
695    }
696
697    /**
698     * Sets the loop points and the loop count. The loop can be infinite.
699     * @param startInFrames loop start marker in frames
700     * @param endInFrames loop end marker in frames
701     * @param loopCount the number of times the loop is looped.
702     *    A value of -1 means infinite looping.
703     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
704     *    {@link #ERROR_INVALID_OPERATION}
705     */
706    public int setLoopPoints(int startInFrames, int endInFrames, int loopCount) {
707        return native_set_loop(startInFrames, endInFrames, loopCount);
708    }
709
710    /**
711     * Sets the initialization state of the instance. To be used in an AudioTrack subclass
712     * constructor to set a subclass-specific post-initialization state.
713     * @param state the state of the AudioTrack instance
714     */
715    protected void setState(int state) {
716        mState = state;
717    }
718
719
720    //---------------------------------------------------------
721    // Transport control methods
722    //--------------------
723    /**
724     * Starts playing an AudioTrack.
725     * @throws IllegalStateException
726     */
727    public void play()
728    throws IllegalStateException {
729        if (mState != STATE_INITIALIZED) {
730            throw(new IllegalStateException("play() called on uninitialized AudioTrack."));
731        }
732
733        synchronized(mPlayStateLock) {
734            native_start();
735            mPlayState = PLAYSTATE_PLAYING;
736        }
737    }
738
739    /**
740     * Stops playing the audio data.
741     * @throws IllegalStateException
742     */
743    public void stop()
744    throws IllegalStateException {
745        if (mState != STATE_INITIALIZED) {
746            throw(new IllegalStateException("stop() called on uninitialized AudioTrack."));
747        }
748
749        // stop playing
750        synchronized(mPlayStateLock) {
751            native_stop();
752            mPlayState = PLAYSTATE_STOPPED;
753        }
754    }
755
756    /**
757     * Pauses the playback of the audio data.
758     * @throws IllegalStateException
759     */
760    public void pause()
761    throws IllegalStateException {
762        if (mState != STATE_INITIALIZED) {
763            throw(new IllegalStateException("pause() called on uninitialized AudioTrack."));
764        }
765        //logd("pause()");
766
767        // pause playback
768        synchronized(mPlayStateLock) {
769            native_pause();
770            mPlayState = PLAYSTATE_PAUSED;
771        }
772    }
773
774
775    //---------------------------------------------------------
776    // Audio data supply
777    //--------------------
778
779    /**
780     * Flushes the audio data currently queued for playback.
781     */
782
783    public void flush() {
784        if (mState == STATE_INITIALIZED) {
785            // flush the data in native layer
786            native_flush();
787        }
788
789    }
790
791    /**
792     * Writes the audio data to the audio hardware for playback.
793     * @param audioData the array that holds the data to play.
794     * @param offsetInBytes the offset in audioData where the data to play starts.
795     * @param sizeInBytes the number of bytes to read in audioData after the offset.
796     * @return the number of bytes that were written or -1 if the object wasn't properly
797     *    initialized.
798     */
799
800    public int write(byte[] audioData,int offsetInBytes, int sizeInBytes) {
801        if ((mDataLoadMode == MODE_STATIC)
802                && (mState == STATE_NO_STATIC_DATA)
803                && (sizeInBytes > 0)) {
804            mState = STATE_INITIALIZED;
805        }
806        //TODO check if future writes should be forbidden for static tracks
807        //     or: how to update data for static tracks?
808
809        if (mState != STATE_INITIALIZED) {
810            return -1;
811        }
812
813        return native_write_byte(audioData, offsetInBytes, sizeInBytes);
814    }
815
816
817    /**
818     * Writes the audio data to the audio hardware for playback.
819     * @param audioData the array that holds the data to play.
820     * @param offsetInShorts the offset in audioData where the data to play starts.
821     * @param sizeInShorts the number of bytes to read in audioData after the offset.
822     * @return the number of shorts that were written or -1 if the object wasn't properly
823     *    initialized.
824     */
825
826    public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
827        if ((mDataLoadMode == MODE_STATIC)
828                && (mState == STATE_NO_STATIC_DATA)
829                && (sizeInShorts > 0)) {
830            mState = STATE_INITIALIZED;
831        }
832        //TODO check if future writes should be forbidden for static tracks
833        //     or: how to update data for static tracks?
834
835        if (mState != STATE_INITIALIZED) {
836            return -1;
837        }
838
839        return native_write_short(audioData, offsetInShorts, sizeInShorts);
840    }
841
842
843    /**
844     * Notifies the native resource to reuse the audio data already loaded in the native
845     * layer. This call is only valid with AudioTrack instances that don't use the streaming
846     * model.
847     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
848     *  {@link #ERROR_INVALID_OPERATION}
849     */
850    public int reloadStaticData() {
851        if (mDataLoadMode == MODE_STREAM) {
852            return ERROR_INVALID_OPERATION;
853        }
854        return native_reload_static();
855    }
856
857
858    //---------------------------------------------------------
859    // Interface definitions
860    //--------------------
861    /**
862     * Interface definition for a callback to be invoked when an AudioTrack has
863     * reached a notification marker set by setNotificationMarkerPosition().
864     */
865    public interface OnMarkerReachedListener  {
866        /**
867         * Called on the listener to notify it that the previously set marker has been reached
868         * by the playback head.
869         */
870        void onMarkerReached(AudioTrack track);
871    }
872
873
874    /**
875     * Interface definition for a callback to be invoked for each periodic AudioTrack
876     * update during playback. The update interval is set by setPositionNotificationPeriod().
877     */
878    public interface OnPeriodicNotificationListener  {
879        /**
880         * Called on the listener to periodically notify it that the playback head has reached
881         * a multiple of the notification period.
882         */
883        void onPeriodicNotification(AudioTrack track);
884    }
885
886
887    //---------------------------------------------------------
888    // Inner classes
889    //--------------------
890    /**
891     * Helper class to handle the forwarding of native events to the appropriate listeners
892     */
893    private class NativeEventHandler extends Handler
894    {
895        private AudioTrack mAudioTrack;
896
897        public NativeEventHandler(AudioTrack mp, Looper looper) {
898            super(looper);
899            mAudioTrack = mp;
900        }
901
902        @Override
903        public void handleMessage(Message msg) {
904            if (mAudioTrack == null) {
905                return;
906            }
907            switch(msg.what) {
908            case NATIVE_EVENT_MARKER:
909                synchronized (mMarkerListenerLock) {
910                    if (mAudioTrack.mMarkerListener != null) {
911                        mAudioTrack.mMarkerListener.onMarkerReached(mAudioTrack);
912                    }
913                }
914                break;
915            case NATIVE_EVENT_NEW_POS:
916                synchronized (mPeriodicListenerLock) {
917                    if (mAudioTrack.mPeriodicListener != null) {
918                        mAudioTrack.mPeriodicListener.onPeriodicNotification(mAudioTrack);
919                    }
920                }
921                break;
922            default:
923                Log.e(TAG, "[ android.media.AudioTrack.NativeEventHandler ] " +
924                        "Unknown event type: " + msg.what);
925                break;
926            }
927        }
928    }
929
930
931    //---------------------------------------------------------
932    // Java methods called from the native side
933    //--------------------
934    @SuppressWarnings("unused")
935    private static void postEventFromNative(Object audiotrack_ref,
936            int what, int arg1, int arg2, Object obj) {
937        //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
938        AudioTrack track = (AudioTrack)((WeakReference)audiotrack_ref).get();
939        if (track == null) {
940            return;
941        }
942
943        if (track.mNativeEventHandler != null) {
944            Message m = track.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj);
945            track.mNativeEventHandler.sendMessage(m);
946        }
947
948    }
949
950
951    //---------------------------------------------------------
952    // Native methods called from the Java side
953    //--------------------
954
955    private native final int native_setup(Object audiotrack_this,
956            int streamType, int sampleRate, int nbChannels, int audioFormat,
957            int buffSizeInBytes, int mode);
958
959    private native final void native_finalize();
960
961    private native final void native_release();
962
963    private native final void native_start();
964
965    private native final void native_stop();
966
967    private native final void native_pause();
968
969    private native final void native_flush();
970
971    private native final int native_write_byte(byte[] audioData,
972                                               int offsetInBytes, int sizeInBytes);
973
974    private native final int native_write_short(short[] audioData,
975                                                int offsetInShorts, int sizeInShorts);
976
977    private native final int native_reload_static();
978
979    private native final int native_get_native_frame_count();
980
981    private native final void native_setVolume(float leftVolume, float rightVolume);
982
983    private native final void native_set_playback_rate(int sampleRateInHz);
984    private native final int  native_get_playback_rate();
985
986    private native final int native_set_marker_pos(int marker);
987    private native final int native_get_marker_pos();
988
989    private native final int native_set_pos_update_period(int updatePeriod);
990    private native final int native_get_pos_update_period();
991
992    private native final int native_set_position(int position);
993    private native final int native_get_position();
994
995    private native final int native_set_loop(int start, int end, int loopCount);
996
997    static private native final int native_get_output_sample_rate();
998    static private native final int native_get_min_buff_size(
999            int sampleRateInHz, int channelConfig, int audioFormat);
1000
1001
1002    //---------------------------------------------------------
1003    // Utility methods
1004    //------------------
1005
1006    private static void logd(String msg) {
1007        Log.d(TAG, "[ android.media.AudioTrack ] " + msg);
1008    }
1009
1010    private static void loge(String msg) {
1011        Log.e(TAG, "[ android.media.AudioTrack ] " + msg);
1012    }
1013
1014}
1015