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