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