• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.audiofx;
18 
19 import android.app.ActivityThread;
20 import android.util.Log;
21 import java.lang.ref.WeakReference;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.os.Message;
25 
26 /**
27  * The Visualizer class enables application to retrieve part of the currently playing audio for
28  * visualization purpose. It is not an audio recording interface and only returns partial and low
29  * quality audio content. However, to protect privacy of certain audio data (e.g voice mail) the use
30  * of the visualizer requires the permission android.permission.RECORD_AUDIO.
31  * <p>The audio session ID passed to the constructor indicates which audio content should be
32  * visualized:<br>
33  * <ul>
34  *   <li>If the session is 0, the audio output mix is visualized</li>
35  *   <li>If the session is not 0, the audio from a particular {@link android.media.MediaPlayer} or
36  *   {@link android.media.AudioTrack}
37  *   using this audio session is visualized </li>
38  * </ul>
39  * <p>Two types of representation of audio content can be captured: <br>
40  * <ul>
41  *   <li>Waveform data: consecutive 8-bit (unsigned) mono samples by using the
42  *   {@link #getWaveForm(byte[])} method</li>
43  *   <li>Frequency data: 8-bit magnitude FFT by using the {@link #getFft(byte[])} method</li>
44  * </ul>
45  * <p>The length of the capture can be retrieved or specified by calling respectively
46  * {@link #getCaptureSize()} and {@link #setCaptureSize(int)} methods. The capture size must be a
47  * power of 2 in the range returned by {@link #getCaptureSizeRange()}.
48  * <p>In addition to the polling capture mode described above with {@link #getWaveForm(byte[])} and
49  *  {@link #getFft(byte[])} methods, a callback mode is also available by installing a listener by
50  *  use of the {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
51  *  The rate at which the listener capture method is called as well as the type of data returned is
52  *  specified.
53  * <p>Before capturing data, the Visualizer must be enabled by calling the
54  * {@link #setEnabled(boolean)} method.
55  * When data capture is not needed any more, the Visualizer should be disabled.
56  * <p>It is good practice to call the {@link #release()} method when the Visualizer is not used
57  * anymore to free up native resources associated to the Visualizer instance.
58  * <p>Creating a Visualizer on the output mix (audio session 0) requires permission
59  * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}
60  * <p>The Visualizer class can also be used to perform measurements on the audio being played back.
61  * The measurements to perform are defined by setting a mask of the requested measurement modes with
62  * {@link #setMeasurementMode(int)}. Supported values are {@link #MEASUREMENT_MODE_NONE} to cancel
63  * any measurement, and {@link #MEASUREMENT_MODE_PEAK_RMS} for peak and RMS monitoring.
64  * Measurements can be retrieved through {@link #getMeasurementPeakRms(MeasurementPeakRms)}.
65  */
66 
67 public class Visualizer {
68 
69     static {
70         System.loadLibrary("audioeffect_jni");
native_init()71         native_init();
72     }
73 
74     private final static String TAG = "Visualizer-JAVA";
75 
76     /**
77      * State of a Visualizer object that was not successfully initialized upon creation
78      */
79     public static final int STATE_UNINITIALIZED = 0;
80     /**
81      * State of a Visualizer object that is ready to be used.
82      */
83     public static final int STATE_INITIALIZED   = 1;
84     /**
85      * State of a Visualizer object that is active.
86      */
87     public static final int STATE_ENABLED   = 2;
88 
89     // to keep in sync with system/media/audio_effects/include/audio_effects/effect_visualizer.h
90     /**
91      * Defines a capture mode where amplification is applied based on the content of the captured
92      * data. This is the default Visualizer mode, and is suitable for music visualization.
93      */
94     public static final int SCALING_MODE_NORMALIZED = 0;
95     /**
96      * Defines a capture mode where the playback volume will affect (scale) the range of the
97      * captured data. A low playback volume will lead to low sample and fft values, and vice-versa.
98      */
99     public static final int SCALING_MODE_AS_PLAYED = 1;
100 
101     /**
102      * Defines a measurement mode in which no measurements are performed.
103      */
104     public static final int MEASUREMENT_MODE_NONE = 0;
105 
106     /**
107      * Defines a measurement mode which computes the peak and RMS value in mB, where 0mB is the
108      * maximum sample value, and -9600mB is the minimum value.
109      * Values for peak and RMS can be retrieved with
110      * {@link #getMeasurementPeakRms(MeasurementPeakRms)}.
111      */
112     public static final int MEASUREMENT_MODE_PEAK_RMS = 1 << 0;
113 
114     // to keep in sync with frameworks/base/media/jni/audioeffect/android_media_Visualizer.cpp
115     private static final int NATIVE_EVENT_PCM_CAPTURE = 0;
116     private static final int NATIVE_EVENT_FFT_CAPTURE = 1;
117     private static final int NATIVE_EVENT_SERVER_DIED = 2;
118 
119     // Error codes:
120     /**
121      * Successful operation.
122      */
123     public  static final int SUCCESS              = 0;
124     /**
125      * Unspecified error.
126      */
127     public  static final int ERROR                = -1;
128     /**
129      * Internal operation status. Not returned by any method.
130      */
131     public  static final int ALREADY_EXISTS       = -2;
132     /**
133      * Operation failed due to bad object initialization.
134      */
135     public  static final int ERROR_NO_INIT              = -3;
136     /**
137      * Operation failed due to bad parameter value.
138      */
139     public  static final int ERROR_BAD_VALUE            = -4;
140     /**
141      * Operation failed because it was requested in wrong state.
142      */
143     public  static final int ERROR_INVALID_OPERATION    = -5;
144     /**
145      * Operation failed due to lack of memory.
146      */
147     public  static final int ERROR_NO_MEMORY            = -6;
148     /**
149      * Operation failed due to dead remote object.
150      */
151     public  static final int ERROR_DEAD_OBJECT          = -7;
152 
153     //--------------------------------------------------------------------------
154     // Member variables
155     //--------------------
156     /**
157      * Indicates the state of the Visualizer instance
158      */
159     private int mState = STATE_UNINITIALIZED;
160     /**
161      * Lock to synchronize access to mState
162      */
163     private final Object mStateLock = new Object();
164     /**
165      * System wide unique Identifier of the visualizer engine used by this Visualizer instance
166      */
167     private int mId;
168 
169     /**
170      * Lock to protect listeners updates against event notifications
171      */
172     private final Object mListenerLock = new Object();
173     /**
174      * Handler for events coming from the native code
175      */
176     private NativeEventHandler mNativeEventHandler = null;
177     /**
178      *  PCM and FFT capture listener registered by client
179      */
180     private OnDataCaptureListener mCaptureListener = null;
181     /**
182      *  Server Died listener registered by client
183      */
184     private OnServerDiedListener mServerDiedListener = null;
185 
186     // accessed by native methods
187     private long mNativeVisualizer;
188     private long mJniData;
189 
190     //--------------------------------------------------------------------------
191     // Constructor, Finalize
192     //--------------------
193     /**
194      * Class constructor.
195      * @param audioSession system wide unique audio session identifier. If audioSession
196      *  is not 0, the visualizer will be attached to the MediaPlayer or AudioTrack in the
197      *  same audio session. Otherwise, the Visualizer will apply to the output mix.
198      *
199      * @throws java.lang.UnsupportedOperationException
200      * @throws java.lang.RuntimeException
201      */
202 
Visualizer(int audioSession)203     public Visualizer(int audioSession)
204     throws UnsupportedOperationException, RuntimeException {
205         int[] id = new int[1];
206 
207         synchronized (mStateLock) {
208             mState = STATE_UNINITIALIZED;
209             // native initialization
210             int result = native_setup(new WeakReference<Visualizer>(this), audioSession, id,
211                     ActivityThread.currentOpPackageName());
212             if (result != SUCCESS && result != ALREADY_EXISTS) {
213                 Log.e(TAG, "Error code "+result+" when initializing Visualizer.");
214                 switch (result) {
215                 case ERROR_INVALID_OPERATION:
216                     throw (new UnsupportedOperationException("Effect library not loaded"));
217                 default:
218                     throw (new RuntimeException("Cannot initialize Visualizer engine, error: "
219                             +result));
220                 }
221             }
222             mId = id[0];
223             if (native_getEnabled()) {
224                 mState = STATE_ENABLED;
225             } else {
226                 mState = STATE_INITIALIZED;
227             }
228         }
229     }
230 
231     /**
232      * Releases the native Visualizer resources. It is a good practice to release the
233      * visualization engine when not in use.
234      */
release()235     public void release() {
236         synchronized (mStateLock) {
237             native_release();
238             mState = STATE_UNINITIALIZED;
239         }
240     }
241 
242     @Override
finalize()243     protected void finalize() {
244         native_finalize();
245     }
246 
247     /**
248      * Enable or disable the visualization engine.
249      * @param enabled requested enable state
250      * @return {@link #SUCCESS} in case of success,
251      * {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT} in case of failure.
252      * @throws IllegalStateException
253      */
setEnabled(boolean enabled)254     public int setEnabled(boolean enabled)
255     throws IllegalStateException {
256         synchronized (mStateLock) {
257             if (mState == STATE_UNINITIALIZED) {
258                 throw(new IllegalStateException("setEnabled() called in wrong state: "+mState));
259             }
260             int status = SUCCESS;
261             if ((enabled && (mState == STATE_INITIALIZED)) ||
262                     (!enabled && (mState == STATE_ENABLED))) {
263                 status = native_setEnabled(enabled);
264                 if (status == SUCCESS) {
265                     mState = enabled ? STATE_ENABLED : STATE_INITIALIZED;
266                 }
267             }
268             return status;
269         }
270     }
271 
272     /**
273      * Get current activation state of the visualizer.
274      * @return true if the visualizer is active, false otherwise
275      */
getEnabled()276     public boolean getEnabled()
277     {
278         synchronized (mStateLock) {
279             if (mState == STATE_UNINITIALIZED) {
280                 throw(new IllegalStateException("getEnabled() called in wrong state: "+mState));
281             }
282             return native_getEnabled();
283         }
284     }
285 
286     /**
287      * Returns the capture size range.
288      * @return the mininum capture size is returned in first array element and the maximum in second
289      * array element.
290      */
getCaptureSizeRange()291     public static native int[] getCaptureSizeRange();
292 
293     /**
294      * Returns the maximum capture rate for the callback capture method. This is the maximum value
295      * for the rate parameter of the
296      * {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
297      * @return the maximum capture rate expressed in milliHertz
298      */
getMaxCaptureRate()299     public static native int getMaxCaptureRate();
300 
301     /**
302      * Sets the capture size, i.e. the number of bytes returned by {@link #getWaveForm(byte[])} and
303      * {@link #getFft(byte[])} methods. The capture size must be a power of 2 in the range returned
304      * by {@link #getCaptureSizeRange()}.
305      * This method must not be called when the Visualizer is enabled.
306      * @param size requested capture size
307      * @return {@link #SUCCESS} in case of success,
308      * {@link #ERROR_BAD_VALUE} in case of failure.
309      * @throws IllegalStateException
310      */
setCaptureSize(int size)311     public int setCaptureSize(int size)
312     throws IllegalStateException {
313         synchronized (mStateLock) {
314             if (mState != STATE_INITIALIZED) {
315                 throw(new IllegalStateException("setCaptureSize() called in wrong state: "+mState));
316             }
317             return native_setCaptureSize(size);
318         }
319     }
320 
321     /**
322      * Returns current capture size.
323      * @return the capture size in bytes.
324      */
getCaptureSize()325     public int getCaptureSize()
326     throws IllegalStateException {
327         synchronized (mStateLock) {
328             if (mState == STATE_UNINITIALIZED) {
329                 throw(new IllegalStateException("getCaptureSize() called in wrong state: "+mState));
330             }
331             return native_getCaptureSize();
332         }
333     }
334 
335     /**
336      * Set the type of scaling applied on the captured visualization data.
337      * @param mode see {@link #SCALING_MODE_NORMALIZED}
338      *     and {@link #SCALING_MODE_AS_PLAYED}
339      * @return {@link #SUCCESS} in case of success,
340      *     {@link #ERROR_BAD_VALUE} in case of failure.
341      * @throws IllegalStateException
342      */
setScalingMode(int mode)343     public int setScalingMode(int mode)
344     throws IllegalStateException {
345         synchronized (mStateLock) {
346             if (mState == STATE_UNINITIALIZED) {
347                 throw(new IllegalStateException("setScalingMode() called in wrong state: "
348                         + mState));
349             }
350             return native_setScalingMode(mode);
351         }
352     }
353 
354     /**
355      * Returns the current scaling mode on the captured visualization data.
356      * @return the scaling mode, see {@link #SCALING_MODE_NORMALIZED}
357      *     and {@link #SCALING_MODE_AS_PLAYED}.
358      * @throws IllegalStateException
359      */
getScalingMode()360     public int getScalingMode()
361     throws IllegalStateException {
362         synchronized (mStateLock) {
363             if (mState == STATE_UNINITIALIZED) {
364                 throw(new IllegalStateException("getScalingMode() called in wrong state: "
365                         + mState));
366             }
367             return native_getScalingMode();
368         }
369     }
370 
371     /**
372      * Sets the combination of measurement modes to be performed by this audio effect.
373      * @param mode a mask of the measurements to perform. The valid values are
374      *     {@link #MEASUREMENT_MODE_NONE} (to cancel any measurement)
375      *     or {@link #MEASUREMENT_MODE_PEAK_RMS}.
376      * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE} in case of failure.
377      * @throws IllegalStateException
378      */
setMeasurementMode(int mode)379     public int setMeasurementMode(int mode)
380             throws IllegalStateException {
381         synchronized (mStateLock) {
382             if (mState == STATE_UNINITIALIZED) {
383                 throw(new IllegalStateException("setMeasurementMode() called in wrong state: "
384                         + mState));
385             }
386             return native_setMeasurementMode(mode);
387         }
388     }
389 
390     /**
391      * Returns the current measurement modes performed by this audio effect
392      * @return the mask of the measurements,
393      *     {@link #MEASUREMENT_MODE_NONE} (when no measurements are performed)
394      *     or {@link #MEASUREMENT_MODE_PEAK_RMS}.
395      * @throws IllegalStateException
396      */
getMeasurementMode()397     public int getMeasurementMode()
398             throws IllegalStateException {
399         synchronized (mStateLock) {
400             if (mState == STATE_UNINITIALIZED) {
401                 throw(new IllegalStateException("getMeasurementMode() called in wrong state: "
402                         + mState));
403             }
404             return native_getMeasurementMode();
405         }
406     }
407 
408     /**
409      * Returns the sampling rate of the captured audio.
410      * @return the sampling rate in milliHertz.
411      */
getSamplingRate()412     public int getSamplingRate()
413     throws IllegalStateException {
414         synchronized (mStateLock) {
415             if (mState == STATE_UNINITIALIZED) {
416                 throw(new IllegalStateException("getSamplingRate() called in wrong state: "+mState));
417             }
418             return native_getSamplingRate();
419         }
420     }
421 
422     /**
423      * Returns a waveform capture of currently playing audio content. The capture consists in
424      * a number of consecutive 8-bit (unsigned) mono PCM samples equal to the capture size returned
425      * by {@link #getCaptureSize()}.
426      * <p>This method must be called when the Visualizer is enabled.
427      * @param waveform array of bytes where the waveform should be returned
428      * @return {@link #SUCCESS} in case of success,
429      * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
430      * in case of failure.
431      * @throws IllegalStateException
432      */
getWaveForm(byte[] waveform)433     public int getWaveForm(byte[] waveform)
434     throws IllegalStateException {
435         synchronized (mStateLock) {
436             if (mState != STATE_ENABLED) {
437                 throw(new IllegalStateException("getWaveForm() called in wrong state: "+mState));
438             }
439             return native_getWaveForm(waveform);
440         }
441     }
442     /**
443      * Returns a frequency capture of currently playing audio content.
444      * <p>This method must be called when the Visualizer is enabled.
445      * <p>The capture is an 8-bit magnitude FFT, the frequency range covered being 0 (DC) to half of
446      * the sampling rate returned by {@link #getSamplingRate()}. The capture returns the real and
447      * imaginary parts of a number of frequency points equal to half of the capture size plus one.
448      * <p>Note: only the real part is returned for the first point (DC) and the last point
449      * (sampling frequency / 2).
450      * <p>The layout in the returned byte array is as follows:
451      * <ul>
452      *   <li> n is the capture size returned by getCaptureSize()</li>
453      *   <li> Rfk, Ifk are respectively  the real and imaginary parts of the kth frequency
454      *   component</li>
455      *   <li> If Fs is the sampling frequency retuned by getSamplingRate() the kth frequency is:
456      *   (k*Fs)/(n/2) </li>
457      * </ul>
458      * <table border="0" cellspacing="0" cellpadding="0">
459      * <tr><td>Index </p></td>
460      *     <td>0 </p></td>
461      *     <td>1 </p></td>
462      *     <td>2 </p></td>
463      *     <td>3 </p></td>
464      *     <td>4 </p></td>
465      *     <td>5 </p></td>
466      *     <td>... </p></td>
467      *     <td>n - 2 </p></td>
468      *     <td>n - 1 </p></td></tr>
469      * <tr><td>Data </p></td>
470      *     <td>Rf0 </p></td>
471      *     <td>Rf(n/2) </p></td>
472      *     <td>Rf1 </p></td>
473      *     <td>If1 </p></td>
474      *     <td>Rf2 </p></td>
475      *     <td>If2 </p></td>
476      *     <td>... </p></td>
477      *     <td>Rf(n-1)/2 </p></td>
478      *     <td>If(n-1)/2 </p></td></tr>
479      * </table>
480      * @param fft array of bytes where the FFT should be returned
481      * @return {@link #SUCCESS} in case of success,
482      * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
483      * in case of failure.
484      * @throws IllegalStateException
485      */
getFft(byte[] fft)486     public int getFft(byte[] fft)
487     throws IllegalStateException {
488         synchronized (mStateLock) {
489             if (mState != STATE_ENABLED) {
490                 throw(new IllegalStateException("getFft() called in wrong state: "+mState));
491             }
492             return native_getFft(fft);
493         }
494     }
495 
496     /**
497      * A class to store peak and RMS values.
498      * Peak and RMS are expressed in mB, as described in the
499      * {@link Visualizer#MEASUREMENT_MODE_PEAK_RMS} measurement mode.
500      */
501     public static final class MeasurementPeakRms {
502         /**
503          * The peak value in mB.
504          */
505         public int mPeak;
506         /**
507          * The RMS value in mB.
508          */
509         public int mRms;
510     }
511 
512     /**
513      * Retrieves the latest peak and RMS measurement.
514      * Sets the peak and RMS fields of the supplied {@link Visualizer.MeasurementPeakRms} to the
515      * latest measured values.
516      * @param measurement a non-null {@link Visualizer.MeasurementPeakRms} instance to store
517      *    the measurement values.
518      * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE},
519      *    {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
520      *    in case of failure.
521      */
getMeasurementPeakRms(MeasurementPeakRms measurement)522     public int getMeasurementPeakRms(MeasurementPeakRms measurement) {
523         if (measurement == null) {
524             Log.e(TAG, "Cannot store measurements in a null object");
525             return ERROR_BAD_VALUE;
526         }
527         synchronized (mStateLock) {
528             if (mState != STATE_ENABLED) {
529                 throw (new IllegalStateException("getMeasurementPeakRms() called in wrong state: "
530                         + mState));
531             }
532             return native_getPeakRms(measurement);
533         }
534     }
535 
536     //---------------------------------------------------------
537     // Interface definitions
538     //--------------------
539     /**
540      * The OnDataCaptureListener interface defines methods called by the Visualizer to periodically
541      * update the audio visualization capture.
542      * The client application can implement this interface and register the listener with the
543      * {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
544      */
545     public interface OnDataCaptureListener  {
546         /**
547          * Method called when a new waveform capture is available.
548          * <p>Data in the waveform buffer is valid only within the scope of the callback.
549          * Applications which need access to the waveform data after returning from the callback
550          * should make a copy of the data instead of holding a reference.
551          * @param visualizer Visualizer object on which the listener is registered.
552          * @param waveform array of bytes containing the waveform representation.
553          * @param samplingRate sampling rate of the visualized audio.
554          */
onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate)555         void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate);
556 
557         /**
558          * Method called when a new frequency capture is available.
559          * <p>Data in the fft buffer is valid only within the scope of the callback.
560          * Applications which need access to the fft data after returning from the callback
561          * should make a copy of the data instead of holding a reference.
562          *
563          * <p>In order to obtain magnitude and phase values the following formulas can
564          * be used:
565          *    <pre class="prettyprint">
566          *       for (int i = 0; i &lt; fft.size(); i += 2) {
567          *           float magnitude = (float)Math.hypot(fft[i], fft[i + 1]);
568          *           float phase = (float)Math.atan2(fft[i + 1], fft[i]);
569          *       }</pre>
570          * @param visualizer Visualizer object on which the listener is registered.
571          * @param fft array of bytes containing the frequency representation.
572          *    The fft array only contains the first half of the actual
573          *    FFT spectrum (frequencies up to Nyquist frequency), exploiting
574          *    the symmetry of the spectrum. For each frequencies bin <code>i</code>:
575          *    <ul>
576          *      <li>the element at index <code>2*i</code> in the array contains
577          *          the real part of a complex number,</li>
578          *      <li>the element at index <code>2*i+1</code> contains the imaginary
579          *          part of the complex number.</li>
580          *    </ul>
581          * @param samplingRate sampling rate of the visualized audio.
582          */
onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate)583         void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate);
584     }
585 
586     /**
587      * Registers an OnDataCaptureListener interface and specifies the rate at which the capture
588      * should be updated as well as the type of capture requested.
589      * <p>Call this method with a null listener to stop receiving the capture updates.
590      * @param listener OnDataCaptureListener registered
591      * @param rate rate in milliHertz at which the capture should be updated
592      * @param waveform true if a waveform capture is requested: the onWaveFormDataCapture()
593      * method will be called on the OnDataCaptureListener interface.
594      * @param fft true if a frequency capture is requested: the onFftDataCapture() method will be
595      * called on the OnDataCaptureListener interface.
596      * @return {@link #SUCCESS} in case of success,
597      * {@link #ERROR_NO_INIT} or {@link #ERROR_BAD_VALUE} in case of failure.
598      */
setDataCaptureListener(OnDataCaptureListener listener, int rate, boolean waveform, boolean fft)599     public int setDataCaptureListener(OnDataCaptureListener listener,
600             int rate, boolean waveform, boolean fft) {
601         synchronized (mListenerLock) {
602             mCaptureListener = listener;
603         }
604         if (listener == null) {
605             // make sure capture callback is stopped in native code
606             waveform = false;
607             fft = false;
608         }
609         int status = native_setPeriodicCapture(rate, waveform, fft);
610         if (status == SUCCESS) {
611             if ((listener != null) && (mNativeEventHandler == null)) {
612                 Looper looper;
613                 if ((looper = Looper.myLooper()) != null) {
614                     mNativeEventHandler = new NativeEventHandler(this, looper);
615                 } else if ((looper = Looper.getMainLooper()) != null) {
616                     mNativeEventHandler = new NativeEventHandler(this, looper);
617                 } else {
618                     mNativeEventHandler = null;
619                     status = ERROR_NO_INIT;
620                 }
621             }
622         }
623         return status;
624     }
625 
626     /**
627      * @hide
628      *
629      * The OnServerDiedListener interface defines a method called by the Visualizer to indicate that
630      * the connection to the native media server has been broken and that the Visualizer object will
631      * need to be released and re-created.
632      * The client application can implement this interface and register the listener with the
633      * {@link #setServerDiedListener(OnServerDiedListener)} method.
634      */
635     public interface OnServerDiedListener  {
636         /**
637          * @hide
638          *
639          * Method called when the native media server has died.
640          * <p>If the native media server encounters a fatal error and needs to restart, the binder
641          * connection from the {@link #Visualizer} to the media server will be broken.  Data capture
642          * callbacks will stop happening, and client initiated calls to the {@link #Visualizer}
643          * instance will fail with the error code {@link #DEAD_OBJECT}.  To restore functionality,
644          * clients should {@link #release()} their old visualizer and create a new instance.
645          */
onServerDied()646         void onServerDied();
647     }
648 
649     /**
650      * @hide
651      *
652      * Registers an OnServerDiedListener interface.
653      * <p>Call this method with a null listener to stop receiving server death notifications.
654      * @return {@link #SUCCESS} in case of success,
655      */
setServerDiedListener(OnServerDiedListener listener)656     public int setServerDiedListener(OnServerDiedListener listener) {
657         synchronized (mListenerLock) {
658             mServerDiedListener = listener;
659         }
660         return SUCCESS;
661     }
662 
663     /**
664      * Helper class to handle the forwarding of native events to the appropriate listeners
665      */
666     private class NativeEventHandler extends Handler
667     {
668         private Visualizer mVisualizer;
669 
NativeEventHandler(Visualizer v, Looper looper)670         public NativeEventHandler(Visualizer v, Looper looper) {
671             super(looper);
672             mVisualizer = v;
673         }
674 
handleCaptureMessage(Message msg)675         private void handleCaptureMessage(Message msg) {
676             OnDataCaptureListener l = null;
677             synchronized (mListenerLock) {
678                 l = mVisualizer.mCaptureListener;
679             }
680 
681             if (l != null) {
682                 byte[] data = (byte[])msg.obj;
683                 int samplingRate = msg.arg1;
684 
685                 switch(msg.what) {
686                 case NATIVE_EVENT_PCM_CAPTURE:
687                     l.onWaveFormDataCapture(mVisualizer, data, samplingRate);
688                     break;
689                 case NATIVE_EVENT_FFT_CAPTURE:
690                     l.onFftDataCapture(mVisualizer, data, samplingRate);
691                     break;
692                 default:
693                     Log.e(TAG,"Unknown native event in handleCaptureMessge: "+msg.what);
694                     break;
695                 }
696             }
697         }
698 
handleServerDiedMessage(Message msg)699         private void handleServerDiedMessage(Message msg) {
700             OnServerDiedListener l = null;
701             synchronized (mListenerLock) {
702                 l = mVisualizer.mServerDiedListener;
703             }
704 
705             if (l != null)
706                 l.onServerDied();
707         }
708 
709         @Override
handleMessage(Message msg)710         public void handleMessage(Message msg) {
711             if (mVisualizer == null) {
712                 return;
713             }
714 
715             switch(msg.what) {
716             case NATIVE_EVENT_PCM_CAPTURE:
717             case NATIVE_EVENT_FFT_CAPTURE:
718                 handleCaptureMessage(msg);
719                 break;
720             case NATIVE_EVENT_SERVER_DIED:
721                 handleServerDiedMessage(msg);
722                 break;
723             default:
724                 Log.e(TAG,"Unknown native event: "+msg.what);
725                 break;
726             }
727         }
728     }
729 
730     //---------------------------------------------------------
731     // Interface definitions
732     //--------------------
733 
native_init()734     private static native final void native_init();
735 
native_setup(Object audioeffect_this, int audioSession, int[] id, String opPackageName)736     private native final int native_setup(Object audioeffect_this,
737                                           int audioSession,
738                                           int[] id,
739                                           String opPackageName);
740 
native_finalize()741     private native final void native_finalize();
742 
native_release()743     private native final void native_release();
744 
native_setEnabled(boolean enabled)745     private native final int native_setEnabled(boolean enabled);
746 
native_getEnabled()747     private native final boolean native_getEnabled();
748 
native_setCaptureSize(int size)749     private native final int native_setCaptureSize(int size);
750 
native_getCaptureSize()751     private native final int native_getCaptureSize();
752 
native_setScalingMode(int mode)753     private native final int native_setScalingMode(int mode);
754 
native_getScalingMode()755     private native final int native_getScalingMode();
756 
native_setMeasurementMode(int mode)757     private native final int native_setMeasurementMode(int mode);
758 
native_getMeasurementMode()759     private native final int native_getMeasurementMode();
760 
native_getSamplingRate()761     private native final int native_getSamplingRate();
762 
native_getWaveForm(byte[] waveform)763     private native final int native_getWaveForm(byte[] waveform);
764 
native_getFft(byte[] fft)765     private native final int native_getFft(byte[] fft);
766 
native_getPeakRms(MeasurementPeakRms measurement)767     private native final int native_getPeakRms(MeasurementPeakRms measurement);
768 
native_setPeriodicCapture(int rate, boolean waveForm, boolean fft)769     private native final int native_setPeriodicCapture(int rate, boolean waveForm, boolean fft);
770 
771     //---------------------------------------------------------
772     // Java methods called from the native side
773     //--------------------
774     @SuppressWarnings("unused")
postEventFromNative(Object effect_ref, int what, int arg1, int arg2, Object obj)775     private static void postEventFromNative(Object effect_ref,
776             int what, int arg1, int arg2, Object obj) {
777         Visualizer visu = (Visualizer)((WeakReference)effect_ref).get();
778         if (visu == null) {
779             return;
780         }
781 
782         if (visu.mNativeEventHandler != null) {
783             Message m = visu.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj);
784             visu.mNativeEventHandler.sendMessage(m);
785         }
786 
787     }
788 }
789 
790