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 }