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