1 /* 2 * Copyright (c) 2009, Google Inc. 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 com.android.soundpooltest; 18 19 import android.app.Activity; 20 import android.widget.LinearLayout; 21 import android.os.Bundle; 22 import android.view.ViewGroup; 23 import android.widget.Button; 24 import android.view.View; 25 import android.view.View.OnClickListener; 26 import android.view.KeyEvent; 27 import android.media.AudioSystem; 28 import android.media.AudioManager; 29 import android.media.SoundPool; 30 import android.media.SoundPool.OnLoadCompleteListener; 31 import android.util.Log; 32 import java.util.HashMap; 33 import java.lang.Math; 34 35 import com.android.soundpooltest.R; 36 37 public class SoundPoolTest extends Activity 38 { 39 private static final String LOG_TAG = "SoundPoolTest"; 40 private static final boolean DEBUG = true; 41 private static final boolean VERBOSE = false; 42 private TestThread mThread; 43 44 private static final int[] mTestFiles = new int[] { 45 R.raw.organ441, 46 R.raw.sine441, 47 R.raw.test1, 48 R.raw.test2, 49 R.raw.test3, 50 R.raw.test4, 51 R.raw.test5 52 }; 53 54 private final static float SEMITONE = 1.059463094f; 55 private final static float DEFAULT_VOLUME = 0.707f; 56 private final static float MAX_VOLUME = 1.0f; 57 private final static float MIN_VOLUME = 0.01f; 58 private final static int LOW_PRIORITY = 1000; 59 private final static int NORMAL_PRIORITY = 2000; 60 private final static int HIGH_PRIORITY = 3000; 61 private final static int DEFAULT_LOOP = -1; 62 private final static int DEFAULT_SRC_QUALITY = 0; 63 private final static double PI_OVER_2 = Math.PI / 2.0; 64 SoundPoolTest()65 public SoundPoolTest() {} 66 67 private final class TestThread extends java.lang.Thread { 68 private boolean mRunning; 69 private SoundPool mSoundPool = null; 70 private int mLastSample; 71 private int mMaxStreams; 72 private int mLoadStatus; 73 private int[] mSounds; 74 private float mScale[]; 75 TestThread()76 TestThread() { 77 super("SoundPool.TestThread"); 78 } 79 80 private final class LoadCompleteCallback implements 81 android.media.SoundPool.OnLoadCompleteListener { onLoadComplete(SoundPool soundPool, int sampleId, int status)82 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { 83 synchronized(mSoundPool) { 84 if (DEBUG) Log.d(LOG_TAG, "Sample " + sampleId + " load status = " + status); 85 if (status != 0) { 86 mLoadStatus = status; 87 } 88 if (sampleId == mLastSample) { 89 mSoundPool.notify(); 90 } 91 } 92 } 93 } 94 loadSound(int resId, int priority)95 private int loadSound(int resId, int priority) { 96 int id = mSoundPool.load(getApplicationContext(), resId, priority); 97 if (id == 0) { 98 Log.e(LOG_TAG, "Unable to open resource"); 99 } 100 return id; 101 } 102 initSoundPool(int numStreams)103 private int initSoundPool(int numStreams) throws java.lang.InterruptedException { 104 105 if (mSoundPool != null) { 106 if ((mMaxStreams == numStreams) && (mLoadStatus == 0)) return mLoadStatus; 107 mSoundPool.release(); 108 mSoundPool = null; 109 } 110 111 // create sound pool 112 mLoadStatus = 0; 113 mMaxStreams = numStreams; 114 mSoundPool = new SoundPool(numStreams, AudioSystem.STREAM_MUSIC, 0); 115 mSoundPool.setOnLoadCompleteListener(new LoadCompleteCallback()); 116 int numSounds = mTestFiles.length; 117 mSounds = new int[numSounds]; 118 119 // load sounds 120 synchronized(mSoundPool) { 121 for (int index = 0; index < numSounds; index++) { 122 mSounds[index] = loadSound(mTestFiles[index], NORMAL_PRIORITY); 123 mLastSample = mSounds[index]; 124 } 125 mSoundPool.wait(); 126 } 127 return mLoadStatus; 128 } 129 TestSounds()130 private boolean TestSounds() throws java.lang.InterruptedException { 131 if (DEBUG) Log.d(LOG_TAG, "Begin sounds test"); 132 int count = mSounds.length; 133 for (int index = 0; index < count; index++) { 134 int id = mSoundPool.play(mSounds[index], DEFAULT_VOLUME, DEFAULT_VOLUME, 135 NORMAL_PRIORITY, DEFAULT_LOOP, 1.0f); 136 if (DEBUG) Log.d(LOG_TAG, "Start note " + id); 137 if (id == 0) { 138 Log.e(LOG_TAG, "Error occurred starting note"); 139 return false; 140 } 141 sleep(450); 142 mSoundPool.stop(id); 143 if (DEBUG) Log.d(LOG_TAG, "Stop note " + id); 144 sleep(50); 145 } 146 if (DEBUG) Log.d(LOG_TAG, "End sounds test"); 147 return true; 148 } 149 TestScales()150 private boolean TestScales() throws java.lang.InterruptedException { 151 if (DEBUG) Log.d(LOG_TAG, "Begin scale test"); 152 153 // interate through pitch table 154 int count = mScale.length; 155 for (int step = 0; step < count; step++) { 156 int id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME, 157 NORMAL_PRIORITY, DEFAULT_LOOP, mScale[step]); 158 if (DEBUG) Log.d(LOG_TAG, "Start note " + id); 159 if (id == 0) { 160 Log.e(LOG_TAG, "Error occurred starting note"); 161 return false; 162 } 163 sleep(450); 164 mSoundPool.stop(id); 165 if (DEBUG) Log.d(LOG_TAG, "Stop note " + id); 166 sleep(50); 167 } 168 if (DEBUG) Log.d(LOG_TAG, "End scale test"); 169 return true; 170 } 171 TestRates()172 private boolean TestRates() throws java.lang.InterruptedException { 173 if (DEBUG) Log.d(LOG_TAG, "Begin rate test"); 174 175 // start the note 176 int count = mScale.length; 177 int id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME, 178 NORMAL_PRIORITY, DEFAULT_LOOP, mScale[0]); 179 if (DEBUG) Log.d(LOG_TAG, "Start note " + id); 180 if (id == 0) { 181 Log.e(LOG_TAG, "Test failed - exiting"); 182 return false; 183 } 184 185 // modify the pitch 186 for (int step = 1; step < count; step++) { 187 sleep(250); 188 mSoundPool.setRate(id, mScale[step]); 189 if (DEBUG) Log.d(LOG_TAG, "Change rate " + mScale[step]); 190 } 191 mSoundPool.stop(id); 192 if (DEBUG) Log.d(LOG_TAG, "Stop note " + id); 193 if (DEBUG) Log.d(LOG_TAG, "End rate test"); 194 return true; 195 } 196 TestPriority()197 private boolean TestPriority() throws java.lang.InterruptedException { 198 if (DEBUG) Log.d(LOG_TAG, "Begin priority test"); 199 boolean result = true; 200 201 // play a normal priority looping sound 202 int normalId = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME, 203 NORMAL_PRIORITY, DEFAULT_LOOP, 1.0f); 204 if (DEBUG) Log.d(LOG_TAG, "Start note " + normalId); 205 if (normalId == 0) { 206 Log.e(LOG_TAG, "Error occurred starting note"); 207 return false; 208 } 209 sleep(1000); 210 211 // play a low priority sound 212 int id = mSoundPool.play(mSounds[1], DEFAULT_VOLUME, DEFAULT_VOLUME, 213 LOW_PRIORITY, DEFAULT_LOOP, 1.0f); 214 if (id != 0) { 215 Log.e(LOG_TAG, "Normal > Low priority test failed"); 216 result = false; 217 mSoundPool.stop(id); 218 } else { 219 sleep(1000); 220 Log.i(LOG_TAG, "Normal > Low priority test passed"); 221 } 222 223 // play a high priority sound 224 id = mSoundPool.play(mSounds[2], DEFAULT_VOLUME, DEFAULT_VOLUME, 225 HIGH_PRIORITY, DEFAULT_LOOP, 1.0f); 226 if (id == 0) { 227 Log.e(LOG_TAG, "High > Normal priority test failed"); 228 result = false; 229 } else { 230 sleep(1000); 231 Log.i(LOG_TAG, "Stopping high priority"); 232 mSoundPool.stop(id); 233 sleep(1000); 234 Log.i(LOG_TAG, "High > Normal priority test passed"); 235 } 236 237 // stop normal note 238 Log.i(LOG_TAG, "Stopping normal priority"); 239 mSoundPool.stop(normalId); 240 sleep(1000); 241 242 if (DEBUG) Log.d(LOG_TAG, "End priority test"); 243 return result; 244 } 245 TestPauseResume()246 private boolean TestPauseResume() throws java.lang.InterruptedException { 247 if (DEBUG) Log.d(LOG_TAG, "Begin pause/resume test"); 248 boolean result = true; 249 250 // play a normal priority looping sound 251 int id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME, 252 NORMAL_PRIORITY, DEFAULT_LOOP, 1.0f); 253 if (DEBUG) Log.d(LOG_TAG, "Start note " + id); 254 if (id == 0) { 255 Log.e(LOG_TAG, "Error occurred starting note"); 256 return false; 257 } 258 sleep(2500); 259 260 // pause and resume sound a few times 261 for (int count = 0; count < 5; count++) { 262 if (DEBUG) Log.d(LOG_TAG, "Pause note " + id); 263 mSoundPool.pause(id); 264 sleep(1000); 265 if (DEBUG) Log.d(LOG_TAG, "Resume note " + id); 266 mSoundPool.resume(id); 267 sleep(1000); 268 } 269 270 if (DEBUG) Log.d(LOG_TAG, "Stop note " + id); 271 mSoundPool.stop(id); 272 sleep(1000); 273 274 // play 5 sounds, forces one to be stolen 275 int ids[] = new int[5]; 276 for (int i = 0; i < 5; i++) { 277 ids[i] = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME, 278 NORMAL_PRIORITY, DEFAULT_LOOP, mScale[i]); 279 if (DEBUG) Log.d(LOG_TAG, "Start note " + ids[i]); 280 if (ids[i] == 0) { 281 Log.e(LOG_TAG, "Error occurred starting note"); 282 return false; 283 } 284 sleep(1000); 285 } 286 287 // pause and resume sound a few times 288 for (int count = 0; count < 5; count++) { 289 if (DEBUG) Log.d(LOG_TAG, "autoPause"); 290 mSoundPool.autoPause(); 291 sleep(1000); 292 if (DEBUG) Log.d(LOG_TAG, "autoResume"); 293 mSoundPool.autoResume(); 294 sleep(1000); 295 } 296 297 for (int i = 0; i < 5; i++) { 298 if (DEBUG) Log.d(LOG_TAG, "Stop note " + ids[i]); 299 mSoundPool.stop(ids[i]); 300 } 301 302 if (DEBUG) Log.d(LOG_TAG, "End pause/resume test"); 303 return result; 304 } 305 TestVolume()306 private boolean TestVolume() throws java.lang.InterruptedException { 307 if (DEBUG) Log.d(LOG_TAG, "Begin volume test"); 308 309 // start the note 310 int id = mSoundPool.play(mSounds[0], 0.0f, 1.0f, NORMAL_PRIORITY, DEFAULT_LOOP, mScale[0]); 311 if (DEBUG) Log.d(LOG_TAG, "Start note " + id); 312 if (id == 0) { 313 Log.e(LOG_TAG, "Test failed - exiting"); 314 return false; 315 } 316 317 // pan from right to left 318 for (int count = 0; count < 101; count++) { 319 sleep(50); 320 double radians = PI_OVER_2 * count / 100.0; 321 float leftVolume = (float) Math.sin(radians); 322 float rightVolume = (float) Math.cos(radians); 323 mSoundPool.setVolume(id, leftVolume, rightVolume); 324 if (DEBUG) Log.d(LOG_TAG, "Change volume (" + leftVolume + "," + rightVolume + ")"); 325 } 326 327 mSoundPool.stop(id); 328 if (DEBUG) Log.d(LOG_TAG, "End volume test"); 329 return true; 330 } 331 run()332 public void run() { 333 if (DEBUG) Log.d(LOG_TAG, "Test thread running"); 334 335 // initialize 336 mRunning = true; 337 int failures = 0; 338 339 // initialize pitch table 340 float pitch = 0.5f; 341 mScale = new float[13]; 342 for (int i = 0; i < 13; ++i) { 343 mScale[i] = pitch; 344 pitch *= SEMITONE; 345 } 346 347 try { 348 349 // do single stream tests 350 initSoundPool(1); 351 if (!TestSounds()) failures = failures + 1; 352 if (!TestScales()) failures = failures + 1; 353 if (!TestRates()) failures = failures + 1; 354 if (!TestPriority()) failures = failures + 1; 355 if (!TestVolume()) failures = failures + 1; 356 357 // do multiple stream tests 358 initSoundPool(4); 359 if (!TestPauseResume()) failures = failures + 1; 360 361 } catch (java.lang.InterruptedException e) { 362 if (DEBUG) Log.d(LOG_TAG, "Test interrupted"); 363 failures = failures + 1; 364 } finally { 365 mRunning = false; 366 } 367 368 // release sound pool 369 if (mSoundPool != null) { 370 mSoundPool.release(); 371 mSoundPool = null; 372 } 373 374 // output stats 375 if (DEBUG) Log.d(LOG_TAG, "Test thread exit"); 376 if (failures == 0) { 377 Log.i(LOG_TAG, "All tests passed"); 378 } else { 379 Log.i(LOG_TAG, failures + " tests failed"); 380 } 381 } 382 quit()383 public void quit() { 384 if (DEBUG) Log.d(LOG_TAG, "interrupt"); 385 interrupt(); 386 while (mRunning) { 387 try { 388 sleep(20); 389 } catch (java.lang.InterruptedException e) { } 390 } 391 if (DEBUG) Log.d(LOG_TAG, "quit"); 392 } 393 } 394 startTests()395 private void startTests() { 396 mThread = new TestThread(); 397 mThread.start(); 398 } 399 onPause()400 protected void onPause() 401 { 402 Log.v(LOG_TAG, "onPause"); 403 super.onPause(); 404 mThread.quit(); 405 mThread = null; 406 } 407 onResume()408 protected void onResume() 409 { 410 Log.v(LOG_TAG, "onResume"); 411 super.onResume(); 412 startTests(); 413 } 414 onCreate(Bundle icicle)415 public void onCreate(Bundle icicle) 416 { 417 super.onCreate(icicle); 418 setVolumeControlStream(AudioManager.STREAM_MUSIC); 419 } 420 } 421 422