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
17package com.android.effectstest;
18
19import android.app.Activity;
20import android.content.Context;
21import android.content.Intent;
22import android.media.audiofx.Visualizer;
23import android.os.Bundle;
24import android.os.Handler;
25import android.os.Looper;
26import android.os.Message;
27import android.util.Log;
28import android.view.KeyEvent;
29import android.view.Menu;
30import android.view.View;
31import android.view.View.OnClickListener;
32import android.view.ViewGroup;
33import android.widget.Button;
34import android.widget.CompoundButton;
35import android.widget.CompoundButton.OnCheckedChangeListener;
36import android.widget.EditText;
37import android.widget.TextView;
38import android.widget.ToggleButton;
39import android.widget.SeekBar;
40
41import java.nio.ByteOrder;
42import java.nio.ByteBuffer;
43import java.util.HashMap;
44import java.util.Map;
45
46public class VisualizerTest extends Activity implements OnCheckedChangeListener {
47
48    private final static String TAG = "Visualizer Test";
49
50    private Visualizer mVisualizer;
51    ToggleButton mOnOffButton;
52    ToggleButton mReleaseButton;
53    boolean mEnabled;
54    EditText mSessionText;
55    static int sSession = 0;
56    int mCaptureSize;
57    ToggleButton mCallbackButton;
58    boolean mCallbackOn;
59    VisualizerListener mVisualizerListener;
60    private static HashMap<Integer, Visualizer> sInstances = new HashMap<Integer, Visualizer>(10);
61    private VisualizerTestHandler mVisualizerTestHandler = null;
62
63    public VisualizerTest() {
64        Log.d(TAG, "contructor");
65    }
66
67    @Override
68    public void onCreate(Bundle icicle) {
69        super.onCreate(icicle);
70
71        TextView textView;
72
73        setContentView(R.layout.visualizertest);
74
75        mSessionText = (EditText) findViewById(R.id.sessionEdit);
76        mSessionText.setOnKeyListener(mSessionKeyListener);
77        mSessionText.setText(Integer.toString(sSession));
78
79        mReleaseButton = (ToggleButton)findViewById(R.id.visuReleaseButton);
80        mOnOffButton = (ToggleButton)findViewById(R.id.visualizerOnOff);
81        mCallbackButton = (ToggleButton)findViewById(R.id.visuCallbackOnOff);
82        mCallbackOn = false;
83        mCallbackButton.setChecked(mCallbackOn);
84
85        mVisualizerTestHandler = new VisualizerTestHandler();
86        mVisualizerListener = new VisualizerListener();
87
88        getEffect(sSession);
89
90        if (mVisualizer != null) {
91            mReleaseButton.setOnCheckedChangeListener(this);
92            mOnOffButton.setOnCheckedChangeListener(this);
93            mCallbackButton.setOnCheckedChangeListener(this);
94        }
95    }
96
97    private static final int MSG_START_CAPTURE = 0;
98    private static final int MSG_STOP_CAPTURE = 1;
99    private static final int MSG_NEW_CAPTURE = 2;
100    private static final int CAPTURE_PERIOD_MS = 100;
101
102    private class VisualizerTestHandler extends Handler {
103        boolean mActive = false;
104        @Override
105        public void handleMessage(Message msg) {
106            switch (msg.what) {
107            case MSG_START_CAPTURE:
108                if (!mActive) {
109                    Log.d(TAG, "Start capture");
110                    mActive = true;
111                    sendMessageDelayed(obtainMessage(MSG_NEW_CAPTURE, 0, 0, null), CAPTURE_PERIOD_MS);
112                }
113                break;
114            case MSG_STOP_CAPTURE:
115                if (mActive) {
116                    Log.d(TAG, "Stop capture");
117                    mActive = false;
118                }
119                break;
120            case MSG_NEW_CAPTURE:
121                if (mActive && mVisualizer != null) {
122                    if (mCaptureSize > 0) {
123                        byte[] data = new byte[mCaptureSize];
124                        if (mVisualizer.getWaveForm(data) == Visualizer.SUCCESS) {
125                            int len = data.length < mCaptureSize ? data.length : mCaptureSize;
126                            displayVal(R.id.waveformMin, data[0]);
127                            displayVal(R.id.waveformMax, data[len-1]);
128                            displayVal(R.id.waveformCenter, data[len/2]);
129                        };
130                        if (mVisualizer.getFft(data) == Visualizer.SUCCESS) {
131                            int len = data.length < mCaptureSize ? data.length : mCaptureSize;
132                            displayVal(R.id.fftMin, data[0]);
133                            displayVal(R.id.fftMax, data[len-1]);
134                            displayVal(R.id.fftCenter, data[len/2]);
135                        };
136                    }
137                    sendMessageDelayed(obtainMessage(MSG_NEW_CAPTURE, 0, 0, null), CAPTURE_PERIOD_MS);
138                }
139                break;
140            }
141        }
142    }
143
144    private class VisualizerListener implements Visualizer.OnDataCaptureListener {
145
146        public VisualizerListener() {
147        }
148        public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate) {
149            if (visualizer == mVisualizer) {
150                if (waveform.length > 0) {
151                    Log.d(TAG, "onWaveFormDataCapture(): "+waveform[0]+" smp rate: "+samplingRate/1000);
152                    displayVal(R.id.waveformMin, waveform[0]);
153                    displayVal(R.id.waveformMax, waveform[waveform.length - 1]);
154                    displayVal(R.id.waveformCenter, waveform[waveform.length/2]);
155                }
156            }
157        }
158        public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) {
159            if (visualizer == mVisualizer) {
160                if (fft.length > 0) {
161                    Log.d(TAG, "onFftDataCapture(): "+fft[0]);
162                    displayVal(R.id.fftMin, fft[0]);
163                    displayVal(R.id.fftMax, fft[fft.length - 1]);
164                    displayVal(R.id.fftCenter, fft[fft.length/2]);
165                }
166            }
167        }
168    }
169
170    @Override
171    public void onResume() {
172        super.onResume();
173    }
174
175    @Override
176    public void onPause() {
177        super.onPause();
178    }
179
180    private View.OnKeyListener mSessionKeyListener
181    = new View.OnKeyListener() {
182        public boolean onKey(View v, int keyCode, KeyEvent event) {
183            if (event.getAction() == KeyEvent.ACTION_DOWN) {
184                switch (keyCode) {
185                    case KeyEvent.KEYCODE_DPAD_CENTER:
186                    case KeyEvent.KEYCODE_ENTER:
187                        try {
188                            sSession = Integer.parseInt(mSessionText.getText().toString());
189                            getEffect(sSession);
190                        } catch (NumberFormatException e) {
191                            Log.d(TAG, "Invalid session #: "+mSessionText.getText().toString());
192                        }
193
194                        return true;
195                }
196            }
197            return false;
198        }
199    };
200
201    // OnCheckedChangeListener
202    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
203        if (buttonView.getId() == R.id.visualizerOnOff) {
204            if (mVisualizer != null) {
205                mEnabled = isChecked;
206                mCallbackButton.setEnabled(!mEnabled);
207                if (mCallbackOn && mEnabled) {
208                    mVisualizer.setDataCaptureListener(mVisualizerListener,
209                            10000,
210                            true,
211                            true);
212                }
213                mVisualizer.setEnabled(mEnabled);
214                if (mCallbackOn) {
215                    if (!mEnabled) {
216                        mVisualizer.setDataCaptureListener(null,
217                                10000,
218                                false,
219                                false);
220                    }
221                } else {
222                    int msg = isChecked ? MSG_START_CAPTURE : MSG_STOP_CAPTURE;
223                    mVisualizerTestHandler.sendMessage(
224                            mVisualizerTestHandler.obtainMessage(msg, 0, 0, null));
225                }
226            }
227        }
228        if (buttonView.getId() == R.id.visuReleaseButton) {
229            if (isChecked) {
230                if (mVisualizer == null) {
231                    getEffect(sSession);
232                }
233            } else {
234                if (mVisualizer != null) {
235                    putEffect(sSession);
236                }
237            }
238        }
239        if (buttonView.getId() == R.id.visuCallbackOnOff) {
240            mCallbackOn = isChecked;
241        }
242    }
243
244    private void displayVal(int viewId, int val) {
245        TextView textView = (TextView)findViewById(viewId);
246        String text = Integer.toString(val);
247        textView.setText(text);
248    }
249
250
251    private void getEffect(int session) {
252        synchronized (sInstances) {
253            if (sInstances.containsKey(session)) {
254                mVisualizer = sInstances.get(session);
255            } else {
256                try{
257                    mVisualizer = new Visualizer(session);
258                } catch (UnsupportedOperationException e) {
259                    Log.e(TAG,"Visualizer library not loaded");
260                    throw (new RuntimeException("Cannot initialize effect"));
261                } catch (RuntimeException e) {
262                    throw e;
263                }
264                sInstances.put(session, mVisualizer);
265            }
266        }
267        mReleaseButton.setEnabled(false);
268        mOnOffButton.setEnabled(false);
269        if (mVisualizer != null) {
270            mCaptureSize = mVisualizer.getCaptureSize();
271
272            mReleaseButton.setChecked(true);
273            mReleaseButton.setEnabled(true);
274
275            mEnabled = mVisualizer.getEnabled();
276            mOnOffButton.setChecked(mEnabled);
277            mOnOffButton.setEnabled(true);
278
279            mCallbackButton.setEnabled(!mEnabled);
280        }
281    }
282
283    private void putEffect(int session) {
284        mOnOffButton.setChecked(false);
285        mOnOffButton.setEnabled(false);
286        synchronized (sInstances) {
287            if (mVisualizer != null) {
288                mVisualizer.release();
289                Log.d(TAG,"Visualizer released");
290                mVisualizer = null;
291                sInstances.remove(session);
292            }
293        }
294    }
295
296}
297