Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.media.cts;
     18 
     19 import android.app.ActivityManager;
     20 import android.content.Context;
     21 import android.content.pm.PackageManager;
     22 import android.media.AudioDeviceInfo;
     23 import android.media.AudioManager;
     24 
     25 import com.android.compatibility.common.util.CtsAndroidTestCase;
     26 
     27 public class AudioNativeTest extends CtsAndroidTestCase {
     28     public static final int MAX_CHANNEL_COUNT = 2;
     29     public static final int MAX_INDEX_MASK = (1 << MAX_CHANNEL_COUNT) - 1;
     30 
     31     private static final int CHANNEL_INDEX_MASK_MAGIC = 0x80000000;
     32 
     33     public void testAppendixBBufferQueue() {
     34         nativeAppendixBBufferQueue();
     35     }
     36 
     37     public void testAppendixBRecording() {
     38         // better to detect presence of microphone here.
     39         if (!hasMicrophone()) {
     40             return;
     41         }
     42         nativeAppendixBRecording();
     43     }
     44 
     45     public void testStereo16Playback() {
     46         assertTrue(AudioTrackNative.test(
     47                 2 /* numChannels */, 48000 /* sampleRate */, false /* useFloat */,
     48                 20 /* msecPerBuffer */, 8 /* numBuffers */));
     49     }
     50 
     51     public void testStereo16Record() {
     52         if (!hasMicrophone()) {
     53             return;
     54         }
     55         assertTrue(AudioRecordNative.test(
     56                 2 /* numChannels */, 48000 /* sampleRate */, false /* useFloat */,
     57                 20 /* msecPerBuffer */, 8 /* numBuffers */));
     58     }
     59 
     60     public void testPlayStreamData() throws Exception {
     61         final String TEST_NAME = "testPlayStreamData";
     62         final boolean TEST_FLOAT_ARRAY[] = {
     63                 false,
     64                 true,
     65         };
     66         // due to downmixer algorithmic latency, source channels greater than 2 may
     67         // sound shorter in duration at 4kHz sampling rate.
     68         final int TEST_SR_ARRAY[] = {
     69                 /* 4000, */ // below limit of OpenSL ES
     70                 12345, // irregular sampling rate
     71                 44100,
     72                 48000,
     73                 96000,
     74                 192000,
     75         };
     76         final int TEST_CHANNELS_ARRAY[] = {
     77                 1,
     78                 2,
     79                 3,
     80                 4,
     81                 5,
     82                 6,
     83                 7,
     84                 // 8  // can fail due to memory issues
     85         };
     86         final float TEST_SWEEP = 0; // sine wave only
     87         final int TEST_TIME_IN_MSEC = 300;
     88         final int TOLERANCE_MSEC = 20;
     89         final boolean TEST_IS_LOW_RAM_DEVICE = isLowRamDevice();
     90         final long TEST_END_SLEEP_MSEC = TEST_IS_LOW_RAM_DEVICE ? 200 : 50;
     91 
     92         for (boolean TEST_FLOAT : TEST_FLOAT_ARRAY) {
     93             double frequency = 400; // frequency changes for each test
     94             for (int TEST_SR : TEST_SR_ARRAY) {
     95                 for (int TEST_CHANNELS : TEST_CHANNELS_ARRAY) {
     96                     // OpenSL ES BUG: we run out of AudioTrack memory for this config on MNC
     97                     // Log.d(TEST_NAME, "open channels:" + TEST_CHANNELS + " sr:" + TEST_SR);
     98                     if (TEST_IS_LOW_RAM_DEVICE && (TEST_CHANNELS > 4 || TEST_SR > 96000)) {
     99                         continue;
    100                     }
    101                     if (TEST_FLOAT == true && TEST_CHANNELS >= 6 && TEST_SR >= 192000) {
    102                         continue;
    103                     }
    104                     AudioTrackNative track = new AudioTrackNative();
    105                     assertTrue(TEST_NAME,
    106                             track.open(TEST_CHANNELS, TEST_SR, TEST_FLOAT, 1 /* numBuffers */));
    107                     assertTrue(TEST_NAME, track.start());
    108 
    109                     final int sourceSamples =
    110                             (int)((long)TEST_SR * TEST_TIME_IN_MSEC * TEST_CHANNELS / 1000);
    111                     final double testFrequency = frequency / TEST_CHANNELS;
    112                     if (TEST_FLOAT) {
    113                         float data[] = AudioHelper.createSoundDataInFloatArray(
    114                                 sourceSamples, TEST_SR,
    115                                 testFrequency, TEST_SWEEP);
    116                         assertEquals(sourceSamples,
    117                                 track.write(data, 0 /* offset */, sourceSamples,
    118                                         AudioTrackNative.WRITE_FLAG_BLOCKING));
    119                     } else {
    120                         short data[] = AudioHelper.createSoundDataInShortArray(
    121                                 sourceSamples, TEST_SR,
    122                                 testFrequency, TEST_SWEEP);
    123                         assertEquals(sourceSamples,
    124                                 track.write(data, 0 /* offset */, sourceSamples,
    125                                         AudioTrackNative.WRITE_FLAG_BLOCKING));
    126                     }
    127 
    128                     while (true) {
    129                         // OpenSL ES BUG: getPositionInMsec returns 0 after a data underrun.
    130 
    131                         long position = track.getPositionInMsec();
    132                         //Log.d(TEST_NAME, "position: " + position[0]);
    133                         if (position >= (long)(TEST_TIME_IN_MSEC - TOLERANCE_MSEC)) {
    134                             break;
    135                         }
    136 
    137                         // It is safer to use a buffer count of 0 to determine termination
    138                         if (track.getBuffersPending() == 0) {
    139                             break;
    140                         }
    141                         Thread.sleep(5 /* millis */);
    142                     }
    143                     track.stop();
    144                     Thread.sleep(TEST_END_SLEEP_MSEC);
    145                     track.close();
    146                     Thread.sleep(TEST_END_SLEEP_MSEC); // put a gap in the tone sequence
    147                     frequency += 50; // increment test tone frequency
    148                 }
    149             }
    150         }
    151     }
    152 
    153     private boolean isLowRamDevice() {
    154         return ((ActivityManager)getContext().getSystemService(Context.ACTIVITY_SERVICE)
    155                 ).isLowRamDevice();
    156     }
    157 
    158     public void testRecordStreamData() throws Exception {
    159         if (!hasMicrophone()) {
    160             return;
    161         }
    162         final String TEST_NAME = "testRecordStreamData";
    163         final boolean TEST_FLOAT_ARRAY[] = {
    164                 false,
    165                 true,
    166         };
    167         final int TEST_SR_ARRAY[] = {
    168                 //4000, // below limit of OpenSL ES
    169                 12345, // irregular sampling rate
    170                 44100,
    171                 48000,
    172                 96000,
    173                 192000,
    174         };
    175         final int TEST_CHANNELS_ARRAY[] = {
    176                 1,
    177                 2,
    178                 3,
    179                 4,
    180                 5,
    181                 6,
    182                 7,
    183                 8,
    184         };
    185         final int SEGMENT_DURATION_IN_MSEC = 20;
    186         final int NUMBER_SEGMENTS = 10;
    187 
    188         for (boolean TEST_FLOAT : TEST_FLOAT_ARRAY) {
    189             for (int TEST_SR : TEST_SR_ARRAY) {
    190                 for (int TEST_CHANNELS : TEST_CHANNELS_ARRAY) {
    191                     // OpenSL ES BUG: we run out of AudioTrack memory for this config on MNC
    192                     if (TEST_FLOAT == true && TEST_CHANNELS >= 8 && TEST_SR >= 192000) {
    193                         continue;
    194                     }
    195                     AudioRecordNative record = new AudioRecordNative();
    196                     doRecordTest(record, TEST_CHANNELS, TEST_SR, TEST_FLOAT,
    197                             SEGMENT_DURATION_IN_MSEC, NUMBER_SEGMENTS);
    198                 }
    199             }
    200         }
    201     }
    202 
    203     public void testRecordAudit() throws Exception {
    204         if (!hasMicrophone()) {
    205             return;
    206         }
    207         AudioRecordNative record = new AudioHelper.AudioRecordAuditNative();
    208         doRecordTest(record, 4 /* numChannels */, 44100 /* sampleRate */, false /* useFloat */,
    209                 1000 /* segmentDurationMs */, 10 /* numSegments */);
    210     }
    211 
    212     public void testOutputChannelMasks() {
    213         if (!hasAudioOutput()) {
    214             return;
    215         }
    216         AudioTrackNative track = new AudioTrackNative();
    217 
    218         int maxOutputChannels = 2;
    219         int validIndexMask = (1 << maxOutputChannels) - 1;
    220 
    221         for (int mask = 0; mask <= MAX_INDEX_MASK; ++mask) {
    222             int channelCount = Long.bitCount(mask);
    223             boolean expectSuccess = (channelCount > 0)
    224                 && ((mask & validIndexMask) != 0);
    225 
    226             // TODO: uncomment this line when b/27484181 is fixed.
    227             // expectSuccess &&= ((mask & ~validIndexMask) == 0);
    228 
    229             boolean ok = track.open(channelCount,
    230                 mask | CHANNEL_INDEX_MASK_MAGIC, 48000, false, 2);
    231             track.close();
    232             assertEquals(expectSuccess, ok);
    233         }
    234     }
    235 
    236     public void testInputChannelMasks() {
    237         if (!hasMicrophone()) {
    238             return;
    239         }
    240 
    241         AudioManager audioManager =
    242                 (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
    243         AudioRecordNative recorder = new AudioRecordNative();
    244 
    245         int maxInputChannels = 0;
    246         for (AudioDeviceInfo deviceInfo :
    247                 audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)) {
    248             for (int channels : deviceInfo.getChannelCounts()) {
    249                 maxInputChannels = Math.max(channels, maxInputChannels);
    250             }
    251         }
    252 
    253         int validIndexMask = (1 << maxInputChannels) - 1;
    254 
    255         for (int mask = 0; mask <= MAX_INDEX_MASK; ++mask) {
    256             int channelCount = Long.bitCount(mask);
    257             boolean expectSuccess = (channelCount > 0)
    258                 && ((mask & validIndexMask) != 0);
    259 
    260             // TODO: uncomment this line when b/27484181 is fixed.
    261             // expectSuccess &&= ((mask & ~validIndexMask) == 0);
    262 
    263             boolean ok = recorder.open(channelCount,
    264                 mask | CHANNEL_INDEX_MASK_MAGIC, 48000, false, 2);
    265             recorder.close();
    266             assertEquals(expectSuccess, ok);
    267         }
    268     }
    269 
    270     static {
    271         System.loadLibrary("audio_jni");
    272     }
    273 
    274     private static final String TAG = "AudioNativeTest";
    275 
    276     private void doRecordTest(AudioRecordNative record,
    277             int numChannels, int sampleRate, boolean useFloat,
    278             int segmentDurationMs, int numSegments) {
    279         final String TEST_NAME = "doRecordTest";
    280         try {
    281             // Log.d(TEST_NAME, "open numChannels:" + numChannels + " sampleRate:" + sampleRate);
    282             assertTrue(TEST_NAME, record.open(numChannels, sampleRate, useFloat,
    283                     numSegments /* numBuffers */));
    284             assertTrue(TEST_NAME, record.start());
    285 
    286             final int sourceSamples =
    287                     (int)((long)sampleRate * segmentDurationMs * numChannels / 1000);
    288 
    289             if (useFloat) {
    290                 float data[] = new float[sourceSamples];
    291                 for (int i = 0; i < numSegments; ++i) {
    292                     assertEquals(sourceSamples,
    293                             record.read(data, 0 /* offset */, sourceSamples,
    294                                     AudioRecordNative.READ_FLAG_BLOCKING));
    295                 }
    296             } else {
    297                 short data[] = new short[sourceSamples];
    298                 for (int i = 0; i < numSegments; ++i) {
    299                     assertEquals(sourceSamples,
    300                             record.read(data, 0 /* offset */, sourceSamples,
    301                                     AudioRecordNative.READ_FLAG_BLOCKING));
    302                 }
    303             }
    304             assertTrue(TEST_NAME, record.stop());
    305         } finally {
    306             record.close();
    307         }
    308     }
    309 
    310     private boolean hasMicrophone() {
    311         return getContext().getPackageManager().hasSystemFeature(
    312                 PackageManager.FEATURE_MICROPHONE);
    313     }
    314 
    315     private boolean hasAudioOutput() {
    316         return getContext().getPackageManager().hasSystemFeature(
    317                 PackageManager.FEATURE_AUDIO_OUTPUT);
    318     }
    319 
    320     private static native void nativeAppendixBBufferQueue();
    321     private static native void nativeAppendixBRecording();
    322 }
    323