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.Visualizer; 23 import android.os.Looper; 24 import android.test.AndroidTestCase; 25 import android.util.Log; 26 27 public class VisualizerTest extends AndroidTestCase { 28 29 private String TAG = "VisualizerTest"; 30 private final static int MIN_CAPTURE_RATE_MAX = 10000; // 10Hz 31 private final static int MIN_CAPTURE_SIZE_MAX = 1024; 32 private final static int MAX_CAPTURE_SIZE_MIN = 512; 33 private final static int MAX_LOOPER_WAIT_COUNT = 10; 34 35 private Visualizer mVisualizer = null; 36 private int mSession = -1; 37 private boolean mInitialized = false; 38 private Looper mLooper = null; 39 private final Object mLock = new Object(); 40 private byte[] mWaveform = null; 41 private byte[] mFft = null; 42 private boolean mCaptureWaveform = false; 43 private boolean mCaptureFft = false; 44 private Thread mListenerThread; 45 46 //----------------------------------------------------------------- 47 // VISUALIZER TESTS: 48 //---------------------------------- 49 50 //----------------------------------------------------------------- 51 // 0 - constructor 52 //---------------------------------- 53 54 //Test case 0.0: test constructor and release test0_0ConstructorAndRelease()55 public void test0_0ConstructorAndRelease() throws Exception { 56 Visualizer visualizer = null; 57 try { 58 visualizer = new Visualizer(0); 59 assertNotNull("could not create Visualizer", visualizer); 60 } catch (IllegalArgumentException e) { 61 fail("Visualizer not found"); 62 } catch (UnsupportedOperationException e) { 63 fail("Effect library not loaded"); 64 } finally { 65 if (visualizer != null) { 66 visualizer.release(); 67 } 68 } 69 } 70 71 72 //----------------------------------------------------------------- 73 // 1 - get/set parameters 74 //---------------------------------- 75 76 //Test case 1.0: capture rates test1_0CaptureRates()77 public void test1_0CaptureRates() throws Exception { 78 getVisualizer(0); 79 try { 80 int captureRate = mVisualizer.getMaxCaptureRate(); 81 assertTrue("insufficient max capture rate", 82 captureRate >= MIN_CAPTURE_RATE_MAX); 83 int samplingRate = mVisualizer.getSamplingRate(); 84 } catch (IllegalArgumentException e) { 85 fail("Bad parameter value"); 86 } catch (UnsupportedOperationException e) { 87 fail("get parameter() rejected"); 88 } catch (IllegalStateException e) { 89 fail("get parameter() called in wrong state"); 90 } finally { 91 releaseVisualizer(); 92 } 93 } 94 95 //Test case 1.1: test capture size test1_1CaptureSize()96 public void test1_1CaptureSize() throws Exception { 97 getVisualizer(0); 98 try { 99 int[] range = mVisualizer.getCaptureSizeRange(); 100 assertTrue("insufficient min capture size", 101 range[0] <= MAX_CAPTURE_SIZE_MIN); 102 assertTrue("insufficient min capture size", 103 range[1] >= MIN_CAPTURE_SIZE_MAX); 104 mVisualizer.setCaptureSize(range[0]); 105 assertEquals("insufficient min capture size", 106 range[0], mVisualizer.getCaptureSize()); 107 mVisualizer.setCaptureSize(range[1]); 108 assertEquals("insufficient min capture size", 109 range[1], mVisualizer.getCaptureSize()); 110 } catch (IllegalArgumentException e) { 111 fail("Bad parameter value"); 112 } catch (UnsupportedOperationException e) { 113 fail("get parameter() rejected"); 114 } catch (IllegalStateException e) { 115 fail("get parameter() called in wrong state"); 116 } finally { 117 releaseVisualizer(); 118 } 119 } 120 121 //----------------------------------------------------------------- 122 // 2 - check capture 123 //---------------------------------- 124 125 //Test case 2.0: test cature in polling mode test2_0PollingCapture()126 public void test2_0PollingCapture() throws Exception { 127 try { 128 getVisualizer(0); 129 mVisualizer.setEnabled(true); 130 assertTrue("visualizer not enabled", mVisualizer.getEnabled()); 131 Thread.sleep(100); 132 // check capture on silence 133 byte[] data = new byte[mVisualizer.getCaptureSize()]; 134 mVisualizer.getWaveForm(data); 135 int energy = computeEnergy(data, true); 136 assertEquals("getWaveForm reports energy for silence", 137 0, energy); 138 mVisualizer.getFft(data); 139 energy = computeEnergy(data, false); 140 assertEquals("getFft reports energy for silence", 141 0, energy); 142 143 } catch (IllegalStateException e) { 144 fail("method called in wrong state"); 145 } catch (InterruptedException e) { 146 fail("sleep() interrupted"); 147 } finally { 148 releaseVisualizer(); 149 } 150 } 151 152 //Test case 2.1: test capture with listener test2_1ListenerCapture()153 public void test2_1ListenerCapture() throws Exception { 154 try { 155 getVisualizer(0); 156 synchronized(mLock) { 157 mInitialized = false; 158 createListenerLooper(); 159 waitForLooperInitialization_l(); 160 } 161 mVisualizer.setEnabled(true); 162 assertTrue("visualizer not enabled", mVisualizer.getEnabled()); 163 164 Thread.sleep(100); 165 166 // check capture on silence 167 synchronized(mLock) { 168 mCaptureWaveform = true; 169 int looperWaitCount = MAX_LOOPER_WAIT_COUNT; 170 while ((mWaveform == null) && (looperWaitCount-- > 0)) { 171 try { 172 mLock.wait(); 173 } catch(Exception e) { 174 } 175 } 176 mCaptureWaveform = false; 177 } 178 assertNotNull("waveform capture failed", mWaveform); 179 int energy = computeEnergy(mWaveform, true); 180 assertEquals("getWaveForm reports energy for silence", 181 0, energy); 182 183 synchronized(mLock) { 184 mCaptureFft = true; 185 int looperWaitCount = MAX_LOOPER_WAIT_COUNT; 186 while ((mFft == null) && (looperWaitCount-- > 0)) { 187 try { 188 mLock.wait(); 189 } catch(Exception e) { 190 } 191 } 192 mCaptureFft = false; 193 } 194 assertNotNull("FFT capture failed", mFft); 195 energy = computeEnergy(mFft, false); 196 assertEquals("getFft reports energy for silence", 197 0, energy); 198 199 } catch (IllegalStateException e) { 200 fail("method called in wrong state"); 201 } catch (InterruptedException e) { 202 fail("sleep() interrupted"); 203 } finally { 204 terminateListenerLooper(); 205 releaseVisualizer(); 206 } 207 } 208 209 //----------------------------------------------------------------- 210 // private methods 211 //---------------------------------- 212 computeEnergy(byte[] data, boolean pcm)213 private int computeEnergy(byte[] data, boolean pcm) { 214 int energy = 0; 215 if (data.length != 0) { 216 if (pcm) { 217 for (int i = 0; i < data.length; i++) { 218 int tmp = ((int)data[i] & 0xFF) - 128; 219 energy += tmp*tmp; 220 } 221 } else { 222 energy = (int)data[0] * (int)data[0]; 223 for (int i = 2; i < data.length; i += 2) { 224 int real = (int)data[i]; 225 int img = (int)data[i + 1]; 226 energy += real * real + img * img; 227 } 228 } 229 } 230 return energy; 231 } 232 getVisualizer(int session)233 private void getVisualizer(int session) { 234 if (mVisualizer == null || session != mSession) { 235 if (session != mSession && mVisualizer != null) { 236 mVisualizer.release(); 237 mVisualizer = null; 238 } 239 try { 240 mVisualizer = new Visualizer(session); 241 mSession = session; 242 } catch (IllegalArgumentException e) { 243 Log.e(TAG, "getVisualizer() Visualizer not found exception: "+e); 244 } catch (UnsupportedOperationException e) { 245 Log.e(TAG, "getVisualizer() Effect library not loaded exception: "+e); 246 } 247 } 248 assertNotNull("could not create mVisualizer", mVisualizer); 249 } 250 releaseVisualizer()251 private void releaseVisualizer() { 252 if (mVisualizer != null) { 253 mVisualizer.release(); 254 mVisualizer = null; 255 } 256 } 257 waitForLooperInitialization_l()258 private void waitForLooperInitialization_l() { 259 int looperWaitCount = MAX_LOOPER_WAIT_COUNT; 260 while (!mInitialized && (looperWaitCount-- > 0)) { 261 try { 262 mLock.wait(); 263 } catch(Exception e) { 264 } 265 } 266 assertTrue(mInitialized); 267 } 268 createListenerLooper()269 private void createListenerLooper() { 270 mListenerThread = new Thread() { 271 @Override 272 public void run() { 273 // Set up a looper to be used by mEffect. 274 Looper.prepare(); 275 276 // Save the looper so that we can terminate this thread 277 // after we are done with it. 278 mLooper = Looper.myLooper(); 279 280 synchronized(mLock) { 281 if (mVisualizer != null) { 282 mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() { 283 public void onWaveFormDataCapture( 284 Visualizer visualizer, byte[] waveform, int samplingRate) { 285 synchronized(mLock) { 286 if (visualizer == mVisualizer) { 287 if (mCaptureWaveform) { 288 mWaveform = waveform; 289 mLock.notify(); 290 } 291 } 292 } 293 } 294 295 public void onFftDataCapture( 296 Visualizer visualizer, byte[] fft, int samplingRate) { 297 synchronized(mLock) { 298 Log.e(TAG, "onFftDataCapture 2 mCaptureFft: "+mCaptureFft); 299 if (visualizer == mVisualizer) { 300 if (mCaptureFft) { 301 mFft = fft; 302 mLock.notify(); 303 } 304 } 305 } 306 } 307 }, 308 10000, 309 true, 310 true); 311 } 312 mInitialized = true; 313 mLock.notify(); 314 } 315 Looper.loop(); // Blocks forever until Looper.quit() is called. 316 } 317 }; 318 mListenerThread.start(); 319 } 320 /* 321 * Terminates the listener looper thread. 322 */ terminateListenerLooper()323 private void terminateListenerLooper() { 324 if (mListenerThread != null) { 325 if (mLooper != null) { 326 mLooper.quit(); 327 mLooper = null; 328 } 329 try { 330 mListenerThread.join(); 331 } catch(InterruptedException e) { 332 } 333 mListenerThread = null; 334 } 335 } 336 } 337