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