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