AudioTrack.java revision 076357b8567458d4b6dfdcf839ef751634cd2bfb
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 {@link #ERROR_BAD_VALUE} if an invalid parameter was passed,
542     *   or {@link #ERROR} if the implementation was unable to query the hardware for its output
543     *     properties,
544     *   or the minimum buffer size expressed  in number of bytes.
545     */
546    static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
547        int channelCount = 0;
548        switch(channelConfig) {
549        case AudioFormat.CHANNEL_CONFIGURATION_MONO:
550            channelCount = 1;
551            break;
552        case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
553            channelCount = 2;
554            break;
555        default:
556            loge("getMinBufferSize(): Invalid channel configuration.");
557            return AudioTrack.ERROR_BAD_VALUE;
558        }
559
560        if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
561            && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {
562            loge("getMinBufferSize(): Invalid audio format.");
563            return AudioTrack.ERROR_BAD_VALUE;
564        }
565
566        if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
567            loge("getMinBufferSize(): " + sampleRateInHz +"Hz is not a supported sample rate.");
568            return AudioTrack.ERROR_BAD_VALUE;
569        }
570
571        int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
572        if ((size == -1) || (size == 0)) {
573            loge("getMinBufferSize(): error querying hardware");
574            return AudioTrack.ERROR;
575        }
576        else {
577            return size;
578        }
579    }
580
581
582    //--------------------------------------------------------------------------
583    // Initialization / configuration
584    //--------------------
585    /**
586     * Sets the listener the AudioTrack notifies when a previously set marker is reached.
587     * @param listener
588     */
589    public void setMarkerReachedListener(OnMarkerReachedListener listener) {
590        synchronized (mMarkerListenerLock) {
591            mMarkerListener = listener;
592        }
593        if ((listener != null) && (mNativeEventHandler == null)) {
594            createNativeEventHandler();
595        }
596    }
597
598
599    /**
600     * Sets the listener the AudioTrack notifies periodically during playback.
601     * @param listener
602     */
603    public void setPeriodicNotificationListener(OnPeriodicNotificationListener listener) {
604        synchronized (mPeriodicListenerLock) {
605            mPeriodicListener = listener;
606        }
607        if ((listener != null) && (mNativeEventHandler == null)) {
608            createNativeEventHandler();
609        }
610    }
611
612
613     /**
614     * Sets the specified left/right output volume values on the AudioTrack. Values are clamped
615     * to the ({@link #getMinVolume()}, {@link #getMaxVolume()}) interval if outside this range.
616     * @param leftVolume output attenuation for the left channel. A value of 0.0f is silence,
617     *      a value of 1.0f is no attenuation.
618     * @param rightVolume output attenuation for the right channel
619     * @return error code or success, see {@link #SUCCESS},
620     *    {@link #ERROR_INVALID_OPERATION}
621     */
622    public int setStereoVolume(float leftVolume, float rightVolume) {
623        if (mState != STATE_INITIALIZED) {
624            return ERROR_INVALID_OPERATION;
625        }
626
627        // clamp the volumes
628        if (leftVolume < getMinVolume()) {
629            leftVolume = getMinVolume();
630        }
631        if (leftVolume > getMaxVolume()) {
632            leftVolume = getMaxVolume();
633        }
634        if (rightVolume < getMinVolume()) {
635            rightVolume = getMinVolume();
636        }
637        if (rightVolume > getMaxVolume()) {
638            rightVolume = getMaxVolume();
639        }
640
641        native_setVolume(leftVolume, rightVolume);
642
643        return SUCCESS;
644    }
645
646
647    /**
648     * Sets the playback sample rate for this track. This sets the sampling rate at which
649     * the audio data will be consumed and played back, not the original sampling rate of the
650     * content. Setting it to half the sample rate of the content will cause the playback to
651     * last twice as long, but will also result result in a negative pitch shift.
652     * The current implementation supports a maximum sample rate of twice the hardware output
653     * sample rate (see {@link #getNativeOutputSampleRate()}). Use {@link #getSampleRate()} to
654     * check the rate actually used in hardware after potential clamping.
655     * @param sampleRateInHz
656     * @return error code or success, see {@link #SUCCESS},
657     *    {@link #ERROR_INVALID_OPERATION}
658     */
659    public int setPlaybackRate(int sampleRateInHz) {
660        if (mState != STATE_INITIALIZED) {
661            return ERROR_INVALID_OPERATION;
662        }
663        native_set_playback_rate(sampleRateInHz);
664        return SUCCESS;
665    }
666
667
668    /**
669     *
670     * @param markerInFrames marker in frames
671     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
672     *  {@link #ERROR_INVALID_OPERATION}
673     */
674    public int setNotificationMarkerPosition(int markerInFrames) {
675        if (mState != STATE_INITIALIZED) {
676            return ERROR_INVALID_OPERATION;
677        }
678        return native_set_marker_pos(markerInFrames);
679    }
680
681
682    /**
683     * @param periodInFrames update period in frames
684     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
685     */
686    public int setPositionNotificationPeriod(int periodInFrames) {
687        if (mState != STATE_INITIALIZED) {
688            return ERROR_INVALID_OPERATION;
689        }
690        return native_set_pos_update_period(periodInFrames);
691    }
692
693
694    /**
695     * Sets the playback head position. The track must be stopped for the position to be changed.
696     * @param positionInFrames playback head position in frames
697     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
698     *    {@link #ERROR_INVALID_OPERATION}
699     */
700    public int setPlaybackHeadPosition(int positionInFrames) {
701        synchronized(mPlayStateLock) {
702            if(mPlayState == PLAYSTATE_STOPPED) {
703                return native_set_position(positionInFrames);
704            } else {
705                return ERROR_INVALID_OPERATION;
706            }
707        }
708    }
709
710    /**
711     * Sets the loop points and the loop count. The loop can be infinite.
712     * @param startInFrames loop start marker in frames
713     * @param endInFrames loop end marker in frames
714     * @param loopCount the number of times the loop is looped.
715     *    A value of -1 means infinite looping.
716     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
717     *    {@link #ERROR_INVALID_OPERATION}
718     */
719    public int setLoopPoints(int startInFrames, int endInFrames, int loopCount) {
720        return native_set_loop(startInFrames, endInFrames, loopCount);
721    }
722
723    /**
724     * Sets the initialization state of the instance. To be used in an AudioTrack subclass
725     * constructor to set a subclass-specific post-initialization state.
726     * @param state the state of the AudioTrack instance
727     */
728    protected void setState(int state) {
729        mState = state;
730    }
731
732
733    //---------------------------------------------------------
734    // Transport control methods
735    //--------------------
736    /**
737     * Starts playing an AudioTrack.
738     * @throws IllegalStateException
739     */
740    public void play()
741    throws IllegalStateException {
742        if (mState != STATE_INITIALIZED) {
743            throw(new IllegalStateException("play() called on uninitialized AudioTrack."));
744        }
745
746        synchronized(mPlayStateLock) {
747            native_start();
748            mPlayState = PLAYSTATE_PLAYING;
749        }
750    }
751
752    /**
753     * Stops playing the audio data.
754     * @throws IllegalStateException
755     */
756    public void stop()
757    throws IllegalStateException {
758        if (mState != STATE_INITIALIZED) {
759            throw(new IllegalStateException("stop() called on uninitialized AudioTrack."));
760        }
761
762        // stop playing
763        synchronized(mPlayStateLock) {
764            native_stop();
765            mPlayState = PLAYSTATE_STOPPED;
766        }
767    }
768
769    /**
770     * Pauses the playback of the audio data.
771     * @throws IllegalStateException
772     */
773    public void pause()
774    throws IllegalStateException {
775        if (mState != STATE_INITIALIZED) {
776            throw(new IllegalStateException("pause() called on uninitialized AudioTrack."));
777        }
778        //logd("pause()");
779
780        // pause playback
781        synchronized(mPlayStateLock) {
782            native_pause();
783            mPlayState = PLAYSTATE_PAUSED;
784        }
785    }
786
787
788    //---------------------------------------------------------
789    // Audio data supply
790    //--------------------
791
792    /**
793     * Flushes the audio data currently queued for playback.
794     */
795
796    public void flush() {
797        if (mState == STATE_INITIALIZED) {
798            // flush the data in native layer
799            native_flush();
800        }
801
802    }
803
804    /**
805     * Writes the audio data to the audio hardware for playback.
806     * @param audioData the array that holds the data to play.
807     * @param offsetInBytes the offset in audioData where the data to play starts.
808     * @param sizeInBytes the number of bytes to read in audioData after the offset.
809     * @return the number of bytes that were written or -1 if the object wasn't properly
810     *    initialized.
811     */
812
813    public int write(byte[] audioData,int offsetInBytes, int sizeInBytes) {
814        if ((mDataLoadMode == MODE_STATIC)
815                && (mState == STATE_NO_STATIC_DATA)
816                && (sizeInBytes > 0)) {
817            mState = STATE_INITIALIZED;
818        }
819        //TODO check if future writes should be forbidden for static tracks
820        //     or: how to update data for static tracks?
821
822        if (mState != STATE_INITIALIZED) {
823            return -1;
824        }
825
826        return native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat);
827    }
828
829
830    /**
831     * Writes the audio data to the audio hardware for playback.
832     * @param audioData the array that holds the data to play.
833     * @param offsetInShorts the offset in audioData where the data to play starts.
834     * @param sizeInShorts the number of bytes to read in audioData after the offset.
835     * @return the number of shorts that were written or -1 if the object wasn't properly
836     *    initialized.
837     */
838
839    public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
840        if ((mDataLoadMode == MODE_STATIC)
841                && (mState == STATE_NO_STATIC_DATA)
842                && (sizeInShorts > 0)) {
843            mState = STATE_INITIALIZED;
844        }
845        //TODO check if future writes should be forbidden for static tracks
846        //     or: how to update data for static tracks?
847
848        if (mState != STATE_INITIALIZED) {
849            return -1;
850        }
851
852        return native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);
853    }
854
855
856    /**
857     * Notifies the native resource to reuse the audio data already loaded in the native
858     * layer. This call is only valid with AudioTrack instances that don't use the streaming
859     * model.
860     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
861     *  {@link #ERROR_INVALID_OPERATION}
862     */
863    public int reloadStaticData() {
864        if (mDataLoadMode == MODE_STREAM) {
865            return ERROR_INVALID_OPERATION;
866        }
867        return native_reload_static();
868    }
869
870
871    //---------------------------------------------------------
872    // Interface definitions
873    //--------------------
874    /**
875     * Interface definition for a callback to be invoked when an AudioTrack has
876     * reached a notification marker set by setNotificationMarkerPosition().
877     */
878    public interface OnMarkerReachedListener  {
879        /**
880         * Called on the listener to notify it that the previously set marker has been reached
881         * by the playback head.
882         */
883        void onMarkerReached(AudioTrack track);
884    }
885
886
887    /**
888     * Interface definition for a callback to be invoked for each periodic AudioTrack
889     * update during playback. The update interval is set by setPositionNotificationPeriod().
890     */
891    public interface OnPeriodicNotificationListener  {
892        /**
893         * Called on the listener to periodically notify it that the playback head has reached
894         * a multiple of the notification period.
895         */
896        void onPeriodicNotification(AudioTrack track);
897    }
898
899
900    //---------------------------------------------------------
901    // Inner classes
902    //--------------------
903    /**
904     * Helper class to handle the forwarding of native events to the appropriate listeners
905     */
906    private class NativeEventHandler extends Handler
907    {
908        private AudioTrack mAudioTrack;
909
910        public NativeEventHandler(AudioTrack mp, Looper looper) {
911            super(looper);
912            mAudioTrack = mp;
913        }
914
915        @Override
916        public void handleMessage(Message msg) {
917            if (mAudioTrack == null) {
918                return;
919            }
920            switch(msg.what) {
921            case NATIVE_EVENT_MARKER:
922                synchronized (mMarkerListenerLock) {
923                    if (mAudioTrack.mMarkerListener != null) {
924                        mAudioTrack.mMarkerListener.onMarkerReached(mAudioTrack);
925                    }
926                }
927                break;
928            case NATIVE_EVENT_NEW_POS:
929                synchronized (mPeriodicListenerLock) {
930                    if (mAudioTrack.mPeriodicListener != null) {
931                        mAudioTrack.mPeriodicListener.onPeriodicNotification(mAudioTrack);
932                    }
933                }
934                break;
935            default:
936                Log.e(TAG, "[ android.media.AudioTrack.NativeEventHandler ] " +
937                        "Unknown event type: " + msg.what);
938                break;
939            }
940        }
941    }
942
943
944    //---------------------------------------------------------
945    // Java methods called from the native side
946    //--------------------
947    @SuppressWarnings("unused")
948    private static void postEventFromNative(Object audiotrack_ref,
949            int what, int arg1, int arg2, Object obj) {
950        //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
951        AudioTrack track = (AudioTrack)((WeakReference)audiotrack_ref).get();
952        if (track == null) {
953            return;
954        }
955
956        if (track.mNativeEventHandler != null) {
957            Message m = track.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj);
958            track.mNativeEventHandler.sendMessage(m);
959        }
960
961    }
962
963
964    //---------------------------------------------------------
965    // Native methods called from the Java side
966    //--------------------
967
968    private native final int native_setup(Object audiotrack_this,
969            int streamType, int sampleRate, int nbChannels, int audioFormat,
970            int buffSizeInBytes, int mode);
971
972    private native final void native_finalize();
973
974    private native final void native_release();
975
976    private native final void native_start();
977
978    private native final void native_stop();
979
980    private native final void native_pause();
981
982    private native final void native_flush();
983
984    private native final int native_write_byte(byte[] audioData,
985                                               int offsetInBytes, int sizeInBytes, int format);
986
987    private native final int native_write_short(short[] audioData,
988                                                int offsetInShorts, int sizeInShorts, int format);
989
990    private native final int native_reload_static();
991
992    private native final int native_get_native_frame_count();
993
994    private native final void native_setVolume(float leftVolume, float rightVolume);
995
996    private native final void native_set_playback_rate(int sampleRateInHz);
997    private native final int  native_get_playback_rate();
998
999    private native final int native_set_marker_pos(int marker);
1000    private native final int native_get_marker_pos();
1001
1002    private native final int native_set_pos_update_period(int updatePeriod);
1003    private native final int native_get_pos_update_period();
1004
1005    private native final int native_set_position(int position);
1006    private native final int native_get_position();
1007
1008    private native final int native_set_loop(int start, int end, int loopCount);
1009
1010    static private native final int native_get_output_sample_rate();
1011    static private native final int native_get_min_buff_size(
1012            int sampleRateInHz, int channelConfig, int audioFormat);
1013
1014
1015    //---------------------------------------------------------
1016    // Utility methods
1017    //------------------
1018
1019    private static void logd(String msg) {
1020        Log.d(TAG, "[ android.media.AudioTrack ] " + msg);
1021    }
1022
1023    private static void loge(String msg) {
1024        Log.e(TAG, "[ android.media.AudioTrack ] " + msg);
1025    }
1026
1027}
1028