/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.effectstest; import android.media.audiofx.Visualizer; import android.os.Handler; import android.os.Message; import android.util.Log; // This class only has `final' members, thus any thread-safety concerns // can only come from the Visualizer effect class. class VisualizerInstanceSync implements VisualizerInstance { private static final String TAG = "VisualizerInstance"; private final Handler mUiHandler; private final Visualizer mVisualizer; private final VisualizerTestHandler mVisualizerTestHandler; private final VisualizerListener mVisualizerListener; VisualizerInstanceSync(int session, Handler uiHandler) { mUiHandler = uiHandler; try { mVisualizer = new Visualizer(session); } catch (UnsupportedOperationException e) { Log.e(TAG, "Visualizer library not loaded"); throw new RuntimeException("Cannot initialize effect"); } catch (RuntimeException e) { throw e; } mVisualizerTestHandler = new VisualizerTestHandler(); mVisualizerListener = new VisualizerListener(); } // Not a "deep" copy, only copies the references. VisualizerInstanceSync(VisualizerInstanceSync other) { mUiHandler = other.mUiHandler; mVisualizer = other.mVisualizer; mVisualizerTestHandler = other.mVisualizerTestHandler; mVisualizerListener = other.mVisualizerListener; } @Override public void enableDataCaptureListener(boolean enable) { mVisualizer.setDataCaptureListener(enable ? mVisualizerListener : null, 10000, enable, enable); } @Override public boolean getEnabled() { return mVisualizer.getEnabled(); } @Override public void release() { mVisualizer.release(); Log.d(TAG, "Visualizer released"); } @Override public void setEnabled(boolean enabled) { mVisualizer.setEnabled(enabled); } @Override public void startStopCapture(boolean start) { mVisualizerTestHandler.sendMessage(mVisualizerTestHandler.obtainMessage( start ? MSG_START_CAPTURE : MSG_STOP_CAPTURE)); } private static final int MSG_START_CAPTURE = 0; private static final int MSG_STOP_CAPTURE = 1; private static final int MSG_NEW_CAPTURE = 2; private static final int CAPTURE_PERIOD_MS = 100; private static int[] dataToMinMaxCenter(byte[] data, int len) { int[] minMaxCenter = new int[3]; minMaxCenter[0] = data[0]; minMaxCenter[1] = data[len - 1]; minMaxCenter[2] = data[len / 2]; return minMaxCenter; } private class VisualizerTestHandler extends Handler { private final int mCaptureSize; private boolean mActive = false; VisualizerTestHandler() { mCaptureSize = mVisualizer.getCaptureSize(); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_START_CAPTURE: if (!mActive) { Log.d(TAG, "Start capture"); mActive = true; sendMessageDelayed(obtainMessage(MSG_NEW_CAPTURE), CAPTURE_PERIOD_MS); } break; case MSG_STOP_CAPTURE: if (mActive) { Log.d(TAG, "Stop capture"); mActive = false; } break; case MSG_NEW_CAPTURE: if (mActive) { if (mCaptureSize > 0) { byte[] data = new byte[mCaptureSize]; if (mVisualizer.getWaveForm(data) == Visualizer.SUCCESS) { int len = data.length < mCaptureSize ? data.length : mCaptureSize; mUiHandler.sendMessage( mUiHandler.obtainMessage( VisualizerTest.MSG_DISPLAY_WAVEFORM_VAL, dataToMinMaxCenter(data, len))); } if (mVisualizer.getFft(data) == Visualizer.SUCCESS) { int len = data.length < mCaptureSize ? data.length : mCaptureSize; mUiHandler.sendMessage( mUiHandler.obtainMessage(VisualizerTest.MSG_DISPLAY_FFT_VAL, dataToMinMaxCenter(data, len))); } } sendMessageDelayed(obtainMessage(MSG_NEW_CAPTURE), CAPTURE_PERIOD_MS); } break; } } } private class VisualizerListener implements Visualizer.OnDataCaptureListener { @Override public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate) { if (visualizer == mVisualizer && waveform.length > 0) { Log.d(TAG, "onWaveFormDataCapture(): " + waveform[0] + " smp rate: " + samplingRate / 1000); mUiHandler.sendMessage( mUiHandler.obtainMessage(VisualizerTest.MSG_DISPLAY_WAVEFORM_VAL, dataToMinMaxCenter(waveform, waveform.length))); } } @Override public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) { if (visualizer == mVisualizer && fft.length > 0) { Log.d(TAG, "onFftDataCapture(): " + fft[0]); mUiHandler.sendMessage( mUiHandler.obtainMessage(VisualizerTest.MSG_DISPLAY_FFT_VAL, dataToMinMaxCenter(fft, fft.length))); } } } }