blob: c5d17eb3cfa05568cfc04c8a0eed2087a6697947 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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.
Narayan Kamath88bde0c2011-07-14 16:37:46 +010035 *
Jean-Michel Triviff14c252009-04-17 11:45:30 -070036 * <p>An AudioTrack instance can operate under two modes: static or streaming.<br>
37 * In Streaming mode, the application writes a continuous stream of data to the AudioTrack, using
Narayan Kamath88bde0c2011-07-14 16:37:46 +010038 * one of the {@code write()} methods. These are blocking and return when the data has been
39 * transferred from the Java layer to the native layer and queued for playback. The streaming
40 * mode is most useful when playing blocks of audio data that for instance are:
41 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042 * <ul>
43 * <li>too big to fit in memory because of the duration of the sound to play,</li>
44 * <li>too big to fit in memory because of the characteristics of the audio data
45 * (high sampling rate, bits per sample ...)</li>
Jean-Michel Triviff14c252009-04-17 11:45:30 -070046 * <li>received or generated while previously queued audio is playing.</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047 * </ul>
Narayan Kamath88bde0c2011-07-14 16:37:46 +010048 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 * The static mode is to be chosen when dealing with short sounds that fit in memory and
Narayan Kamath88bde0c2011-07-14 16:37:46 +010050 * that need to be played with the smallest latency possible. The static mode will
51 * therefore be preferred for UI and game sounds that are played often, and with the
52 * smallest overhead possible.
53 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 * <p>Upon creation, an AudioTrack object initializes its associated audio buffer.
55 * The size of this buffer, specified during the construction, determines how long an AudioTrack
56 * can play before running out of data.<br>
57 * For an AudioTrack using the static mode, this size is the maximum size of the sound that can
58 * be played from it.<br>
59 * For the streaming mode, data will be written to the hardware in chunks of
60 * sizes inferior to the total buffer size.
61 */
62public class AudioTrack
63{
64 //---------------------------------------------------------
65 // Constants
66 //--------------------
67 /** Minimum value for a channel volume */
68 private static final float VOLUME_MIN = 0.0f;
69 /** Maximum value for a channel volume */
70 private static final float VOLUME_MAX = 1.0f;
71
Jean-Michel Triviff14c252009-04-17 11:45:30 -070072 /** indicates AudioTrack state is stopped */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 public static final int PLAYSTATE_STOPPED = 1; // matches SL_PLAYSTATE_STOPPED
Jean-Michel Triviff14c252009-04-17 11:45:30 -070074 /** indicates AudioTrack state is paused */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 public static final int PLAYSTATE_PAUSED = 2; // matches SL_PLAYSTATE_PAUSED
Jean-Michel Triviff14c252009-04-17 11:45:30 -070076 /** indicates AudioTrack state is playing */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 public static final int PLAYSTATE_PLAYING = 3; // matches SL_PLAYSTATE_PLAYING
78
79 /**
80 * Creation mode where audio data is transferred from Java to the native layer
81 * only once before the audio starts playing.
82 */
83 public static final int MODE_STATIC = 0;
84 /**
85 * Creation mode where audio data is streamed from Java to the native layer
86 * as the audio is playing.
87 */
88 public static final int MODE_STREAM = 1;
89
90 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -070091 * State of an AudioTrack that was not successfully initialized upon creation.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 */
93 public static final int STATE_UNINITIALIZED = 0;
94 /**
95 * State of an AudioTrack that is ready to be used.
96 */
97 public static final int STATE_INITIALIZED = 1;
98 /**
99 * State of a successfully initialized AudioTrack that uses static data,
100 * but that hasn't received that data yet.
101 */
102 public static final int STATE_NO_STATIC_DATA = 2;
103
104 // Error codes:
105 // to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp
106 /**
107 * Denotes a successful operation.
108 */
109 public static final int SUCCESS = 0;
110 /**
111 * Denotes a generic operation failure.
112 */
113 public static final int ERROR = -1;
114 /**
115 * Denotes a failure due to the use of an invalid value.
116 */
117 public static final int ERROR_BAD_VALUE = -2;
118 /**
119 * Denotes a failure due to the improper use of a method.
120 */
121 public static final int ERROR_INVALID_OPERATION = -3;
122
123 private static final int ERROR_NATIVESETUP_AUDIOSYSTEM = -16;
Eric Laurenta553c252009-07-17 12:17:14 -0700124 private static final int ERROR_NATIVESETUP_INVALIDCHANNELMASK = -17;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 private static final int ERROR_NATIVESETUP_INVALIDFORMAT = -18;
126 private static final int ERROR_NATIVESETUP_INVALIDSTREAMTYPE = -19;
127 private static final int ERROR_NATIVESETUP_NATIVEINITFAILED = -20;
128
129 // Events:
130 // to keep in sync with frameworks/base/include/media/AudioTrack.h
131 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700132 * Event id denotes when playback head has reached a previously set marker.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 */
134 private static final int NATIVE_EVENT_MARKER = 3;
135 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700136 * Event id denotes when previously set update period has elapsed during playback.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 */
138 private static final int NATIVE_EVENT_NEW_POS = 4;
139
140 private final static String TAG = "AudioTrack-Java";
141
142
143 //--------------------------------------------------------------------------
144 // Member variables
145 //--------------------
146 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700147 * Indicates the state of the AudioTrack instance.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 */
149 private int mState = STATE_UNINITIALIZED;
150 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700151 * Indicates the play state of the AudioTrack instance.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 */
153 private int mPlayState = PLAYSTATE_STOPPED;
154 /**
155 * Lock to make sure mPlayState updates are reflecting the actual state of the object.
156 */
157 private final Object mPlayStateLock = new Object();
158 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800159 * The listener the AudioTrack notifies when the playback position reaches a marker
160 * or for periodic updates during the progression of the playback head.
161 * @see #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 */
The Android Open Source Project4df24232009-03-05 14:34:35 -0800163 private OnPlaybackPositionUpdateListener mPositionListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700165 * Lock to protect event listener updates against event notifications.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 */
The Android Open Source Project4df24232009-03-05 14:34:35 -0800167 private final Object mPositionListenerLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 /**
169 * Size of the native audio buffer.
170 */
171 private int mNativeBufferSizeInBytes = 0;
172 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700173 * Handler for marker events coming from the native code.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 */
The Android Open Source Project4df24232009-03-05 14:34:35 -0800175 private NativeEventHandlerDelegate mEventHandlerDelegate = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700177 * Looper associated with the thread that creates the AudioTrack instance.
The Android Open Source Project10592532009-03-18 17:39:46 -0700178 */
179 private Looper mInitializationLooper = null;
180 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 * The audio data sampling rate in Hz.
182 */
183 private int mSampleRate = 22050;
184 /**
Eric Laurent3026a022009-07-27 07:12:26 -0700185 * The number of audio output channels (1 is mono, 2 is stereo).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 */
187 private int mChannelCount = 1;
188 /**
Eric Laurent3026a022009-07-27 07:12:26 -0700189 * The audio channel mask.
190 */
191 private int mChannels = AudioFormat.CHANNEL_OUT_MONO;
192
193 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 * The type of the audio stream to play. See
195 * {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
196 * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and
197 * {@link AudioManager#STREAM_ALARM}
198 */
199 private int mStreamType = AudioManager.STREAM_MUSIC;
200 /**
201 * The way audio is consumed by the hardware, streaming or static.
202 */
203 private int mDataLoadMode = MODE_STREAM;
204 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700205 * The current audio channel configuration.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 */
Eric Laurenta553c252009-07-17 12:17:14 -0700207 private int mChannelConfiguration = AudioFormat.CHANNEL_OUT_MONO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 /**
209 * The encoding of the audio samples.
210 * @see AudioFormat#ENCODING_PCM_8BIT
211 * @see AudioFormat#ENCODING_PCM_16BIT
212 */
213 private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
Eric Laurent619346f2010-06-21 09:27:30 -0700214 /**
215 * Audio session ID
216 */
217 private int mSessionId = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218
219
220 //--------------------------------
221 // Used exclusively by native code
222 //--------------------
223 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700224 * Accessed by native methods: provides access to C++ AudioTrack object.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 */
226 @SuppressWarnings("unused")
227 private int mNativeTrackInJavaObj;
228 /**
229 * Accessed by native methods: provides access to the JNI data (i.e. resources used by
230 * the native AudioTrack object, but not stored in it).
231 */
232 @SuppressWarnings("unused")
233 private int mJniData;
234
235
236 //--------------------------------------------------------------------------
237 // Constructor, Finalize
238 //--------------------
239 /**
240 * Class constructor.
241 * @param streamType the type of the audio stream. See
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 * {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
243 * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and
244 * {@link AudioManager#STREAM_ALARM}
245 * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but
246 * not limited to) 44100, 22050 and 11025.
247 * @param channelConfig describes the configuration of the audio channels.
Eric Laurenta553c252009-07-17 12:17:14 -0700248 * See {@link AudioFormat#CHANNEL_OUT_MONO} and
249 * {@link AudioFormat#CHANNEL_OUT_STEREO}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 * @param audioFormat the format in which the audio data is represented.
251 * See {@link AudioFormat#ENCODING_PCM_16BIT} and
252 * {@link AudioFormat#ENCODING_PCM_8BIT}
253 * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read
254 * from for playback. If using the AudioTrack in streaming mode, you can write data into
255 * this buffer in smaller chunks than this size. If using the AudioTrack in static mode,
256 * this is the maximum size of the sound that will be played for this instance.
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700257 * See {@link #getMinBufferSize(int, int, int)} to determine the minimum required buffer size
258 * for the successful creation of an AudioTrack instance in streaming mode. Using values
259 * smaller than getMinBufferSize() will result in an initialization failure.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}
261 * @throws java.lang.IllegalArgumentException
262 */
263 public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
264 int bufferSizeInBytes, int mode)
265 throws IllegalArgumentException {
Eric Laurent619346f2010-06-21 09:27:30 -0700266 this(streamType, sampleRateInHz, channelConfig, audioFormat,
267 bufferSizeInBytes, mode, 0);
268 }
269
270 /**
271 * Class constructor with audio session. Use this constructor when the AudioTrack must be
272 * attached to a particular audio session. The primary use of the audio session ID is to
273 * associate audio effects to a particular instance of AudioTrack: if an audio session ID
274 * is provided when creating an AudioEffect, this effect will be applied only to audio tracks
275 * and media players in the same session and not to the output mix.
276 * When an AudioTrack is created without specifying a session, it will create its own session
277 * which can be retreived by calling the {@link #getAudioSessionId()} method.
278 * If a session ID is provided, this AudioTrack will share effects attached to this session
279 * with all other media players or audio tracks in the same session.
280 * @param streamType the type of the audio stream. See
281 * {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
282 * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and
283 * {@link AudioManager#STREAM_ALARM}
284 * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but
285 * not limited to) 44100, 22050 and 11025.
286 * @param channelConfig describes the configuration of the audio channels.
287 * See {@link AudioFormat#CHANNEL_OUT_MONO} and
288 * {@link AudioFormat#CHANNEL_OUT_STEREO}
289 * @param audioFormat the format in which the audio data is represented.
290 * See {@link AudioFormat#ENCODING_PCM_16BIT} and
291 * {@link AudioFormat#ENCODING_PCM_8BIT}
292 * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read
293 * from for playback. If using the AudioTrack in streaming mode, you can write data into
294 * this buffer in smaller chunks than this size. If using the AudioTrack in static mode,
295 * this is the maximum size of the sound that will be played for this instance.
296 * See {@link #getMinBufferSize(int, int, int)} to determine the minimum required buffer size
297 * for the successful creation of an AudioTrack instance in streaming mode. Using values
298 * smaller than getMinBufferSize() will result in an initialization failure.
299 * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}
300 * @param sessionId Id of audio session the AudioTrack must be attached to
301 * @throws java.lang.IllegalArgumentException
Eric Laurent619346f2010-06-21 09:27:30 -0700302 */
303 public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
304 int bufferSizeInBytes, int mode, int sessionId)
305 throws IllegalArgumentException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 mState = STATE_UNINITIALIZED;
The Android Open Source Project10592532009-03-18 17:39:46 -0700307
308 // remember which looper is associated with the AudioTrack instanciation
309 if ((mInitializationLooper = Looper.myLooper()) == null) {
310 mInitializationLooper = Looper.getMainLooper();
311 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312
313 audioParamCheck(streamType, sampleRateInHz, channelConfig, audioFormat, mode);
314
315 audioBuffSizeCheck(bufferSizeInBytes);
316
Eric Laurent619346f2010-06-21 09:27:30 -0700317 if (sessionId < 0) {
318 throw (new IllegalArgumentException("Invalid audio session ID: "+sessionId));
319 }
320
321 int[] session = new int[1];
322 session[0] = sessionId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 // native initialization
324 int initResult = native_setup(new WeakReference<AudioTrack>(this),
Eric Laurent3026a022009-07-27 07:12:26 -0700325 mStreamType, mSampleRate, mChannels, mAudioFormat,
Eric Laurent619346f2010-06-21 09:27:30 -0700326 mNativeBufferSizeInBytes, mDataLoadMode, session);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 if (initResult != SUCCESS) {
328 loge("Error code "+initResult+" when initializing AudioTrack.");
329 return; // with mState == STATE_UNINITIALIZED
330 }
331
Eric Laurent619346f2010-06-21 09:27:30 -0700332 mSessionId = session[0];
333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 if (mDataLoadMode == MODE_STATIC) {
335 mState = STATE_NO_STATIC_DATA;
336 } else {
337 mState = STATE_INITIALIZED;
338 }
339 }
340
341
342 // Convenience method for the constructor's parameter checks.
343 // This is where constructor IllegalArgumentException-s are thrown
344 // postconditions:
345 // mStreamType is valid
346 // mChannelCount is valid
Eric Laurent3026a022009-07-27 07:12:26 -0700347 // mChannels is valid
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 // mAudioFormat is valid
349 // mSampleRate is valid
350 // mDataLoadMode is valid
351 private void audioParamCheck(int streamType, int sampleRateInHz,
352 int channelConfig, int audioFormat, int mode) {
353
354 //--------------
355 // stream type
356 if( (streamType != AudioManager.STREAM_ALARM) && (streamType != AudioManager.STREAM_MUSIC)
357 && (streamType != AudioManager.STREAM_RING) && (streamType != AudioManager.STREAM_SYSTEM)
358 && (streamType != AudioManager.STREAM_VOICE_CALL)
359 && (streamType != AudioManager.STREAM_NOTIFICATION)
Eric Laurenta553c252009-07-17 12:17:14 -0700360 && (streamType != AudioManager.STREAM_BLUETOOTH_SCO)
361 && (streamType != AudioManager.STREAM_DTMF)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 throw (new IllegalArgumentException("Invalid stream type."));
363 } else {
364 mStreamType = streamType;
365 }
366
367 //--------------
368 // sample rate
369 if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
370 throw (new IllegalArgumentException(sampleRateInHz
371 + "Hz is not a supported sample rate."));
372 } else {
373 mSampleRate = sampleRateInHz;
374 }
375
376 //--------------
377 // channel config
Eric Laurent3026a022009-07-27 07:12:26 -0700378 mChannelConfiguration = channelConfig;
379
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 switch (channelConfig) {
Eric Laurent3026a022009-07-27 07:12:26 -0700381 case AudioFormat.CHANNEL_OUT_DEFAULT: //AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
Eric Laurenta553c252009-07-17 12:17:14 -0700382 case AudioFormat.CHANNEL_OUT_MONO:
Eric Laurent3026a022009-07-27 07:12:26 -0700383 case AudioFormat.CHANNEL_CONFIGURATION_MONO:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 mChannelCount = 1;
Eric Laurent3026a022009-07-27 07:12:26 -0700385 mChannels = AudioFormat.CHANNEL_OUT_MONO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 break;
Eric Laurenta553c252009-07-17 12:17:14 -0700387 case AudioFormat.CHANNEL_OUT_STEREO:
Eric Laurent3026a022009-07-27 07:12:26 -0700388 case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 mChannelCount = 2;
Eric Laurent3026a022009-07-27 07:12:26 -0700390 mChannels = AudioFormat.CHANNEL_OUT_STEREO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 break;
392 default:
393 mChannelCount = 0;
Eric Laurent3026a022009-07-27 07:12:26 -0700394 mChannels = AudioFormat.CHANNEL_INVALID;
395 mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_INVALID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 throw(new IllegalArgumentException("Unsupported channel configuration."));
397 }
398
399 //--------------
400 // audio format
401 switch (audioFormat) {
402 case AudioFormat.ENCODING_DEFAULT:
403 mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
404 break;
405 case AudioFormat.ENCODING_PCM_16BIT:
406 case AudioFormat.ENCODING_PCM_8BIT:
407 mAudioFormat = audioFormat;
408 break;
409 default:
410 mAudioFormat = AudioFormat.ENCODING_INVALID;
411 throw(new IllegalArgumentException("Unsupported sample encoding."
412 + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT."));
413 }
414
415 //--------------
416 // audio load mode
417 if ( (mode != MODE_STREAM) && (mode != MODE_STATIC) ) {
418 throw(new IllegalArgumentException("Invalid mode."));
419 } else {
420 mDataLoadMode = mode;
421 }
422 }
423
424
425 // Convenience method for the contructor's audio buffer size check.
426 // preconditions:
427 // mChannelCount is valid
428 // mAudioFormat is valid
429 // postcondition:
430 // mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
431 private void audioBuffSizeCheck(int audioBufferSize) {
432 // NB: this section is only valid with PCM data.
433 // To update when supporting compressed formats
434 int frameSizeInBytes = mChannelCount
435 * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
436 if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
437 throw (new IllegalArgumentException("Invalid audio buffer size."));
438 }
439
440 mNativeBufferSizeInBytes = audioBufferSize;
441 }
442
443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 /**
445 * Releases the native AudioTrack resources.
446 */
447 public void release() {
448 // even though native_release() stops the native AudioTrack, we need to stop
449 // AudioTrack subclasses too.
450 try {
451 stop();
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800452 } catch(IllegalStateException ise) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 // don't raise an exception, we're releasing the resources.
454 }
455 native_release();
456 mState = STATE_UNINITIALIZED;
457 }
458
459 @Override
460 protected void finalize() {
461 native_finalize();
462 }
463
464 //--------------------------------------------------------------------------
465 // Getters
466 //--------------------
467 /**
468 * Returns the minimum valid volume value. Volume values set under this one will
469 * be clamped at this value.
470 * @return the minimum volume expressed as a linear attenuation.
471 */
472 static public float getMinVolume() {
473 return AudioTrack.VOLUME_MIN;
474 }
475
476 /**
477 * Returns the maximum valid volume value. Volume values set above this one will
478 * be clamped at this value.
479 * @return the maximum volume expressed as a linear attenuation.
480 */
481 static public float getMaxVolume() {
482 return AudioTrack.VOLUME_MAX;
483 }
484
485 /**
486 * Returns the configured audio data sample rate in Hz
487 */
488 public int getSampleRate() {
489 return mSampleRate;
490 }
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 /**
Eric Laurent88e209d2009-07-07 07:10:45 -0700493 * Returns the current playback rate in Hz.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 */
495 public int getPlaybackRate() {
496 return native_get_playback_rate();
497 }
498
499 /**
500 * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT}
501 * and {@link AudioFormat#ENCODING_PCM_8BIT}.
502 */
503 public int getAudioFormat() {
504 return mAudioFormat;
505 }
506
507 /**
508 * Returns the type of audio stream this AudioTrack is configured for.
509 * Compare the result against {@link AudioManager#STREAM_VOICE_CALL},
510 * {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING},
511 * {@link AudioManager#STREAM_MUSIC} or {@link AudioManager#STREAM_ALARM}
512 */
513 public int getStreamType() {
514 return mStreamType;
515 }
516
517 /**
518 * Returns the configured channel configuration.
519
Eric Laurenta553c252009-07-17 12:17:14 -0700520 * See {@link AudioFormat#CHANNEL_OUT_MONO}
521 * and {@link AudioFormat#CHANNEL_OUT_STEREO}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 */
523 public int getChannelConfiguration() {
524 return mChannelConfiguration;
525 }
526
527 /**
528 * Returns the configured number of channels.
529 */
530 public int getChannelCount() {
531 return mChannelCount;
532 }
533
534 /**
535 * Returns the state of the AudioTrack instance. This is useful after the
536 * AudioTrack instance has been created to check if it was initialized
537 * properly. This ensures that the appropriate hardware resources have been
538 * acquired.
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700539 * @see #STATE_INITIALIZED
540 * @see #STATE_NO_STATIC_DATA
541 * @see #STATE_UNINITIALIZED
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 */
543 public int getState() {
544 return mState;
545 }
546
547 /**
548 * Returns the playback state of the AudioTrack instance.
549 * @see #PLAYSTATE_STOPPED
550 * @see #PLAYSTATE_PAUSED
551 * @see #PLAYSTATE_PLAYING
552 */
553 public int getPlayState() {
Narayan Kamath06e03332011-07-19 15:43:52 +0100554 synchronized (mPlayStateLock) {
555 return mPlayState;
556 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 }
558
559 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700560 * Returns the native frame count used by the hardware.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 */
562 protected int getNativeFrameCount() {
563 return native_get_native_frame_count();
564 }
565
566 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700567 * Returns marker position expressed in frames.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 */
569 public int getNotificationMarkerPosition() {
570 return native_get_marker_pos();
571 }
572
573 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700574 * Returns the notification update period expressed in frames.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 */
576 public int getPositionNotificationPeriod() {
577 return native_get_pos_update_period();
578 }
579
580 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700581 * Returns the playback head position expressed in frames
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 */
583 public int getPlaybackHeadPosition() {
584 return native_get_position();
585 }
586
587 /**
588 * Returns the hardware output sample rate
589 */
590 static public int getNativeOutputSampleRate(int streamType) {
591 return native_get_output_sample_rate(streamType);
592 }
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 * Returns the minimum buffer size required for the successful creation of an AudioTrack
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700596 * object to be created in the {@link #MODE_STREAM} mode. Note that this size doesn't
597 * guarantee a smooth playback under load, and higher values should be chosen according to
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800598 * the expected frequency at which the buffer will be refilled with additional data to play.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 * @param sampleRateInHz the sample rate expressed in Hertz.
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800600 * @param channelConfig describes the configuration of the audio channels.
Eric Laurenta553c252009-07-17 12:17:14 -0700601 * See {@link AudioFormat#CHANNEL_OUT_MONO} and
602 * {@link AudioFormat#CHANNEL_OUT_STEREO}
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800603 * @param audioFormat the format in which the audio data is represented.
604 * See {@link AudioFormat#ENCODING_PCM_16BIT} and
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 * {@link AudioFormat#ENCODING_PCM_8BIT}
606 * @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed,
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800607 * or {@link #ERROR} if the implementation was unable to query the hardware for its output
608 * properties,
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700609 * or the minimum buffer size expressed in bytes.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 */
611 static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
612 int channelCount = 0;
613 switch(channelConfig) {
Eric Laurenta553c252009-07-17 12:17:14 -0700614 case AudioFormat.CHANNEL_OUT_MONO:
Eric Laurent3026a022009-07-27 07:12:26 -0700615 case AudioFormat.CHANNEL_CONFIGURATION_MONO:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 channelCount = 1;
617 break;
Eric Laurenta553c252009-07-17 12:17:14 -0700618 case AudioFormat.CHANNEL_OUT_STEREO:
Eric Laurent3026a022009-07-27 07:12:26 -0700619 case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 channelCount = 2;
621 break;
622 default:
623 loge("getMinBufferSize(): Invalid channel configuration.");
624 return AudioTrack.ERROR_BAD_VALUE;
625 }
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800626
627 if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {
629 loge("getMinBufferSize(): Invalid audio format.");
630 return AudioTrack.ERROR_BAD_VALUE;
631 }
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
634 loge("getMinBufferSize(): " + sampleRateInHz +"Hz is not a supported sample rate.");
635 return AudioTrack.ERROR_BAD_VALUE;
636 }
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
639 if ((size == -1) || (size == 0)) {
640 loge("getMinBufferSize(): error querying hardware");
641 return AudioTrack.ERROR;
642 }
643 else {
644 return size;
645 }
646 }
647
Eric Laurent619346f2010-06-21 09:27:30 -0700648 /**
649 * Returns the audio session ID.
650 *
651 * @return the ID of the audio session this AudioTrack belongs to.
Eric Laurent619346f2010-06-21 09:27:30 -0700652 */
653 public int getAudioSessionId() {
654 return mSessionId;
655 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656
657 //--------------------------------------------------------------------------
658 // Initialization / configuration
659 //--------------------
660 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800661 * Sets the listener the AudioTrack notifies when a previously set marker is reached or
662 * for each periodic playback head position update.
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700663 * Notifications will be received in the same thread as the one in which the AudioTrack
664 * instance was created.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 * @param listener
666 */
The Android Open Source Project4df24232009-03-05 14:34:35 -0800667 public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener) {
668 setPlaybackPositionUpdateListener(listener, null);
669 }
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800670
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700671 /**
672 * Sets the listener the AudioTrack notifies when a previously set marker is reached or
673 * for each periodic playback head position update.
674 * Use this method to receive AudioTrack events in the Handler associated with another
675 * thread than the one in which you created the AudioTrack instance.
676 * @param listener
677 * @param handler the Handler that will receive the event notification messages.
678 */
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800679 public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener,
The Android Open Source Project4df24232009-03-05 14:34:35 -0800680 Handler handler) {
681 synchronized (mPositionListenerLock) {
682 mPositionListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800684 if (listener != null) {
685 mEventHandlerDelegate = new NativeEventHandlerDelegate(this, handler);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 }
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 }
689
690
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691
692 /**
693 * Sets the specified left/right output volume values on the AudioTrack. Values are clamped
694 * to the ({@link #getMinVolume()}, {@link #getMaxVolume()}) interval if outside this range.
695 * @param leftVolume output attenuation for the left channel. A value of 0.0f is silence,
696 * a value of 1.0f is no attenuation.
697 * @param rightVolume output attenuation for the right channel
698 * @return error code or success, see {@link #SUCCESS},
699 * {@link #ERROR_INVALID_OPERATION}
700 */
701 public int setStereoVolume(float leftVolume, float rightVolume) {
702 if (mState != STATE_INITIALIZED) {
703 return ERROR_INVALID_OPERATION;
704 }
705
706 // clamp the volumes
707 if (leftVolume < getMinVolume()) {
708 leftVolume = getMinVolume();
709 }
710 if (leftVolume > getMaxVolume()) {
711 leftVolume = getMaxVolume();
712 }
713 if (rightVolume < getMinVolume()) {
714 rightVolume = getMinVolume();
715 }
716 if (rightVolume > getMaxVolume()) {
717 rightVolume = getMaxVolume();
718 }
719
720 native_setVolume(leftVolume, rightVolume);
721
722 return SUCCESS;
723 }
724
725
726 /**
727 * Sets the playback sample rate for this track. This sets the sampling rate at which
728 * the audio data will be consumed and played back, not the original sampling rate of the
729 * content. Setting it to half the sample rate of the content will cause the playback to
Eric Laurent88e209d2009-07-07 07:10:45 -0700730 * last twice as long, but will also result in a negative pitch shift.
731 * The valid sample rate range if from 1Hz to twice the value returned by
732 * {@link #getNativeOutputSampleRate(int)}.
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700733 * @param sampleRateInHz the sample rate expressed in Hz
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
735 * {@link #ERROR_INVALID_OPERATION}
736 */
737 public int setPlaybackRate(int sampleRateInHz) {
738 if (mState != STATE_INITIALIZED) {
739 return ERROR_INVALID_OPERATION;
740 }
741 if (sampleRateInHz <= 0) {
742 return ERROR_BAD_VALUE;
743 }
Eric Laurent88e209d2009-07-07 07:10:45 -0700744 return native_set_playback_rate(sampleRateInHz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 }
746
747
748 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700749 * Sets the position of the notification marker.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 * @param markerInFrames marker in frames
751 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
752 * {@link #ERROR_INVALID_OPERATION}
753 */
754 public int setNotificationMarkerPosition(int markerInFrames) {
755 if (mState != STATE_INITIALIZED) {
756 return ERROR_INVALID_OPERATION;
757 }
758 return native_set_marker_pos(markerInFrames);
759 }
760
761
762 /**
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700763 * Sets the period for the periodic notification event.
764 * @param periodInFrames update period expressed in frames
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
766 */
767 public int setPositionNotificationPeriod(int periodInFrames) {
768 if (mState != STATE_INITIALIZED) {
769 return ERROR_INVALID_OPERATION;
770 }
771 return native_set_pos_update_period(periodInFrames);
772 }
773
774
775 /**
776 * Sets the playback head position. The track must be stopped for the position to be changed.
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700777 * @param positionInFrames playback head position expressed in frames
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
779 * {@link #ERROR_INVALID_OPERATION}
780 */
781 public int setPlaybackHeadPosition(int positionInFrames) {
782 synchronized(mPlayStateLock) {
783 if ((mPlayState == PLAYSTATE_STOPPED) || (mPlayState == PLAYSTATE_PAUSED)) {
784 return native_set_position(positionInFrames);
785 } else {
786 return ERROR_INVALID_OPERATION;
787 }
788 }
789 }
790
791 /**
792 * Sets the loop points and the loop count. The loop can be infinite.
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700793 * @param startInFrames loop start marker expressed in frames
794 * @param endInFrames loop end marker expressed in frames
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 * @param loopCount the number of times the loop is looped.
796 * A value of -1 means infinite looping.
797 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
798 * {@link #ERROR_INVALID_OPERATION}
799 */
800 public int setLoopPoints(int startInFrames, int endInFrames, int loopCount) {
801 if (mDataLoadMode == MODE_STREAM) {
802 return ERROR_INVALID_OPERATION;
803 }
804 return native_set_loop(startInFrames, endInFrames, loopCount);
805 }
806
807 /**
808 * Sets the initialization state of the instance. To be used in an AudioTrack subclass
809 * constructor to set a subclass-specific post-initialization state.
810 * @param state the state of the AudioTrack instance
811 */
812 protected void setState(int state) {
813 mState = state;
814 }
815
816
817 //---------------------------------------------------------
818 // Transport control methods
819 //--------------------
820 /**
821 * Starts playing an AudioTrack.
Narayan Kamath88bde0c2011-07-14 16:37:46 +0100822 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 * @throws IllegalStateException
824 */
825 public void play()
826 throws IllegalStateException {
827 if (mState != STATE_INITIALIZED) {
828 throw(new IllegalStateException("play() called on uninitialized AudioTrack."));
829 }
830
831 synchronized(mPlayStateLock) {
832 native_start();
833 mPlayState = PLAYSTATE_PLAYING;
834 }
835 }
836
837 /**
838 * Stops playing the audio data.
Narayan Kamath88bde0c2011-07-14 16:37:46 +0100839 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 * @throws IllegalStateException
841 */
842 public void stop()
843 throws IllegalStateException {
844 if (mState != STATE_INITIALIZED) {
845 throw(new IllegalStateException("stop() called on uninitialized AudioTrack."));
846 }
847
848 // stop playing
849 synchronized(mPlayStateLock) {
850 native_stop();
851 mPlayState = PLAYSTATE_STOPPED;
852 }
853 }
854
855 /**
Narayan Kamath88bde0c2011-07-14 16:37:46 +0100856 * Pauses the playback of the audio data. Data that has not been played
857 * back will not be discarded. Subsequent calls to {@link #play} will play
858 * this data back.
859 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860 * @throws IllegalStateException
861 */
862 public void pause()
863 throws IllegalStateException {
864 if (mState != STATE_INITIALIZED) {
865 throw(new IllegalStateException("pause() called on uninitialized AudioTrack."));
866 }
867 //logd("pause()");
868
869 // pause playback
870 synchronized(mPlayStateLock) {
871 native_pause();
872 mPlayState = PLAYSTATE_PAUSED;
873 }
874 }
875
876
877 //---------------------------------------------------------
878 // Audio data supply
879 //--------------------
880
881 /**
Narayan Kamath88bde0c2011-07-14 16:37:46 +0100882 * Flushes the audio data currently queued for playback. Any data that has
883 * not been played back will be discarded.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 public void flush() {
886 if (mState == STATE_INITIALIZED) {
887 // flush the data in native layer
888 native_flush();
889 }
890
891 }
892
893 /**
Narayan Kamath88bde0c2011-07-14 16:37:46 +0100894 * Writes the audio data to the audio hardware for playback. Will block until
895 * all data has been written to the audio mixer.
896 * Note that the actual playback of this data might occur after this function
897 * returns. This function is thread safe with respect to {@link #stop} calls,
898 * in which case all of the specified data might not be written to the mixer.
899 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 * @param audioData the array that holds the data to play.
Narayan Kamath88bde0c2011-07-14 16:37:46 +0100901 * @param offsetInBytes the offset expressed in bytes in audioData where the data to play
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700902 * starts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 * @param sizeInBytes the number of bytes to read in audioData after the offset.
904 * @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION}
905 * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
906 * the parameters don't resolve to valid data and indexes.
907 */
908
909 public int write(byte[] audioData,int offsetInBytes, int sizeInBytes) {
910 if ((mDataLoadMode == MODE_STATIC)
911 && (mState == STATE_NO_STATIC_DATA)
912 && (sizeInBytes > 0)) {
913 mState = STATE_INITIALIZED;
914 }
915
916 if (mState != STATE_INITIALIZED) {
917 return ERROR_INVALID_OPERATION;
918 }
919
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800920 if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 || (offsetInBytes + sizeInBytes > audioData.length)) {
922 return ERROR_BAD_VALUE;
923 }
924
925 return native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat);
926 }
927
928
929 /**
Narayan Kamath88bde0c2011-07-14 16:37:46 +0100930 * Writes the audio data to the audio hardware for playback. Will block until
931 * all data has been written to the audio mixer.
932 * Note that the actual playback of this data might occur after this function
933 * returns. This function is thread safe with respect to {@link #stop} calls,
934 * in which case all of the specified data might not be written to the mixer.
935 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 * @param audioData the array that holds the data to play.
Jean-Michel Triviff14c252009-04-17 11:45:30 -0700937 * @param offsetInShorts the offset expressed in shorts in audioData where the data to play
938 * starts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 * @param sizeInShorts the number of bytes to read in audioData after the offset.
940 * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION}
941 * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
942 * the parameters don't resolve to valid data and indexes.
943 */
944
945 public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
946 if ((mDataLoadMode == MODE_STATIC)
947 && (mState == STATE_NO_STATIC_DATA)
948 && (sizeInShorts > 0)) {
949 mState = STATE_INITIALIZED;
950 }
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 if (mState != STATE_INITIALIZED) {
953 return ERROR_INVALID_OPERATION;
954 }
955
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800956 if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 || (offsetInShorts + sizeInShorts > audioData.length)) {
958 return ERROR_BAD_VALUE;
959 }
960
961 return native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);
962 }
963
964
965 /**
966 * Notifies the native resource to reuse the audio data already loaded in the native
967 * layer. This call is only valid with AudioTrack instances that don't use the streaming
968 * model.
969 * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
970 * {@link #ERROR_INVALID_OPERATION}
971 */
972 public int reloadStaticData() {
973 if (mDataLoadMode == MODE_STREAM) {
974 return ERROR_INVALID_OPERATION;
975 }
976 return native_reload_static();
977 }
978
Eric Laurent7070b362010-07-16 07:43:46 -0700979 //--------------------------------------------------------------------------
980 // Audio effects management
981 //--------------------
982
983 /**
Eric Laurent1a5149e2010-09-21 18:18:20 -0700984 * Attaches an auxiliary effect to the audio track. A typical auxiliary
985 * effect is a reverberation effect which can be applied on any sound source
986 * that directs a certain amount of its energy to this effect. This amount
987 * is defined by setAuxEffectSendLevel().
Eric Laurent7070b362010-07-16 07:43:46 -0700988 * {@see #setAuxEffectSendLevel(float)}.
Eric Laurent1a5149e2010-09-21 18:18:20 -0700989 * <p>After creating an auxiliary effect (e.g.
990 * {@link android.media.audiofx.EnvironmentalReverb}), retrieve its ID with
991 * {@link android.media.audiofx.AudioEffect#getId()} and use it when calling
Eric Laurent7070b362010-07-16 07:43:46 -0700992 * this method to attach the audio track to the effect.
Eric Laurent1a5149e2010-09-21 18:18:20 -0700993 * <p>To detach the effect from the audio track, call this method with a
994 * null effect id.
Eric Laurent7070b362010-07-16 07:43:46 -0700995 *
996 * @param effectId system wide unique id of the effect to attach
997 * @return error code or success, see {@link #SUCCESS},
998 * {@link #ERROR_INVALID_OPERATION}, {@link #ERROR_BAD_VALUE}
Eric Laurent7070b362010-07-16 07:43:46 -0700999 */
1000 public int attachAuxEffect(int effectId) {
1001 if (mState != STATE_INITIALIZED) {
1002 return ERROR_INVALID_OPERATION;
1003 }
1004 return native_attachAuxEffect(effectId);
1005 }
1006
1007 /**
1008 * Sets the send level of the audio track to the attached auxiliary effect
Narayan Kamath88bde0c2011-07-14 16:37:46 +01001009 * {@link #attachAuxEffect(int)}. The level value range is 0 to 1.0.
Eric Laurent7070b362010-07-16 07:43:46 -07001010 * <p>By default the send level is 0, so even if an effect is attached to the player
1011 * this method must be called for the effect to be applied.
1012 * <p>Note that the passed level value is a raw scalar. UI controls should be scaled
1013 * logarithmically: the gain applied by audio framework ranges from -72dB to 0dB,
1014 * so an appropriate conversion from linear UI input x to level is:
1015 * x == 0 -> level = 0
1016 * 0 < x <= R -> level = 10^(72*(x-R)/20/R)
1017 *
1018 * @param level send level scalar
1019 * @return error code or success, see {@link #SUCCESS},
1020 * {@link #ERROR_INVALID_OPERATION}
Eric Laurent7070b362010-07-16 07:43:46 -07001021 */
1022 public int setAuxEffectSendLevel(float level) {
1023 if (mState != STATE_INITIALIZED) {
1024 return ERROR_INVALID_OPERATION;
1025 }
1026 // clamp the level
1027 if (level < getMinVolume()) {
1028 level = getMinVolume();
1029 }
1030 if (level > getMaxVolume()) {
1031 level = getMaxVolume();
1032 }
1033 native_setAuxEffectSendLevel(level);
1034 return SUCCESS;
1035 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036
1037 //---------------------------------------------------------
1038 // Interface definitions
1039 //--------------------
1040 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -08001041 * Interface definition for a callback to be invoked when the playback head position of
1042 * an AudioTrack has reached a notification marker or has increased by a certain period.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 */
The Android Open Source Project4df24232009-03-05 14:34:35 -08001044 public interface OnPlaybackPositionUpdateListener {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 /**
1046 * Called on the listener to notify it that the previously set marker has been reached
1047 * by the playback head.
1048 */
1049 void onMarkerReached(AudioTrack track);
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -08001050
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 /**
1052 * Called on the listener to periodically notify it that the playback head has reached
1053 * a multiple of the notification period.
1054 */
1055 void onPeriodicNotification(AudioTrack track);
1056 }
1057
1058
1059 //---------------------------------------------------------
1060 // Inner classes
1061 //--------------------
1062 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -08001063 * Helper class to handle the forwarding of native events to the appropriate listener
1064 * (potentially) handled in a different thread
1065 */
1066 private class NativeEventHandlerDelegate {
1067 private final AudioTrack mAudioTrack;
1068 private final Handler mHandler;
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -08001069
The Android Open Source Project4df24232009-03-05 14:34:35 -08001070 NativeEventHandlerDelegate(AudioTrack track, Handler handler) {
1071 mAudioTrack = track;
1072 // find the looper for our new event handler
1073 Looper looper;
1074 if (handler != null) {
1075 looper = handler.getLooper();
1076 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07001077 // no given handler, use the looper the AudioTrack was created in
1078 looper = mInitializationLooper;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001079 }
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -08001080
The Android Open Source Project4df24232009-03-05 14:34:35 -08001081 // construct the event handler with this looper
1082 if (looper != null) {
1083 // implement the event handler delegate
1084 mHandler = new Handler(looper) {
1085 @Override
1086 public void handleMessage(Message msg) {
1087 if (mAudioTrack == null) {
1088 return;
1089 }
1090 OnPlaybackPositionUpdateListener listener = null;
1091 synchronized (mPositionListenerLock) {
1092 listener = mAudioTrack.mPositionListener;
1093 }
1094 switch(msg.what) {
1095 case NATIVE_EVENT_MARKER:
1096 if (listener != null) {
1097 listener.onMarkerReached(mAudioTrack);
1098 }
1099 break;
1100 case NATIVE_EVENT_NEW_POS:
1101 if (listener != null) {
1102 listener.onPeriodicNotification(mAudioTrack);
1103 }
1104 break;
1105 default:
1106 Log.e(TAG, "[ android.media.AudioTrack.NativeEventHandler ] " +
1107 "Unknown event type: " + msg.what);
1108 break;
1109 }
1110 }
1111 };
1112 } else {
1113 mHandler = null;
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -08001114 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 }
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -08001116
The Android Open Source Project4df24232009-03-05 14:34:35 -08001117 Handler getHandler() {
1118 return mHandler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119 }
1120 }
1121
1122
1123 //---------------------------------------------------------
1124 // Java methods called from the native side
1125 //--------------------
1126 @SuppressWarnings("unused")
1127 private static void postEventFromNative(Object audiotrack_ref,
1128 int what, int arg1, int arg2, Object obj) {
1129 //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
1130 AudioTrack track = (AudioTrack)((WeakReference)audiotrack_ref).get();
1131 if (track == null) {
1132 return;
1133 }
1134
The Android Open Source Project4df24232009-03-05 14:34:35 -08001135 if (track.mEventHandlerDelegate != null) {
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -08001136 Message m =
The Android Open Source Project4df24232009-03-05 14:34:35 -08001137 track.mEventHandlerDelegate.getHandler().obtainMessage(what, arg1, arg2, obj);
1138 track.mEventHandlerDelegate.getHandler().sendMessage(m);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 }
1140
1141 }
1142
1143
1144 //---------------------------------------------------------
1145 // Native methods called from the Java side
1146 //--------------------
1147
1148 private native final int native_setup(Object audiotrack_this,
1149 int streamType, int sampleRate, int nbChannels, int audioFormat,
Eric Laurent619346f2010-06-21 09:27:30 -07001150 int buffSizeInBytes, int mode, int[] sessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151
1152 private native final void native_finalize();
1153
1154 private native final void native_release();
1155
1156 private native final void native_start();
1157
1158 private native final void native_stop();
1159
1160 private native final void native_pause();
1161
1162 private native final void native_flush();
1163
1164 private native final int native_write_byte(byte[] audioData,
1165 int offsetInBytes, int sizeInBytes, int format);
1166
1167 private native final int native_write_short(short[] audioData,
1168 int offsetInShorts, int sizeInShorts, int format);
1169
1170 private native final int native_reload_static();
1171
1172 private native final int native_get_native_frame_count();
1173
1174 private native final void native_setVolume(float leftVolume, float rightVolume);
1175
Eric Laurent88e209d2009-07-07 07:10:45 -07001176 private native final int native_set_playback_rate(int sampleRateInHz);
1177 private native final int native_get_playback_rate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178
1179 private native final int native_set_marker_pos(int marker);
1180 private native final int native_get_marker_pos();
1181
1182 private native final int native_set_pos_update_period(int updatePeriod);
1183 private native final int native_get_pos_update_period();
1184
1185 private native final int native_set_position(int position);
1186 private native final int native_get_position();
1187
1188 private native final int native_set_loop(int start, int end, int loopCount);
1189
1190 static private native final int native_get_output_sample_rate(int streamType);
1191 static private native final int native_get_min_buff_size(
1192 int sampleRateInHz, int channelConfig, int audioFormat);
1193
Eric Laurent619346f2010-06-21 09:27:30 -07001194 private native final int native_get_session_id();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195
Eric Laurent7070b362010-07-16 07:43:46 -07001196 private native final int native_attachAuxEffect(int effectId);
1197 private native final void native_setAuxEffectSendLevel(float level);
1198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 //---------------------------------------------------------
1200 // Utility methods
1201 //------------------
1202
1203 private static void logd(String msg) {
1204 Log.d(TAG, "[ android.media.AudioTrack ] " + msg);
1205 }
1206
1207 private static void loge(String msg) {
1208 Log.e(TAG, "[ android.media.AudioTrack ] " + msg);
1209 }
1210
1211}