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