AudioTrack.java revision 105925376f8d0f6b318c9938c7b83ef7fef094da
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     * @hide
427     * Returns the current playback rate in Hz. Note that this rate may differ from one set using
428     * {@link #setPlaybackRate(int)} as the value effectively set is implementation-dependent.
429     */
430    public int getPlaybackRate() {
431        return native_get_playback_rate();
432    }
433
434    /**
435     * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT}
436     * and {@link AudioFormat#ENCODING_PCM_8BIT}.
437     */
438    public int getAudioFormat() {
439        return mAudioFormat;
440    }
441
442    /**
443     * Returns the type of audio stream this AudioTrack is configured for.
444     * Compare the result against {@link AudioManager#STREAM_VOICE_CALL},
445     * {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING},
446     * {@link AudioManager#STREAM_MUSIC} or {@link AudioManager#STREAM_ALARM}
447     */
448    public int getStreamType() {
449        return mStreamType;
450    }
451
452    /**
453     * Returns the configured channel configuration.
454
455     * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO}
456     * and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}.
457     */
458    public int getChannelConfiguration() {
459        return mChannelConfiguration;
460    }
461
462    /**
463     * Returns the configured number of channels.
464     */
465    public int getChannelCount() {
466        return mChannelCount;
467    }
468
469    /**
470     * Returns the state of the AudioTrack instance. This is useful after the
471     * AudioTrack instance has been created to check if it was initialized
472     * properly. This ensures that the appropriate hardware resources have been
473     * acquired.
474     */
475    public int getState() {
476        return mState;
477    }
478
479    /**
480     * Returns the playback state of the AudioTrack instance.
481     * @see #PLAYSTATE_STOPPED
482     * @see #PLAYSTATE_PAUSED
483     * @see #PLAYSTATE_PLAYING
484     */
485    public int getPlayState() {
486        return mPlayState;
487    }
488
489    /**
490     *  Returns the native frame count used by the hardware
491     */
492    protected int getNativeFrameCount() {
493        return native_get_native_frame_count();
494    }
495
496    /**
497     * @return marker position in frames
498     */
499    public int getNotificationMarkerPosition() {
500        return native_get_marker_pos();
501    }
502
503    /**
504     * @return update period in frames
505     */
506    public int getPositionNotificationPeriod() {
507        return native_get_pos_update_period();
508    }
509
510    /**
511     * @return playback head position in frames
512     */
513    public int getPlaybackHeadPosition() {
514        return native_get_position();
515    }
516
517    /**
518     *  Returns the hardware output sample rate
519     */
520    static public int getNativeOutputSampleRate(int streamType) {
521        return native_get_output_sample_rate(streamType);
522    }
523
524    /**
525     * {@hide}
526     * Returns the minimum buffer size required for the successful creation of an AudioTrack
527     * object to be created in the {@link #MODE_STREAM} mode.
528     * @param sampleRateInHz the sample rate expressed in Hertz.
529     * @param channelConfig describes the configuration of the audio channels.
530     *   See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
531     *   {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
532     * @param audioFormat the format in which the audio data is represented.
533     *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
534     *   {@link AudioFormat#ENCODING_PCM_8BIT}
535     * @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed,
536     *   or {@link #ERROR} if the implementation was unable to query the hardware for its output
537     *     properties,
538     *   or the minimum buffer size expressed  in number of bytes.
539     */
540    static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
541        int channelCount = 0;
542        switch(channelConfig) {
543        case AudioFormat.CHANNEL_CONFIGURATION_MONO:
544            channelCount = 1;
545            break;
546        case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
547            channelCount = 2;
548            break;
549        default:
550            loge("getMinBufferSize(): Invalid channel configuration.");
551            return AudioTrack.ERROR_BAD_VALUE;
552        }
553
554        if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
555            && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {
556            loge("getMinBufferSize(): Invalid audio format.");
557            return AudioTrack.ERROR_BAD_VALUE;
558        }
559
560        if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
561            loge("getMinBufferSize(): " + sampleRateInHz +"Hz is not a supported sample rate.");
562            return AudioTrack.ERROR_BAD_VALUE;
563        }
564
565        int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
566        if ((size == -1) || (size == 0)) {
567            loge("getMinBufferSize(): error querying hardware");
568            return AudioTrack.ERROR;
569        }
570        else {
571            return size;
572        }
573    }
574
575
576    //--------------------------------------------------------------------------
577    // Initialization / configuration
578    //--------------------
579    /**
580     * Sets the listener the AudioTrack notifies when a previously set marker is reached or
581     * for each periodic playback head position update.
582     * @param listener
583     */
584    public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener) {
585        setPlaybackPositionUpdateListener(listener, null);
586    }
587
588
589    public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener,
590                                                    Handler handler) {
591        synchronized (mPositionListenerLock) {
592            mPositionListener = listener;
593        }
594        if (listener != null) {
595            mEventHandlerDelegate = new NativeEventHandlerDelegate(this, handler);
596        }
597
598    }
599
600
601
602     /**
603     * Sets the specified left/right output volume values on the AudioTrack. Values are clamped
604     * to the ({@link #getMinVolume()}, {@link #getMaxVolume()}) interval if outside this range.
605     * @param leftVolume output attenuation for the left channel. A value of 0.0f is silence,
606     *      a value of 1.0f is no attenuation.
607     * @param rightVolume output attenuation for the right channel
608     * @return error code or success, see {@link #SUCCESS},
609     *    {@link #ERROR_INVALID_OPERATION}
610     */
611    public int setStereoVolume(float leftVolume, float rightVolume) {
612        if (mState != STATE_INITIALIZED) {
613            return ERROR_INVALID_OPERATION;
614        }
615
616        // clamp the volumes
617        if (leftVolume < getMinVolume()) {
618            leftVolume = getMinVolume();
619        }
620        if (leftVolume > getMaxVolume()) {
621            leftVolume = getMaxVolume();
622        }
623        if (rightVolume < getMinVolume()) {
624            rightVolume = getMinVolume();
625        }
626        if (rightVolume > getMaxVolume()) {
627            rightVolume = getMaxVolume();
628        }
629
630        native_setVolume(leftVolume, rightVolume);
631
632        return SUCCESS;
633    }
634
635
636    /**
637     * Sets the playback sample rate for this track. This sets the sampling rate at which
638     * the audio data will be consumed and played back, not the original sampling rate of the
639     * content. Setting it to half the sample rate of the content will cause the playback to
640     * last twice as long, but will also result result in a negative pitch shift.
641     * The current implementation supports a maximum sample rate of twice the hardware output
642     * sample rate (see {@link #getNativeOutputSampleRate(int)}). Use {@link #getSampleRate()} to
643     * check the rate actually used in hardware after potential clamping.
644     * @param sampleRateInHz
645     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
646     *    {@link #ERROR_INVALID_OPERATION}
647     */
648    public int setPlaybackRate(int sampleRateInHz) {
649        if (mState != STATE_INITIALIZED) {
650            return ERROR_INVALID_OPERATION;
651        }
652        if (sampleRateInHz <= 0) {
653            return ERROR_BAD_VALUE;
654        }
655        native_set_playback_rate(sampleRateInHz);
656        return SUCCESS;
657    }
658
659
660    /**
661     *
662     * @param markerInFrames marker in frames
663     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
664     *  {@link #ERROR_INVALID_OPERATION}
665     */
666    public int setNotificationMarkerPosition(int markerInFrames) {
667        if (mState != STATE_INITIALIZED) {
668            return ERROR_INVALID_OPERATION;
669        }
670        return native_set_marker_pos(markerInFrames);
671    }
672
673
674    /**
675     * @param periodInFrames update period in frames
676     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
677     */
678    public int setPositionNotificationPeriod(int periodInFrames) {
679        if (mState != STATE_INITIALIZED) {
680            return ERROR_INVALID_OPERATION;
681        }
682        return native_set_pos_update_period(periodInFrames);
683    }
684
685
686    /**
687     * Sets the playback head position. The track must be stopped for the position to be changed.
688     * @param positionInFrames playback head position in frames
689     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
690     *    {@link #ERROR_INVALID_OPERATION}
691     */
692    public int setPlaybackHeadPosition(int positionInFrames) {
693        synchronized(mPlayStateLock) {
694            if ((mPlayState == PLAYSTATE_STOPPED) || (mPlayState == PLAYSTATE_PAUSED)) {
695                return native_set_position(positionInFrames);
696            } else {
697                return ERROR_INVALID_OPERATION;
698            }
699        }
700    }
701
702    /**
703     * Sets the loop points and the loop count. The loop can be infinite.
704     * @param startInFrames loop start marker in frames
705     * @param endInFrames loop end marker in frames
706     * @param loopCount the number of times the loop is looped.
707     *    A value of -1 means infinite looping.
708     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
709     *    {@link #ERROR_INVALID_OPERATION}
710     */
711    public int setLoopPoints(int startInFrames, int endInFrames, int loopCount) {
712        if (mDataLoadMode == MODE_STREAM) {
713            return ERROR_INVALID_OPERATION;
714        }
715        return native_set_loop(startInFrames, endInFrames, loopCount);
716    }
717
718    /**
719     * Sets the initialization state of the instance. To be used in an AudioTrack subclass
720     * constructor to set a subclass-specific post-initialization state.
721     * @param state the state of the AudioTrack instance
722     */
723    protected void setState(int state) {
724        mState = state;
725    }
726
727
728    //---------------------------------------------------------
729    // Transport control methods
730    //--------------------
731    /**
732     * Starts playing an AudioTrack.
733     * @throws IllegalStateException
734     */
735    public void play()
736    throws IllegalStateException {
737        if (mState != STATE_INITIALIZED) {
738            throw(new IllegalStateException("play() called on uninitialized AudioTrack."));
739        }
740
741        synchronized(mPlayStateLock) {
742            native_start();
743            mPlayState = PLAYSTATE_PLAYING;
744        }
745    }
746
747    /**
748     * Stops playing the audio data.
749     * @throws IllegalStateException
750     */
751    public void stop()
752    throws IllegalStateException {
753        if (mState != STATE_INITIALIZED) {
754            throw(new IllegalStateException("stop() called on uninitialized AudioTrack."));
755        }
756
757        // stop playing
758        synchronized(mPlayStateLock) {
759            native_stop();
760            mPlayState = PLAYSTATE_STOPPED;
761        }
762    }
763
764    /**
765     * Pauses the playback of the audio data.
766     * @throws IllegalStateException
767     */
768    public void pause()
769    throws IllegalStateException {
770        if (mState != STATE_INITIALIZED) {
771            throw(new IllegalStateException("pause() called on uninitialized AudioTrack."));
772        }
773        //logd("pause()");
774
775        // pause playback
776        synchronized(mPlayStateLock) {
777            native_pause();
778            mPlayState = PLAYSTATE_PAUSED;
779        }
780    }
781
782
783    //---------------------------------------------------------
784    // Audio data supply
785    //--------------------
786
787    /**
788     * Flushes the audio data currently queued for playback.
789     */
790
791    public void flush() {
792        if (mState == STATE_INITIALIZED) {
793            // flush the data in native layer
794            native_flush();
795        }
796
797    }
798
799    /**
800     * Writes the audio data to the audio hardware for playback.
801     * @param audioData the array that holds the data to play.
802     * @param offsetInBytes the offset in audioData where the data to play starts.
803     * @param sizeInBytes the number of bytes to read in audioData after the offset.
804     * @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION}
805     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
806     *    the parameters don't resolve to valid data and indexes.
807     */
808
809    public int write(byte[] audioData,int offsetInBytes, int sizeInBytes) {
810        if ((mDataLoadMode == MODE_STATIC)
811                && (mState == STATE_NO_STATIC_DATA)
812                && (sizeInBytes > 0)) {
813            mState = STATE_INITIALIZED;
814        }
815
816        if (mState != STATE_INITIALIZED) {
817            return ERROR_INVALID_OPERATION;
818        }
819
820        if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
821                || (offsetInBytes + sizeInBytes > audioData.length)) {
822            return ERROR_BAD_VALUE;
823        }
824
825        return native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat);
826    }
827
828
829    /**
830     * Writes the audio data to the audio hardware for playback.
831     * @param audioData the array that holds the data to play.
832     * @param offsetInShorts the offset in audioData where the data to play starts.
833     * @param sizeInShorts the number of bytes to read in audioData after the offset.
834     * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION}
835      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
836      *    the parameters don't resolve to valid data and indexes.
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
846        if (mState != STATE_INITIALIZED) {
847            return ERROR_INVALID_OPERATION;
848        }
849
850        if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
851                || (offsetInShorts + sizeInShorts > audioData.length)) {
852            return ERROR_BAD_VALUE;
853        }
854
855        return native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);
856    }
857
858
859    /**
860     * Notifies the native resource to reuse the audio data already loaded in the native
861     * layer. This call is only valid with AudioTrack instances that don't use the streaming
862     * model.
863     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
864     *  {@link #ERROR_INVALID_OPERATION}
865     */
866    public int reloadStaticData() {
867        if (mDataLoadMode == MODE_STREAM) {
868            return ERROR_INVALID_OPERATION;
869        }
870        return native_reload_static();
871    }
872
873
874    //---------------------------------------------------------
875    // Interface definitions
876    //--------------------
877    /**
878     * Interface definition for a callback to be invoked when the playback head position of
879     * an AudioTrack has reached a notification marker or has increased by a certain period.
880     */
881    public interface OnPlaybackPositionUpdateListener  {
882        /**
883         * Called on the listener to notify it that the previously set marker has been reached
884         * by the playback head.
885         */
886        void onMarkerReached(AudioTrack track);
887
888        /**
889         * Called on the listener to periodically notify it that the playback head has reached
890         * a multiple of the notification period.
891         */
892        void onPeriodicNotification(AudioTrack track);
893    }
894
895
896    //---------------------------------------------------------
897    // Inner classes
898    //--------------------
899    /**
900     * Helper class to handle the forwarding of native events to the appropriate listener
901     * (potentially) handled in a different thread
902     */
903    private class NativeEventHandlerDelegate {
904        private final AudioTrack mAudioTrack;
905        private final Handler mHandler;
906
907        NativeEventHandlerDelegate(AudioTrack track, Handler handler) {
908            mAudioTrack = track;
909            // find the looper for our new event handler
910            Looper looper;
911            if (handler != null) {
912                looper = handler.getLooper();
913            } else {
914                // no given handler, use the looper the AudioTrack was created in
915                looper = mInitializationLooper;
916            }
917
918            // construct the event handler with this looper
919            if (looper != null) {
920                // implement the event handler delegate
921                mHandler = new Handler(looper) {
922                    @Override
923                    public void handleMessage(Message msg) {
924                        if (mAudioTrack == null) {
925                            return;
926                        }
927                        OnPlaybackPositionUpdateListener listener = null;
928                        synchronized (mPositionListenerLock) {
929                            listener = mAudioTrack.mPositionListener;
930                        }
931                        switch(msg.what) {
932                        case NATIVE_EVENT_MARKER:
933                            if (listener != null) {
934                                listener.onMarkerReached(mAudioTrack);
935                            }
936                            break;
937                        case NATIVE_EVENT_NEW_POS:
938                            if (listener != null) {
939                                listener.onPeriodicNotification(mAudioTrack);
940                            }
941                            break;
942                        default:
943                            Log.e(TAG, "[ android.media.AudioTrack.NativeEventHandler ] " +
944                                    "Unknown event type: " + msg.what);
945                            break;
946                        }
947                    }
948                };
949            } else {
950                mHandler = null;
951            }
952        }
953
954        Handler getHandler() {
955            return mHandler;
956        }
957    }
958
959
960    //---------------------------------------------------------
961    // Java methods called from the native side
962    //--------------------
963    @SuppressWarnings("unused")
964    private static void postEventFromNative(Object audiotrack_ref,
965            int what, int arg1, int arg2, Object obj) {
966        //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
967        AudioTrack track = (AudioTrack)((WeakReference)audiotrack_ref).get();
968        if (track == null) {
969            return;
970        }
971
972        if (track.mEventHandlerDelegate != null) {
973            Message m =
974                track.mEventHandlerDelegate.getHandler().obtainMessage(what, arg1, arg2, obj);
975            track.mEventHandlerDelegate.getHandler().sendMessage(m);
976        }
977
978    }
979
980
981    //---------------------------------------------------------
982    // Native methods called from the Java side
983    //--------------------
984
985    private native final int native_setup(Object audiotrack_this,
986            int streamType, int sampleRate, int nbChannels, int audioFormat,
987            int buffSizeInBytes, int mode);
988
989    private native final void native_finalize();
990
991    private native final void native_release();
992
993    private native final void native_start();
994
995    private native final void native_stop();
996
997    private native final void native_pause();
998
999    private native final void native_flush();
1000
1001    private native final int native_write_byte(byte[] audioData,
1002                                               int offsetInBytes, int sizeInBytes, int format);
1003
1004    private native final int native_write_short(short[] audioData,
1005                                                int offsetInShorts, int sizeInShorts, int format);
1006
1007    private native final int native_reload_static();
1008
1009    private native final int native_get_native_frame_count();
1010
1011    private native final void native_setVolume(float leftVolume, float rightVolume);
1012
1013    private native final void native_set_playback_rate(int sampleRateInHz);
1014    private native final int  native_get_playback_rate();
1015
1016    private native final int native_set_marker_pos(int marker);
1017    private native final int native_get_marker_pos();
1018
1019    private native final int native_set_pos_update_period(int updatePeriod);
1020    private native final int native_get_pos_update_period();
1021
1022    private native final int native_set_position(int position);
1023    private native final int native_get_position();
1024
1025    private native final int native_set_loop(int start, int end, int loopCount);
1026
1027    static private native final int native_get_output_sample_rate(int streamType);
1028    static private native final int native_get_min_buff_size(
1029            int sampleRateInHz, int channelConfig, int audioFormat);
1030
1031
1032    //---------------------------------------------------------
1033    // Utility methods
1034    //------------------
1035
1036    private static void logd(String msg) {
1037        Log.d(TAG, "[ android.media.AudioTrack ] " + msg);
1038    }
1039
1040    private static void loge(String msg) {
1041        Log.e(TAG, "[ android.media.AudioTrack ] " + msg);
1042    }
1043
1044}
1045