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