FileDocCategorySizeDatePackage
AudioTrack.javaAPI DocAndroid 1.5 API40080Wed May 06 22:42:00 BST 2009android.media

AudioTrack

public class AudioTrack extends Object
The AudioTrack class manages and plays a single audio resource for Java applications. It allows to stream PCM audio buffers to the audio hardware for playback. This is achieved by "pushing" the data to the AudioTrack object using one of the {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods.

An AudioTrack instance can operate under two modes: static or streaming.
In Streaming mode, the application writes a continuous stream of data to the AudioTrack, using one of the write() methods. These are blocking and return when the data has been transferred from the Java layer to the native layer and queued for playback. The streaming mode is most useful when playing blocks of audio data that for instance are:

  • too big to fit in memory because of the duration of the sound to play,
  • too big to fit in memory because of the characteristics of the audio data (high sampling rate, bits per sample ...)
  • received or generated while previously queued audio is playing.
The static mode is to be chosen when dealing with short sounds that fit in memory and that need to be played with the smallest latency possible. AudioTrack instances in static mode can play the sound without the need to transfer the audio data from Java to native layer each time the sound is to be played. The static mode will therefore be preferred for UI and game sounds that are played often, and with the smallest overhead possible.

Upon creation, an AudioTrack object initializes its associated audio buffer. The size of this buffer, specified during the construction, determines how long an AudioTrack can play before running out of data.
For an AudioTrack using the static mode, this size is the maximum size of the sound that can be played from it.
For the streaming mode, data will be written to the hardware in chunks of sizes inferior to the total buffer size.

Fields Summary
private static final float
VOLUME_MIN
Minimum value for a channel volume
private static final float
VOLUME_MAX
Maximum value for a channel volume
public static final int
PLAYSTATE_STOPPED
indicates AudioTrack state is stopped
public static final int
PLAYSTATE_PAUSED
indicates AudioTrack state is paused
public static final int
PLAYSTATE_PLAYING
indicates AudioTrack state is playing
public static final int
MODE_STATIC
Creation mode where audio data is transferred from Java to the native layer only once before the audio starts playing.
public static final int
MODE_STREAM
Creation mode where audio data is streamed from Java to the native layer as the audio is playing.
public static final int
STATE_UNINITIALIZED
State of an AudioTrack that was not successfully initialized upon creation.
public static final int
STATE_INITIALIZED
State of an AudioTrack that is ready to be used.
public static final int
STATE_NO_STATIC_DATA
State of a successfully initialized AudioTrack that uses static data, but that hasn't received that data yet.
public static final int
SUCCESS
Denotes a successful operation.
public static final int
ERROR
Denotes a generic operation failure.
public static final int
ERROR_BAD_VALUE
Denotes a failure due to the use of an invalid value.
public static final int
ERROR_INVALID_OPERATION
Denotes a failure due to the improper use of a method.
private static final int
ERROR_NATIVESETUP_AUDIOSYSTEM
private static final int
ERROR_NATIVESETUP_INVALIDCHANNELCOUNT
private static final int
ERROR_NATIVESETUP_INVALIDFORMAT
private static final int
ERROR_NATIVESETUP_INVALIDSTREAMTYPE
private static final int
ERROR_NATIVESETUP_NATIVEINITFAILED
private static final int
NATIVE_EVENT_MARKER
Event id denotes when playback head has reached a previously set marker.
private static final int
NATIVE_EVENT_NEW_POS
Event id denotes when previously set update period has elapsed during playback.
private static final String
TAG
private int
mState
Indicates the state of the AudioTrack instance.
private int
mPlayState
Indicates the play state of the AudioTrack instance.
private final Object
mPlayStateLock
Lock to make sure mPlayState updates are reflecting the actual state of the object.
private OnPlaybackPositionUpdateListener
mPositionListener
The listener the AudioTrack notifies when the playback position reaches a marker or for periodic updates during the progression of the playback head.
private final Object
mPositionListenerLock
Lock to protect event listener updates against event notifications.
private int
mNativeBufferSizeInBytes
Size of the native audio buffer.
private NativeEventHandlerDelegate
mEventHandlerDelegate
Handler for marker events coming from the native code.
private android.os.Looper
mInitializationLooper
Looper associated with the thread that creates the AudioTrack instance.
private int
mSampleRate
The audio data sampling rate in Hz.
private int
mChannelCount
The number of input audio channels (1 is mono, 2 is stereo).
private int
mStreamType
The type of the audio stream to play. See {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and {@link AudioManager#STREAM_ALARM}
private int
mDataLoadMode
The way audio is consumed by the hardware, streaming or static.
private int
mChannelConfiguration
The current audio channel configuration.
private int
mAudioFormat
The encoding of the audio samples.
private int
mNativeTrackInJavaObj
Accessed by native methods: provides access to C++ AudioTrack object.
private int
mJniData
Accessed by native methods: provides access to the JNI data (i.e. resources used by the native AudioTrack object, but not stored in it).
Constructors Summary
public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)
Class constructor.

param
streamType the type of the audio stream. See {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and {@link AudioManager#STREAM_ALARM}
param
sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but not limited to) 44100, 22050 and 11025.
param
channelConfig describes the configuration of the audio channels. See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
param
audioFormat the format in which the audio data is represented. See {@link AudioFormat#ENCODING_PCM_16BIT} and {@link AudioFormat#ENCODING_PCM_8BIT}
param
bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read from for playback. If using the AudioTrack in streaming mode, you can write data into this buffer in smaller chunks than this size. If using the AudioTrack in static mode, this is the maximum size of the sound that will be played for this instance. See {@link #getMinBufferSize(int, int, int)} to determine the minimum required buffer size for the successful creation of an AudioTrack instance in streaming mode. Using values smaller than getMinBufferSize() will result in an initialization failure.
param
mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}
throws
java.lang.IllegalArgumentException

        mState = STATE_UNINITIALIZED;
        
        // remember which looper is associated with the AudioTrack instanciation
        if ((mInitializationLooper = Looper.myLooper()) == null) {
            mInitializationLooper = Looper.getMainLooper();
        }

        audioParamCheck(streamType, sampleRateInHz, channelConfig, audioFormat, mode);

        audioBuffSizeCheck(bufferSizeInBytes);

        // native initialization
        int initResult = native_setup(new WeakReference<AudioTrack>(this),
                mStreamType, mSampleRate, mChannelCount, mAudioFormat,
                mNativeBufferSizeInBytes, mDataLoadMode);
        if (initResult != SUCCESS) {
            loge("Error code "+initResult+" when initializing AudioTrack.");
            return; // with mState == STATE_UNINITIALIZED
        }

        if (mDataLoadMode == MODE_STATIC) {
            mState = STATE_NO_STATIC_DATA;
        } else {
            mState = STATE_INITIALIZED;
        }
    
Methods Summary
private voidaudioBuffSizeCheck(int audioBufferSize)

        // NB: this section is only valid with PCM data.
        //     To update when supporting compressed formats
        int frameSizeInBytes = mChannelCount
                * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
        if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
            throw (new IllegalArgumentException("Invalid audio buffer size."));
        }

        mNativeBufferSizeInBytes = audioBufferSize;
    
private voidaudioParamCheck(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int mode)


        //--------------
        // stream type
        if( (streamType != AudioManager.STREAM_ALARM) && (streamType != AudioManager.STREAM_MUSIC)
           && (streamType != AudioManager.STREAM_RING) && (streamType != AudioManager.STREAM_SYSTEM)
           && (streamType != AudioManager.STREAM_VOICE_CALL)
           && (streamType != AudioManager.STREAM_NOTIFICATION)
           && (streamType != AudioManager.STREAM_BLUETOOTH_SCO)) {
            throw (new IllegalArgumentException("Invalid stream type."));
        } else {
            mStreamType = streamType;
        }

        //--------------
        // sample rate
        if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
            throw (new IllegalArgumentException(sampleRateInHz
                    + "Hz is not a supported sample rate."));
        } else {
            mSampleRate = sampleRateInHz;
        }

        //--------------
        // channel config
        switch (channelConfig) {
        case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT:
        case AudioFormat.CHANNEL_CONFIGURATION_MONO:
            mChannelCount = 1;
            mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
            break;
        case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
            mChannelCount = 2;
            mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
            break;
        default:
            mChannelCount = 0;
            mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_INVALID;
            throw(new IllegalArgumentException("Unsupported channel configuration."));
        }

        //--------------
        // audio format
        switch (audioFormat) {
        case AudioFormat.ENCODING_DEFAULT:
            mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
            break;
        case AudioFormat.ENCODING_PCM_16BIT:
        case AudioFormat.ENCODING_PCM_8BIT:
            mAudioFormat = audioFormat;
            break;
        default:
            mAudioFormat = AudioFormat.ENCODING_INVALID;
            throw(new IllegalArgumentException("Unsupported sample encoding."
                + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT."));
        }

        //--------------
        // audio load mode
        if ( (mode != MODE_STREAM) && (mode != MODE_STATIC) ) {
            throw(new IllegalArgumentException("Invalid mode."));
        } else {
            mDataLoadMode = mode;
        }
    
protected voidfinalize()

        native_finalize();
    
public voidflush()
Flushes the audio data currently queued for playback.

        if (mState == STATE_INITIALIZED) {
            // flush the data in native layer
            native_flush();
        }

    
public intgetAudioFormat()
Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT} and {@link AudioFormat#ENCODING_PCM_8BIT}.

        return mAudioFormat;
    
public intgetChannelConfiguration()
Returns the configured channel configuration. See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}.

        return mChannelConfiguration;
    
public intgetChannelCount()
Returns the configured number of channels.

        return mChannelCount;
    
public static floatgetMaxVolume()
Returns the maximum valid volume value. Volume values set above this one will be clamped at this value.

return
the maximum volume expressed as a linear attenuation.

        return AudioTrack.VOLUME_MAX;
    
public static intgetMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)
Returns the minimum buffer size required for the successful creation of an AudioTrack object to be created in the {@link #MODE_STREAM} mode. Note that this size doesn't guarantee a smooth playback under load, and higher values should be chosen according to the expected frequency at which the buffer will be refilled with additional data to play.

param
sampleRateInHz the sample rate expressed in Hertz.
param
channelConfig describes the configuration of the audio channels. See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
param
audioFormat the format in which the audio data is represented. See {@link AudioFormat#ENCODING_PCM_16BIT} and {@link AudioFormat#ENCODING_PCM_8BIT}
return
{@link #ERROR_BAD_VALUE} if an invalid parameter was passed, or {@link #ERROR} if the implementation was unable to query the hardware for its output properties, or the minimum buffer size expressed in bytes.

        int channelCount = 0;
        switch(channelConfig) {
        case AudioFormat.CHANNEL_CONFIGURATION_MONO:
            channelCount = 1;
            break;
        case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
            channelCount = 2;
            break;
        default:
            loge("getMinBufferSize(): Invalid channel configuration.");
            return AudioTrack.ERROR_BAD_VALUE;
        }
        
        if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT) 
            && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {
            loge("getMinBufferSize(): Invalid audio format.");
            return AudioTrack.ERROR_BAD_VALUE;
        }
        
        if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
            loge("getMinBufferSize(): " + sampleRateInHz +"Hz is not a supported sample rate.");
            return AudioTrack.ERROR_BAD_VALUE;
        }
        
        int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
        if ((size == -1) || (size == 0)) {
            loge("getMinBufferSize(): error querying hardware");
            return AudioTrack.ERROR;
        }
        else {
            return size;
        }
    
public static floatgetMinVolume()
Returns the minimum valid volume value. Volume values set under this one will be clamped at this value.

return
the minimum volume expressed as a linear attenuation.

        return AudioTrack.VOLUME_MIN;
    
protected intgetNativeFrameCount()
Returns the native frame count used by the hardware.

        return native_get_native_frame_count();
    
public static intgetNativeOutputSampleRate(int streamType)
Returns the hardware output sample rate

        return native_get_output_sample_rate(streamType);
    
public intgetNotificationMarkerPosition()
Returns marker position expressed in frames.

        return native_get_marker_pos();
    
public intgetPlayState()
Returns the playback state of the AudioTrack instance.

see
#PLAYSTATE_STOPPED
see
#PLAYSTATE_PAUSED
see
#PLAYSTATE_PLAYING

        return mPlayState;
    
public intgetPlaybackHeadPosition()
Returns the playback head position expressed in frames

        return native_get_position();
    
public intgetPlaybackRate()
Returns the current playback rate in Hz. Note that this rate may differ from the one set with {@link #setPlaybackRate(int)} as the value effectively used is implementation-dependent.

        return native_get_playback_rate();
    
public intgetPositionNotificationPeriod()
Returns the notification update period expressed in frames.

        return native_get_pos_update_period();
    
public intgetSampleRate()
Returns the configured audio data sample rate in Hz

        return mSampleRate;
    
public intgetState()
Returns the state of the AudioTrack instance. This is useful after the AudioTrack instance has been created to check if it was initialized properly. This ensures that the appropriate hardware resources have been acquired.

see
#STATE_INITIALIZED
see
#STATE_NO_STATIC_DATA
see
#STATE_UNINITIALIZED

        return mState;
    
public intgetStreamType()
Returns the type of audio stream this AudioTrack is configured for. Compare the result against {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} or {@link AudioManager#STREAM_ALARM}

        return mStreamType;
    
private static voidlogd(java.lang.String msg)

        Log.d(TAG, "[ android.media.AudioTrack ] " + msg);
    
private static voidloge(java.lang.String msg)

        Log.e(TAG, "[ android.media.AudioTrack ] " + msg);
    
private final native voidnative_finalize()

private final native voidnative_flush()

private final native intnative_get_marker_pos()

private static final native intnative_get_min_buff_size(int sampleRateInHz, int channelConfig, int audioFormat)

private final native intnative_get_native_frame_count()

private static final native intnative_get_output_sample_rate(int streamType)

private final native intnative_get_playback_rate()

private final native intnative_get_pos_update_period()

private final native intnative_get_position()

private final native voidnative_pause()

private final native voidnative_release()

private final native intnative_reload_static()

private final native voidnative_setVolume(float leftVolume, float rightVolume)

private final native intnative_set_loop(int start, int end, int loopCount)

private final native intnative_set_marker_pos(int marker)

private final native voidnative_set_playback_rate(int sampleRateInHz)

private final native intnative_set_pos_update_period(int updatePeriod)

private final native intnative_set_position(int position)

private final native intnative_setup(java.lang.Object audiotrack_this, int streamType, int sampleRate, int nbChannels, int audioFormat, int buffSizeInBytes, int mode)

private final native voidnative_start()

private final native voidnative_stop()

private final native intnative_write_byte(byte[] audioData, int offsetInBytes, int sizeInBytes, int format)

private final native intnative_write_short(short[] audioData, int offsetInShorts, int sizeInShorts, int format)

public voidpause()
Pauses the playback of the audio data.

throws
IllegalStateException

        if (mState != STATE_INITIALIZED) {
            throw(new IllegalStateException("pause() called on uninitialized AudioTrack."));
        }
        //logd("pause()");

        // pause playback
        synchronized(mPlayStateLock) {
            native_pause();
            mPlayState = PLAYSTATE_PAUSED;
        }
    
public voidplay()
Starts playing an AudioTrack.

throws
IllegalStateException

        if (mState != STATE_INITIALIZED) {
            throw(new IllegalStateException("play() called on uninitialized AudioTrack."));
        }

        synchronized(mPlayStateLock) {
            native_start();
            mPlayState = PLAYSTATE_PLAYING;
        }
    
private static voidpostEventFromNative(java.lang.Object audiotrack_ref, int what, int arg1, int arg2, java.lang.Object obj)

        //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
        AudioTrack track = (AudioTrack)((WeakReference)audiotrack_ref).get();
        if (track == null) {
            return;
        }

        if (track.mEventHandlerDelegate != null) {
            Message m = 
                track.mEventHandlerDelegate.getHandler().obtainMessage(what, arg1, arg2, obj);
            track.mEventHandlerDelegate.getHandler().sendMessage(m);
        }

    
public voidrelease()
Releases the native AudioTrack resources.

        // even though native_release() stops the native AudioTrack, we need to stop
        // AudioTrack subclasses too.
        try {
            stop();
        } catch(IllegalStateException ise) { 
            // don't raise an exception, we're releasing the resources.
        }
        native_release();
        mState = STATE_UNINITIALIZED;
    
public intreloadStaticData()
Notifies the native resource to reuse the audio data already loaded in the native layer. This call is only valid with AudioTrack instances that don't use the streaming model.

return
error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}

        if (mDataLoadMode == MODE_STREAM) {
            return ERROR_INVALID_OPERATION;
        }
        return native_reload_static();
    
public intsetLoopPoints(int startInFrames, int endInFrames, int loopCount)
Sets the loop points and the loop count. The loop can be infinite.

param
startInFrames loop start marker expressed in frames
param
endInFrames loop end marker expressed in frames
param
loopCount the number of times the loop is looped. A value of -1 means infinite looping.
return
error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}

        if (mDataLoadMode == MODE_STREAM) {
            return ERROR_INVALID_OPERATION;
        }
        return native_set_loop(startInFrames, endInFrames, loopCount);
    
public intsetNotificationMarkerPosition(int markerInFrames)
Sets the position of the notification marker.

param
markerInFrames marker in frames
return
error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}

        if (mState != STATE_INITIALIZED) {
            return ERROR_INVALID_OPERATION;
        }
        return native_set_marker_pos(markerInFrames);
    
public intsetPlaybackHeadPosition(int positionInFrames)
Sets the playback head position. The track must be stopped for the position to be changed.

param
positionInFrames playback head position expressed in frames
return
error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}

        synchronized(mPlayStateLock) {
            if ((mPlayState == PLAYSTATE_STOPPED) || (mPlayState == PLAYSTATE_PAUSED)) {
                return native_set_position(positionInFrames);
            } else {
                return ERROR_INVALID_OPERATION;
            }
        }
    
public voidsetPlaybackPositionUpdateListener(android.media.AudioTrack$OnPlaybackPositionUpdateListener listener)
Sets the listener the AudioTrack notifies when a previously set marker is reached or for each periodic playback head position update. Notifications will be received in the same thread as the one in which the AudioTrack instance was created.

param
listener

        setPlaybackPositionUpdateListener(listener, null);
    
public voidsetPlaybackPositionUpdateListener(android.media.AudioTrack$OnPlaybackPositionUpdateListener listener, android.os.Handler handler)
Sets the listener the AudioTrack notifies when a previously set marker is reached or for each periodic playback head position update. Use this method to receive AudioTrack events in the Handler associated with another thread than the one in which you created the AudioTrack instance.

param
listener
param
handler the Handler that will receive the event notification messages.

        synchronized (mPositionListenerLock) {
            mPositionListener = listener;
        }
        if (listener != null) {
            mEventHandlerDelegate = new NativeEventHandlerDelegate(this, handler);
        }
        
    
public intsetPlaybackRate(int sampleRateInHz)
Sets the playback sample rate for this track. This sets the sampling rate at which the audio data will be consumed and played back, not the original sampling rate of the content. Setting it to half the sample rate of the content will cause the playback to last twice as long, but will also result result in a negative pitch shift. The current implementation supports a maximum sample rate of 64kHz. Use {@link #getSampleRate()} to check the rate actually used in hardware after potential clamping.

param
sampleRateInHz the sample rate expressed in Hz
return
error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}

        if (mState != STATE_INITIALIZED) {
            return ERROR_INVALID_OPERATION;
        }
        if (sampleRateInHz <= 0) {
            return ERROR_BAD_VALUE;
        }
        native_set_playback_rate(sampleRateInHz);
        return SUCCESS;
    
public intsetPositionNotificationPeriod(int periodInFrames)
Sets the period for the periodic notification event.

param
periodInFrames update period expressed in frames
return
error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}

        if (mState != STATE_INITIALIZED) {
            return ERROR_INVALID_OPERATION;
        }
        return native_set_pos_update_period(periodInFrames);
    
protected voidsetState(int state)
Sets the initialization state of the instance. To be used in an AudioTrack subclass constructor to set a subclass-specific post-initialization state.

param
state the state of the AudioTrack instance

        mState = state;
    
public intsetStereoVolume(float leftVolume, float rightVolume)
Sets the specified left/right output volume values on the AudioTrack. Values are clamped to the ({@link #getMinVolume()}, {@link #getMaxVolume()}) interval if outside this range.

param
leftVolume output attenuation for the left channel. A value of 0.0f is silence, a value of 1.0f is no attenuation.
param
rightVolume output attenuation for the right channel
return
error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}

        if (mState != STATE_INITIALIZED) {
            return ERROR_INVALID_OPERATION;
        }

        // clamp the volumes
        if (leftVolume < getMinVolume()) {
            leftVolume = getMinVolume();
        }
        if (leftVolume > getMaxVolume()) {
            leftVolume = getMaxVolume();
        }
        if (rightVolume < getMinVolume()) {
            rightVolume = getMinVolume();
        }
        if (rightVolume > getMaxVolume()) {
            rightVolume = getMaxVolume();
        }

        native_setVolume(leftVolume, rightVolume);

        return SUCCESS;
    
public voidstop()
Stops playing the audio data.

throws
IllegalStateException

        if (mState != STATE_INITIALIZED) {
            throw(new IllegalStateException("stop() called on uninitialized AudioTrack."));
        }

        // stop playing
        synchronized(mPlayStateLock) {
            native_stop();
            mPlayState = PLAYSTATE_STOPPED;
        }
    
public intwrite(byte[] audioData, int offsetInBytes, int sizeInBytes)
Writes the audio data to the audio hardware for playback.

param
audioData the array that holds the data to play.
param
offsetInBytes the offset expressed in bytes in audioData where the data to play starts.
param
sizeInBytes the number of bytes to read in audioData after the offset.
return
the number of bytes that were written or {@link #ERROR_INVALID_OPERATION} if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes.

        if ((mDataLoadMode == MODE_STATIC)
                && (mState == STATE_NO_STATIC_DATA)
                && (sizeInBytes > 0)) {
            mState = STATE_INITIALIZED;
        }

        if (mState != STATE_INITIALIZED) {
            return ERROR_INVALID_OPERATION;
        }

        if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0) 
                || (offsetInBytes + sizeInBytes > audioData.length)) {
            return ERROR_BAD_VALUE;
        }

        return native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat);
    
public intwrite(short[] audioData, int offsetInShorts, int sizeInShorts)
Writes the audio data to the audio hardware for playback.

param
audioData the array that holds the data to play.
param
offsetInShorts the offset expressed in shorts in audioData where the data to play starts.
param
sizeInShorts the number of bytes to read in audioData after the offset.
return
the number of shorts that were written or {@link #ERROR_INVALID_OPERATION} if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if the parameters don't resolve to valid data and indexes.

        if ((mDataLoadMode == MODE_STATIC)
                && (mState == STATE_NO_STATIC_DATA)
                && (sizeInShorts > 0)) {
            mState = STATE_INITIALIZED;
        }
        
        if (mState != STATE_INITIALIZED) {
            return ERROR_INVALID_OPERATION;
        }

        if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0) 
                || (offsetInShorts + sizeInShorts > audioData.length)) {
            return ERROR_BAD_VALUE;
        }

        return native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);