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.BassBoost; 23 import android.os.Looper; 24 import android.test.AndroidTestCase; 25 import android.util.Log; 26 27 public class BassBoostTest extends PostProcTestBase { 28 29 private String TAG = "BassBoostTest"; 30 private final static short TEST_STRENGTH = 500; 31 private final static short TEST_STRENGTH2 = 1000; 32 private final static float STRENGTH_TOLERANCE = 1.1f; // 10% 33 private final static int MAX_LOOPER_WAIT_COUNT = 10; 34 35 private BassBoost mBassBoost = null; 36 private BassBoost mBassBoost2 = null; 37 private ListenerThread mEffectListenerLooper = null; 38 39 //----------------------------------------------------------------- 40 // BASS BOOST TESTS: 41 //---------------------------------- 42 43 //----------------------------------------------------------------- 44 // 0 - constructor 45 //---------------------------------- 46 47 //Test case 0.0: test constructor and release 48 public void test0_0ConstructorAndRelease() throws Exception { 49 if (!isBassBoostAvailable()) { 50 return; 51 } 52 BassBoost eq = null; 53 try { 54 eq = new BassBoost(0, getSessionId()); 55 try { 56 assertTrue("invalid effect ID", (eq.getId() != 0)); 57 } catch (IllegalStateException e) { 58 fail("BassBoost not initialized"); 59 } 60 // test passed 61 } catch (IllegalArgumentException e) { 62 fail("BassBoost not found"); 63 } catch (UnsupportedOperationException e) { 64 fail("Effect library not loaded"); 65 } finally { 66 if (eq != null) { 67 eq.release(); 68 } 69 } 70 } 71 72 73 //----------------------------------------------------------------- 74 // 1 - get/set parameters 75 //---------------------------------- 76 77 //Test case 1.0: test strength 78 public void test1_0Strength() throws Exception { 79 if (!isBassBoostAvailable()) { 80 return; 81 } 82 getBassBoost(getSessionId()); 83 try { 84 if (mBassBoost.getStrengthSupported()) { 85 short strength = mBassBoost.getRoundedStrength(); 86 strength = (strength == TEST_STRENGTH) ? TEST_STRENGTH2 : TEST_STRENGTH; 87 mBassBoost.setStrength((short)strength); 88 short strength2 = mBassBoost.getRoundedStrength(); 89 // allow STRENGTH_TOLERANCE difference between set strength and rounded strength 90 assertTrue("got incorrect strength", 91 ((float)strength2 > (float)strength / STRENGTH_TOLERANCE) && 92 ((float)strength2 < (float)strength * STRENGTH_TOLERANCE)); 93 } else { 94 short strength = mBassBoost.getRoundedStrength(); 95 assertTrue("got incorrect strength", strength >= 0 && strength <= 1000); 96 } 97 // test passed 98 } catch (IllegalArgumentException e) { 99 fail("Bad parameter value"); 100 } catch (UnsupportedOperationException e) { 101 fail("get parameter() rejected"); 102 } catch (IllegalStateException e) { 103 fail("get parameter() called in wrong state"); 104 } finally { 105 releaseBassBoost(); 106 } 107 } 108 109 //Test case 1.1: test properties 110 public void test1_1Properties() throws Exception { 111 if (!isBassBoostAvailable()) { 112 return; 113 } 114 getBassBoost(getSessionId()); 115 try { 116 BassBoost.Settings settings = mBassBoost.getProperties(); 117 String str = settings.toString(); 118 settings = new BassBoost.Settings(str); 119 120 short strength = settings.strength; 121 if (mBassBoost.getStrengthSupported()) { 122 strength = (strength == TEST_STRENGTH) ? TEST_STRENGTH2 : TEST_STRENGTH; 123 } 124 settings.strength = strength; 125 mBassBoost.setProperties(settings); 126 settings = mBassBoost.getProperties(); 127 128 if (mBassBoost.getStrengthSupported()) { 129 // allow STRENGTH_TOLERANCE difference between set strength and rounded strength 130 assertTrue("got incorrect strength", 131 ((float)settings.strength > (float)strength / STRENGTH_TOLERANCE) && 132 ((float)settings.strength < (float)strength * STRENGTH_TOLERANCE)); 133 } 134 // test passed 135 } catch (IllegalArgumentException e) { 136 fail("Bad parameter value"); 137 } catch (UnsupportedOperationException e) { 138 fail("get parameter() rejected"); 139 } catch (IllegalStateException e) { 140 fail("get parameter() called in wrong state"); 141 } finally { 142 releaseBassBoost(); 143 } 144 } 145 146 //Test case 1.2: test setStrength() throws exception after release 147 public void test1_2SetStrengthAfterRelease() throws Exception { 148 if (!isBassBoostAvailable()) { 149 return; 150 } 151 getBassBoost(getSessionId()); 152 mBassBoost.release(); 153 try { 154 mBassBoost.setStrength(TEST_STRENGTH); 155 fail("setStrength() processed after release()"); 156 } catch (IllegalStateException e) { 157 // test passed 158 } finally { 159 releaseBassBoost(); 160 } 161 } 162 163 //----------------------------------------------------------------- 164 // 2 - Effect enable/disable 165 //---------------------------------- 166 167 //Test case 2.0: test setEnabled() and getEnabled() in valid state 168 public void test2_0SetEnabledGetEnabled() throws Exception { 169 if (!isBassBoostAvailable()) { 170 return; 171 } 172 getBassBoost(getSessionId()); 173 try { 174 mBassBoost.setEnabled(true); 175 assertTrue("invalid state from getEnabled", mBassBoost.getEnabled()); 176 mBassBoost.setEnabled(false); 177 assertFalse("invalid state to getEnabled", mBassBoost.getEnabled()); 178 // test passed 179 } catch (IllegalStateException e) { 180 fail("setEnabled() in wrong state"); 181 } finally { 182 releaseBassBoost(); 183 } 184 } 185 186 //Test case 2.1: test setEnabled() throws exception after release 187 public void test2_1SetEnabledAfterRelease() throws Exception { 188 if (!isBassBoostAvailable()) { 189 return; 190 } 191 getBassBoost(getSessionId()); 192 mBassBoost.release(); 193 try { 194 mBassBoost.setEnabled(true); 195 fail("setEnabled() processed after release()"); 196 } catch (IllegalStateException e) { 197 // test passed 198 } finally { 199 releaseBassBoost(); 200 } 201 } 202 203 //----------------------------------------------------------------- 204 // 3 priority and listeners 205 //---------------------------------- 206 207 //Test case 3.0: test control status listener 208 public void test3_0ControlStatusListener() throws Exception { 209 if (!isBassBoostAvailable()) { 210 return; 211 } 212 synchronized(mLock) { 213 mHasControl = true; 214 mInitialized = false; 215 createListenerLooper(true, false, false); 216 waitForLooperInitialization_l(); 217 218 getBassBoost(mSession); 219 int looperWaitCount = MAX_LOOPER_WAIT_COUNT; 220 while (mHasControl && (looperWaitCount-- > 0)) { 221 try { 222 mLock.wait(); 223 } catch(Exception e) { 224 } 225 } 226 terminateListenerLooper(); 227 releaseBassBoost(); 228 } 229 assertFalse("effect control not lost by effect1", mHasControl); 230 } 231 232 //Test case 3.1: test enable status listener 233 public void test3_1EnableStatusListener() throws Exception { 234 if (!isBassBoostAvailable()) { 235 return; 236 } 237 synchronized(mLock) { 238 mInitialized = false; 239 createListenerLooper(false, true, false); 240 waitForLooperInitialization_l(); 241 242 mBassBoost2.setEnabled(true); 243 mIsEnabled = true; 244 getBassBoost(mSession); 245 mBassBoost.setEnabled(false); 246 int looperWaitCount = MAX_LOOPER_WAIT_COUNT; 247 while (mIsEnabled && (looperWaitCount-- > 0)) { 248 try { 249 mLock.wait(); 250 } catch(Exception e) { 251 } 252 } 253 terminateListenerLooper(); 254 releaseBassBoost(); 255 } 256 assertFalse("enable status not updated", mIsEnabled); 257 } 258 259 //Test case 3.2: test parameter changed listener 260 public void test3_2ParameterChangedListener() throws Exception { 261 if (!isBassBoostAvailable()) { 262 return; 263 } 264 synchronized(mLock) { 265 mInitialized = false; 266 createListenerLooper(false, false, true); 267 waitForLooperInitialization_l(); 268 269 getBassBoost(mSession); 270 mChangedParameter = -1; 271 mBassBoost.setStrength(TEST_STRENGTH); 272 int looperWaitCount = MAX_LOOPER_WAIT_COUNT; 273 while ((mChangedParameter == -1) && (looperWaitCount-- > 0)) { 274 try { 275 mLock.wait(); 276 } catch(Exception e) { 277 } 278 } 279 terminateListenerLooper(); 280 releaseBassBoost(); 281 } 282 assertEquals("parameter change not received", 283 BassBoost.PARAM_STRENGTH, mChangedParameter); 284 } 285 286 //----------------------------------------------------------------- 287 // private methods 288 //---------------------------------- 289 290 private void getBassBoost(int session) { 291 if (mBassBoost == null || session != mSession) { 292 if (session != mSession && mBassBoost != null) { 293 mBassBoost.release(); 294 mBassBoost = null; 295 } 296 try { 297 mBassBoost = new BassBoost(0, session); 298 mSession = session; 299 } catch (IllegalArgumentException e) { 300 Log.e(TAG, "getBassBoost() BassBoost not found exception: "+e); 301 } catch (UnsupportedOperationException e) { 302 Log.e(TAG, "getBassBoost() Effect library not loaded exception: "+e); 303 } 304 } 305 assertNotNull("could not create mBassBoost", mBassBoost); 306 } 307 308 private void releaseBassBoost() { 309 if (mBassBoost != null) { 310 mBassBoost.release(); 311 mBassBoost = null; 312 } 313 } 314 315 private void waitForLooperInitialization_l() { 316 int looperWaitCount = MAX_LOOPER_WAIT_COUNT; 317 while (!mInitialized && (looperWaitCount-- > 0)) { 318 try { 319 mLock.wait(); 320 } catch(Exception e) { 321 } 322 } 323 assertTrue(mInitialized); 324 } 325 326 // Initializes the bassboot listener looper 327 class ListenerThread extends Thread { 328 boolean mControl; 329 boolean mEnable; 330 boolean mParameter; 331 332 public ListenerThread(boolean control, boolean enable, boolean parameter) { 333 super(); 334 mControl = control; 335 mEnable = enable; 336 mParameter = parameter; 337 } 338 339 public void cleanUp() { 340 if (mBassBoost2 != null) { 341 mBassBoost2.setControlStatusListener(null); 342 mBassBoost2.setEnableStatusListener(null); 343 mBassBoost2.setParameterListener( 344 (BassBoost.OnParameterChangeListener)null); 345 } 346 } 347 } 348 349 private void createListenerLooper(boolean control, boolean enable, boolean parameter) { 350 mEffectListenerLooper = new ListenerThread(control, enable, parameter) { 351 @Override 352 public void run() { 353 // Set up a looper 354 Looper.prepare(); 355 356 // Save the looper so that we can terminate this thread 357 // after we are done with it. 358 mLooper = Looper.myLooper(); 359 360 mSession = getSessionId(); 361 mBassBoost2 = new BassBoost(0, mSession); 362 assertNotNull("could not create bassboot2", mBassBoost2); 363 364 synchronized(mLock) { 365 if (mControl) { 366 mBassBoost2.setControlStatusListener( 367 new AudioEffect.OnControlStatusChangeListener() { 368 public void onControlStatusChange( 369 AudioEffect effect, boolean controlGranted) { 370 synchronized(mLock) { 371 if (effect == mBassBoost2) { 372 mHasControl = controlGranted; 373 mLock.notify(); 374 } 375 } 376 } 377 }); 378 } 379 if (mEnable) { 380 mBassBoost2.setEnableStatusListener( 381 new AudioEffect.OnEnableStatusChangeListener() { 382 public void onEnableStatusChange(AudioEffect effect, boolean enabled) { 383 synchronized(mLock) { 384 if (effect == mBassBoost2) { 385 mIsEnabled = enabled; 386 mLock.notify(); 387 } 388 } 389 } 390 }); 391 } 392 if (mParameter) { 393 mBassBoost2.setParameterListener(new BassBoost.OnParameterChangeListener() { 394 public void onParameterChange(BassBoost effect, int status, 395 int param, short value) 396 { 397 synchronized(mLock) { 398 if (effect == mBassBoost2) { 399 mChangedParameter = param; 400 mLock.notify(); 401 } 402 } 403 } 404 }); 405 } 406 407 mInitialized = true; 408 mLock.notify(); 409 } 410 Looper.loop(); // Blocks forever until Looper.quit() is called. 411 } 412 }; 413 mEffectListenerLooper.start(); 414 } 415 416 // Terminates the listener looper thread. 417 private void terminateListenerLooper() { 418 if (mEffectListenerLooper != null) { 419 mEffectListenerLooper.cleanUp(); 420 if (mLooper != null) { 421 mLooper.quit(); 422 mLooper = null; 423 } 424 try { 425 mEffectListenerLooper.join(); 426 } catch(InterruptedException e) { 427 } 428 mEffectListenerLooper = null; 429 } 430 431 if (mBassBoost2 != null) { 432 mBassBoost2.release(); 433 mBassBoost2 = null; 434 } 435 } 436 } 437