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