Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2010 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.media.audiofx.AudioEffect;
     20 import android.media.AudioFormat;
     21 import android.media.AudioManager;
     22 import android.media.audiofx.EnvironmentalReverb;
     23 import android.os.Looper;
     24 import android.platform.test.annotations.AppModeFull;
     25 import android.test.AndroidTestCase;
     26 import android.util.Log;
     27 
     28 @AppModeFull(reason = "Fails in instant mode")
     29 public class EnvReverbTest extends PostProcTestBase {
     30 
     31     private String TAG = "EnvReverbTest";
     32     private final static int MILLIBEL_TOLERANCE = 100;            // +/-1dB
     33     private final static float DELAY_TOLERANCE = 1.05f;           // 5%
     34     private final static float RATIO_TOLERANCE = 1.05f;           // 5%
     35     private final static int MAX_LOOPER_WAIT_COUNT = 10;
     36 
     37     private EnvironmentalReverb mReverb = null;
     38     private EnvironmentalReverb mReverb2 = null;
     39     private ListenerThread mEffectListenerLooper = null;
     40 
     41     //-----------------------------------------------------------------
     42     // ENVIRONMENTAL REVERB TESTS:
     43     //----------------------------------
     44 
     45     //-----------------------------------------------------------------
     46     // 0 - constructor
     47     //----------------------------------
     48 
     49     //Test case 0.0: test constructor and release
     50     public void test0_0ConstructorAndRelease() throws Exception {
     51         if (!isEnvReverbAvailable()) {
     52             return;
     53         }
     54         EnvironmentalReverb envReverb = null;
     55          try {
     56             envReverb = new EnvironmentalReverb(0, 0);
     57             try {
     58                 assertTrue("invalid effect ID", (envReverb.getId() != 0));
     59             } catch (IllegalStateException e) {
     60                 fail("EnvironmentalReverb not initialized");
     61             }
     62         } catch (IllegalArgumentException e) {
     63             fail("EnvironmentalReverb not found");
     64         } catch (UnsupportedOperationException e) {
     65             fail("Effect library not loaded");
     66         } finally {
     67             if (envReverb != null) {
     68                 envReverb.release();
     69             }
     70         }
     71     }
     72 
     73 
     74     //-----------------------------------------------------------------
     75     // 1 - get/set parameters
     76     //----------------------------------
     77 
     78     //Test case 1.0: test room level and room HF level
     79     public void test1_0Room() throws Exception {
     80         if (!isEnvReverbAvailable()) {
     81             return;
     82         }
     83         getReverb(0);
     84         try {
     85             short level = mReverb.getRoomLevel();
     86             level = (short)((level == 0) ? -1000 : 0);
     87             mReverb.setRoomLevel(level);
     88             short level2 = mReverb.getRoomLevel();
     89             assertTrue("got incorrect room level",
     90                     (level2 > (level - MILLIBEL_TOLERANCE)) &&
     91                     (level2 < (level + MILLIBEL_TOLERANCE)));
     92 
     93             level = mReverb.getRoomHFLevel();
     94             level = (short)((level == 0) ? -1000 : 0);
     95             mReverb.setRoomHFLevel(level);
     96             level2 = mReverb.getRoomHFLevel();
     97             assertTrue("got incorrect room HF level",
     98                     (level2 > (level - MILLIBEL_TOLERANCE)) &&
     99                     (level2 < (level + MILLIBEL_TOLERANCE)));
    100 
    101         } catch (IllegalArgumentException e) {
    102             fail("Bad parameter value");
    103         } catch (UnsupportedOperationException e) {
    104             fail("get parameter() rejected");
    105         } catch (IllegalStateException e) {
    106             fail("get parameter() called in wrong state");
    107         } finally {
    108             releaseReverb();
    109         }
    110     }
    111 
    112     //Test case 1.1: test decay time and ratio
    113     public void test1_1Decay() throws Exception {
    114         if (!isEnvReverbAvailable()) {
    115             return;
    116         }
    117         getReverb(0);
    118         try {
    119             int time = mReverb.getDecayTime();
    120             time = (time == 500) ? 1000 : 500;
    121             mReverb.setDecayTime(time);
    122             int time2 = mReverb.getDecayTime();
    123             assertTrue("got incorrect decay time",
    124                     ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
    125                     ((float)time2 < (float)(time * DELAY_TOLERANCE)));
    126             short ratio = mReverb.getDecayHFRatio();
    127             ratio = (short)((ratio == 500) ? 1000 : 500);
    128             mReverb.setDecayHFRatio(ratio);
    129             short ratio2 = mReverb.getDecayHFRatio();
    130             assertTrue("got incorrect decay HF ratio",
    131                     ((float)ratio2 > (float)(ratio / RATIO_TOLERANCE)) &&
    132                     ((float)ratio2 < (float)(ratio * RATIO_TOLERANCE)));
    133 
    134         } catch (IllegalArgumentException e) {
    135             fail("Bad parameter value");
    136         } catch (UnsupportedOperationException e) {
    137             fail("get parameter() rejected");
    138         } catch (IllegalStateException e) {
    139             fail("get parameter() called in wrong state");
    140         } finally {
    141             releaseReverb();
    142         }
    143     }
    144 
    145 
    146     //Test case 1.2: test reverb level and delay
    147     public void test1_2Reverb() throws Exception {
    148         if (!isEnvReverbAvailable()) {
    149             return;
    150         }
    151         getReverb(0);
    152         try {
    153             short level = mReverb.getReverbLevel();
    154             level = (short)((level == 0) ? -1000 : 0);
    155             mReverb.setReverbLevel(level);
    156             short level2 = mReverb.getReverbLevel();
    157             assertTrue("got incorrect reverb level",
    158                     (level2 > (level - MILLIBEL_TOLERANCE)) &&
    159                     (level2 < (level + MILLIBEL_TOLERANCE)));
    160 
    161 // FIXME:uncomment actual test when early reflections are implemented in the reverb
    162 //            int time = mReverb.getReverbDelay();
    163 //             mReverb.setReverbDelay(time);
    164 //            int time2 = mReverb.getReverbDelay();
    165 //            assertTrue("got incorrect reverb delay",
    166 //                    ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
    167 //                    ((float)time2 < (float)(time * DELAY_TOLERANCE)));
    168             mReverb.setReverbDelay(0);
    169             int time2 = mReverb.getReverbDelay();
    170             assertEquals("got incorrect reverb delay", mReverb.getReverbDelay(), 0);
    171         } catch (IllegalArgumentException e) {
    172             fail("Bad parameter value");
    173         } catch (UnsupportedOperationException e) {
    174             fail("get parameter() rejected");
    175         } catch (IllegalStateException e) {
    176             fail("get parameter() called in wrong state");
    177         } finally {
    178             releaseReverb();
    179         }
    180     }
    181 
    182     //Test case 1.3: test early reflections level and delay
    183     public void test1_3Reflections() throws Exception {
    184         if (!isEnvReverbAvailable()) {
    185             return;
    186         }
    187         getReverb(0);
    188         try {
    189 // FIXME:uncomment actual test when early reflections are implemented in the reverb
    190 //            short level = mReverb.getReflectionsLevel();
    191 //            level = (short)((level == 0) ? -1000 : 0);
    192 //            mReverb.setReflectionsLevel(level);
    193 //            short level2 = mReverb.getReflectionsLevel();
    194 //            assertTrue("got incorrect reflections level",
    195 //                    (level2 > (level - MILLIBEL_TOLERANCE)) &&
    196 //                    (level2 < (level + MILLIBEL_TOLERANCE)));
    197 //
    198 //            int time = mReverb.getReflectionsDelay();
    199 //            time = (time == 20) ? 0 : 20;
    200 //            mReverb.setReflectionsDelay(time);
    201 //            int time2 = mReverb.getReflectionsDelay();
    202 //            assertTrue("got incorrect reflections delay",
    203 //                    ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
    204 //                    ((float)time2 < (float)(time * DELAY_TOLERANCE)));
    205             mReverb.setReflectionsLevel((short) 0);
    206             assertEquals("got incorrect reverb delay",
    207                     mReverb.getReflectionsLevel(), (short) 0);
    208             mReverb.setReflectionsDelay(0);
    209             assertEquals("got incorrect reverb delay",
    210                     mReverb.getReflectionsDelay(), 0);
    211 
    212         } catch (IllegalArgumentException e) {
    213             fail("Bad parameter value");
    214         } catch (UnsupportedOperationException e) {
    215             fail("get parameter() rejected");
    216         } catch (IllegalStateException e) {
    217             fail("get parameter() called in wrong state");
    218         } finally {
    219             releaseReverb();
    220         }
    221     }
    222 
    223     //Test case 1.4: test diffusion and density
    224     public void test1_4DiffusionAndDensity() throws Exception {
    225         if (!isEnvReverbAvailable()) {
    226             return;
    227         }
    228         getReverb(0);
    229         try {
    230             short ratio = mReverb.getDiffusion();
    231             ratio = (short)((ratio == 500) ? 1000 : 500);
    232             mReverb.setDiffusion(ratio);
    233             short ratio2 = mReverb.getDiffusion();
    234             assertTrue("got incorrect diffusion",
    235                     ((float)ratio2 > (float)(ratio / RATIO_TOLERANCE)) &&
    236                     ((float)ratio2 < (float)(ratio * RATIO_TOLERANCE)));
    237 
    238             ratio = mReverb.getDensity();
    239             ratio = (short)((ratio == 500) ? 1000 : 500);
    240             mReverb.setDensity(ratio);
    241             ratio2 = mReverb.getDensity();
    242             assertTrue("got incorrect density",
    243                     ((float)ratio2 > (float)(ratio / RATIO_TOLERANCE)) &&
    244                     ((float)ratio2 < (float)(ratio * RATIO_TOLERANCE)));
    245 
    246         } catch (IllegalArgumentException e) {
    247             fail("Bad parameter value");
    248         } catch (UnsupportedOperationException e) {
    249             fail("get parameter() rejected");
    250         } catch (IllegalStateException e) {
    251             fail("get parameter() called in wrong state");
    252         } finally {
    253             releaseReverb();
    254         }
    255     }
    256 
    257     //Test case 1.5: test properties
    258     public void test1_5Properties() throws Exception {
    259         if (!isEnvReverbAvailable()) {
    260             return;
    261         }
    262         getReverb(0);
    263         try {
    264             EnvironmentalReverb.Settings settings = mReverb.getProperties();
    265             String str = settings.toString();
    266             settings = new EnvironmentalReverb.Settings(str);
    267             short level = (short)((settings.roomLevel == 0) ? -1000 : 0);
    268             settings.roomLevel = level;
    269             mReverb.setProperties(settings);
    270             settings = mReverb.getProperties();
    271             assertTrue("setProperties failed",
    272                     (settings.roomLevel >= (level - MILLIBEL_TOLERANCE)) &&
    273                     (settings.roomLevel <= (level + MILLIBEL_TOLERANCE)));
    274         } catch (IllegalArgumentException e) {
    275             fail("Bad parameter value");
    276         } catch (UnsupportedOperationException e) {
    277             fail("get parameter() rejected");
    278         } catch (IllegalStateException e) {
    279             fail("get parameter() called in wrong state");
    280         } finally {
    281             releaseReverb();
    282         }
    283     }
    284 
    285     //-----------------------------------------------------------------
    286     // 2 - Effect enable/disable
    287     //----------------------------------
    288 
    289     //Test case 2.0: test setEnabled() and getEnabled() in valid state
    290     public void test2_0SetEnabledGetEnabled() throws Exception {
    291         if (!isEnvReverbAvailable()) {
    292             return;
    293         }
    294         getReverb(0);
    295         try {
    296             mReverb.setEnabled(true);
    297             assertTrue("invalid state from getEnabled", mReverb.getEnabled());
    298             mReverb.setEnabled(false);
    299             assertFalse("invalid state to getEnabled", mReverb.getEnabled());
    300         } catch (IllegalStateException e) {
    301             fail("setEnabled() in wrong state");
    302         } finally {
    303             releaseReverb();
    304         }
    305     }
    306 
    307     //Test case 2.1: test setEnabled() throws exception after release
    308     public void test2_1SetEnabledAfterRelease() throws Exception {
    309         if (!isEnvReverbAvailable()) {
    310             return;
    311         }
    312         getReverb(0);
    313         mReverb.release();
    314         try {
    315             mReverb.setEnabled(true);
    316             fail("setEnabled() processed after release()");
    317         } catch (IllegalStateException e) {
    318             // test passed
    319         } finally {
    320             releaseReverb();
    321         }
    322     }
    323 
    324     //-----------------------------------------------------------------
    325     // 3 priority and listeners
    326     //----------------------------------
    327 
    328     //Test case 3.0: test control status listener
    329     public void test3_0ControlStatusListener() throws Exception {
    330         if (!isEnvReverbAvailable()) {
    331             return;
    332         }
    333         synchronized(mLock) {
    334             mHasControl = true;
    335             mInitialized = false;
    336             createListenerLooper(true, false, false);
    337             waitForLooperInitialization_l();
    338 
    339             getReverb(0);
    340             int looperWaitCount = MAX_LOOPER_WAIT_COUNT;
    341             while (mHasControl && (looperWaitCount-- > 0)) {
    342                 try {
    343                     mLock.wait();
    344                 } catch(Exception e) {
    345                 }
    346             }
    347             terminateListenerLooper();
    348             releaseReverb();
    349         }
    350         assertFalse("effect control not lost by effect1", mHasControl);
    351     }
    352 
    353     //Test case 3.1: test enable status listener
    354     public void test3_1EnableStatusListener() throws Exception {
    355         if (!isEnvReverbAvailable()) {
    356             return;
    357         }
    358          synchronized(mLock) {
    359             mInitialized = false;
    360             createListenerLooper(false, true, false);
    361             waitForLooperInitialization_l();
    362 
    363             mReverb2.setEnabled(true);
    364             mIsEnabled = true;
    365             getReverb(0);
    366             mReverb.setEnabled(false);
    367             int looperWaitCount = MAX_LOOPER_WAIT_COUNT;
    368             while (mIsEnabled && (looperWaitCount-- > 0)) {
    369                 try {
    370                     mLock.wait();
    371                 } catch(Exception e) {
    372                 }
    373             }
    374             terminateListenerLooper();
    375             releaseReverb();
    376         }
    377         assertFalse("enable status not updated", mIsEnabled);
    378     }
    379 
    380     //Test case 3.2: test parameter changed listener
    381     public void test3_2ParameterChangedListener() throws Exception {
    382         if (!isEnvReverbAvailable()) {
    383             return;
    384         }
    385         synchronized(mLock) {
    386             mInitialized = false;
    387             createListenerLooper(false, false, true);
    388             waitForLooperInitialization_l();
    389 
    390             getReverb(0);
    391             mChangedParameter = -1;
    392             mReverb.setRoomLevel((short)0);
    393 
    394             int looperWaitCount = MAX_LOOPER_WAIT_COUNT;
    395             while ((mChangedParameter == -1) && (looperWaitCount-- > 0)) {
    396                 try {
    397                     mLock.wait();
    398                 } catch(Exception e) {
    399                 }
    400             }
    401             terminateListenerLooper();
    402             releaseReverb();
    403         }
    404         assertEquals("parameter change not received",
    405                 EnvironmentalReverb.PARAM_ROOM_LEVEL, mChangedParameter);
    406     }
    407 
    408     //-----------------------------------------------------------------
    409     // private methods
    410     //----------------------------------
    411 
    412     private void getReverb(int session) {
    413          if (mReverb == null || session != mSession) {
    414              if (session != mSession && mReverb != null) {
    415                  mReverb.release();
    416                  mReverb = null;
    417              }
    418              try {
    419                 mReverb = new EnvironmentalReverb(0, session);
    420                 mSession = session;
    421             } catch (IllegalArgumentException e) {
    422                 Log.e(TAG, "getReverb() EnvironmentalReverb not found exception: "+e);
    423             } catch (UnsupportedOperationException e) {
    424                 Log.e(TAG, "getReverb() Effect library not loaded exception: "+e);
    425             }
    426          }
    427          assertNotNull("could not create mReverb", mReverb);
    428     }
    429 
    430     private void releaseReverb() {
    431         if (mReverb != null) {
    432             mReverb.release();
    433             mReverb = null;
    434         }
    435     }
    436 
    437     private void waitForLooperInitialization_l() {
    438         int looperWaitCount = MAX_LOOPER_WAIT_COUNT;
    439         while (!mInitialized && (looperWaitCount-- > 0)) {
    440             try {
    441                 mLock.wait();
    442             } catch(Exception e) {
    443             }
    444         }
    445         assertTrue(mInitialized);
    446     }
    447 
    448     // Initializes the reverb listener looper
    449     class ListenerThread extends Thread {
    450         boolean mControl;
    451         boolean mEnable;
    452         boolean mParameter;
    453 
    454         public ListenerThread(boolean control, boolean enable, boolean parameter) {
    455             super();
    456             mControl = control;
    457             mEnable = enable;
    458             mParameter = parameter;
    459         }
    460 
    461         public void cleanUp() {
    462             if (mReverb2 != null) {
    463                 mReverb2.setControlStatusListener(null);
    464                 mReverb2.setEnableStatusListener(null);
    465                 mReverb2.setParameterListener(
    466                             (EnvironmentalReverb.OnParameterChangeListener)null);
    467             }
    468         }
    469     }
    470 
    471     private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
    472         mEffectListenerLooper = new ListenerThread(control, enable, parameter) {
    473             @Override
    474             public void run() {
    475                 // Set up a looper
    476                 Looper.prepare();
    477 
    478                 // Save the looper so that we can terminate this thread
    479                 // after we are done with it.
    480                 mLooper = Looper.myLooper();
    481 
    482                 mReverb2 = new EnvironmentalReverb(0, 0);
    483                 assertNotNull("could not create reverb2", mReverb2);
    484 
    485                 synchronized(mLock) {
    486                     if (mControl) {
    487                         mReverb2.setControlStatusListener(
    488                                 new AudioEffect.OnControlStatusChangeListener() {
    489                             public void onControlStatusChange(
    490                                     AudioEffect effect, boolean controlGranted) {
    491                                 synchronized(mLock) {
    492                                     if (effect == mReverb2) {
    493                                         mHasControl = controlGranted;
    494                                         mLock.notify();
    495                                     }
    496                                 }
    497                             }
    498                         });
    499                     }
    500                     if (mEnable) {
    501                         mReverb2.setEnableStatusListener(
    502                                 new AudioEffect.OnEnableStatusChangeListener() {
    503                             public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
    504                                 synchronized(mLock) {
    505                                     if (effect == mReverb2) {
    506                                         mIsEnabled = enabled;
    507                                         mLock.notify();
    508                                     }
    509                                 }
    510                             }
    511                         });
    512                     }
    513                     if (mParameter) {
    514                         mReverb2.setParameterListener(new EnvironmentalReverb.OnParameterChangeListener() {
    515                             public void onParameterChange(EnvironmentalReverb effect,
    516                                     int status, int param, int value)
    517                             {
    518                                 synchronized(mLock) {
    519                                     if (effect == mReverb2) {
    520                                         mChangedParameter = param;
    521                                         mLock.notify();
    522                                     }
    523                                 }
    524                             }
    525                         });
    526                     }
    527 
    528                     mInitialized = true;
    529                     mLock.notify();
    530                 }
    531                 Looper.loop();  // Blocks forever until Looper.quit() is called.
    532             }
    533         };
    534         mEffectListenerLooper.start();
    535     }
    536 
    537     // Terminates the listener looper thread.
    538     private void terminateListenerLooper() {
    539         if (mEffectListenerLooper != null) {
    540             mEffectListenerLooper.cleanUp();
    541             if (mLooper != null) {
    542                 mLooper.quit();
    543                 mLooper = null;
    544             }
    545             try {
    546                 mEffectListenerLooper.join();
    547             } catch(InterruptedException e) {
    548             }
    549             mEffectListenerLooper = null;
    550         }
    551         if (mReverb2 != null) {
    552             mReverb2.release();
    553             mReverb2 = null;
    554         }
    555     }
    556 }