Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2009 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 
     17 package android.media.cts;
     18 
     19 import android.app.ActivityManager;
     20 import android.content.Context;
     21 import android.content.pm.PackageManager;
     22 import android.media.AudioAttributes;
     23 import android.media.AudioFormat;
     24 import android.media.AudioManager;
     25 import android.media.AudioPresentation;
     26 import android.media.AudioTimestamp;
     27 import android.media.AudioTrack;
     28 import android.media.PlaybackParams;
     29 import android.platform.test.annotations.Presubmit;
     30 import android.support.test.filters.LargeTest;
     31 import android.util.Log;
     32 
     33 import com.android.compatibility.common.util.CtsAndroidTestCase;
     34 import com.android.compatibility.common.util.DeviceReportLog;
     35 import com.android.compatibility.common.util.ResultType;
     36 import com.android.compatibility.common.util.ResultUnit;
     37 
     38 import java.nio.ByteBuffer;
     39 import java.nio.FloatBuffer;
     40 import java.nio.ShortBuffer;
     41 import java.util.HashMap;
     42 import java.util.Locale;
     43 
     44 public class AudioTrackTest extends CtsAndroidTestCase {
     45     private String TAG = "AudioTrackTest";
     46     private final long WAIT_MSEC = 200;
     47     private final int OFFSET_DEFAULT = 0;
     48     private final int OFFSET_NEGATIVE = -10;
     49     private static final String REPORT_LOG_NAME = "CtsMediaTestCases";
     50 
     51     private void log(String testName, String message) {
     52         Log.v(TAG, "[" + testName + "] " + message);
     53     }
     54 
     55     private void loge(String testName, String message) {
     56         Log.e(TAG, "[" + testName + "] " + message);
     57     }
     58 
     59     // -----------------------------------------------------------------
     60     // private class to hold test results
     61     private static class TestResults {
     62         public boolean mResult = false;
     63         public String mResultLog = "";
     64 
     65         public TestResults(boolean b, String s) {
     66             mResult = b;
     67             mResultLog = s;
     68         }
     69     }
     70 
     71     // -----------------------------------------------------------------
     72     // generic test methods
     73     public TestResults constructorTestMultiSampleRate(
     74     // parameters tested by this method
     75             int _inTest_streamType, int _inTest_mode, int _inTest_config, int _inTest_format,
     76             // parameter-dependent expected results
     77             int _expected_stateForMode) {
     78 
     79         int[] testSampleRates = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 };
     80         String failedRates = "Failure for rate(s): ";
     81         boolean localRes, finalRes = true;
     82 
     83         for (int i = 0; i < testSampleRates.length; i++) {
     84             AudioTrack track = null;
     85             try {
     86                 track = new AudioTrack(_inTest_streamType, testSampleRates[i], _inTest_config,
     87                         _inTest_format, AudioTrack.getMinBufferSize(testSampleRates[i],
     88                                 _inTest_config, _inTest_format), _inTest_mode);
     89             } catch (IllegalArgumentException iae) {
     90                 Log.e("MediaAudioTrackTest", "[ constructorTestMultiSampleRate ] exception at SR "
     91                         + testSampleRates[i] + ": \n" + iae);
     92                 localRes = false;
     93             }
     94             if (track != null) {
     95                 localRes = (track.getState() == _expected_stateForMode);
     96                 track.release();
     97             } else {
     98                 localRes = false;
     99             }
    100 
    101             if (!localRes) {
    102                 // log the error for the test runner
    103                 failedRates += Integer.toString(testSampleRates[i]) + "Hz ";
    104                 // log the error for logcat
    105                 log("constructorTestMultiSampleRate", "failed to construct "
    106                         + "AudioTrack(streamType="
    107                         + _inTest_streamType
    108                         + ", sampleRateInHz="
    109                         + testSampleRates[i]
    110                         + ", channelConfig="
    111                         + _inTest_config
    112                         + ", audioFormat="
    113                         + _inTest_format
    114                         + ", bufferSizeInBytes="
    115                         + AudioTrack.getMinBufferSize(testSampleRates[i], _inTest_config,
    116                                 AudioFormat.ENCODING_PCM_16BIT) + ", mode=" + _inTest_mode);
    117                 // mark test as failed
    118                 finalRes = false;
    119             }
    120         }
    121         return new TestResults(finalRes, failedRates);
    122     }
    123 
    124     // -----------------------------------------------------------------
    125     // AUDIOTRACK TESTS:
    126     // ----------------------------------
    127 
    128     // -----------------------------------------------------------------
    129     // AudioTrack constructor and AudioTrack.getMinBufferSize(...) for 16bit PCM
    130     // ----------------------------------
    131 
    132     // Test case 1: constructor for streaming AudioTrack, mono, 16bit at misc
    133     // valid sample rates
    134     public void testConstructorMono16MusicStream() throws Exception {
    135 
    136         TestResults res = constructorTestMultiSampleRate(AudioManager.STREAM_MUSIC,
    137                 AudioTrack.MODE_STREAM, AudioFormat.CHANNEL_CONFIGURATION_MONO,
    138                 AudioFormat.ENCODING_PCM_16BIT, AudioTrack.STATE_INITIALIZED);
    139 
    140         assertTrue("testConstructorMono16MusicStream: " + res.mResultLog, res.mResult);
    141     }
    142 
    143     // Test case 2: constructor for streaming AudioTrack, stereo, 16bit at misc
    144     // valid sample rates
    145     public void testConstructorStereo16MusicStream() throws Exception {
    146 
    147         TestResults res = constructorTestMultiSampleRate(AudioManager.STREAM_MUSIC,
    148                 AudioTrack.MODE_STREAM, AudioFormat.CHANNEL_CONFIGURATION_STEREO,
    149                 AudioFormat.ENCODING_PCM_16BIT, AudioTrack.STATE_INITIALIZED);
    150 
    151         assertTrue("testConstructorStereo16MusicStream: " + res.mResultLog, res.mResult);
    152     }
    153 
    154     // Test case 3: constructor for static AudioTrack, mono, 16bit at misc valid
    155     // sample rates
    156     public void testConstructorMono16MusicStatic() throws Exception {
    157 
    158         TestResults res = constructorTestMultiSampleRate(AudioManager.STREAM_MUSIC,
    159                 AudioTrack.MODE_STATIC, AudioFormat.CHANNEL_CONFIGURATION_MONO,
    160                 AudioFormat.ENCODING_PCM_16BIT, AudioTrack.STATE_NO_STATIC_DATA);
    161 
    162         assertTrue("testConstructorMono16MusicStatic: " + res.mResultLog, res.mResult);
    163     }
    164 
    165     // Test case 4: constructor for static AudioTrack, stereo, 16bit at misc
    166     // valid sample rates
    167     public void testConstructorStereo16MusicStatic() throws Exception {
    168 
    169         TestResults res = constructorTestMultiSampleRate(AudioManager.STREAM_MUSIC,
    170                 AudioTrack.MODE_STATIC, AudioFormat.CHANNEL_CONFIGURATION_STEREO,
    171                 AudioFormat.ENCODING_PCM_16BIT, AudioTrack.STATE_NO_STATIC_DATA);
    172 
    173         assertTrue("testConstructorStereo16MusicStatic: " + res.mResultLog, res.mResult);
    174     }
    175 
    176     // -----------------------------------------------------------------
    177     // AudioTrack constructor and AudioTrack.getMinBufferSize(...) for 8bit PCM
    178     // ----------------------------------
    179 
    180     // Test case 1: constructor for streaming AudioTrack, mono, 8bit at misc
    181     // valid sample rates
    182     public void testConstructorMono8MusicStream() throws Exception {
    183 
    184         TestResults res = constructorTestMultiSampleRate(AudioManager.STREAM_MUSIC,
    185                 AudioTrack.MODE_STREAM, AudioFormat.CHANNEL_CONFIGURATION_MONO,
    186                 AudioFormat.ENCODING_PCM_8BIT, AudioTrack.STATE_INITIALIZED);
    187 
    188         assertTrue("testConstructorMono8MusicStream: " + res.mResultLog, res.mResult);
    189     }
    190 
    191     // Test case 2: constructor for streaming AudioTrack, stereo, 8bit at misc
    192     // valid sample rates
    193     public void testConstructorStereo8MusicStream() throws Exception {
    194 
    195         TestResults res = constructorTestMultiSampleRate(AudioManager.STREAM_MUSIC,
    196                 AudioTrack.MODE_STREAM, AudioFormat.CHANNEL_CONFIGURATION_STEREO,
    197                 AudioFormat.ENCODING_PCM_8BIT, AudioTrack.STATE_INITIALIZED);
    198 
    199         assertTrue("testConstructorStereo8MusicStream: " + res.mResultLog, res.mResult);
    200     }
    201 
    202     // Test case 3: constructor for static AudioTrack, mono, 8bit at misc valid
    203     // sample rates
    204     public void testConstructorMono8MusicStatic() throws Exception {
    205 
    206         TestResults res = constructorTestMultiSampleRate(AudioManager.STREAM_MUSIC,
    207                 AudioTrack.MODE_STATIC, AudioFormat.CHANNEL_CONFIGURATION_MONO,
    208                 AudioFormat.ENCODING_PCM_8BIT, AudioTrack.STATE_NO_STATIC_DATA);
    209 
    210         assertTrue("testConstructorMono8MusicStatic: " + res.mResultLog, res.mResult);
    211     }
    212 
    213     // Test case 4: constructor for static AudioTrack, stereo, 8bit at misc
    214     // valid sample rates
    215     public void testConstructorStereo8MusicStatic() throws Exception {
    216 
    217         TestResults res = constructorTestMultiSampleRate(AudioManager.STREAM_MUSIC,
    218                 AudioTrack.MODE_STATIC, AudioFormat.CHANNEL_CONFIGURATION_STEREO,
    219                 AudioFormat.ENCODING_PCM_8BIT, AudioTrack.STATE_NO_STATIC_DATA);
    220 
    221         assertTrue("testConstructorStereo8MusicStatic: " + res.mResultLog, res.mResult);
    222     }
    223 
    224     // -----------------------------------------------------------------
    225     // AudioTrack constructor for all stream types
    226     // ----------------------------------
    227 
    228     // Test case 1: constructor for all stream types
    229     public void testConstructorStreamType() throws Exception {
    230         // constants for test
    231         final int TYPE_TEST_SR = 22050;
    232         final int TYPE_TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
    233         final int TYPE_TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    234         final int TYPE_TEST_MODE = AudioTrack.MODE_STREAM;
    235         final int[] STREAM_TYPES = { AudioManager.STREAM_ALARM, AudioManager.STREAM_MUSIC,
    236                 AudioManager.STREAM_NOTIFICATION, AudioManager.STREAM_RING,
    237                 AudioManager.STREAM_SYSTEM, AudioManager.STREAM_VOICE_CALL };
    238         final String[] STREAM_NAMES = { "STREAM_ALARM", "STREAM_MUSIC", "STREAM_NOTIFICATION",
    239                 "STREAM_RING", "STREAM_SYSTEM", "STREAM_VOICE_CALL" };
    240 
    241         boolean localTestRes = true;
    242         AudioTrack track = null;
    243         // test: loop constructor on all stream types
    244         for (int i = 0; i < STREAM_TYPES.length; i++) {
    245             try {
    246                 // -------- initialization --------------
    247                 track = new AudioTrack(STREAM_TYPES[i], TYPE_TEST_SR, TYPE_TEST_CONF,
    248                         TYPE_TEST_FORMAT, AudioTrack.getMinBufferSize(TYPE_TEST_SR, TYPE_TEST_CONF,
    249                                 TYPE_TEST_FORMAT), TYPE_TEST_MODE);
    250             } catch (IllegalArgumentException iae) {
    251                 loge("testConstructorStreamType", "exception for stream type " + STREAM_NAMES[i]
    252                         + ": " + iae);
    253                 localTestRes = false;
    254             }
    255             // -------- test --------------
    256             if (track != null) {
    257                 if (track.getState() != AudioTrack.STATE_INITIALIZED) {
    258                     localTestRes = false;
    259                     Log.e("MediaAudioTrackTest",
    260                             "[ testConstructorStreamType ] failed for stream type "
    261                                     + STREAM_NAMES[i]);
    262                 }
    263                 // -------- tear down --------------
    264                 track.release();
    265             } else {
    266                 localTestRes = false;
    267             }
    268         }
    269 
    270         assertTrue("testConstructorStreamType", localTestRes);
    271     }
    272 
    273     // -----------------------------------------------------------------
    274     // AudioTrack construction with Builder
    275     // ----------------------------------
    276 
    277     // Test case 1: build AudioTrack with default parameters, test documented default params
    278     public void testBuilderDefault() throws Exception {
    279         // constants for test
    280         final String TEST_NAME = "testBuilderDefault";
    281         final int expectedDefaultEncoding = AudioFormat.ENCODING_PCM_16BIT;
    282         final int expectedDefaultRate =
    283                 AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
    284         final int expectedDefaultChannels = AudioFormat.CHANNEL_OUT_STEREO;
    285         // use Builder
    286         final int buffSizeInBytes = AudioTrack.getMinBufferSize(
    287                 expectedDefaultRate, expectedDefaultChannels, expectedDefaultEncoding);
    288         final AudioTrack track = new AudioTrack.Builder()
    289                 .setBufferSizeInBytes(buffSizeInBytes)
    290                 .build();
    291         // save results
    292         final int observedState = track.getState();
    293         final int observedFormat = track.getAudioFormat();
    294         final int observedChannelConf = track.getChannelConfiguration();
    295         final int observedRate = track.getSampleRate();
    296         // release track before the test exits (either successfully or with an exception)
    297         track.release();
    298         // compare results
    299         assertEquals(TEST_NAME + ": Track initialized", AudioTrack.STATE_INITIALIZED,
    300                 observedState);
    301         assertEquals(TEST_NAME + ": Default track encoding", expectedDefaultEncoding,
    302                 observedFormat);
    303         assertEquals(TEST_NAME + ": Default track channels", expectedDefaultChannels,
    304                 observedChannelConf);
    305     }
    306 
    307     // Test case 2: build AudioTrack with AudioFormat, test it's used
    308     public void testBuilderFormat() throws Exception {
    309         // constants for test
    310         final String TEST_NAME = "testBuilderFormat";
    311         final int TEST_RATE = 32000;
    312         final int TEST_CHANNELS = AudioFormat.CHANNEL_OUT_STEREO;
    313         // use Builder
    314         final int buffSizeInBytes = AudioTrack.getMinBufferSize(
    315                 TEST_RATE, TEST_CHANNELS, AudioFormat.ENCODING_PCM_16BIT);
    316         final AudioTrack track = new AudioTrack.Builder()
    317                 .setAudioAttributes(new AudioAttributes.Builder().build())
    318                 .setBufferSizeInBytes(buffSizeInBytes)
    319                 .setAudioFormat(new AudioFormat.Builder()
    320                         .setChannelMask(TEST_CHANNELS).setSampleRate(TEST_RATE).build())
    321                 .build();
    322         // save results
    323         final int observedState = track.getState();
    324         final int observedChannelConf = track.getChannelConfiguration();
    325         final int observedRate = track.getSampleRate();
    326         // release track before the test exits (either successfully or with an exception)
    327         track.release();
    328         // compare results
    329         assertEquals(TEST_NAME + ": Track initialized", AudioTrack.STATE_INITIALIZED,
    330                 observedState);
    331         assertEquals(TEST_NAME + ": Track channels", TEST_CHANNELS, observedChannelConf);
    332         assertEquals(TEST_NAME + ": Track sample rate", TEST_RATE, observedRate);
    333     }
    334 
    335     // Test case 3: build AudioTrack with session ID, test it's used
    336     public void testBuilderSession() throws Exception {
    337         // constants for test
    338         final String TEST_NAME = "testBuilderSession";
    339         // generate a session ID
    340         final int expectedSessionId = new AudioManager(getContext()).generateAudioSessionId();
    341         // use builder
    342         final AudioTrack track = new AudioTrack.Builder()
    343                 .setSessionId(expectedSessionId)
    344                 .build();
    345         // save results
    346         final int observedSessionId = track.getAudioSessionId();
    347         // release track before the test exits (either successfully or with an exception)
    348         track.release();
    349         // compare results
    350         assertEquals(TEST_NAME + ": Assigned track session ID", expectedSessionId,
    351                 observedSessionId);
    352     }
    353 
    354     // Test case 4: build AudioTrack with AudioAttributes built from stream type, test it's used
    355     public void testBuilderAttributesStream() throws Exception {
    356         // constants for test
    357         final String TEST_NAME = "testBuilderAttributesStream";
    358         //     use a stream type documented in AudioAttributes.Builder.setLegacyStreamType(int)
    359         final int expectedStreamType = AudioManager.STREAM_ALARM;
    360         final int expectedContentType = AudioAttributes.CONTENT_TYPE_SPEECH;
    361         final AudioAttributes aa = new AudioAttributes.Builder()
    362                 .setLegacyStreamType(expectedStreamType)
    363                 .setContentType(expectedContentType)
    364                 .build();
    365         // use builder
    366         final AudioTrack track = new AudioTrack.Builder()
    367                 .setAudioAttributes(aa)
    368                 .build();
    369         // save results
    370         final int observedStreamType = track.getStreamType();
    371         // release track before the test exits (either successfully or with an exception)
    372         track.release();
    373         // compare results
    374         assertEquals(TEST_NAME + ": track stream type", expectedStreamType, observedStreamType);
    375         //    also test content type was preserved in the attributes even though they
    376         //     were first configured with a legacy stream type
    377         assertEquals(TEST_NAME + ": attributes content type", expectedContentType,
    378                 aa.getContentType());
    379     }
    380 
    381     // Test case 5: build AudioTrack with attributes and performance mode
    382     public void testBuilderAttributesPerformanceMode() throws Exception {
    383         // constants for test
    384         final String TEST_NAME = "testBuilderAttributesPerformanceMode";
    385         final int testPerformanceModes[] = new int[] {
    386             AudioTrack.PERFORMANCE_MODE_NONE,
    387             AudioTrack.PERFORMANCE_MODE_LOW_LATENCY,
    388             AudioTrack.PERFORMANCE_MODE_POWER_SAVING,
    389         };
    390         // construct various attributes with different preset performance modes.
    391         final AudioAttributes testAttributes[] = new AudioAttributes[] {
    392             new AudioAttributes.Builder().build(),
    393             new AudioAttributes.Builder().setFlags(AudioAttributes.FLAG_LOW_LATENCY).build(),
    394             new AudioAttributes.Builder().setFlags(AudioAttributes.FLAG_DEEP_BUFFER).build(),
    395         };
    396         for (int performanceMode : testPerformanceModes) {
    397             for (AudioAttributes attributes : testAttributes) {
    398                 final AudioTrack track = new AudioTrack.Builder()
    399                     .setPerformanceMode(performanceMode)
    400                     .setAudioAttributes(attributes)
    401                     .build();
    402                 // save results
    403                 final int actualPerformanceMode = track.getPerformanceMode();
    404                 // release track before the test exits
    405                 track.release();
    406                 final String result = "Attribute flags: " + attributes.getAllFlags()
    407                         + " set performance mode: " + performanceMode
    408                         + " actual performance mode: " + actualPerformanceMode;
    409                 Log.d(TEST_NAME, result);
    410                 assertTrue(TEST_NAME + ": " + result,
    411                         actualPerformanceMode == performanceMode  // either successful
    412                         || actualPerformanceMode == AudioTrack.PERFORMANCE_MODE_NONE // or none
    413                         || performanceMode == AudioTrack.PERFORMANCE_MODE_NONE);
    414             }
    415         }
    416     }
    417 
    418     // -----------------------------------------------------------------
    419     // Playback head position
    420     // ----------------------------------
    421 
    422     // Test case 1: getPlaybackHeadPosition() at 0 after initialization
    423     public void testPlaybackHeadPositionAfterInit() throws Exception {
    424         // constants for test
    425         final String TEST_NAME = "testPlaybackHeadPositionAfterInit";
    426         final int TEST_SR = 22050;
    427         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
    428         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    429         final int TEST_MODE = AudioTrack.MODE_STREAM;
    430         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    431 
    432         // -------- initialization --------------
    433         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    434                 AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT), TEST_MODE);
    435         // -------- test --------------
    436         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    437         assertTrue(TEST_NAME, track.getPlaybackHeadPosition() == 0);
    438         // -------- tear down --------------
    439         track.release();
    440     }
    441 
    442     // Test case 2: getPlaybackHeadPosition() increases after play()
    443     public void testPlaybackHeadPositionIncrease() throws Exception {
    444         // constants for test
    445         final String TEST_NAME = "testPlaybackHeadPositionIncrease";
    446         final int TEST_SR = 22050;
    447         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
    448         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    449         final int TEST_MODE = AudioTrack.MODE_STREAM;
    450         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    451 
    452         // -------- initialization --------------
    453         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    454         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    455                 2 * minBuffSize, TEST_MODE);
    456         byte data[] = new byte[minBuffSize];
    457         // -------- test --------------
    458         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    459         track.write(data, OFFSET_DEFAULT, data.length);
    460         track.write(data, OFFSET_DEFAULT, data.length);
    461         track.play();
    462         Thread.sleep(100);
    463         log(TEST_NAME, "position =" + track.getPlaybackHeadPosition());
    464         assertTrue(TEST_NAME, track.getPlaybackHeadPosition() > 0);
    465         // -------- tear down --------------
    466         track.release();
    467     }
    468 
    469     // Test case 3: getPlaybackHeadPosition() is 0 after flush();
    470     public void testPlaybackHeadPositionAfterFlush() throws Exception {
    471         // constants for test
    472         final String TEST_NAME = "testPlaybackHeadPositionAfterFlush";
    473         final int TEST_SR = 22050;
    474         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
    475         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    476         final int TEST_MODE = AudioTrack.MODE_STREAM;
    477         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    478 
    479         // -------- initialization --------------
    480         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    481         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    482                 2 * minBuffSize, TEST_MODE);
    483         byte data[] = new byte[minBuffSize];
    484         // -------- test --------------
    485         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    486         track.write(data, OFFSET_DEFAULT, data.length);
    487         track.write(data, OFFSET_DEFAULT, data.length);
    488         track.play();
    489         Thread.sleep(WAIT_MSEC);
    490         track.stop();
    491         track.flush();
    492         log(TEST_NAME, "position =" + track.getPlaybackHeadPosition());
    493         assertTrue(TEST_NAME, track.getPlaybackHeadPosition() == 0);
    494         // -------- tear down --------------
    495         track.release();
    496     }
    497 
    498     // Test case 3: getPlaybackHeadPosition() is 0 after stop();
    499     public void testPlaybackHeadPositionAfterStop() throws Exception {
    500         // constants for test
    501         final String TEST_NAME = "testPlaybackHeadPositionAfterStop";
    502         final int TEST_SR = 22050;
    503         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
    504         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    505         final int TEST_MODE = AudioTrack.MODE_STREAM;
    506         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    507         final int TEST_LOOP_CNT = 10;
    508 
    509         // -------- initialization --------------
    510         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    511         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    512                 2 * minBuffSize, TEST_MODE);
    513         byte data[] = new byte[minBuffSize];
    514         // -------- test --------------
    515         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    516         track.write(data, OFFSET_DEFAULT, data.length);
    517         track.write(data, OFFSET_DEFAULT, data.length);
    518         track.play();
    519         Thread.sleep(WAIT_MSEC);
    520         track.stop();
    521         int count = 0;
    522         int pos;
    523         do {
    524             Thread.sleep(WAIT_MSEC);
    525             pos = track.getPlaybackHeadPosition();
    526             count++;
    527         } while((pos != 0) && (count < TEST_LOOP_CNT));
    528         log(TEST_NAME, "position =" + pos + ", read count ="+count);
    529         assertTrue(TEST_NAME, pos == 0);
    530         // -------- tear down --------------
    531         track.release();
    532     }
    533 
    534     // Test case 4: getPlaybackHeadPosition() is > 0 after play(); pause();
    535     public void testPlaybackHeadPositionAfterPause() throws Exception {
    536         // constants for test
    537         final String TEST_NAME = "testPlaybackHeadPositionAfterPause";
    538         final int TEST_SR = 22050;
    539         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
    540         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    541         final int TEST_MODE = AudioTrack.MODE_STREAM;
    542         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    543 
    544         // -------- initialization --------------
    545         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    546         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    547                 2 * minBuffSize, TEST_MODE);
    548         byte data[] = new byte[minBuffSize];
    549         // -------- test --------------
    550         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    551         track.write(data, OFFSET_DEFAULT, data.length);
    552         track.write(data, OFFSET_DEFAULT, data.length);
    553         track.play();
    554         Thread.sleep(100);
    555         track.pause();
    556         int pos = track.getPlaybackHeadPosition();
    557         log(TEST_NAME, "position =" + pos);
    558         assertTrue(TEST_NAME, pos > 0);
    559         // -------- tear down --------------
    560         track.release();
    561     }
    562 
    563     // Test case 5: getPlaybackHeadPosition() remains 0 after pause(); flush(); play();
    564     public void testPlaybackHeadPositionAfterFlushAndPlay() throws Exception {
    565         // constants for test
    566         final String TEST_NAME = "testPlaybackHeadPositionAfterFlushAndPlay";
    567         final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
    568         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    569         final int TEST_MODE = AudioTrack.MODE_STREAM;
    570         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    571         final int TEST_SR = AudioTrack.getNativeOutputSampleRate(TEST_STREAM_TYPE);
    572 
    573         // -------- initialization --------------
    574         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    575         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    576                 2 * minBuffSize, TEST_MODE);
    577         byte data[] = new byte[minBuffSize];
    578         // -------- test --------------
    579         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    580         track.write(data, OFFSET_DEFAULT, data.length);
    581         track.write(data, OFFSET_DEFAULT, data.length);
    582         track.play();
    583         Thread.sleep(100);
    584         track.pause();
    585 
    586         int pos = track.getPlaybackHeadPosition();
    587         log(TEST_NAME, "position after pause =" + pos);
    588         assertTrue(TEST_NAME, pos > 0);
    589 
    590         track.flush();
    591         pos = track.getPlaybackHeadPosition();
    592         log(TEST_NAME, "position after flush =" + pos);
    593         assertTrue(TEST_NAME, pos == 0);
    594 
    595         track.play();
    596         pos = track.getPlaybackHeadPosition();
    597         log(TEST_NAME, "position after play =" + pos);
    598         assertTrue(TEST_NAME, pos == 0);
    599 
    600         Thread.sleep(100);
    601         pos = track.getPlaybackHeadPosition();
    602         log(TEST_NAME, "position after 100 ms sleep =" + pos);
    603         assertTrue(TEST_NAME, pos == 0);
    604         // -------- tear down --------------
    605         track.release();
    606     }
    607 
    608     // -----------------------------------------------------------------
    609     // Playback properties
    610     // ----------------------------------
    611 
    612     // Common code for the testSetStereoVolume* and testSetVolume* tests
    613     private void testSetVolumeCommon(String testName, float vol, boolean isStereo) throws Exception {
    614         // constants for test
    615         final int TEST_SR = 22050;
    616         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
    617         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    618         final int TEST_MODE = AudioTrack.MODE_STREAM;
    619         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    620 
    621         // -------- initialization --------------
    622         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    623         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    624                 2 * minBuffSize, TEST_MODE);
    625         byte data[] = new byte[minBuffSize];
    626         // -------- test --------------
    627         track.write(data, OFFSET_DEFAULT, data.length);
    628         track.write(data, OFFSET_DEFAULT, data.length);
    629         track.play();
    630         if (isStereo) {
    631             // TODO to really test this, do a pan instead of using same value for left and right
    632             assertTrue(testName, track.setStereoVolume(vol, vol) == AudioTrack.SUCCESS);
    633         } else {
    634             assertTrue(testName, track.setVolume(vol) == AudioTrack.SUCCESS);
    635         }
    636         // -------- tear down --------------
    637         track.release();
    638     }
    639 
    640     // Test case 1: setStereoVolume() with max volume returns SUCCESS
    641     public void testSetStereoVolumeMax() throws Exception {
    642         final String TEST_NAME = "testSetStereoVolumeMax";
    643         float maxVol = AudioTrack.getMaxVolume();
    644         testSetVolumeCommon(TEST_NAME, maxVol, true /*isStereo*/);
    645     }
    646 
    647     // Test case 2: setStereoVolume() with min volume returns SUCCESS
    648     public void testSetStereoVolumeMin() throws Exception {
    649         final String TEST_NAME = "testSetStereoVolumeMin";
    650         float minVol = AudioTrack.getMinVolume();
    651         testSetVolumeCommon(TEST_NAME, minVol, true /*isStereo*/);
    652     }
    653 
    654     // Test case 3: setStereoVolume() with mid volume returns SUCCESS
    655     public void testSetStereoVolumeMid() throws Exception {
    656         final String TEST_NAME = "testSetStereoVolumeMid";
    657         float midVol = (AudioTrack.getMaxVolume() - AudioTrack.getMinVolume()) / 2;
    658         testSetVolumeCommon(TEST_NAME, midVol, true /*isStereo*/);
    659     }
    660 
    661     // Test case 4: setPlaybackRate() with half the content rate returns SUCCESS
    662     public void testSetPlaybackRate() throws Exception {
    663         // constants for test
    664         final String TEST_NAME = "testSetPlaybackRate";
    665         final int TEST_SR = 22050;
    666         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
    667         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    668         final int TEST_MODE = AudioTrack.MODE_STREAM;
    669         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    670 
    671         // -------- initialization --------------
    672         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    673         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    674                 2 * minBuffSize, TEST_MODE);
    675         byte data[] = new byte[minBuffSize];
    676         // -------- test --------------
    677         track.write(data, OFFSET_DEFAULT, data.length);
    678         track.write(data, OFFSET_DEFAULT, data.length);
    679         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    680         track.play();
    681         assertTrue(TEST_NAME, track.setPlaybackRate((int) (TEST_SR / 2)) == AudioTrack.SUCCESS);
    682         // -------- tear down --------------
    683         track.release();
    684     }
    685 
    686     // Test case 5: setPlaybackRate(0) returns bad value error
    687     public void testSetPlaybackRateZero() throws Exception {
    688         // constants for test
    689         final String TEST_NAME = "testSetPlaybackRateZero";
    690         final int TEST_SR = 22050;
    691         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
    692         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    693         final int TEST_MODE = AudioTrack.MODE_STREAM;
    694         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    695 
    696         // -------- initialization --------------
    697         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    698         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    699                 minBuffSize, TEST_MODE);
    700         // -------- test --------------
    701         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    702         assertTrue(TEST_NAME, track.setPlaybackRate(0) == AudioTrack.ERROR_BAD_VALUE);
    703         // -------- tear down --------------
    704         track.release();
    705     }
    706 
    707     // Test case 6: setPlaybackRate() accepts values twice the output sample
    708     // rate
    709     public void testSetPlaybackRateTwiceOutputSR() throws Exception {
    710         // constants for test
    711         final String TEST_NAME = "testSetPlaybackRateTwiceOutputSR";
    712         final int TEST_SR = 22050;
    713         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
    714         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    715         final int TEST_MODE = AudioTrack.MODE_STREAM;
    716         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    717 
    718         // -------- initialization --------------
    719         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    720         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    721                 2 * minBuffSize, TEST_MODE);
    722         byte data[] = new byte[minBuffSize];
    723         int outputSR = AudioTrack.getNativeOutputSampleRate(TEST_STREAM_TYPE);
    724         // -------- test --------------
    725         track.write(data, OFFSET_DEFAULT, data.length);
    726         track.write(data, OFFSET_DEFAULT, data.length);
    727         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    728         track.play();
    729         assertTrue(TEST_NAME, track.setPlaybackRate(2 * outputSR) == AudioTrack.SUCCESS);
    730         // -------- tear down --------------
    731         track.release();
    732     }
    733 
    734     // Test case 7: setPlaybackRate() and retrieve value, should be the same for
    735     // half the content SR
    736     public void testSetGetPlaybackRate() throws Exception {
    737         // constants for test
    738         final String TEST_NAME = "testSetGetPlaybackRate";
    739         final int TEST_SR = 22050;
    740         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
    741         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    742         final int TEST_MODE = AudioTrack.MODE_STREAM;
    743         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    744 
    745         // -------- initialization --------------
    746         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    747         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    748                 2 * minBuffSize, TEST_MODE);
    749         byte data[] = new byte[minBuffSize];
    750         // -------- test --------------
    751         track.write(data, OFFSET_DEFAULT, data.length);
    752         track.write(data, OFFSET_DEFAULT, data.length);
    753         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    754         track.play();
    755         track.setPlaybackRate((int) (TEST_SR / 2));
    756         assertTrue(TEST_NAME, track.getPlaybackRate() == (int) (TEST_SR / 2));
    757         // -------- tear down --------------
    758         track.release();
    759     }
    760 
    761     // Test case 8: setPlaybackRate() invalid operation if track not initialized
    762     public void testSetPlaybackRateUninit() throws Exception {
    763         // constants for test
    764         final String TEST_NAME = "testSetPlaybackRateUninit";
    765         final int TEST_SR = 22050;
    766         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    767         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    768         final int TEST_MODE = AudioTrack.MODE_STATIC;
    769         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    770 
    771         // -------- initialization --------------
    772         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    773         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    774                 minBuffSize, TEST_MODE);
    775         // -------- test --------------
    776         assertEquals(TEST_NAME, AudioTrack.STATE_NO_STATIC_DATA, track.getState());
    777         assertEquals(TEST_NAME, AudioTrack.ERROR_INVALID_OPERATION,
    778                 track.setPlaybackRate(TEST_SR / 2));
    779         // -------- tear down --------------
    780         track.release();
    781     }
    782 
    783     // Test case 9: setVolume() with max volume returns SUCCESS
    784     public void testSetVolumeMax() throws Exception {
    785         final String TEST_NAME = "testSetVolumeMax";
    786         float maxVol = AudioTrack.getMaxVolume();
    787         testSetVolumeCommon(TEST_NAME, maxVol, false /*isStereo*/);
    788     }
    789 
    790     // Test case 10: setVolume() with min volume returns SUCCESS
    791     public void testSetVolumeMin() throws Exception {
    792         final String TEST_NAME = "testSetVolumeMin";
    793         float minVol = AudioTrack.getMinVolume();
    794         testSetVolumeCommon(TEST_NAME, minVol, false /*isStereo*/);
    795     }
    796 
    797     // Test case 11: setVolume() with mid volume returns SUCCESS
    798     public void testSetVolumeMid() throws Exception {
    799         final String TEST_NAME = "testSetVolumeMid";
    800         float midVol = (AudioTrack.getMaxVolume() - AudioTrack.getMinVolume()) / 2;
    801         testSetVolumeCommon(TEST_NAME, midVol, false /*isStereo*/);
    802     }
    803 
    804     // -----------------------------------------------------------------
    805     // Playback progress
    806     // ----------------------------------
    807 
    808     // Test case 1: setPlaybackHeadPosition() on playing track
    809     public void testSetPlaybackHeadPositionPlaying() throws Exception {
    810         // constants for test
    811         final String TEST_NAME = "testSetPlaybackHeadPositionPlaying";
    812         final int TEST_SR = 22050;
    813         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    814         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    815         final int TEST_MODE = AudioTrack.MODE_STREAM;
    816         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    817 
    818         // -------- initialization --------------
    819         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    820         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    821                 2 * minBuffSize, TEST_MODE);
    822         byte data[] = new byte[minBuffSize];
    823         // -------- test --------------
    824         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    825         track.write(data, OFFSET_DEFAULT, data.length);
    826         track.write(data, OFFSET_DEFAULT, data.length);
    827         track.play();
    828         assertTrue(TEST_NAME,
    829                 track.setPlaybackHeadPosition(10) == AudioTrack.ERROR_INVALID_OPERATION);
    830         // -------- tear down --------------
    831         track.release();
    832     }
    833 
    834     // Test case 2: setPlaybackHeadPosition() on stopped track
    835     public void testSetPlaybackHeadPositionStopped() throws Exception {
    836         // constants for test
    837         final String TEST_NAME = "testSetPlaybackHeadPositionStopped";
    838         final int TEST_SR = 22050;
    839         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    840         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    841         final int TEST_MODE = AudioTrack.MODE_STATIC;
    842         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    843 
    844         // -------- initialization --------------
    845         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    846         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    847                 2 * minBuffSize, TEST_MODE);
    848         byte data[] = new byte[minBuffSize];
    849         // -------- test --------------
    850         assertEquals(TEST_NAME, AudioTrack.STATE_NO_STATIC_DATA, track.getState());
    851         track.write(data, OFFSET_DEFAULT, data.length);
    852         track.write(data, OFFSET_DEFAULT, data.length);
    853         assertEquals(TEST_NAME, AudioTrack.STATE_INITIALIZED, track.getState());
    854         track.play();
    855         track.stop();
    856         assertEquals(TEST_NAME, AudioTrack.PLAYSTATE_STOPPED, track.getPlayState());
    857         assertEquals(TEST_NAME, AudioTrack.SUCCESS, track.setPlaybackHeadPosition(10));
    858         // -------- tear down --------------
    859         track.release();
    860     }
    861 
    862     // Test case 3: setPlaybackHeadPosition() on paused track
    863     public void testSetPlaybackHeadPositionPaused() throws Exception {
    864         // constants for test
    865         final String TEST_NAME = "testSetPlaybackHeadPositionPaused";
    866         final int TEST_SR = 22050;
    867         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    868         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    869         final int TEST_MODE = AudioTrack.MODE_STATIC;
    870         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    871 
    872         // -------- initialization --------------
    873         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    874         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    875                 2 * minBuffSize, TEST_MODE);
    876         byte data[] = new byte[minBuffSize];
    877         // -------- test --------------
    878         assertEquals(TEST_NAME, AudioTrack.STATE_NO_STATIC_DATA, track.getState());
    879         track.write(data, OFFSET_DEFAULT, data.length);
    880         track.write(data, OFFSET_DEFAULT, data.length);
    881         assertEquals(TEST_NAME, AudioTrack.STATE_INITIALIZED, track.getState());
    882         track.play();
    883         track.pause();
    884         assertEquals(TEST_NAME, AudioTrack.PLAYSTATE_PAUSED, track.getPlayState());
    885         assertEquals(TEST_NAME, AudioTrack.SUCCESS, track.setPlaybackHeadPosition(10));
    886         // -------- tear down --------------
    887         track.release();
    888     }
    889 
    890     // Test case 4: setPlaybackHeadPosition() beyond what has been written
    891     public void testSetPlaybackHeadPositionTooFar() throws Exception {
    892         // constants for test
    893         final String TEST_NAME = "testSetPlaybackHeadPositionTooFar";
    894         final int TEST_SR = 22050;
    895         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    896         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    897         final int TEST_MODE = AudioTrack.MODE_STATIC;
    898         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    899 
    900         // -------- initialization --------------
    901         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    902         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    903                 2 * minBuffSize, TEST_MODE);
    904         byte data[] = new byte[minBuffSize];
    905         // make up a frame index that's beyond what has been written: go from
    906         // buffer size to frame
    907         // count (given the audio track properties), and add 77.
    908         int frameIndexTooFar = (2 * minBuffSize / 2) + 77;
    909         // -------- test --------------
    910         assertEquals(TEST_NAME, AudioTrack.STATE_NO_STATIC_DATA, track.getState());
    911         track.write(data, OFFSET_DEFAULT, data.length);
    912         track.write(data, OFFSET_DEFAULT, data.length);
    913         assertEquals(TEST_NAME, AudioTrack.STATE_INITIALIZED, track.getState());
    914         track.play();
    915         track.stop();
    916         assertEquals(TEST_NAME, AudioTrack.PLAYSTATE_STOPPED, track.getPlayState());
    917         assertEquals(TEST_NAME, AudioTrack.ERROR_BAD_VALUE,
    918                 track.setPlaybackHeadPosition(frameIndexTooFar));
    919         // -------- tear down --------------
    920         track.release();
    921     }
    922 
    923     // Test case 5: setLoopPoints() fails for MODE_STREAM
    924     public void testSetLoopPointsStream() throws Exception {
    925         // constants for test
    926         final String TEST_NAME = "testSetLoopPointsStream";
    927         final int TEST_SR = 22050;
    928         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    929         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    930         final int TEST_MODE = AudioTrack.MODE_STREAM;
    931         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    932 
    933         // -------- initialization --------------
    934         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    935         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    936                 2 * minBuffSize, TEST_MODE);
    937         byte data[] = new byte[minBuffSize];
    938         // -------- test --------------
    939         track.write(data, OFFSET_DEFAULT, data.length);
    940         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    941         assertTrue(TEST_NAME, track.setLoopPoints(2, 50, 2) == AudioTrack.ERROR_INVALID_OPERATION);
    942         // -------- tear down --------------
    943         track.release();
    944     }
    945 
    946     // Test case 6: setLoopPoints() fails start > end
    947     public void testSetLoopPointsStartAfterEnd() throws Exception {
    948         // constants for test
    949         final String TEST_NAME = "testSetLoopPointsStartAfterEnd";
    950         final int TEST_SR = 22050;
    951         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    952         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    953         final int TEST_MODE = AudioTrack.MODE_STATIC;
    954         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    955 
    956         // -------- initialization --------------
    957         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    958         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    959                 minBuffSize, TEST_MODE);
    960         byte data[] = new byte[minBuffSize];
    961         // -------- test --------------
    962         track.write(data, OFFSET_DEFAULT, data.length);
    963         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    964         assertTrue(TEST_NAME, track.setLoopPoints(50, 0, 2) == AudioTrack.ERROR_BAD_VALUE);
    965         // -------- tear down --------------
    966         track.release();
    967     }
    968 
    969     // Test case 6: setLoopPoints() success
    970     public void testSetLoopPointsSuccess() throws Exception {
    971         // constants for test
    972         final String TEST_NAME = "testSetLoopPointsSuccess";
    973         final int TEST_SR = 22050;
    974         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    975         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    976         final int TEST_MODE = AudioTrack.MODE_STATIC;
    977         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
    978 
    979         // -------- initialization --------------
    980         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
    981         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
    982                 minBuffSize, TEST_MODE);
    983         byte data[] = new byte[minBuffSize];
    984         // -------- test --------------
    985         track.write(data, OFFSET_DEFAULT, data.length);
    986         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
    987         assertTrue(TEST_NAME, track.setLoopPoints(0, 50, 2) == AudioTrack.SUCCESS);
    988         // -------- tear down --------------
    989         track.release();
    990     }
    991 
    992     // Test case 7: setLoopPoints() fails with loop length bigger than content
    993     public void testSetLoopPointsLoopTooLong() throws Exception {
    994         // constants for test
    995         final String TEST_NAME = "testSetLoopPointsLoopTooLong";
    996         final int TEST_SR = 22050;
    997         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    998         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    999         final int TEST_MODE = AudioTrack.MODE_STATIC;
   1000         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1001 
   1002         // -------- initialization --------------
   1003         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1004         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1005                 minBuffSize, TEST_MODE);
   1006         byte data[] = new byte[minBuffSize];
   1007         int dataSizeInFrames = minBuffSize / 2;
   1008         // -------- test --------------
   1009         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_NO_STATIC_DATA);
   1010         track.write(data, OFFSET_DEFAULT, data.length);
   1011         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1012         assertTrue(TEST_NAME, track.setLoopPoints(10, dataSizeInFrames + 20, 2) ==
   1013             AudioTrack.ERROR_BAD_VALUE);
   1014         // -------- tear down --------------
   1015         track.release();
   1016     }
   1017 
   1018     // Test case 8: setLoopPoints() fails with start beyond what can be written
   1019     // for the track
   1020     public void testSetLoopPointsStartTooFar() throws Exception {
   1021         // constants for test
   1022         final String TEST_NAME = "testSetLoopPointsStartTooFar";
   1023         final int TEST_SR = 22050;
   1024         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1025         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
   1026         final int TEST_MODE = AudioTrack.MODE_STATIC;
   1027         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1028 
   1029         // -------- initialization --------------
   1030         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1031         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1032                 minBuffSize, TEST_MODE);
   1033         byte data[] = new byte[minBuffSize];
   1034         int dataSizeInFrames = minBuffSize / 2;// 16bit data
   1035         // -------- test --------------
   1036         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_NO_STATIC_DATA);
   1037         track.write(data, OFFSET_DEFAULT, data.length);
   1038         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1039         assertTrue(TEST_NAME,
   1040                 track.setLoopPoints(dataSizeInFrames + 20, dataSizeInFrames + 50, 2) ==
   1041                     AudioTrack.ERROR_BAD_VALUE);
   1042         // -------- tear down --------------
   1043         track.release();
   1044     }
   1045 
   1046     // Test case 9: setLoopPoints() fails with end beyond what can be written
   1047     // for the track
   1048     public void testSetLoopPointsEndTooFar() throws Exception {
   1049         // constants for test
   1050         final String TEST_NAME = "testSetLoopPointsEndTooFar";
   1051         final int TEST_SR = 22050;
   1052         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1053         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
   1054         final int TEST_MODE = AudioTrack.MODE_STATIC;
   1055         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1056 
   1057         // -------- initialization --------------
   1058         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1059         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1060                 minBuffSize, TEST_MODE);
   1061         byte data[] = new byte[minBuffSize];
   1062         int dataSizeInFrames = minBuffSize / 2;// 16bit data
   1063         // -------- test --------------
   1064         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_NO_STATIC_DATA);
   1065         track.write(data, OFFSET_DEFAULT, data.length);
   1066         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1067         int loopCount = 2;
   1068         assertTrue(TEST_NAME,
   1069                 track.setLoopPoints(dataSizeInFrames - 10, dataSizeInFrames + 50, loopCount) ==
   1070                     AudioTrack.ERROR_BAD_VALUE);
   1071         // -------- tear down --------------
   1072         track.release();
   1073     }
   1074 
   1075     // -----------------------------------------------------------------
   1076     // Audio data supply
   1077     // ----------------------------------
   1078 
   1079     // Test case 1: write() fails when supplying less data (bytes) than declared
   1080     public void testWriteByteOffsetTooBig() throws Exception {
   1081         // constants for test
   1082         final String TEST_NAME = "testWriteByteOffsetTooBig";
   1083         final int TEST_SR = 22050;
   1084         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1085         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
   1086         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1087         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1088 
   1089         // -------- initialization --------------
   1090         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1091         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1092                 2 * minBuffSize, TEST_MODE);
   1093         byte data[] = new byte[minBuffSize];
   1094         // -------- test --------------
   1095         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1096         int offset = 10;
   1097         assertTrue(TEST_NAME, track.write(data, offset, data.length) == AudioTrack.ERROR_BAD_VALUE);
   1098         // -------- tear down --------------
   1099         track.release();
   1100     }
   1101 
   1102     // Test case 2: write() fails when supplying less data (shorts) than
   1103     // declared
   1104     public void testWriteShortOffsetTooBig() throws Exception {
   1105         // constants for test
   1106         final String TEST_NAME = "testWriteShortOffsetTooBig";
   1107         final int TEST_SR = 22050;
   1108         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1109         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
   1110         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1111         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1112 
   1113         // -------- initialization --------------
   1114         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1115         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1116                 2 * minBuffSize, TEST_MODE);
   1117         short data[] = new short[minBuffSize / 2];
   1118         // -------- test --------------
   1119         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1120         int offset = 10;
   1121         assertTrue(TEST_NAME, track.write(data, offset, data.length)
   1122                                                             == AudioTrack.ERROR_BAD_VALUE);
   1123         // -------- tear down --------------
   1124         track.release();
   1125     }
   1126 
   1127     // Test case 3: write() fails when supplying less data (bytes) than declared
   1128     public void testWriteByteSizeTooBig() throws Exception {
   1129         // constants for test
   1130         final String TEST_NAME = "testWriteByteSizeTooBig";
   1131         final int TEST_SR = 22050;
   1132         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1133         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
   1134         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1135         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1136 
   1137         // -------- initialization --------------
   1138         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1139         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1140                 2 * minBuffSize, TEST_MODE);
   1141         byte data[] = new byte[minBuffSize];
   1142         // -------- test --------------
   1143         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1144         assertTrue(TEST_NAME, track.write(data, OFFSET_DEFAULT, data.length + 10)
   1145                                                         == AudioTrack.ERROR_BAD_VALUE);
   1146         // -------- tear down --------------
   1147         track.release();
   1148     }
   1149 
   1150     // Test case 4: write() fails when supplying less data (shorts) than
   1151     // declared
   1152     public void testWriteShortSizeTooBig() throws Exception {
   1153         // constants for test
   1154         final String TEST_NAME = "testWriteShortSizeTooBig";
   1155         final int TEST_SR = 22050;
   1156         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1157         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
   1158         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1159         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1160 
   1161         // -------- initialization --------------
   1162         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1163         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1164                 2 * minBuffSize, TEST_MODE);
   1165         short data[] = new short[minBuffSize / 2];
   1166         // -------- test --------------
   1167         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1168         assertTrue(TEST_NAME, track.write(data, OFFSET_DEFAULT, data.length + 10)
   1169                                                         == AudioTrack.ERROR_BAD_VALUE);
   1170         // -------- tear down --------------
   1171         track.release();
   1172     }
   1173 
   1174     // Test case 5: write() fails with negative offset
   1175     public void testWriteByteNegativeOffset() throws Exception {
   1176         // constants for test
   1177         final String TEST_NAME = "testWriteByteNegativeOffset";
   1178         final int TEST_SR = 22050;
   1179         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1180         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
   1181         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1182         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1183 
   1184         // -------- initialization --------------
   1185         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1186         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1187                 2 * minBuffSize, TEST_MODE);
   1188         byte data[] = new byte[minBuffSize];
   1189         // -------- test --------------
   1190         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1191         assertTrue(TEST_NAME, track.write(data, OFFSET_NEGATIVE, data.length - 10) ==
   1192             AudioTrack.ERROR_BAD_VALUE);
   1193         // -------- tear down --------------
   1194         track.release();
   1195     }
   1196 
   1197     // Test case 6: write() fails with negative offset
   1198     public void testWriteShortNegativeOffset() throws Exception {
   1199         // constants for test
   1200         final String TEST_NAME = "testWriteShortNegativeOffset";
   1201         final int TEST_SR = 22050;
   1202         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1203         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
   1204         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1205         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1206 
   1207         // -------- initialization --------------
   1208         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1209         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1210                 2 * minBuffSize, TEST_MODE);
   1211         short data[] = new short[minBuffSize / 2];
   1212         // -------- test --------------
   1213         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1214         assertTrue(TEST_NAME,
   1215         track.write(data, OFFSET_NEGATIVE, data.length - 10) == AudioTrack.ERROR_BAD_VALUE);
   1216         // -------- tear down --------------
   1217         track.release();
   1218     }
   1219 
   1220     // Test case 7: write() fails with negative size
   1221     public void testWriteByteNegativeSize() throws Exception {
   1222         // constants for test
   1223         final String TEST_NAME = "testWriteByteNegativeSize";
   1224         final int TEST_SR = 22050;
   1225         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1226         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
   1227         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1228         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1229 
   1230         // -------- initialization --------------
   1231         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1232         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1233                 2 * minBuffSize, TEST_MODE);
   1234         byte data[] = new byte[minBuffSize];
   1235         // -------- test --------------
   1236         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1237         int dataLength = -10;
   1238         assertTrue(TEST_NAME, track.write(data, OFFSET_DEFAULT, dataLength)
   1239                                                     == AudioTrack.ERROR_BAD_VALUE);
   1240         // -------- tear down --------------
   1241         track.release();
   1242     }
   1243 
   1244     // Test case 8: write() fails with negative size
   1245     public void testWriteShortNegativeSize() throws Exception {
   1246         // constants for test
   1247         final String TEST_NAME = "testWriteShortNegativeSize";
   1248         final int TEST_SR = 22050;
   1249         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1250         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
   1251         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1252         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1253 
   1254         // -------- initialization --------------
   1255         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1256         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1257                 2 * minBuffSize, TEST_MODE);
   1258         short data[] = new short[minBuffSize / 2];
   1259         // -------- test --------------
   1260         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1261         int dataLength = -10;
   1262         assertTrue(TEST_NAME, track.write(data, OFFSET_DEFAULT, dataLength)
   1263                                                         == AudioTrack.ERROR_BAD_VALUE);
   1264         // -------- tear down --------------
   1265         track.release();
   1266     }
   1267 
   1268     // Test case 9: write() succeeds and returns the size that was written for
   1269     // 16bit
   1270     public void testWriteByte() throws Exception {
   1271         // constants for test
   1272         final String TEST_NAME = "testWriteByte";
   1273         final int TEST_SR = 22050;
   1274         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1275         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
   1276         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1277         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1278 
   1279         // -------- initialization --------------
   1280         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1281         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1282                 2 * minBuffSize, TEST_MODE);
   1283         byte data[] = new byte[minBuffSize];
   1284         // -------- test --------------
   1285         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1286         assertTrue(TEST_NAME, track.write(data, OFFSET_DEFAULT, data.length) == data.length);
   1287         // -------- tear down --------------
   1288         track.release();
   1289     }
   1290 
   1291     // Test case 10: write() succeeds and returns the size that was written for
   1292     // 16bit
   1293     public void testWriteShort() throws Exception {
   1294         // constants for test
   1295         final String TEST_NAME = "testWriteShort";
   1296         final int TEST_SR = 22050;
   1297         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1298         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
   1299         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1300         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1301 
   1302         // -------- initialization --------------
   1303         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1304         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1305                 2 * minBuffSize, TEST_MODE);
   1306         short data[] = new short[minBuffSize / 2];
   1307         // -------- test --------------
   1308         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1309         assertTrue(TEST_NAME, track.write(data, OFFSET_DEFAULT, data.length) == data.length);
   1310         track.flush();
   1311         // -------- tear down --------------
   1312         track.release();
   1313     }
   1314 
   1315     // Test case 11: write() succeeds and returns the size that was written for
   1316     // 8bit
   1317     public void testWriteByte8bit() throws Exception {
   1318         // constants for test
   1319         final String TEST_NAME = "testWriteByte8bit";
   1320         final int TEST_SR = 22050;
   1321         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1322         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
   1323         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1324         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1325 
   1326         // -------- initialization --------------
   1327         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1328         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1329                 2 * minBuffSize, TEST_MODE);
   1330         byte data[] = new byte[minBuffSize];
   1331         // -------- test --------------
   1332         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1333         assertEquals(TEST_NAME, data.length, track.write(data, OFFSET_DEFAULT, data.length));
   1334         // -------- tear down --------------
   1335         track.release();
   1336     }
   1337 
   1338     // Test case 12: write() succeeds and returns the size that was written for
   1339     // 8bit
   1340     public void testWriteShort8bit() throws Exception {
   1341         // constants for test
   1342         final String TEST_NAME = "testWriteShort8bit";
   1343         final int TEST_SR = 22050;
   1344         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1345         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
   1346         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1347         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1348 
   1349         // -------- initialization --------------
   1350         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1351         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1352                 2 * minBuffSize, TEST_MODE);
   1353         short data[] = new short[minBuffSize / 2];
   1354         // -------- test --------------
   1355         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1356         assertEquals(TEST_NAME, data.length, track.write(data, OFFSET_DEFAULT, data.length));
   1357         // -------- tear down --------------
   1358         track.release();
   1359     }
   1360 
   1361     // -----------------------------------------------------------------
   1362     // Getters
   1363     // ----------------------------------
   1364 
   1365     // Test case 1: getMinBufferSize() return ERROR_BAD_VALUE if SR < 4000
   1366     public void testGetMinBufferSizeTooLowSR() throws Exception {
   1367         // constant for test
   1368         final String TEST_NAME = "testGetMinBufferSizeTooLowSR";
   1369         final int TEST_SR = 3999;
   1370         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1371         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
   1372 
   1373         // -------- initialization & test --------------
   1374         assertTrue(TEST_NAME, AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT) ==
   1375             AudioTrack.ERROR_BAD_VALUE);
   1376     }
   1377 
   1378     // Test case 2: getMinBufferSize() return ERROR_BAD_VALUE if sample rate too high
   1379     public void testGetMinBufferSizeTooHighSR() throws Exception {
   1380         // constant for test
   1381         final String TEST_NAME = "testGetMinBufferSizeTooHighSR";
   1382         // FIXME need an API to retrieve AudioTrack.SAMPLE_RATE_HZ_MAX
   1383         final int TEST_SR = 192001;
   1384         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1385         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
   1386 
   1387         // -------- initialization & test --------------
   1388         assertTrue(TEST_NAME, AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT) ==
   1389             AudioTrack.ERROR_BAD_VALUE);
   1390     }
   1391 
   1392     public void testAudioTrackProperties() throws Exception {
   1393         // constants for test
   1394         final String TEST_NAME = "testAudioTrackProperties";
   1395         final int TEST_SR = 22050;
   1396         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1397         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
   1398         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1399         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1400 
   1401         // -------- initialization --------------
   1402         int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1403         MockAudioTrack track = new MockAudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF,
   1404                 TEST_FORMAT, 2 * minBuffSize, TEST_MODE);
   1405         assertEquals(TEST_NAME, AudioTrack.STATE_INITIALIZED, track.getState());
   1406         assertEquals(TEST_NAME, TEST_FORMAT, track.getAudioFormat());
   1407         assertEquals(TEST_NAME, TEST_CONF, track.getChannelConfiguration());
   1408         assertEquals(TEST_NAME, TEST_SR, track.getSampleRate());
   1409         assertEquals(TEST_NAME, TEST_STREAM_TYPE, track.getStreamType());
   1410         final int hannelCount = 1;
   1411         assertEquals(hannelCount, track.getChannelCount());
   1412         final int notificationMarkerPosition = 0;
   1413         assertEquals(TEST_NAME, notificationMarkerPosition, track.getNotificationMarkerPosition());
   1414         final int markerInFrames = 2;
   1415         assertEquals(TEST_NAME, AudioTrack.SUCCESS,
   1416                 track.setNotificationMarkerPosition(markerInFrames));
   1417         assertEquals(TEST_NAME, markerInFrames, track.getNotificationMarkerPosition());
   1418         final int positionNotificationPeriod = 0;
   1419         assertEquals(TEST_NAME, positionNotificationPeriod, track.getPositionNotificationPeriod());
   1420         final int periodInFrames = 2;
   1421         assertEquals(TEST_NAME, AudioTrack.SUCCESS,
   1422                 track.setPositionNotificationPeriod(periodInFrames));
   1423         assertEquals(TEST_NAME, periodInFrames, track.getPositionNotificationPeriod());
   1424         track.setState(AudioTrack.STATE_NO_STATIC_DATA);
   1425         assertEquals(TEST_NAME, AudioTrack.STATE_NO_STATIC_DATA, track.getState());
   1426         track.setState(AudioTrack.STATE_UNINITIALIZED);
   1427         assertEquals(TEST_NAME, AudioTrack.STATE_UNINITIALIZED, track.getState());
   1428         int frameCount = 2 * minBuffSize;
   1429         if (TEST_CONF == AudioFormat.CHANNEL_CONFIGURATION_STEREO) {
   1430             frameCount /= 2;
   1431         }
   1432         if (TEST_FORMAT == AudioFormat.ENCODING_PCM_16BIT) {
   1433             frameCount /= 2;
   1434         }
   1435         assertTrue(TEST_NAME, track.getNativeFrameCount() >= frameCount);
   1436         assertEquals(TEST_NAME, track.getNativeFrameCount(), track.getBufferSizeInFrames());
   1437     }
   1438 
   1439     public void testReloadStaticData() throws Exception {
   1440         // constants for test
   1441         final String TEST_NAME = "testReloadStaticData";
   1442         final int TEST_SR = 22050;
   1443         final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
   1444         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
   1445         final int TEST_MODE = AudioTrack.MODE_STATIC;
   1446         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1447 
   1448         // -------- initialization --------------
   1449         int bufferSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   1450         byte data[] = AudioHelper.createSoundDataInByteArray(
   1451                 bufferSize, TEST_SR, 1024 /* frequency */, 0 /* sweep */);
   1452         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
   1453                 bufferSize, TEST_MODE);
   1454         // -------- test --------------
   1455         track.write(data, OFFSET_DEFAULT, bufferSize);
   1456         assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
   1457         track.play();
   1458         Thread.sleep(WAIT_MSEC);
   1459         track.stop();
   1460         Thread.sleep(WAIT_MSEC);
   1461         assertEquals(TEST_NAME, AudioTrack.SUCCESS, track.reloadStaticData());
   1462         track.play();
   1463         Thread.sleep(WAIT_MSEC);
   1464         track.stop();
   1465         // -------- tear down --------------
   1466         track.release();
   1467     }
   1468 
   1469     @Presubmit
   1470     public void testPlayStaticDataShort() throws Exception {
   1471         if (!hasAudioOutput()) {
   1472             Log.w(TAG,"AUDIO_OUTPUT feature not found. This system might not have a valid "
   1473                     + "audio output HAL");
   1474             return;
   1475         }
   1476         // constants for test
   1477         final String TEST_NAME = "testPlayStaticDataShort";
   1478         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_FLOAT;
   1479         final int TEST_SR = 48000;
   1480         final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
   1481         final int TEST_MODE = AudioTrack.MODE_STATIC;
   1482         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1483         final double TEST_SWEEP = 100;
   1484         final int TEST_LOOPS = 1;
   1485         final double TEST_FREQUENCY = 400;
   1486         final long WAIT_TIME_MS = 50; // compensate for cold start when run in isolation.
   1487         final double TEST_LOOP_DURATION = 0.25;
   1488 
   1489         playOnceStaticData(TEST_NAME, TEST_MODE, TEST_STREAM_TYPE, TEST_SWEEP,
   1490                 TEST_LOOPS, TEST_FORMAT, TEST_FREQUENCY, TEST_SR, TEST_CONF,
   1491                 WAIT_TIME_MS, TEST_LOOP_DURATION);
   1492 
   1493     }
   1494 
   1495     public void testPlayStaticData() throws Exception {
   1496         if (!hasAudioOutput()) {
   1497             Log.w(TAG,"AUDIO_OUTPUT feature not found. This system might not have a valid "
   1498                     + "audio output HAL");
   1499             return;
   1500         }
   1501         // constants for test
   1502         final String TEST_NAME = "testPlayStaticData";
   1503         final int TEST_FORMAT_ARRAY[] = {  // 6 chirps repeated (TEST_LOOPS+1) times, 3 times
   1504                 AudioFormat.ENCODING_PCM_8BIT,
   1505                 AudioFormat.ENCODING_PCM_16BIT,
   1506                 AudioFormat.ENCODING_PCM_FLOAT,
   1507         };
   1508         final int TEST_SR_ARRAY[] = {
   1509                 12055, // Note multichannel tracks will sound very short at low sample rates
   1510                 48000,
   1511         };
   1512         final int TEST_CONF_ARRAY[] = {
   1513                 AudioFormat.CHANNEL_OUT_MONO,    // 1.0
   1514                 AudioFormat.CHANNEL_OUT_STEREO,  // 2.0
   1515                 AudioFormat.CHANNEL_OUT_7POINT1_SURROUND, // 7.1
   1516         };
   1517         final int TEST_MODE = AudioTrack.MODE_STATIC;
   1518         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1519         final double TEST_SWEEP = 100;
   1520         final int TEST_LOOPS = 1;
   1521         final double TEST_LOOP_DURATION=1;
   1522 
   1523         for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
   1524             double frequency = 400; // frequency changes for each test
   1525             for (int TEST_SR : TEST_SR_ARRAY) {
   1526                 for (int TEST_CONF : TEST_CONF_ARRAY) {
   1527                     playOnceStaticData(TEST_NAME, TEST_MODE, TEST_STREAM_TYPE, TEST_SWEEP,
   1528                             TEST_LOOPS, TEST_FORMAT, frequency, TEST_SR, TEST_CONF, WAIT_MSEC, TEST_LOOP_DURATION);
   1529 
   1530                     frequency += 70; // increment test tone frequency
   1531                 }
   1532             }
   1533         }
   1534     }
   1535 
   1536     private void playOnceStaticData(String testName, int testMode, int testStreamType,
   1537             double testSweep, int testLoops, int testFormat, double testFrequency, int testSr,
   1538             int testConf, long waitMsec, double testLoopDuration)
   1539             throws InterruptedException {
   1540         // -------- initialization --------------
   1541         final int channelCount = Integer.bitCount(testConf);
   1542         final int bufferFrames = (int)(testLoopDuration * testSr);
   1543         final int bufferSamples = bufferFrames * channelCount;
   1544         final int bufferSize = bufferSamples
   1545                 * AudioFormat.getBytesPerSample(testFormat);
   1546         final double frequency = testFrequency / channelCount;
   1547         final long MILLISECONDS_PER_SECOND = 1000;
   1548         AudioTrack track = new AudioTrack(testStreamType, testSr,
   1549                 testConf, testFormat, bufferSize, testMode);
   1550         assertEquals(testName, AudioTrack.STATE_NO_STATIC_DATA, track.getState());
   1551 
   1552         // -------- test --------------
   1553 
   1554         // test setLoopPoints and setPosition can be called here.
   1555         assertEquals(testName,
   1556                 android.media.AudioTrack.SUCCESS,
   1557                 track.setPlaybackHeadPosition(bufferFrames/2));
   1558         assertEquals(testName,
   1559                 android.media.AudioTrack.SUCCESS,
   1560                 track.setLoopPoints(
   1561                         0 /*startInFrames*/, bufferFrames, 10 /*loopCount*/));
   1562         // only need to write once to the static track
   1563         switch (testFormat) {
   1564         case AudioFormat.ENCODING_PCM_8BIT: {
   1565             byte data[] = AudioHelper.createSoundDataInByteArray(
   1566                     bufferSamples, testSr,
   1567                     frequency, testSweep);
   1568             assertEquals(testName,
   1569                     bufferSamples,
   1570                     track.write(data, 0 /*offsetInBytes*/, data.length));
   1571             } break;
   1572         case AudioFormat.ENCODING_PCM_16BIT: {
   1573             short data[] = AudioHelper.createSoundDataInShortArray(
   1574                     bufferSamples, testSr,
   1575                     frequency, testSweep);
   1576             assertEquals(testName,
   1577                     bufferSamples,
   1578                     track.write(data, 0 /*offsetInBytes*/, data.length));
   1579             } break;
   1580         case AudioFormat.ENCODING_PCM_FLOAT: {
   1581             float data[] = AudioHelper.createSoundDataInFloatArray(
   1582                     bufferSamples, testSr,
   1583                     frequency, testSweep);
   1584             assertEquals(testName,
   1585                     bufferSamples,
   1586                     track.write(data, 0 /*offsetInBytes*/, data.length,
   1587                             AudioTrack.WRITE_BLOCKING));
   1588             } break;
   1589         }
   1590         assertEquals(testName, AudioTrack.STATE_INITIALIZED, track.getState());
   1591         // test setLoopPoints and setPosition can be called here.
   1592         assertEquals(testName,
   1593                 android.media.AudioTrack.SUCCESS,
   1594                 track.setPlaybackHeadPosition(0 /*positionInFrames*/));
   1595         assertEquals(testName,
   1596                 android.media.AudioTrack.SUCCESS,
   1597                 track.setLoopPoints(0 /*startInFrames*/, bufferFrames, testLoops));
   1598 
   1599         track.play();
   1600         Thread.sleep((int)(testLoopDuration * MILLISECONDS_PER_SECOND) * (testLoops + 1));
   1601         Thread.sleep(waitMsec);
   1602 
   1603         // Check position after looping. AudioTrack.getPlaybackHeadPosition() returns
   1604         // the running count of frames played, not the actual static buffer position.
   1605         int position = track.getPlaybackHeadPosition();
   1606         assertEquals(testName, bufferFrames * (testLoops + 1), position);
   1607 
   1608         track.stop();
   1609         Thread.sleep(waitMsec);
   1610         // -------- tear down --------------
   1611         track.release();
   1612     }
   1613 
   1614     @Presubmit
   1615     public void testPlayStreamDataShort() throws Exception {
   1616         // constants for test
   1617         final String TEST_NAME = "testPlayStreamDataShort";
   1618         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
   1619         final int TEST_SR = 48000;
   1620         final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
   1621         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1622         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1623         final float TEST_SWEEP = 0; // sine wave only
   1624         final boolean TEST_IS_LOW_RAM_DEVICE = isLowRamDevice();
   1625         final double TEST_FREQUENCY = 1000;
   1626         final long NO_WAIT = 0;
   1627 
   1628         playOnceStreamData(TEST_NAME, TEST_MODE, TEST_STREAM_TYPE, TEST_SWEEP,
   1629                 TEST_IS_LOW_RAM_DEVICE, TEST_FORMAT, TEST_FREQUENCY, TEST_SR, TEST_CONF,
   1630                 NO_WAIT);
   1631     }
   1632 
   1633     public void testPlayStreamData() throws Exception {
   1634         // constants for test
   1635         final String TEST_NAME = "testPlayStreamData";
   1636         final int TEST_FORMAT_ARRAY[] = {  // should hear 40 increasing frequency tones, 3 times
   1637                 AudioFormat.ENCODING_PCM_8BIT,
   1638                 AudioFormat.ENCODING_PCM_16BIT,
   1639                 AudioFormat.ENCODING_PCM_FLOAT,
   1640         };
   1641         // due to downmixer algorithmic latency, source channels greater than 2 may
   1642         // sound shorter in duration at 4kHz sampling rate.
   1643         final int TEST_SR_ARRAY[] = {
   1644                 4000,
   1645                 44100,
   1646                 48000,
   1647                 96000,
   1648                 192000,
   1649         };
   1650         final int TEST_CONF_ARRAY[] = {
   1651                 AudioFormat.CHANNEL_OUT_MONO,    // 1.0
   1652                 AudioFormat.CHANNEL_OUT_STEREO,  // 2.0
   1653                 AudioFormat.CHANNEL_OUT_STEREO | AudioFormat.CHANNEL_OUT_FRONT_CENTER, // 3.0
   1654                 AudioFormat.CHANNEL_OUT_QUAD,    // 4.0
   1655                 AudioFormat.CHANNEL_OUT_QUAD | AudioFormat.CHANNEL_OUT_FRONT_CENTER,   // 5.0
   1656                 AudioFormat.CHANNEL_OUT_5POINT1, // 5.1
   1657                 AudioFormat.CHANNEL_OUT_5POINT1 | AudioFormat.CHANNEL_OUT_BACK_CENTER, // 6.1
   1658                 AudioFormat.CHANNEL_OUT_7POINT1_SURROUND, // 7.1
   1659         };
   1660         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1661         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1662         final float TEST_SWEEP = 0; // sine wave only
   1663         final boolean TEST_IS_LOW_RAM_DEVICE = isLowRamDevice();
   1664 
   1665         for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
   1666             double frequency = 400; // frequency changes for each test
   1667             for (int TEST_SR : TEST_SR_ARRAY) {
   1668                 for (int TEST_CONF : TEST_CONF_ARRAY) {
   1669                     playOnceStreamData(TEST_NAME, TEST_MODE, TEST_STREAM_TYPE, TEST_SWEEP,
   1670                             TEST_IS_LOW_RAM_DEVICE, TEST_FORMAT, frequency, TEST_SR, TEST_CONF,
   1671                             WAIT_MSEC);
   1672                     frequency += 50; // increment test tone frequency
   1673                 }
   1674             }
   1675         }
   1676     }
   1677 
   1678     private void playOnceStreamData(String testName, int testMode, int testStream,
   1679             float testSweep, boolean isLowRamDevice, int testFormat, double testFrequency,
   1680             int testSr, int testConf, long waitMsec) throws InterruptedException {
   1681         final int channelCount = Integer.bitCount(testConf);
   1682         if (isLowRamDevice
   1683                 && (testSr > 96000 || channelCount > 4)) {
   1684             return; // ignore. FIXME: reenable when AF memory allocation is updated.
   1685         }
   1686         // -------- initialization --------------
   1687         final int minBufferSize = AudioTrack.getMinBufferSize(testSr,
   1688                 testConf, testFormat); // in bytes
   1689         AudioTrack track = new AudioTrack(testStream, testSr,
   1690                 testConf, testFormat, minBufferSize, testMode);
   1691         assertTrue(testName, track.getState() == AudioTrack.STATE_INITIALIZED);
   1692 
   1693         // compute parameters for the source signal data.
   1694         AudioFormat format = track.getFormat();
   1695         assertEquals(testName, testSr, format.getSampleRate());
   1696         assertEquals(testName, testConf, format.getChannelMask());
   1697         assertEquals(testName, channelCount, format.getChannelCount());
   1698         assertEquals(testName, testFormat, format.getEncoding());
   1699         final int sourceSamples = channelCount
   1700                 * AudioHelper.frameCountFromMsec(500,
   1701                 format); // duration of test tones
   1702         final double frequency = testFrequency / channelCount;
   1703 
   1704         int written = 0;
   1705         // For streaming tracks, it's ok to issue the play() command
   1706         // before any audio is written.
   1707         track.play();
   1708         // -------- test --------------
   1709 
   1710         // samplesPerWrite can be any positive value.
   1711         // We prefer this to be a multiple of channelCount so write()
   1712         // does not return a short count.
   1713         // If samplesPerWrite is very large, it is limited to the data length
   1714         // and we simply write (blocking) the entire source data and not even loop.
   1715         // We choose a value here which simulates double buffer writes.
   1716         final int buffers = 2; // double buffering mode
   1717         final int samplesPerWrite =
   1718                 (track.getBufferSizeInFrames() / buffers) * channelCount;
   1719         switch (testFormat) {
   1720             case AudioFormat.ENCODING_PCM_8BIT: {
   1721                 byte data[] = AudioHelper.createSoundDataInByteArray(
   1722                         sourceSamples, testSr,
   1723                         frequency, testSweep);
   1724                 while (written < data.length) {
   1725                     int samples = Math.min(data.length - written, samplesPerWrite);
   1726                     int ret = track.write(data, written, samples);
   1727                     assertEquals(testName, samples, ret);
   1728                     written += ret;
   1729                 }
   1730             }
   1731             break;
   1732             case AudioFormat.ENCODING_PCM_16BIT: {
   1733                 short data[] = AudioHelper.createSoundDataInShortArray(
   1734                         sourceSamples, testSr,
   1735                         frequency, testSweep);
   1736                 while (written < data.length) {
   1737                     int samples = Math.min(data.length - written, samplesPerWrite);
   1738                     int ret = track.write(data, written, samples);
   1739                     assertEquals(testName, samples, ret);
   1740                     written += ret;
   1741                 }
   1742             }
   1743             break;
   1744             case AudioFormat.ENCODING_PCM_FLOAT: {
   1745                 float data[] = AudioHelper.createSoundDataInFloatArray(
   1746                         sourceSamples, testSr,
   1747                         frequency, testSweep);
   1748                 while (written < data.length) {
   1749                     int samples = Math.min(data.length - written, samplesPerWrite);
   1750                     int ret = track.write(data, written, samples,
   1751                             AudioTrack.WRITE_BLOCKING);
   1752                     assertEquals(testName, samples, ret);
   1753                     written += ret;
   1754                 }
   1755             }
   1756             break;
   1757         }
   1758 
   1759         // For streaming tracks, AudioTrack.stop() doesn't immediately stop playback.
   1760         // Rather, it allows the remaining data in the internal buffer to drain.
   1761         track.stop();
   1762         Thread.sleep(waitMsec); // wait for the data to drain.
   1763         // -------- tear down --------------
   1764         track.release();
   1765         Thread.sleep(waitMsec); // wait for release to complete
   1766     }
   1767 
   1768     public void testPlayStreamByteBuffer() throws Exception {
   1769         // constants for test
   1770         final String TEST_NAME = "testPlayStreamByteBuffer";
   1771         final int TEST_FORMAT_ARRAY[] = {  // should hear 4 tones played 3 times
   1772                 AudioFormat.ENCODING_PCM_8BIT,
   1773                 AudioFormat.ENCODING_PCM_16BIT,
   1774                 AudioFormat.ENCODING_PCM_FLOAT,
   1775         };
   1776         final int TEST_SR_ARRAY[] = {
   1777                 48000,
   1778         };
   1779         final int TEST_CONF_ARRAY[] = {
   1780                 AudioFormat.CHANNEL_OUT_STEREO,
   1781         };
   1782         final int TEST_WRITE_MODE_ARRAY[] = {
   1783                 AudioTrack.WRITE_BLOCKING,
   1784                 AudioTrack.WRITE_NON_BLOCKING,
   1785         };
   1786         final int TEST_MODE = AudioTrack.MODE_STREAM;
   1787         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   1788         final float TEST_SWEEP = 0; // sine wave only
   1789 
   1790         for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
   1791             double frequency = 800; // frequency changes for each test
   1792             for (int TEST_SR : TEST_SR_ARRAY) {
   1793                 for (int TEST_CONF : TEST_CONF_ARRAY) {
   1794                     for (int TEST_WRITE_MODE : TEST_WRITE_MODE_ARRAY) {
   1795                         for (int useDirect = 0; useDirect < 2; ++useDirect) {
   1796                             // -------- initialization --------------
   1797                             int minBufferSize = AudioTrack.getMinBufferSize(TEST_SR,
   1798                                     TEST_CONF, TEST_FORMAT); // in bytes
   1799                             int bufferSize = 12 * minBufferSize;
   1800                             int bufferSamples = bufferSize
   1801                                     / AudioFormat.getBytesPerSample(TEST_FORMAT);
   1802 
   1803                             // create audio track and confirm settings
   1804                             AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR,
   1805                                     TEST_CONF, TEST_FORMAT, minBufferSize, TEST_MODE);
   1806                             assertEquals(TEST_NAME + ": state",
   1807                                     AudioTrack.STATE_INITIALIZED, track.getState());
   1808                             assertEquals(TEST_NAME + ": sample rate",
   1809                                     TEST_SR, track.getSampleRate());
   1810                             assertEquals(TEST_NAME + ": channel mask",
   1811                                     TEST_CONF, track.getChannelConfiguration());
   1812                             assertEquals(TEST_NAME + ": encoding",
   1813                                     TEST_FORMAT, track.getAudioFormat());
   1814 
   1815                             ByteBuffer bb = (useDirect == 1)
   1816                                     ? ByteBuffer.allocateDirect(bufferSize)
   1817                                             : ByteBuffer.allocate(bufferSize);
   1818                             bb.order(java.nio.ByteOrder.nativeOrder());
   1819 
   1820                             // -------- test --------------
   1821                             switch (TEST_FORMAT) {
   1822                                 case AudioFormat.ENCODING_PCM_8BIT: {
   1823                                     byte data[] = AudioHelper.createSoundDataInByteArray(
   1824                                             bufferSamples, TEST_SR,
   1825                                             frequency, TEST_SWEEP);
   1826                                     bb.put(data);
   1827                                     bb.flip();
   1828                                 } break;
   1829                                 case AudioFormat.ENCODING_PCM_16BIT: {
   1830                                     short data[] = AudioHelper.createSoundDataInShortArray(
   1831                                             bufferSamples, TEST_SR,
   1832                                             frequency, TEST_SWEEP);
   1833                                     ShortBuffer sb = bb.asShortBuffer();
   1834                                     sb.put(data);
   1835                                     bb.limit(sb.limit() * 2);
   1836                                 } break;
   1837                                 case AudioFormat.ENCODING_PCM_FLOAT: {
   1838                                     float data[] = AudioHelper.createSoundDataInFloatArray(
   1839                                             bufferSamples, TEST_SR,
   1840                                             frequency, TEST_SWEEP);
   1841                                     FloatBuffer fb = bb.asFloatBuffer();
   1842                                     fb.put(data);
   1843                                     bb.limit(fb.limit() * 4);
   1844                                 } break;
   1845                             }
   1846 
   1847                             boolean hasPlayed = false;
   1848                             int written = 0;
   1849                             while (written < bufferSize) {
   1850                                 int ret = track.write(bb,
   1851                                         Math.min(bufferSize - written, minBufferSize),
   1852                                         TEST_WRITE_MODE);
   1853                                 assertTrue(TEST_NAME, ret >= 0);
   1854                                 written += ret;
   1855                                 if (!hasPlayed) {
   1856                                     track.play();
   1857                                     hasPlayed = true;
   1858                                 }
   1859                             }
   1860 
   1861                             track.stop();
   1862                             Thread.sleep(WAIT_MSEC);
   1863                             // -------- tear down --------------
   1864                             track.release();
   1865                             frequency += 200; // increment test tone frequency
   1866                         }
   1867                     }
   1868                 }
   1869             }
   1870         }
   1871     }
   1872 
   1873     public void testPlayChannelIndexStreamBuffer() throws Exception {
   1874         // should hear 4 tones played 3 or 4 times depending
   1875         // on the device output capabilities (e.g. stereo or 5.1 or otherwise)
   1876         final String TEST_NAME = "testPlayChannelIndexStreamBuffer";
   1877         final int TEST_FORMAT_ARRAY[] = {
   1878                 AudioFormat.ENCODING_PCM_8BIT,
   1879                 //AudioFormat.ENCODING_PCM_16BIT,
   1880                 //AudioFormat.ENCODING_PCM_FLOAT,
   1881         };
   1882         final int TEST_SR_ARRAY[] = {
   1883                 48000,
   1884         };
   1885         // The following channel index masks are iterated over and route
   1886         // the AudioTrack channels to the output sink channels based on
   1887         // the set bits in counting order (lsb to msb).
   1888         //
   1889         // For a stereo output sink, the sound may come from L and R, L only, none, or R only.
   1890         // For a 5.1 output sink, the sound may come from a variety of outputs
   1891         // as commented below.
   1892         final int TEST_CONF_ARRAY[] = { // matches output sink channels:
   1893                 (1 << 0) | (1 << 1), // Stereo(L, R) 5.1(FL, FR)
   1894                 (1 << 0) | (1 << 2), // Stereo(L)    5.1(FL, FC)
   1895                 (1 << 4) | (1 << 5), // Stereo(None) 5.1(BL, BR)
   1896                 (1 << 1) | (1 << 2), // Stereo(R)    5.1(FR, FC)
   1897         };
   1898         final int TEST_WRITE_MODE_ARRAY[] = {
   1899                 AudioTrack.WRITE_BLOCKING,
   1900                 AudioTrack.WRITE_NON_BLOCKING,
   1901         };
   1902         final float TEST_SWEEP = 0;
   1903 
   1904         for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
   1905             for (int TEST_CONF : TEST_CONF_ARRAY) {
   1906                 double frequency = 800; // frequency changes for each test
   1907                 for (int TEST_SR : TEST_SR_ARRAY) {
   1908                     for (int TEST_WRITE_MODE : TEST_WRITE_MODE_ARRAY) {
   1909                         for (int useDirect = 0; useDirect < 2; ++useDirect) {
   1910                             AudioFormat format = new AudioFormat.Builder()
   1911                                     .setEncoding(TEST_FORMAT)
   1912                                     .setSampleRate(TEST_SR)
   1913                                     .setChannelIndexMask(TEST_CONF)
   1914                                     .build();
   1915                             AudioTrack track = new AudioTrack.Builder()
   1916                                     .setAudioFormat(format)
   1917                                     .build();
   1918                             assertEquals(TEST_NAME,
   1919                                     AudioTrack.STATE_INITIALIZED, track.getState());
   1920 
   1921                             // create the byte buffer and fill with test data
   1922                             final int frameSize = AudioHelper.frameSizeFromFormat(format);
   1923                             final int frameCount =
   1924                                     AudioHelper.frameCountFromMsec(300 /* ms */, format);
   1925                             final int bufferSize = frameCount * frameSize;
   1926                             final int bufferSamples = frameCount * format.getChannelCount();
   1927                             ByteBuffer bb = (useDirect == 1)
   1928                                     ? ByteBuffer.allocateDirect(bufferSize)
   1929                                             : ByteBuffer.allocate(bufferSize);
   1930                             bb.order(java.nio.ByteOrder.nativeOrder());
   1931 
   1932                             switch (TEST_FORMAT) {
   1933                             case AudioFormat.ENCODING_PCM_8BIT: {
   1934                                 byte data[] = AudioHelper.createSoundDataInByteArray(
   1935                                         bufferSamples, TEST_SR,
   1936                                         frequency, TEST_SWEEP);
   1937                                 bb.put(data);
   1938                                 bb.flip();
   1939                             } break;
   1940                             case AudioFormat.ENCODING_PCM_16BIT: {
   1941                                 short data[] = AudioHelper.createSoundDataInShortArray(
   1942                                         bufferSamples, TEST_SR,
   1943                                         frequency, TEST_SWEEP);
   1944                                 ShortBuffer sb = bb.asShortBuffer();
   1945                                 sb.put(data);
   1946                                 bb.limit(sb.limit() * 2);
   1947                             } break;
   1948                             case AudioFormat.ENCODING_PCM_FLOAT: {
   1949                                 float data[] = AudioHelper.createSoundDataInFloatArray(
   1950                                         bufferSamples, TEST_SR,
   1951                                         frequency, TEST_SWEEP);
   1952                                 FloatBuffer fb = bb.asFloatBuffer();
   1953                                 fb.put(data);
   1954                                 bb.limit(fb.limit() * 4);
   1955                             } break;
   1956                             }
   1957 
   1958                             // start the AudioTrack
   1959                             // This can be done before or after the first write.
   1960                             // Current behavior for streaming tracks is that
   1961                             // actual playback does not begin before the internal
   1962                             // data buffer is completely full.
   1963                             track.play();
   1964 
   1965                             // write data
   1966                             final long startTime = System.currentTimeMillis();
   1967                             final long maxDuration = frameCount * 1000 / TEST_SR + 1000;
   1968                             for (int written = 0; written < bufferSize; ) {
   1969                                 // ret may return a short count if write
   1970                                 // is non blocking or even if write is blocking
   1971                                 // when a stop/pause/flush is issued from another thread.
   1972                                 final int kBatchFrames = 1000;
   1973                                 int ret = track.write(bb,
   1974                                         Math.min(bufferSize - written, frameSize * kBatchFrames),
   1975                                         TEST_WRITE_MODE);
   1976                                 // for non-blocking mode, this loop may spin quickly
   1977                                 assertTrue(TEST_NAME + ": write error " + ret, ret >= 0);
   1978                                 assertTrue(TEST_NAME + ": write timeout",
   1979                                         (System.currentTimeMillis() - startTime) <= maxDuration);
   1980                                 written += ret;
   1981                             }
   1982 
   1983                             // for streaming tracks, stop will allow the rest of the data to
   1984                             // drain out, but we don't know how long to wait unless
   1985                             // we check the position before stop. if we check position
   1986                             // after we stop, we read 0.
   1987                             final int position = track.getPlaybackHeadPosition();
   1988                             final int remainingTimeMs = (int)((double)(frameCount - position)
   1989                                     * 1000 / TEST_SR);
   1990                             track.stop();
   1991                             Thread.sleep(remainingTimeMs);
   1992                             // tear down
   1993                             track.release();
   1994                             // add a gap to make tones distinct
   1995                             Thread.sleep(100 /* millis */);
   1996                             frequency += 200; // increment test tone frequency
   1997                         }
   1998                     }
   1999                 }
   2000             }
   2001         }
   2002     }
   2003 
   2004     private boolean hasAudioOutput() {
   2005         return getContext().getPackageManager()
   2006             .hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
   2007     }
   2008 
   2009     private boolean isLowRamDevice() {
   2010         return ((ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE))
   2011                 .isLowRamDevice();
   2012     }
   2013 
   2014     public void testGetTimestamp() throws Exception {
   2015         if (!hasAudioOutput()) {
   2016             Log.w(TAG, "AUDIO_OUTPUT feature not found. This system might not have a valid "
   2017                     + "audio output HAL");
   2018             return;
   2019         }
   2020         String streamName = "test_get_timestamp";
   2021         doTestTimestamp(
   2022                 22050 /* sampleRate */,
   2023                 AudioFormat.CHANNEL_OUT_MONO ,
   2024                 AudioFormat.ENCODING_PCM_16BIT,
   2025                 AudioTrack.MODE_STREAM,
   2026                 streamName);
   2027     }
   2028 
   2029     public void testFastTimestamp() throws Exception {
   2030         if (!hasAudioOutput()) {
   2031             Log.w(TAG, "AUDIO_OUTPUT feature not found. This system might not have a valid "
   2032                     + "audio output HAL");
   2033             return;
   2034         }
   2035         String streamName = "test_fast_timestamp";
   2036         doTestTimestamp(
   2037                 AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC),
   2038                 AudioFormat.CHANNEL_OUT_MONO,
   2039                 AudioFormat.ENCODING_PCM_16BIT,
   2040                 AudioTrack.MODE_STREAM,
   2041                 streamName);
   2042     }
   2043 
   2044     private void doTestTimestamp(int sampleRate, int channelMask, int encoding, int transferMode,
   2045             String streamName) throws Exception {
   2046         // constants for test
   2047         final String TEST_NAME = "testGetTimestamp";
   2048         final int TEST_LOOP_CNT = 10;
   2049         final int TEST_BUFFER_MS = 100;
   2050         final int TEST_USAGE = AudioAttributes.USAGE_MEDIA;
   2051         // For jitter we allow 30 msec in frames.  This is a large margin.
   2052         // Often this is just 0 or 1 frames, but that can depend on hardware.
   2053         final int TEST_JITTER_FRAMES_ALLOWED = sampleRate * 30 / 1000;
   2054 
   2055         // -------- initialization --------------
   2056         final int frameSize =
   2057                 AudioFormat.getBytesPerSample(encoding)
   2058                 * AudioFormat.channelCountFromOutChannelMask(channelMask);
   2059         // see whether we can use fast mode
   2060         final int nativeOutputSampleRate =
   2061                 AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
   2062         Log.d(TAG, "Native output sample rate " + nativeOutputSampleRate);
   2063         final boolean fast = (sampleRate == nativeOutputSampleRate);
   2064 
   2065         AudioAttributes attributes = (fast ? new AudioAttributes.Builder()
   2066                 .setFlags(AudioAttributes.FLAG_LOW_LATENCY) : new AudioAttributes.Builder())
   2067                 .setUsage(TEST_USAGE)
   2068                 .build();
   2069         AudioFormat format = new AudioFormat.Builder()
   2070                 //.setChannelIndexMask((1 << AudioFormat.channelCountFromOutChannelMask(channelMask)) - 1)
   2071                 .setChannelMask(channelMask)
   2072                 .setEncoding(encoding)
   2073                 .setSampleRate(sampleRate)
   2074                 .build();
   2075         // not specifying the buffer size in the builder should get us the minimum buffer size.
   2076         AudioTrack track = new AudioTrack.Builder()
   2077                 .setAudioAttributes(attributes)
   2078                 .setAudioFormat(format)
   2079                 .setTransferMode(transferMode)
   2080                 .build();
   2081         assertEquals(AudioTrack.STATE_INITIALIZED, track.getState());
   2082         // We generally use a transfer size of 100ms for testing, but in rare cases
   2083         // (e.g. Bluetooth) this needs to be larger to exceed the internal track buffer.
   2084         final int frameCount =
   2085                 Math.max(track.getBufferCapacityInFrames(), sampleRate * TEST_BUFFER_MS / 1000);
   2086         track.play();
   2087 
   2088         ByteBuffer data = ByteBuffer.allocate(frameCount * frameSize);
   2089         data.order(java.nio.ByteOrder.nativeOrder()).limit(frameCount * frameSize);
   2090         AudioTimestamp timestamp = new AudioTimestamp();
   2091         long framesWritten = 0, lastFramesPresented = 0, lastFramesPresentedAt = 0;
   2092         int cumulativeJitterCount = 0;
   2093         int differentials = 0;
   2094         float cumulativeJitter = 0;
   2095         float maxJitter = 0;
   2096         for (int i = 0; i < TEST_LOOP_CNT; i++) {
   2097             final long writeTime = System.nanoTime();
   2098 
   2099             data.position(0);
   2100             assertEquals(data.limit(),
   2101                     track.write(data, data.limit(), AudioTrack.WRITE_BLOCKING));
   2102             assertEquals(data.position(), data.limit());
   2103             framesWritten += data.limit() / frameSize;
   2104 
   2105             // track.getTimestamp may return false if there are no physical HAL outputs.
   2106             // This may occur on TV devices without connecting an HDMI monitor.
   2107             // It may also be true immediately after start-up, as the mixing thread could
   2108             // be idle, but since we've already pushed much more than the minimum buffer size,
   2109             // that is unlikely.
   2110             // Nevertheless, we don't want to have unnecessary failures, so we ignore the
   2111             // first iteration if we don't get a timestamp.
   2112             final boolean result = track.getTimestamp(timestamp);
   2113             assertTrue("timestamp could not be read", result || i == 0);
   2114             if (!result) {
   2115                 continue;
   2116             }
   2117 
   2118             final long framesPresented = timestamp.framePosition;
   2119             final long framesPresentedAt = timestamp.nanoTime;
   2120 
   2121             // We read timestamp here to ensure that seen is greater than presented.
   2122             // This is an "on-the-fly" read without pausing because pausing may cause the
   2123             // timestamp to become stale and affect our jitter measurements.
   2124             final int framesSeen = track.getPlaybackHeadPosition();
   2125             assertTrue("server frames ahead of client frames", framesWritten >= framesSeen);
   2126             assertTrue("presented frames ahead of server frames", framesSeen >= framesPresented);
   2127 
   2128             if (i > 0) { // need delta info from previous iteration (skipping first)
   2129                 final long deltaFrames = framesPresented - lastFramesPresented;
   2130                 final long deltaTime = framesPresentedAt - lastFramesPresentedAt;
   2131                 final long NANOSECONDS_PER_SECOND = 1000000000;
   2132                 final long expectedFrames = deltaTime * sampleRate / NANOSECONDS_PER_SECOND;
   2133                 final long jitterFrames = Math.abs(deltaFrames - expectedFrames);
   2134 
   2135                 Log.d(TAG, "framesWritten(" + framesWritten
   2136                         + ") framesSeen(" + framesSeen
   2137                         + ") framesPresented(" + framesPresented
   2138                         + ") framesPresentedAt(" + framesPresentedAt
   2139                         + ") lastframesPresented(" + lastFramesPresented
   2140                         + ") lastFramesPresentedAt(" + lastFramesPresentedAt
   2141                         + ") deltaFrames(" + deltaFrames
   2142                         + ") deltaTime(" + deltaTime
   2143                         + ") expectedFrames(" + expectedFrames
   2144                         + ") writeTime(" + writeTime
   2145                         + ") jitter(" + jitterFrames + ")");
   2146                 assertTrue("timestamp time should be increasing", deltaTime >= 0);
   2147                 assertTrue("timestamp frames should be increasing", deltaFrames >= 0);
   2148 
   2149                 // the first nonzero value may have a jump, wait for the second.
   2150                 if (lastFramesPresented != 0) {
   2151                     if (differentials++ > 1) {
   2152                         // We check that the timestamp position is reasonably accurate.
   2153                         assertTrue("jitterFrames(" + jitterFrames + ") < "
   2154                                 + TEST_JITTER_FRAMES_ALLOWED,
   2155                                 jitterFrames < TEST_JITTER_FRAMES_ALLOWED);
   2156                         cumulativeJitter += jitterFrames;
   2157                         cumulativeJitterCount++;
   2158                         if (jitterFrames > maxJitter) {
   2159                             maxJitter = jitterFrames;
   2160                         }
   2161                     }
   2162                     final long NANOS_PER_SECOND = 1000000000;
   2163                     final long closeTimeNs = frameCount * 2 * NANOS_PER_SECOND / sampleRate;
   2164                     // We check that the timestamp time is reasonably current.
   2165                     assertTrue("framesPresentedAt(" + framesPresentedAt
   2166                             + ") close to writeTime(" + writeTime
   2167                             + ") tolerance(" + closeTimeNs
   2168                             + ")", Math.abs(framesPresentedAt - writeTime) <= closeTimeNs);
   2169                     assertTrue("timestamps must have causal time",
   2170                             writeTime >= lastFramesPresentedAt);
   2171                 }
   2172             }
   2173             lastFramesPresented = framesPresented;
   2174             lastFramesPresentedAt = framesPresentedAt;
   2175         }
   2176         // Full drain.
   2177         Thread.sleep(1000 /* millis */);
   2178         // check that we are really at the end of playback.
   2179         assertTrue("timestamp should be valid while draining", track.getTimestamp(timestamp));
   2180         // fast tracks and sw emulated tracks may not fully drain.  we log the status here.
   2181         if (framesWritten != timestamp.framePosition) {
   2182             Log.d(TAG, "timestamp should fully drain.  written: "
   2183                     + framesWritten + " position: " + timestamp.framePosition);
   2184         }
   2185         assertTrue("sufficient nonzero timestamps", differentials > 2);
   2186 
   2187         track.release();
   2188         // Log the average jitter
   2189         if (cumulativeJitterCount > 0) {
   2190             DeviceReportLog log = new DeviceReportLog(REPORT_LOG_NAME, streamName);
   2191             final float averageJitterInFrames = cumulativeJitter / cumulativeJitterCount;
   2192             final float averageJitterInMs = averageJitterInFrames * 1000 / sampleRate;
   2193             final float maxJitterInMs = maxJitter * 1000 / sampleRate;
   2194             // ReportLog needs at least one Value and Summary.
   2195             log.addValue("maximum_jitter", maxJitterInMs,
   2196                     ResultType.LOWER_BETTER, ResultUnit.MS);
   2197             log.setSummary("average_jitter", averageJitterInMs,
   2198                     ResultType.LOWER_BETTER, ResultUnit.MS);
   2199             log.submit(getInstrumentation());
   2200         }
   2201     }
   2202 
   2203     public void testVariableRatePlayback() throws Exception {
   2204         final String TEST_NAME = "testVariableRatePlayback";
   2205         final int TEST_SR = 24000;
   2206         final int TEST_FINAL_SR = 96000;
   2207         final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
   2208         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT; // required for test
   2209         final int TEST_MODE = AudioTrack.MODE_STATIC; // required for test
   2210         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   2211 
   2212         final int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
   2213         final int bufferSizeInBytes = minBuffSize * 100;
   2214         final int numChannels =  AudioFormat.channelCountFromOutChannelMask(TEST_CONF);
   2215         final int bytesPerSample = AudioFormat.getBytesPerSample(TEST_FORMAT);
   2216         final int bytesPerFrame = numChannels * bytesPerSample;
   2217         final int frameCount = bufferSizeInBytes / bytesPerFrame;
   2218 
   2219         AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF,
   2220                 TEST_FORMAT, bufferSizeInBytes, TEST_MODE);
   2221 
   2222         // create byte array and write it
   2223         byte[] vai = AudioHelper.createSoundDataInByteArray(bufferSizeInBytes, TEST_SR,
   2224                 600 /* frequency */, 0 /* sweep */);
   2225         assertEquals(vai.length, track.write(vai, 0 /* offsetInBytes */, vai.length));
   2226 
   2227         // sweep up test and sweep down test
   2228         int[] sampleRates = {TEST_SR, TEST_FINAL_SR};
   2229         int[] deltaMss = {10, 10};
   2230         int[] deltaFreqs = {200, -200};
   2231 
   2232         for (int i = 0; i < 2; ++i) {
   2233             int remainingTime;
   2234             int sampleRate = sampleRates[i];
   2235             final int deltaMs = deltaMss[i];
   2236             final int deltaFreq = deltaFreqs[i];
   2237             final int lastCheckMs = 500; // check the last 500 ms
   2238 
   2239             assertEquals(TEST_NAME, AudioTrack.SUCCESS, track.setPlaybackRate(sampleRate));
   2240             track.play();
   2241             do {
   2242                 Thread.sleep(deltaMs);
   2243                 final int position = track.getPlaybackHeadPosition();
   2244                 sampleRate += deltaFreq;
   2245                 sampleRate = Math.min(TEST_FINAL_SR, Math.max(TEST_SR, sampleRate));
   2246                 assertEquals(TEST_NAME, AudioTrack.SUCCESS, track.setPlaybackRate(sampleRate));
   2247                 remainingTime = (int)((double)(frameCount - position) * 1000
   2248                         / sampleRate / bytesPerFrame);
   2249             } while (remainingTime >= lastCheckMs + deltaMs);
   2250 
   2251             // ensure the final frequency set is constant and plays frames as expected
   2252             final int position1 = track.getPlaybackHeadPosition();
   2253             Thread.sleep(lastCheckMs);
   2254             final int position2 = track.getPlaybackHeadPosition();
   2255 
   2256             final int tolerance60MsInFrames = sampleRate * 60 / 1000;
   2257             final int expected = lastCheckMs * sampleRate / 1000;
   2258             final int actual = position2 - position1;
   2259 
   2260             // Log.d(TAG, "Variable Playback: expected(" + expected + ")  actual(" + actual
   2261             //        + ")  diff(" + (expected - actual) + ")");
   2262             assertEquals(expected, actual, tolerance60MsInFrames);
   2263             track.stop();
   2264         }
   2265         track.release();
   2266     }
   2267 
   2268     // Test that AudioTrack stop limits drain to only those frames written at the time of stop.
   2269     // This ensures consistent stop behavior on Android P and beyond, where data written
   2270     // immediately after a stop doesn't get caught in the drain.
   2271     @LargeTest
   2272     public void testStopDrain() throws Exception {
   2273         final String TEST_NAME = "testStopDrain";
   2274         final int TEST_SR = 8000;
   2275         final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO; // required for test
   2276         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT; // required for test
   2277         final int TEST_MODE = AudioTrack.MODE_STREAM; // required for test
   2278         final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
   2279 
   2280         final int channelCount = AudioFormat.channelCountFromOutChannelMask(TEST_CONF);
   2281         final int bytesPerSample = AudioFormat.getBytesPerSample(TEST_FORMAT);
   2282         final int bytesPerFrame = channelCount * bytesPerSample;
   2283         final int frameCount = TEST_SR * 3; // 3 seconds of buffer.
   2284         final int bufferSizeInBytes = frameCount * bytesPerFrame;
   2285 
   2286         final AudioTrack track = new AudioTrack(
   2287                 TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT, bufferSizeInBytes, TEST_MODE);
   2288 
   2289         try {
   2290             // Create 6 seconds of data, but send down only 3 seconds to fill buffer.
   2291             final byte[] soundData = AudioHelper.createSoundDataInByteArray(
   2292                     bufferSizeInBytes * 2, TEST_SR, 600 /* frequency */, 0 /* sweep */);
   2293             assertEquals("cannot fill AudioTrack buffer",
   2294                     bufferSizeInBytes,
   2295                     track.write(soundData, 0 /* offsetInBytes */, bufferSizeInBytes));
   2296 
   2297             // Set the track playing.
   2298             track.play();
   2299 
   2300             // Note that the timings here are very generous for our test (really the
   2301             // granularity we need is on the order of a second).  If we don't get scheduled
   2302             // to run within about a second or so - this should be extremely rare -
   2303             // the result should be a false pass (rather than a false fail).
   2304 
   2305             // After 1.5 seconds stop.
   2306             Thread.sleep(1500 /* millis */); // Assume device starts within 1.5 sec.
   2307             track.stop();
   2308 
   2309             // We should drain 1.5 seconds and fill another 3 seconds of data.
   2310             // We shouldn't be able to write 6 seconds of data - that indicates stop continues
   2311             // to drain beyond the frames written at the time of stop.
   2312             int length = 0;
   2313             while (length < soundData.length) {
   2314                 Thread.sleep(800 /* millis */); // assume larger than AF thread loop period
   2315                 final int delta = track.write(soundData, length, soundData.length - length);
   2316                 assertTrue("track write error: " + delta, delta >= 0);
   2317                 if (delta == 0) break;
   2318                 length += delta;
   2319             }
   2320 
   2321             // Check to see we limit the data drained (should be able to exactly fill the buffer).
   2322             assertEquals("stop drain must be limited " + bufferSizeInBytes + " != " + length,
   2323                     bufferSizeInBytes, length);
   2324         } finally {
   2325             track.release();
   2326         }
   2327     }
   2328 
   2329     public void testVariableSpeedPlayback() throws Exception {
   2330         if (!hasAudioOutput()) {
   2331             Log.w(TAG,"AUDIO_OUTPUT feature not found. This system might not have a valid "
   2332                     + "audio output HAL");
   2333             return;
   2334         }
   2335 
   2336         final String TEST_NAME = "testVariableSpeedPlayback";
   2337         final int TEST_FORMAT = AudioFormat.ENCODING_PCM_FLOAT; // required for test
   2338         final int TEST_MODE = AudioTrack.MODE_STATIC;           // required for test
   2339         final int TEST_SR = 48000;
   2340 
   2341         AudioFormat format = new AudioFormat.Builder()
   2342                 //.setChannelIndexMask((1 << 0))  // output to first channel, FL
   2343                 .setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
   2344                 .setEncoding(TEST_FORMAT)
   2345                 .setSampleRate(TEST_SR)
   2346                 .build();
   2347 
   2348         // create track
   2349         final int frameCount = AudioHelper.frameCountFromMsec(100 /*ms*/, format);
   2350         final int frameSize = AudioHelper.frameSizeFromFormat(format);
   2351         AudioTrack track = new AudioTrack.Builder()
   2352                 .setAudioFormat(format)
   2353                 .setBufferSizeInBytes(frameCount * frameSize)
   2354                 .setTransferMode(TEST_MODE)
   2355                 .build();
   2356 
   2357         // create float array and write it
   2358         final int sampleCount = frameCount * format.getChannelCount();
   2359         float[] vaf = AudioHelper.createSoundDataInFloatArray(
   2360                 sampleCount, TEST_SR, 600 /* frequency */, 0 /* sweep */);
   2361         assertEquals(vaf.length, track.write(vaf, 0 /* offsetInFloats */, vaf.length,
   2362                 AudioTrack.WRITE_NON_BLOCKING));
   2363 
   2364         // sweep speed and pitch
   2365         final float[][][] speedAndPitch = {
   2366              // { {speedStart, pitchStart} {speedEnd, pitchEnd} }
   2367                 { {0.5f, 0.5f}, {2.0f, 2.0f} },  // speed by SR conversion (chirp)
   2368                 { {0.5f, 1.0f}, {2.0f, 1.0f} },  // speed by time stretch (constant pitch)
   2369                 { {1.0f, 0.5f}, {1.0f, 2.0f} },  // pitch by SR conversion (chirp)
   2370         };
   2371 
   2372         // sanity test that playback params works as expected
   2373         PlaybackParams params = new PlaybackParams().allowDefaults();
   2374         assertEquals(TEST_NAME, 1.0f, params.getSpeed());
   2375         assertEquals(TEST_NAME, 1.0f, params.getPitch());
   2376         assertEquals(TEST_NAME,
   2377                 params.AUDIO_FALLBACK_MODE_DEFAULT,
   2378                 params.getAudioFallbackMode());
   2379         track.setPlaybackParams(params); // OK
   2380         params.setAudioFallbackMode(params.AUDIO_FALLBACK_MODE_FAIL);
   2381         assertEquals(TEST_NAME,
   2382                 params.AUDIO_FALLBACK_MODE_FAIL, params.getAudioFallbackMode());
   2383         params.setPitch(0.0f);
   2384         try {
   2385             track.setPlaybackParams(params);
   2386             fail("IllegalArgumentException should be thrown on out of range data");
   2387         } catch (IllegalArgumentException e) {
   2388             ; // expect this is invalid
   2389         }
   2390         // on failure, the AudioTrack params should not change.
   2391         PlaybackParams paramCheck = track.getPlaybackParams();
   2392         assertEquals(TEST_NAME,
   2393                 paramCheck.AUDIO_FALLBACK_MODE_DEFAULT, paramCheck.getAudioFallbackMode());
   2394         assertEquals(TEST_NAME,
   2395                 1.0f, paramCheck.getPitch());
   2396 
   2397         // now try to see if we can do extreme pitch correction that should probably be muted.
   2398         params.setAudioFallbackMode(params.AUDIO_FALLBACK_MODE_MUTE);
   2399         assertEquals(TEST_NAME,
   2400                 params.AUDIO_FALLBACK_MODE_MUTE, params.getAudioFallbackMode());
   2401         params.setPitch(0.1f);
   2402         track.setPlaybackParams(params); // OK
   2403 
   2404         // now do our actual playback
   2405         final int TEST_TIME_MS = 2000;
   2406         final int TEST_DELTA_MS = 100;
   2407         final int testSteps = TEST_TIME_MS / TEST_DELTA_MS;
   2408 
   2409         for (int i = 0; i < speedAndPitch.length; ++i) {
   2410             final float speedStart = speedAndPitch[i][0][0];
   2411             final float pitchStart = speedAndPitch[i][0][1];
   2412             final float speedEnd = speedAndPitch[i][1][0];
   2413             final float pitchEnd = speedAndPitch[i][1][1];
   2414             final float speedInc = (speedEnd - speedStart) / testSteps;
   2415             final float pitchInc = (pitchEnd - pitchStart) / testSteps;
   2416 
   2417             PlaybackParams playbackParams = new PlaybackParams()
   2418                     .setPitch(pitchStart)
   2419                     .setSpeed(speedStart)
   2420                     .allowDefaults();
   2421 
   2422             // set track in infinite loop to be a sine generator
   2423             track.setLoopPoints(0, frameCount, -1 /* loopCount */); // cleared by stop()
   2424             track.play();
   2425 
   2426             Thread.sleep(300 /* millis */); // warm up track
   2427 
   2428             int anticipatedPosition = track.getPlaybackHeadPosition();
   2429             for (int j = 0; j < testSteps; ++j) {
   2430                 // set playback settings
   2431                 final float pitch = playbackParams.getPitch();
   2432                 final float speed = playbackParams.getSpeed();
   2433 
   2434                 track.setPlaybackParams(playbackParams);
   2435 
   2436                 // verify that settings have changed
   2437                 PlaybackParams checkParams = track.getPlaybackParams();
   2438                 assertEquals(TAG, pitch, checkParams.getPitch());
   2439                 assertEquals(TAG, speed, checkParams.getSpeed());
   2440 
   2441                 // sleep for playback
   2442                 Thread.sleep(TEST_DELTA_MS);
   2443                 // Log.d(TAG, "position[" + j + "] " + track.getPlaybackHeadPosition());
   2444                 anticipatedPosition +=
   2445                         playbackParams.getSpeed() * TEST_DELTA_MS * TEST_SR / 1000;
   2446                 playbackParams.setPitch(playbackParams.getPitch() + pitchInc);
   2447                 playbackParams.setSpeed(playbackParams.getSpeed() + speedInc);
   2448             }
   2449             final int endPosition = track.getPlaybackHeadPosition();
   2450             final int tolerance100MsInFrames = 100 * TEST_SR / 1000;
   2451             assertEquals(TAG, anticipatedPosition, endPosition, tolerance100MsInFrames);
   2452             track.stop();
   2453 
   2454             Thread.sleep(100 /* millis */); // distinct pause between each test
   2455         }
   2456         track.release();
   2457     }
   2458 
   2459     // Test AudioTrack to ensure we can build after a failure.
   2460     public void testAudioTrackBufferSize() throws Exception {
   2461         // constants for test
   2462         final String TEST_NAME = "testAudioTrackBufferSize";
   2463 
   2464         // use builder with parameters that should fail
   2465         final int superBigBufferSize = 1 << 28;
   2466         try {
   2467             final AudioTrack track = new AudioTrack.Builder()
   2468                 .setBufferSizeInBytes(superBigBufferSize)
   2469                 .build();
   2470             track.release();
   2471             fail(TEST_NAME + ": should throw exception on failure");
   2472         } catch (UnsupportedOperationException e) {
   2473             ;
   2474         }
   2475 
   2476         // we should be able to create again with minimum buffer size
   2477         final int verySmallBufferSize = 2 * 3 * 4; // frame size multiples
   2478         final AudioTrack track2 = new AudioTrack.Builder()
   2479                 .setBufferSizeInBytes(verySmallBufferSize)
   2480                 .build();
   2481 
   2482         final int observedState2 = track2.getState();
   2483         final int observedBufferSize2 = track2.getBufferSizeInFrames();
   2484         track2.release();
   2485 
   2486         // succeeds for minimum buffer size
   2487         assertEquals(TEST_NAME + ": state", AudioTrack.STATE_INITIALIZED, observedState2);
   2488         // should force the minimum size buffer which is > 0
   2489         assertTrue(TEST_NAME + ": buffer frame count", observedBufferSize2 > 0);
   2490     }
   2491 
   2492     // Test AudioTrack to see if there are any problems with large frame counts.
   2493     public void testAudioTrackLargeFrameCount() throws Exception {
   2494         // constants for test
   2495         final String TEST_NAME = "testAudioTrackLargeFrameCount";
   2496         final int[] BUFFER_SIZES = { 4294968, 42949680, 429496800, Integer.MAX_VALUE };
   2497         final int[] MODES = { AudioTrack.MODE_STATIC, AudioTrack.MODE_STREAM };
   2498 
   2499         for (int mode : MODES) {
   2500             for (int bufferSizeInBytes : BUFFER_SIZES) {
   2501                 try {
   2502                     final AudioTrack track = new AudioTrack.Builder()
   2503                         .setAudioFormat(new AudioFormat.Builder()
   2504                             .setEncoding(AudioFormat.ENCODING_PCM_8BIT)
   2505                             .setSampleRate(44100)
   2506                             .setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
   2507                             .build())
   2508                         .setTransferMode(mode)
   2509                         .setBufferSizeInBytes(bufferSizeInBytes) // 1 byte == 1 frame
   2510                         .build();
   2511                     track.release(); // OK to successfully complete
   2512                 } catch (UnsupportedOperationException e) {
   2513                     ; // OK to throw unsupported exception
   2514                 }
   2515             }
   2516         }
   2517     }
   2518 
   2519     public void testSetPresentationDefaultTrack() throws Exception {
   2520         final AudioTrack track = new AudioTrack.Builder().build();
   2521         assertEquals(AudioTrack.ERROR, track.setPresentation(createAudioPresentation()));
   2522     }
   2523 
   2524 /* Do not run in JB-MR1. will be re-opened in the next platform release.
   2525     public void testResourceLeakage() throws Exception {
   2526         final int BUFFER_SIZE = 600 * 1024;
   2527         ByteBuffer data = ByteBuffer.allocate(BUFFER_SIZE);
   2528         for (int i = 0; i < 10; i++) {
   2529             Log.i(TAG, "testResourceLeakage round " + i);
   2530             data.rewind();
   2531             AudioTrack track = new AudioTrack(AudioManager.STREAM_VOICE_CALL,
   2532                                               44100,
   2533                                               AudioFormat.CHANNEL_OUT_STEREO,
   2534                                               AudioFormat.ENCODING_PCM_16BIT,
   2535                                               data.capacity(),
   2536                                               AudioTrack.MODE_STREAM);
   2537             assertTrue(track != null);
   2538             track.write(data.array(), 0, data.capacity());
   2539             track.play();
   2540             Thread.sleep(100);
   2541             track.stop();
   2542             track.release();
   2543         }
   2544     }
   2545 */
   2546 
   2547     /* MockAudioTrack allows testing of protected getNativeFrameCount() and setState(). */
   2548     private class MockAudioTrack extends AudioTrack {
   2549 
   2550         public MockAudioTrack(int streamType, int sampleRateInHz, int channelConfig,
   2551                 int audioFormat, int bufferSizeInBytes, int mode) throws IllegalArgumentException {
   2552             super(streamType, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, mode);
   2553         }
   2554 
   2555         public void setState(int state) {
   2556             super.setState(state);
   2557         }
   2558 
   2559         public int getNativeFrameCount() {
   2560             return super.getNativeFrameCount();
   2561         }
   2562     }
   2563 
   2564     private static AudioPresentation createAudioPresentation() {
   2565         return new AudioPresentation(
   2566                 42 /*presentationId*/,
   2567                 43 /*programId*/,
   2568                 new HashMap<String, String>(),
   2569                 Locale.US.toString(),
   2570                 AudioPresentation.MASTERING_NOT_INDICATED,
   2571                 false /*audioDescriptionAvailable*/,
   2572                 false /*spokenSubtitlesAvailable*/,
   2573                 false /*dialogueEnhancementAvailable*/);
   2574     }
   2575 }
   2576