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