• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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 com.android.effectstest;
18 
19 import android.app.Activity;
20 import android.media.audiofx.Visualizer;
21 import android.os.Bundle;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.os.Message;
25 import android.util.Log;
26 import android.view.KeyEvent;
27 import android.view.View;
28 import android.view.View.OnClickListener;
29 import android.widget.Button;
30 import android.widget.CompoundButton;
31 import android.widget.CompoundButton.OnCheckedChangeListener;
32 import android.widget.EditText;
33 import android.widget.TextView;
34 import android.widget.ToggleButton;
35 
36 import java.util.HashMap;
37 
38 public class VisualizerTest extends Activity implements OnCheckedChangeListener {
39 
40     private final static String TAG = "Visualizer Test";
41 
42     private VisualizerInstance mVisualizer;
43     ToggleButton mMultithreadedButton;
44     ToggleButton mOnOffButton;
45     ToggleButton mReleaseButton;
46     boolean mUseMTInstance;
47     boolean mEnabled;
48     EditText mSessionText;
49     static int sSession = 0;
50     ToggleButton mCallbackButton;
51     boolean mCallbackOn;
52     private static HashMap<Integer, VisualizerInstance> sInstances =
53             new HashMap<Integer, VisualizerInstance>(10);
54     private Handler mUiHandler;
55 
VisualizerTest()56     public VisualizerTest() {
57         Log.d(TAG, "contructor");
58         mUiHandler = new UiHandler(Looper.getMainLooper());
59     }
60 
61     @Override
onCreate(Bundle icicle)62     public void onCreate(Bundle icicle) {
63         super.onCreate(icicle);
64 
65         TextView textView;
66 
67         setContentView(R.layout.visualizertest);
68 
69         mSessionText = findViewById(R.id.sessionEdit);
70         mSessionText.setOnKeyListener(mSessionKeyListener);
71         mSessionText.setText(Integer.toString(sSession));
72 
73         mMultithreadedButton = (ToggleButton) findViewById(R.id.visuMultithreadedOnOff);
74         mReleaseButton = (ToggleButton) findViewById(R.id.visuReleaseButton);
75         mOnOffButton = (ToggleButton) findViewById(R.id.visualizerOnOff);
76         mCallbackButton = (ToggleButton) findViewById(R.id.visuCallbackOnOff);
77         mCallbackOn = false;
78         mCallbackButton.setChecked(mCallbackOn);
79 
80         final Button hammerReleaseTest = (Button) findViewById(R.id.hammer_on_release_bug);
81         hammerReleaseTest.setEnabled(false);
82 
83         mMultithreadedButton.setOnCheckedChangeListener(this);
84         if (getEffect(sSession) != null) {
85             mReleaseButton.setOnCheckedChangeListener(this);
86             mOnOffButton.setOnCheckedChangeListener(this);
87             mCallbackButton.setOnCheckedChangeListener(this);
88 
89             hammerReleaseTest.setEnabled(true);
90             hammerReleaseTest.setOnClickListener(new OnClickListener() {
91                 @Override
92                 public void onClick(View v) {
93                     runHammerReleaseTest(hammerReleaseTest);
94                 }
95             });
96         }
97     }
98 
99     public static final int MSG_DISPLAY_WAVEFORM_VAL = 0;
100     public static final int MSG_DISPLAY_FFT_VAL = 1;
101 
102     private class UiHandler extends Handler {
UiHandler(Looper looper)103         UiHandler(Looper looper) {
104             super(looper);
105         }
106 
107         @Override
handleMessage(Message msg)108         public void handleMessage(Message msg) {
109             switch (msg.what) {
110                 case MSG_DISPLAY_WAVEFORM_VAL:
111                 case MSG_DISPLAY_FFT_VAL:
112                     int[] minMaxCenter = (int[]) msg.obj;
113                     boolean waveform = msg.what == MSG_DISPLAY_WAVEFORM_VAL;
114                     displayVal(waveform ? R.id.waveformMin : R.id.fftMin, minMaxCenter[0]);
115                     displayVal(waveform ? R.id.waveformMax : R.id.fftMax, minMaxCenter[1]);
116                     displayVal(waveform ? R.id.waveformCenter : R.id.fftCenter, minMaxCenter[2]);
117                     break;
118                 }
119         }
120     }
121 
122     private View.OnKeyListener mSessionKeyListener = new View.OnKeyListener() {
123         public boolean onKey(View v, int keyCode, KeyEvent event) {
124             if (event.getAction() == KeyEvent.ACTION_DOWN) {
125                 switch (keyCode) {
126                     case KeyEvent.KEYCODE_DPAD_CENTER:
127                     case KeyEvent.KEYCODE_ENTER:
128                         try {
129                             sSession = Integer.parseInt(mSessionText.getText().toString());
130                             getEffect(sSession);
131                         } catch (NumberFormatException e) {
132                             Log.d(TAG, "Invalid session #: "+mSessionText.getText().toString());
133                         }
134 
135                         return true;
136                 }
137             }
138             return false;
139         }
140     };
141 
142     // OnCheckedChangeListener
143     @Override
onCheckedChanged(CompoundButton buttonView, boolean isChecked)144     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
145         if (buttonView.getId() == R.id.visuMultithreadedOnOff) {
146             mUseMTInstance = isChecked;
147             Log.d(TAG, "Multi-threaded client: " + (isChecked ? "enabled" : "disabled"));
148         }
149         if (buttonView.getId() == R.id.visualizerOnOff) {
150             if (mVisualizer != null) {
151                 mEnabled = isChecked;
152                 mCallbackButton.setEnabled(!mEnabled);
153                 if (mCallbackOn && mEnabled) {
154                     mVisualizer.enableDataCaptureListener(true);
155                 }
156                 mVisualizer.setEnabled(mEnabled);
157                 if (mCallbackOn) {
158                     if (!mEnabled) {
159                         mVisualizer.enableDataCaptureListener(false);
160                     }
161                 } else {
162                     mVisualizer.startStopCapture(isChecked);
163                 }
164             }
165         }
166         if (buttonView.getId() == R.id.visuReleaseButton) {
167             if (isChecked) {
168                 if (mVisualizer == null) {
169                     getEffect(sSession);
170                 }
171             } else {
172                 if (mVisualizer != null) {
173                     putEffect(sSession);
174                 }
175             }
176         }
177         if (buttonView.getId() == R.id.visuCallbackOnOff) {
178             mCallbackOn = isChecked;
179         }
180     }
181 
displayVal(int viewId, int val)182     private void displayVal(int viewId, int val) {
183         TextView textView = (TextView)findViewById(viewId);
184         String text = Integer.toString(val);
185         textView.setText(text);
186     }
187 
188 
getEffect(int session)189     private VisualizerInstance getEffect(int session) {
190         synchronized (sInstances) {
191             if (sInstances.containsKey(session)) {
192                 mVisualizer = sInstances.get(session);
193             } else {
194                 try {
195                     mVisualizer = mUseMTInstance
196                             ? new VisualizerInstanceMT(session, mUiHandler, 0 /*extraThreadCount*/)
197                             : new VisualizerInstanceSync(session, mUiHandler);
198                 } catch (RuntimeException e) {
199                     throw e;
200                 }
201                 sInstances.put(session, mVisualizer);
202             }
203         }
204         mReleaseButton.setEnabled(false);
205         mOnOffButton.setEnabled(false);
206         if (mVisualizer != null) {
207             mReleaseButton.setChecked(true);
208             mReleaseButton.setEnabled(true);
209 
210             mEnabled = mVisualizer.getEnabled();
211             mOnOffButton.setChecked(mEnabled);
212             mOnOffButton.setEnabled(true);
213 
214             mCallbackButton.setEnabled(!mEnabled);
215         }
216         return mVisualizer;
217     }
218 
putEffect(int session)219     private void putEffect(int session) {
220         mOnOffButton.setChecked(false);
221         mOnOffButton.setEnabled(false);
222         synchronized (sInstances) {
223             if (mVisualizer != null) {
224                 mVisualizer.release();
225                 sInstances.remove(session);
226                 mVisualizer = null;
227             }
228         }
229     }
230 
231     // Stress-tests releasing of AudioEffect by doing repeated creation
232     // and subsequent releasing. Unlike a similar class in BassBoostTest,
233     // this one doesn't sets a control status listener because Visualizer
234     // doesn't inherit from AudioEffect and doesn't implement this method
235     // by itself.
236     class HammerReleaseTest extends Thread {
237         private static final int NUM_EFFECTS = 10;
238         private static final int NUM_ITERATIONS = 100;
239         private final int mSession;
240         private final Runnable mOnComplete;
241 
HammerReleaseTest(int session, Runnable onComplete)242         HammerReleaseTest(int session, Runnable onComplete) {
243             mSession = session;
244             mOnComplete = onComplete;
245         }
246 
247         @Override
run()248         public void run() {
249             Log.w(TAG, "HammerReleaseTest started");
250             Visualizer[] effects = new Visualizer[NUM_EFFECTS];
251             for (int i = 0; i < NUM_ITERATIONS; i++) {
252                 for (int j = 0; j < NUM_EFFECTS; j++) {
253                     effects[j] = new Visualizer(mSession);
254                     this.yield();
255                 }
256                 for (int j = NUM_EFFECTS - 1; j >= 0; j--) {
257                     Log.w(TAG, "HammerReleaseTest releasing effect " + (Object) effects[j]);
258                     effects[j].release();
259                     effects[j] = null;
260                     this.yield();
261                 }
262             }
263             Log.w(TAG, "HammerReleaseTest ended");
264             runOnUiThread(mOnComplete);
265         }
266     }
267 
runHammerReleaseTest(Button controlButton)268     private void runHammerReleaseTest(Button controlButton) {
269         controlButton.setEnabled(false);
270         HammerReleaseTest thread = new HammerReleaseTest(sSession,
271                 () -> {
272                     controlButton.setEnabled(true);
273                 });
274         thread.start();
275     }
276 
277 }
278