Merge "Added Visualizer effect." into gingerbread
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
index 66670f3..e9ff8a3 100644
--- a/include/media/AudioEffect.h
+++ b/include/media/AudioEffect.h
@@ -307,29 +307,18 @@
             int32_t     priority() const { return mPriority; }
 
 
-    /* Enables the effect engine.
+    /* Enables or disables the effect engine.
      *
      * Parameters:
-     *      None.
+     *  enabled: requested enable state.
      *
      * Returned status (from utils/Errors.h) can be:
      *  - NO_ERROR: successful operation
-     *  - INVALID_OPERATION: the application does not have control of the effect engine
+     *  - INVALID_OPERATION: the application does not have control of the effect engine or the
+     *  effect is already in the requested state.
      */
-            status_t    enable();
-
-    /* Disables the effect engine.
-     *
-     * Parameters:
-     *      None.
-     *
-     * Returned status (from utils/Errors.h) can be:
-     *  - NO_ERROR: successful operation
-     *  - INVALID_OPERATION: the application does not have control of the effect engine
-     */
-             status_t    disable();
-
-             bool        isEnabled() const;
+    virtual status_t    setEnabled(bool enabled);
+            bool        getEnabled() const;
 
     /* Sets a parameter value.
      *
@@ -342,7 +331,7 @@
      *  - BAD_VALUE: invalid parameter identifier or value.
      *  - DEAD_OBJECT: the effect engine has been deleted.
      */
-             status_t   setParameter(effect_param_t *param);
+     virtual status_t   setParameter(effect_param_t *param);
 
     /* Prepare a new parameter value that will be set by next call to
      * setParameterCommit(). This method can be used to set multiple parameters
@@ -359,7 +348,7 @@
      *  - NO_MEMORY: no more space available in shared memory used for deferred parameter
      *  setting.
      */
-             status_t   setParameterDeferred(effect_param_t *param);
+     virtual status_t   setParameterDeferred(effect_param_t *param);
 
      /* Commit all parameter values previously prepared by setParameterDeferred().
       *
@@ -373,7 +362,7 @@
       *     as to which of the parameters caused this error.
       *  - DEAD_OBJECT: the effect engine has been deleted.
       */
-             status_t   setParameterCommit();
+     virtual status_t   setParameterCommit();
 
     /* Gets a parameter value.
      *
@@ -387,13 +376,17 @@
      *  - BAD_VALUE: invalid parameter identifier.
      *  - DEAD_OBJECT: the effect engine has been deleted.
      */
-             status_t   getParameter(effect_param_t *param);
+     virtual status_t   getParameter(effect_param_t *param);
 
      /* Sends a command and receives a response to/from effect engine.
       *     See EffectApi.h for details on effect command() function, valid command codes
       *     and formats.
       */
-             status_t command(int32_t cmdCode, int32_t cmdSize, void *cmdData, int32_t *replySize, void *replyData);
+     virtual status_t command(int32_t cmdCode,
+                              int32_t cmdSize,
+                              void *cmdData,
+                              int32_t *replySize,
+                              void *replyData);
 
 
      /*
@@ -409,6 +402,17 @@
       */
      static status_t guidToString(const effect_uuid_t *guid, char *str, size_t maxLen);
 
+protected:
+     volatile int32_t        mEnabled;           // enable state
+     int32_t                 mSessionId;         // audio session ID
+     int32_t                 mPriority;          // priority for effect control
+     status_t                mStatus;            // effect status
+     effect_callback_t       mCbf;               // callback function for status, control and
+                                                 // parameter changes notifications
+     void*                   mUserData;          // client context for callback function
+     effect_descriptor_t     mDescriptor;        // effect descriptor
+     int32_t                 mId;                // system wide unique effect engine instance ID
+
 private:
 
      // Implements the IEffectClient interface
@@ -419,9 +423,17 @@
         EffectClient(AudioEffect *effect) : mEffect(effect){}
 
         // IEffectClient
-        virtual void controlStatusChanged(bool controlGranted) {mEffect->controlStatusChanged(controlGranted);}
-        virtual void enableStatusChanged(bool enabled) {mEffect->enableStatusChanged(enabled);}
-        virtual void commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData) {
+        virtual void controlStatusChanged(bool controlGranted) {
+            mEffect->controlStatusChanged(controlGranted);
+        }
+        virtual void enableStatusChanged(bool enabled) {
+            mEffect->enableStatusChanged(enabled);
+        }
+        virtual void commandExecuted(int cmdCode,
+                                     int cmdSize,
+                                     void *pCmdData,
+                                     int replySize,
+                                     void *pReplyData) {
             mEffect->commandExecuted(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
         }
 
@@ -446,14 +458,6 @@
     sp<EffectClient>        mIEffectClient;     // IEffectClient implementation
     sp<IMemory>             mCblkMemory;        // shared memory for deferred parameter setting
     effect_param_cblk_t*    mCblk;              // control block for deferred parameter setting
-    int32_t                 mPriority;          // priority for effect control
-    status_t                mStatus;            // effect status
-    volatile int32_t        mEnabled;           // enable state
-    effect_callback_t       mCbf;               // callback function for status, control, parameter changes notifications
-    void*                   mUserData;          // client context for callback function
-    effect_descriptor_t     mDescriptor;        // effect descriptor
-    int32_t                 mId;                // system wide unique effect engine instance identifier
-    int32_t                 mSessionId;         // audio session ID
 };
 
 
diff --git a/include/media/EffectVisualizerApi.h b/include/media/EffectVisualizerApi.h
new file mode 100644
index 0000000..1155db8
--- /dev/null
+++ b/include/media/EffectVisualizerApi.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_EFFECTVISUALIZERAPI_H_
+#define ANDROID_EFFECTVISUALIZERAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+//TODO replace by openSL ES include when available
+static const effect_uuid_t SL_IID_VISUALIZATION_ =
+    { 0xe46b26a0, 0xdddd, 0x11db, 0x8afd, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_VISUALIZATION = &SL_IID_VISUALIZATION_;
+
+#define VISUALIZER_CAPTURE_SIZE_MAX 1024  // maximum capture size in samples
+#define VISUALIZER_CAPTURE_SIZE_MIN 128   // minimum capture size in samples
+
+/* enumerated parameters for Visualizer effect */
+typedef enum
+{
+    VISU_PARAM_CAPTURE_SIZE,        // Sets the number PCM samples in the capture.
+} t_visualizer_params;
+
+/* commands */
+typedef enum
+{
+    VISU_CMD_CAPTURE = EFFECT_CMD_FIRST_PROPRIETARY, // Gets the latest PCM capture.
+}t_visualizer_cmds;
+
+// VISU_CMD_CAPTURE retrieves the latest PCM snapshot captured by the visualizer engine.
+// It returns the number of samples specified by VISU_PARAM_CAPTURE_SIZE
+// in 8 bit unsigned format (0 = 0x80)
+
+#if __cplusplus
+}  // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTVISUALIZERAPI_H_*/
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index e892875..9416ca1 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -48,10 +48,6 @@
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
     virtual sp<IOMX>            getOMX() = 0;
-
-    // Take a peek at currently playing audio, for visualization purposes.
-    // This returns a buffer of 16 bit mono PCM data, or NULL if no visualization buffer is currently available.
-    virtual sp<IMemory>         snoop() = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
new file mode 100644
index 0000000..5d51de8
--- /dev/null
+++ b/include/media/Visualizer.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_MEDIA_VISUALIZER_H
+#define ANDROID_MEDIA_VISUALIZER_H
+
+#include <media/AudioEffect.h>
+#include <media/EffectVisualizerApi.h>
+#include <string.h>
+
+/**
+ * The Visualizer class enables application to retrieve part of the currently playing audio for
+ * visualization purpose. It is not an audio recording interface and only returns partial and low
+ * quality audio content. However, to protect privacy of certain audio data (e.g voice mail) the use
+ * of the visualizer requires the permission android.permission.RECORD_AUDIO.
+ * The audio session ID passed to the constructor indicates which audio content should be
+ * visualized:
+ * - If the session is 0, the audio output mix is visualized
+ * - If the session is not 0, the audio from a particular MediaPlayer or AudioTrack
+ *   using this audio session is visualized
+ * Two types of representation of audio content can be captured:
+ * - Waveform data: consecutive 8-bit (unsigned) mono samples by using the getWaveForm() method
+ * - Frequency data: 8-bit magnitude FFT by using the getFft() method
+ *
+ * The length of the capture can be retrieved or specified by calling respectively
+ * getCaptureSize() and setCaptureSize() methods. Note that the size of the FFT
+ * is half of the specified capture size but both sides of the spectrum are returned yielding in a
+ * number of bytes equal to the capture size. The capture size must be a power of 2 in the range
+ * returned by getMinCaptureSize() and getMaxCaptureSize().
+ * In addition to the polling capture mode, a callback mode is also available by installing a
+ * callback function by use of the setCaptureCallBack() method. The rate at which the callback
+ * is called as well as the type of data returned is specified.
+ * Before capturing data, the Visualizer must be enabled by calling the setEnabled() method.
+ * When data capture is not needed any more, the Visualizer should be disabled.
+ */
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class Visualizer: public AudioEffect {
+public:
+
+    enum callback_flags {
+        CAPTURE_WAVEFORM = 0x00000001,  // capture callback returns a PCM wave form
+        CAPTURE_FFT = 0x00000002,       // apture callback returns a frequency representation
+        CAPTURE_CALL_JAVA = 0x00000004  // the callback thread can call java
+    };
+
+
+    /* Constructor.
+     * See AudioEffect constructor for details on parameters.
+     */
+                        Visualizer(int32_t priority = 0,
+                                   effect_callback_t cbf = 0,
+                                   void* user = 0,
+                                   int sessionId = 0);
+
+                        ~Visualizer();
+
+    virtual status_t    setEnabled(bool enabled);
+
+    // maximum capture size in samples
+    static uint32_t getMaxCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MAX; }
+    // minimum capture size in samples
+    static uint32_t getMinCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MIN; }
+    // maximum capture rate in millihertz
+    static uint32_t getMaxCaptureRate() { return CAPTURE_RATE_MAX; }
+
+    // callback used to return periodic PCM or FFT captures to the application. Either one or both
+    // types of data are returned (PCM and FFT) according to flags indicated when installing the
+    // callback. When a type of data is not present, the corresponding size (waveformSize or
+    // fftSize) is 0.
+    typedef void (*capture_cbk_t)(void* user,
+                                    uint32_t waveformSize,
+                                    uint8_t *waveform,
+                                    uint32_t fftSize,
+                                    uint8_t *fft,
+                                    uint32_t samplingrate);
+
+    // install a callback to receive periodic captures. The capture rate is specified in milliHertz
+    // and the capture format is according to flags  (see callback_flags).
+    status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate);
+
+    // set the capture size capture size must be a power of two in the range
+    // [VISUALIZER_CAPTURE_SIZE_MAX. VISUALIZER_CAPTURE_SIZE_MIN]
+    // must be called when the visualizer is not enabled
+    status_t setCaptureSize(uint32_t size);
+    uint32_t getCaptureSize() { return mCaptureSize; }
+
+    // returns the capture rate indicated when installing the callback
+    uint32_t getCaptureRate() { return mCaptureRate; }
+
+    // returns the sampling rate of the audio being captured
+    uint32_t getSamplingRate() { return mSampleRate; }
+
+    // return a capture in PCM 8 bit unsigned format. The size of the capture is equal to
+    // getCaptureSize()
+    status_t getWaveForm(uint8_t *waveform);
+
+    // return a capture in FFT 8 bit signed format. The size of the capture is equal to
+    // getCaptureSize() but the length of the FFT is half of the size (both parts of the spectrum
+    // are returned
+    status_t getFft(uint8_t *fft);
+
+private:
+
+    static const uint32_t CAPTURE_RATE_MAX = 20000;
+    static const uint32_t CAPTURE_RATE_DEF = 10000;
+    static const uint32_t CAPTURE_SIZE_DEF = VISUALIZER_CAPTURE_SIZE_MAX;
+
+    /* internal class to handle the callback */
+    class CaptureThread : public Thread
+    {
+    public:
+        CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava = false);
+
+    private:
+        friend class Visualizer;
+        virtual bool        threadLoop();
+        virtual status_t    readyToRun();
+        virtual void        onFirstRef();
+        Visualizer& mReceiver;
+        Mutex       mLock;
+        uint32_t mSleepTimeUs;
+    };
+
+    status_t doFft(uint8_t *fft, uint8_t *waveform);
+    void periodicCapture();
+    uint32_t initCaptureSize();
+
+    Mutex mLock;
+    uint32_t mCaptureRate;
+    uint32_t mCaptureSize;
+    uint32_t mSampleRate;
+    capture_cbk_t mCaptureCallBack;
+    void *mCaptureCbkUser;
+    sp<CaptureThread> mCaptureThread;
+    uint32_t mCaptureFlags;
+    void *mFftTable;
+};
+
+
+}; // namespace android
+
+#endif // ANDROID_MEDIA_VISUALIZER_H
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 62a4e50..4963f73 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -166,7 +166,6 @@
             void            notify(int msg, int ext1, int ext2);
     static  sp<IMemory>     decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
     static  sp<IMemory>     decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
-    static  int             snoop(short *data, int len, int kind);
             status_t        invoke(const Parcel& request, Parcel *reply);
             status_t        setMetadataFilter(const Parcel& filter);
             status_t        getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
diff --git a/media/libeffects/Android.mk b/media/libeffects/Android.mk
index b5f1d42..54e87f3 100644
--- a/media/libeffects/Android.mk
+++ b/media/libeffects/Android.mk
@@ -94,3 +94,33 @@
 include $(BUILD_SHARED_LIBRARY)
 
 endif
+
+
+# Visualizer library
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	EffectVisualizer.cpp
+
+LOCAL_CFLAGS+= -O2
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+LOCAL_MODULE:= libvisualizer
+
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+LOCAL_LDLIBS += -ldl
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_C_INCLUDES := \
+	$(call include-path-for, graphics corecg)
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/EffectVisualizer.cpp b/media/libeffects/EffectVisualizer.cpp
new file mode 100644
index 0000000..f27e296
--- /dev/null
+++ b/media/libeffects/EffectVisualizer.cpp
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#define LOG_TAG "Visualizer"
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <new>
+#include <media/EffectVisualizerApi.h>
+
+namespace android {
+
+// effect_interface_t interface implementation for visualizer effect
+extern "C" const struct effect_interface_s gVisualizerInterface;
+
+// Google Visualizer UUID: d069d9e0-8329-11df-9168-0002a5d5c51b
+const effect_descriptor_t gVisualizerDescriptor = {
+        {0xe46b26a0, 0xdddd, 0x11db, 0x8afd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
+        {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
+        EFFECT_API_VERSION,
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST),
+        0, // TODO
+        1,
+        "Visualizer",
+        "Google Inc.",
+};
+
+enum visualizer_state_e {
+    VISUALIZER_STATE_UNINITIALIZED,
+    VISUALIZER_STATE_INITIALIZED,
+    VISUALIZER_STATE_ACTIVE,
+};
+
+struct VisualizerContext {
+    const struct effect_interface_s *mItfe;
+    effect_config_t mConfig;
+    uint32_t mState;
+    uint32_t mCaptureIdx;
+    uint32_t mCaptureSize;
+    uint32_t mCurrentBuf;
+    uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
+};
+
+
+//
+//--- Local functions
+//
+
+void Visualizer_reset(VisualizerContext *pContext)
+{
+    pContext->mCaptureIdx = 0;
+    pContext->mCurrentBuf = 0;
+    memset(pContext->mCaptureBuf[0], 0, VISUALIZER_CAPTURE_SIZE_MAX);
+    memset(pContext->mCaptureBuf[1], 0, VISUALIZER_CAPTURE_SIZE_MAX);
+}
+
+//----------------------------------------------------------------------------
+// Visualizer_configure()
+//----------------------------------------------------------------------------
+// Purpose: Set input and output audio configuration.
+//
+// Inputs:
+//  pContext:   effect engine context
+//  pConfig:    pointer to effect_config_t structure holding input and output
+//      configuration parameters
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int Visualizer_configure(VisualizerContext *pContext, effect_config_t *pConfig)
+{
+    LOGV("Visualizer_configure start");
+
+    if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
+    if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
+    if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
+    if (pConfig->inputCfg.channels != CHANNEL_STEREO) return -EINVAL;
+    if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
+            pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
+    if (pConfig->inputCfg.format != SAMPLE_FORMAT_PCM_S15) return -EINVAL;
+
+    memcpy(&pContext->mConfig, pConfig, sizeof(effect_config_t));
+
+    Visualizer_reset(pContext);
+
+    return 0;
+}
+
+
+//----------------------------------------------------------------------------
+// Visualizer_init()
+//----------------------------------------------------------------------------
+// Purpose: Initialize engine with default configuration.
+//
+// Inputs:
+//  pContext:   effect engine context
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int Visualizer_init(VisualizerContext *pContext)
+{
+    pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+    pContext->mConfig.inputCfg.channels = CHANNEL_STEREO;
+    pContext->mConfig.inputCfg.format = SAMPLE_FORMAT_PCM_S15;
+    pContext->mConfig.inputCfg.samplingRate = 44100;
+    pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
+    pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
+    pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
+    pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
+    pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+    pContext->mConfig.outputCfg.channels = CHANNEL_STEREO;
+    pContext->mConfig.outputCfg.format = SAMPLE_FORMAT_PCM_S15;
+    pContext->mConfig.outputCfg.samplingRate = 44100;
+    pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
+    pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
+    pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
+    pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+    pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX;
+
+    Visualizer_configure(pContext, &pContext->mConfig);
+
+    return 0;
+}
+
+//
+//--- Effect Library Interface Implementation
+//
+
+extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects) {
+    *pNumEffects = 1;
+    return 0;
+}
+
+extern "C" int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) {
+    if (pDescriptor == NULL) {
+        return -EINVAL;
+    }
+    if (index > 0) {
+        return -EINVAL;
+    }
+    memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
+    return 0;
+}
+
+extern "C" int EffectCreate(effect_uuid_t *uuid,
+        int32_t sessionId,
+        int32_t ioId,
+        effect_interface_t *pInterface) {
+    int ret;
+    int i;
+
+    if (pInterface == NULL || uuid == NULL) {
+        return -EINVAL;
+    }
+
+    if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
+        return -EINVAL;
+    }
+
+    VisualizerContext *pContext = new VisualizerContext;
+
+    pContext->mItfe = &gVisualizerInterface;
+    pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
+
+    ret = Visualizer_init(pContext);
+    if (ret < 0) {
+        LOGW("EffectCreate() init failed");
+        delete pContext;
+        return ret;
+    }
+
+    *pInterface = (effect_interface_t)pContext;
+
+    pContext->mState = VISUALIZER_STATE_INITIALIZED;
+
+    LOGV("EffectCreate %p", pContext);
+
+    return 0;
+
+}
+
+extern "C" int EffectRelease(effect_interface_t interface) {
+    VisualizerContext * pContext = (VisualizerContext *)interface;
+
+    LOGV("EffectRelease %p", interface);
+    if (pContext == NULL) {
+        return -EINVAL;
+    }
+    pContext->mState = VISUALIZER_STATE_UNINITIALIZED;
+    delete pContext;
+
+    return 0;
+}
+
+//
+//--- Effect Control Interface Implementation
+//
+
+static inline int16_t clamp16(int32_t sample)
+{
+    if ((sample>>15) ^ (sample>>31))
+        sample = 0x7FFF ^ (sample>>31);
+    return sample;
+}
+
+extern "C" int Visualizer_process(
+        effect_interface_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
+{
+    android::VisualizerContext * pContext = (android::VisualizerContext *)self;
+
+    if (pContext == NULL) {
+        return -EINVAL;
+    }
+    if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
+        return -ENOSYS;
+    }
+
+    if (inBuffer == NULL || inBuffer->raw == NULL ||
+        outBuffer == NULL || outBuffer->raw == NULL ||
+        inBuffer->frameCount != outBuffer->frameCount ||
+        inBuffer->frameCount == 0) {
+        return -EINVAL;
+    }
+
+    // all code below assumes stereo 16 bit PCM output and input
+    uint32_t captIdx;
+    uint32_t inIdx;
+    uint8_t *buf = pContext->mCaptureBuf[pContext->mCurrentBuf];
+    for (inIdx = 0, captIdx = pContext->mCaptureIdx;
+         inIdx < inBuffer->frameCount && captIdx < pContext->mCaptureSize;
+         inIdx++, captIdx++) {
+        int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
+        smp = (smp + (1 << 8)) >> 9;
+        buf[captIdx] = ((uint8_t)smp)^0x80;
+    }
+    pContext->mCaptureIdx = captIdx;
+
+    // go to next buffer when buffer full
+    if (pContext->mCaptureIdx == pContext->mCaptureSize) {
+        pContext->mCurrentBuf ^= 1;
+        pContext->mCaptureIdx = 0;
+    }
+
+    if (inBuffer->raw != outBuffer->raw) {
+        if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+            for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
+                outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
+            }
+        } else {
+            memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
+        }
+    }
+    return 0;
+}   // end Visualizer_process
+
+extern "C" int Visualizer_command(effect_interface_t self, int cmdCode, int cmdSize,
+        void *pCmdData, int *replySize, void *pReplyData) {
+
+    android::VisualizerContext * pContext = (android::VisualizerContext *)self;
+    int retsize;
+
+    if (pContext == NULL || pContext->mState == VISUALIZER_STATE_UNINITIALIZED) {
+        return -EINVAL;
+    }
+
+//    LOGV("Visualizer_command command %d cmdSize %d",cmdCode, cmdSize);
+
+    switch (cmdCode) {
+    case EFFECT_CMD_INIT:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        *(int *) pReplyData = Visualizer_init(pContext);
+        break;
+    case EFFECT_CMD_CONFIGURE:
+        if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
+                || pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        *(int *) pReplyData = Visualizer_configure(pContext,
+                (effect_config_t *) pCmdData);
+        break;
+    case EFFECT_CMD_RESET:
+        Visualizer_reset(pContext);
+        break;
+    case EFFECT_CMD_ENABLE:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
+            return -ENOSYS;
+        }
+        pContext->mState = VISUALIZER_STATE_ACTIVE;
+        LOGV("EFFECT_CMD_ENABLE() OK");
+        *(int *)pReplyData = 0;
+        break;
+    case EFFECT_CMD_DISABLE:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
+            return -ENOSYS;
+        }
+        pContext->mState = VISUALIZER_STATE_INITIALIZED;
+        LOGV("EFFECT_CMD_DISABLE() OK");
+        *(int *)pReplyData = 0;
+        break;
+    case EFFECT_CMD_GET_PARAM: {
+        if (pCmdData == NULL ||
+            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
+            pReplyData == NULL ||
+            *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
+            return -EINVAL;
+        }
+        memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
+        effect_param_t *p = (effect_param_t *)pReplyData;
+        p->status = 0;
+        *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
+        if (p->psize != sizeof(uint32_t) ||
+            *(uint32_t *)p->data != VISU_PARAM_CAPTURE_SIZE) {
+            p->status = -EINVAL;
+            break;
+        }
+        LOGV("get mCaptureSize = %d", pContext->mCaptureSize);
+        *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
+        p->vsize = sizeof(uint32_t);
+        *replySize += sizeof(uint32_t);
+        } break;
+    case EFFECT_CMD_SET_PARAM: {
+        if (pCmdData == NULL ||
+            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
+            pReplyData == NULL || *replySize != sizeof(int32_t)) {
+            return -EINVAL;
+        }
+        *(int32_t *)pReplyData = 0;
+        effect_param_t *p = (effect_param_t *)pCmdData;
+        if (p->psize != sizeof(uint32_t) ||
+            p->vsize != sizeof(uint32_t) ||
+            *(uint32_t *)p->data != VISU_PARAM_CAPTURE_SIZE) {
+            *(int32_t *)pReplyData = -EINVAL;
+            break;;
+        }
+        pContext->mCaptureSize = *((uint32_t *)p->data + 1);
+        LOGV("set mCaptureSize = %d", pContext->mCaptureSize);
+        } break;
+    case EFFECT_CMD_SET_DEVICE:
+    case EFFECT_CMD_SET_VOLUME:
+    case EFFECT_CMD_SET_AUDIO_MODE:
+        break;
+
+
+    case VISU_CMD_CAPTURE:
+        if (pReplyData == NULL || *replySize != (int)pContext->mCaptureSize) {
+            LOGV("VISU_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d",
+                    *replySize, pContext->mCaptureSize);
+            return -EINVAL;
+        }
+        if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
+            memcpy(pReplyData,
+                   pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
+                   pContext->mCaptureSize);
+        } else {
+            memset(pReplyData, 0x80, pContext->mCaptureSize);
+        }
+        break;
+
+    default:
+        LOGW("Visualizer_command invalid command %d",cmdCode);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+// effect_interface_t interface implementation for visualizer effect
+const struct effect_interface_s gVisualizerInterface = {
+        Visualizer_process,
+        Visualizer_command
+};
+
+} // namespace
+
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index de9e51d..977e6be 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -30,7 +30,8 @@
     MediaProfiles.cpp \
     IEffect.cpp \
     IEffectClient.cpp \
-    AudioEffect.cpp
+    AudioEffect.cpp \
+    Visualizer.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libui libcutils libutils libbinder libsonivox libicuuc libexpat libsurfaceflinger_client libcamera_client
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 4afa2dc..783249d 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -171,7 +171,7 @@
     LOGV("Destructor %p", this);
 
     if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) {
-        disable();
+        setEnabled(false);
         if (mIEffect != NULL) {
             mIEffect->disconnect();
             mIEffect->asBinder()->unlinkToDeath(mIEffectClient);
@@ -196,36 +196,28 @@
     return mDescriptor;
 }
 
-bool AudioEffect::isEnabled() const
+bool AudioEffect::getEnabled() const
 {
     return (mEnabled != 0);
 }
 
-status_t AudioEffect::enable()
+status_t AudioEffect::setEnabled(bool enabled)
 {
     if (mStatus != NO_ERROR) {
         return INVALID_OPERATION;
     }
-    LOGV("enable %p", this);
 
-    if (android_atomic_or(1, &mEnabled) == 0) {
-       return mIEffect->enable();
+    if (enabled) {
+        LOGV("enable %p", this);
+        if (android_atomic_or(1, &mEnabled) == 0) {
+           return mIEffect->enable();
+        }
+    } else {
+        LOGV("disable %p", this);
+        if (android_atomic_and(~1, &mEnabled) == 1) {
+           return mIEffect->disable();
+        }
     }
-
-    return INVALID_OPERATION;
-}
-
-status_t AudioEffect::disable()
-{
-    if (mStatus != NO_ERROR) {
-        return INVALID_OPERATION;
-    }
-    LOGV("disable %p", this);
-
-    if (android_atomic_and(~1, &mEnabled) == 1) {
-       return mIEffect->disable();
-    }
-
     return INVALID_OPERATION;
 }
 
@@ -349,7 +341,7 @@
 
 void AudioEffect::enableStatusChanged(bool enabled)
 {
-    LOGV("enableStatusChanged %p enabled %d", this, enabled);
+    LOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf);
     if (mStatus == ALREADY_EXISTS) {
         mEnabled = enabled;
         if (mCbf) {
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 1ae222e..4abfa75 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -35,8 +35,7 @@
     DECODE_FD,
     CREATE_MEDIA_RECORDER,
     CREATE_METADATA_RETRIEVER,
-    GET_OMX,
-    SNOOP
+    GET_OMX
 };
 
 class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
@@ -134,14 +133,6 @@
         return interface_cast<IMemory>(reply.readStrongBinder());
     }
 
-    virtual sp<IMemory> snoop()
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
-        remote()->transact(SNOOP, data, &reply);
-        return interface_cast<IMemory>(reply.readStrongBinder());
-    }
-
     virtual sp<IOMX> getOMX() {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
@@ -221,12 +212,6 @@
             reply->writeStrongBinder(player->asBinder());
             return NO_ERROR;
         } break;
-        case SNOOP: {
-            CHECK_INTERFACE(IMediaPlayerService, data, reply);
-            sp<IMemory> snooped_audio = snoop();
-            reply->writeStrongBinder(snooped_audio->asBinder());
-            return NO_ERROR;
-        } break;
         case CREATE_MEDIA_RECORDER: {
             CHECK_INTERFACE(IMediaPlayerService, data, reply);
             pid_t pid = data.readInt32();
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
new file mode 100644
index 0000000..47e96e5
--- /dev/null
+++ b/media/libmedia/Visualizer.cpp
@@ -0,0 +1,330 @@
+/*
+**
+** Copyright 2010, 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.
+*/
+
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Visualizer"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include <media/Visualizer.h>
+
+extern "C" {
+#define FLOATING_POINT 1
+#include "fftwrap.h"
+}
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+Visualizer::Visualizer (int32_t priority,
+         effect_callback_t cbf,
+         void* user,
+         int sessionId)
+    :   AudioEffect(SL_IID_VISUALIZATION, NULL, priority, cbf, user, sessionId),
+        mCaptureRate(CAPTURE_RATE_DEF),
+        mCaptureSize(CAPTURE_SIZE_DEF),
+        mSampleRate(44100000),
+        mCaptureCallBack(NULL),
+        mCaptureCbkUser(NULL)
+{
+    initCaptureSize();
+    if (mCaptureSize != 0) {
+        mFftTable = spx_fft_init(mCaptureSize);
+    } else {
+        mFftTable = NULL;
+    }
+}
+
+Visualizer::~Visualizer()
+{
+    if (mFftTable != NULL) {
+        spx_fft_destroy(mFftTable);
+    }
+}
+
+status_t Visualizer::setEnabled(bool enabled)
+{
+    Mutex::Autolock _l(mLock);
+
+    sp<CaptureThread> t = mCaptureThread;
+    if (t != 0) {
+        if (enabled) {
+            if (t->exitPending()) {
+                if (t->requestExitAndWait() == WOULD_BLOCK) {
+                    LOGE("Visualizer::enable() called from thread");
+                    return INVALID_OPERATION;
+                }
+            }
+        }
+        t->mLock.lock();
+     }
+
+    status_t status = AudioEffect::setEnabled(enabled);
+
+    if (status == NO_ERROR) {
+        if (t != 0) {
+            if (enabled) {
+                t->run("AudioTrackThread");
+            } else {
+                t->requestExit();
+            }
+        }
+    }
+
+    if (t != 0) {
+        t->mLock.unlock();
+    }
+
+    return status;
+}
+
+status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate)
+{
+    if (rate > CAPTURE_RATE_MAX) {
+        return BAD_VALUE;
+    }
+    Mutex::Autolock _l(mLock);
+
+    if (mEnabled) {
+        return INVALID_OPERATION;
+    }
+
+    sp<CaptureThread> t = mCaptureThread;
+    if (t != 0) {
+        t->mLock.lock();
+    }
+    mCaptureThread.clear();
+    mCaptureCallBack = cbk;
+    mCaptureCbkUser = user;
+    mCaptureFlags = flags;
+    mCaptureRate = rate;
+
+    if (t != 0) {
+        t->mLock.unlock();
+    }
+
+    if (cbk != NULL) {
+        mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
+        if (mCaptureThread == 0) {
+            LOGE("Could not create callback thread");
+            return NO_INIT;
+        }
+    }
+    LOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
+            rate, mCaptureThread.get(), mCaptureFlags);
+    return NO_ERROR;
+}
+
+status_t Visualizer::setCaptureSize(uint32_t size)
+{
+    if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
+        size < VISUALIZER_CAPTURE_SIZE_MIN ||
+        AudioSystem::popCount(size) != 1) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mLock);
+    if (mEnabled) {
+        return INVALID_OPERATION;
+    }
+
+    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+    effect_param_t *p = (effect_param_t *)buf32;
+
+    p->psize = sizeof(uint32_t);
+    p->vsize = sizeof(uint32_t);
+    *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE;
+    *((int32_t *)p->data + 1)= size;
+    status_t status = setParameter(p);
+
+    LOGV("setCaptureSize size %d  status %d p->status %d", size, status, p->status);
+
+    if (status == NO_ERROR) {
+        status = p->status;
+    }
+    if (status == NO_ERROR) {
+        mCaptureSize = size;
+        if (mFftTable != NULL) {
+            spx_fft_destroy(mFftTable);
+        }
+        mFftTable = spx_fft_init(mCaptureSize);
+        LOGV("setCaptureSize size %d mFftTable %p", mCaptureSize, mFftTable);
+    }
+
+    return status;
+}
+
+status_t Visualizer::getWaveForm(uint8_t *waveform)
+{
+    if (waveform == NULL) {
+        return BAD_VALUE;
+    }
+    if (mCaptureSize == 0) {
+        return NO_INIT;
+    }
+
+    status_t status = NO_ERROR;
+    if (mEnabled) {
+        int32_t replySize = mCaptureSize;
+        status_t status = command(VISU_CMD_CAPTURE, 0, NULL, &replySize, waveform);
+        if (replySize == 0) {
+            status = NOT_ENOUGH_DATA;
+        }
+    } else {
+        memset(waveform, 0x80, mCaptureSize);
+    }
+    return status;
+}
+
+status_t Visualizer::getFft(uint8_t *fft)
+{
+    if (fft == NULL) {
+        return BAD_VALUE;
+    }
+    if (mCaptureSize == 0) {
+        return NO_INIT;
+    }
+
+    status_t status = NO_ERROR;
+    if (mEnabled) {
+        uint8_t buf[mCaptureSize];
+        status_t status = getWaveForm(buf);
+        if (status == NO_ERROR) {
+            status = doFft(fft, buf);
+        }
+    } else {
+        memset(fft, 0, mCaptureSize);
+    }
+    return status;
+}
+
+status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
+{
+    if (mFftTable == NULL) {
+        return NO_INIT;
+    }
+
+    float fsrc[mCaptureSize];
+    for (uint32_t i = 0; i < mCaptureSize; i++) {
+        fsrc[i] = (int16_t)(waveform[i] ^ 0x80) << 8;
+    }
+    float fdst[mCaptureSize];
+    spx_fft_float(mFftTable, fsrc, fdst);
+    for (uint32_t i = 0; i < mCaptureSize; i++) {
+        fft[i] = (uint8_t)((int32_t)fdst[i] >> 8);
+    }
+    return NO_ERROR;
+}
+
+void Visualizer::periodicCapture()
+{
+    Mutex::Autolock _l(mLock);
+    LOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
+            this, mCaptureCallBack, mCaptureFlags);
+    if (mCaptureCallBack != NULL &&
+        (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
+        mCaptureSize != 0) {
+        uint8_t waveform[mCaptureSize];
+        status_t status = getWaveForm(waveform);
+        if (status != NO_ERROR) {
+            return;
+        }
+        uint8_t fft[mCaptureSize];
+        if (mCaptureFlags & CAPTURE_FFT) {
+            status = doFft(fft, waveform);
+        }
+        if (status != NO_ERROR) {
+            return;
+        }
+        uint8_t *wavePtr = NULL;
+        uint8_t *fftPtr = NULL;
+        uint32_t waveSize = 0;
+        uint32_t fftSize = 0;
+        if (mCaptureFlags & CAPTURE_WAVEFORM) {
+            wavePtr = waveform;
+            waveSize = mCaptureSize;
+        }
+        if (mCaptureFlags & CAPTURE_FFT) {
+            fftPtr = fft;
+            fftSize = mCaptureSize;
+        }
+        mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
+    }
+}
+
+uint32_t Visualizer::initCaptureSize()
+{
+    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+    effect_param_t *p = (effect_param_t *)buf32;
+
+    p->psize = sizeof(uint32_t);
+    p->vsize = sizeof(uint32_t);
+    *(int32_t *)p->data = VISU_PARAM_CAPTURE_SIZE;
+    status_t status = getParameter(p);
+
+    if (status == NO_ERROR) {
+        status = p->status;
+    }
+
+    uint32_t size = 0;
+    if (status == NO_ERROR) {
+        size = *((int32_t *)p->data + 1);
+    }
+    mCaptureSize = size;
+
+    LOGV("initCaptureSize size %d status %d", mCaptureSize, status);
+
+    return size;
+}
+
+//-------------------------------------------------------------------------
+
+Visualizer::CaptureThread::CaptureThread(Visualizer& receiver, uint32_t captureRate, bool bCanCallJava)
+    : Thread(bCanCallJava), mReceiver(receiver)
+{
+    mSleepTimeUs = 1000000000 / captureRate;
+    LOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
+}
+
+bool Visualizer::CaptureThread::threadLoop()
+{
+    LOGV("CaptureThread %p enter", this);
+    while (!exitPending())
+    {
+        usleep(mSleepTimeUs);
+        mReceiver.periodicCapture();
+    }
+    LOGV("CaptureThread %p exiting", this);
+    return false;
+}
+
+status_t Visualizer::CaptureThread::readyToRun()
+{
+    return NO_ERROR;
+}
+
+void Visualizer::CaptureThread::onFirstRef()
+{
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index d5a3c13..b43f75f 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -658,61 +658,4 @@
 
 }
 
-extern "C" {
-#define FLOATING_POINT 1
-#include "fftwrap.h"
-}
-
-static void *ffttable = NULL;
-
-// peeks at the audio data and fills 'data' with the requested kind
-// (currently kind=0 returns mono 16 bit PCM data, and kind=1 returns
-// 256 point FFT data). Return value is number of samples returned,
-// which may be 0.
-/*static*/ int MediaPlayer::snoop(short* data, int len, int kind) {
-
-    sp<IMemory> p;
-    const sp<IMediaPlayerService>& service = getMediaPlayerService();
-    if (service != 0) {
-        // Take a peek at the waveform. The returned data consists of 16 bit mono PCM data.
-        p = service->snoop();
-
-        if (p == NULL) {
-            return 0;
-        }
-
-        if (kind == 0) { // return waveform data
-            int plen = p->size();
-            len *= 2; // number of shorts -> number of bytes
-            short *src = (short*) p->pointer();
-            if (plen > len) {
-                plen = len;
-            }
-            memcpy(data, src, plen);
-            return plen / sizeof(short); // return number of samples
-        } else if (kind == 1) {
-            // TODO: use a more efficient FFT
-            // Right now this uses the speex library, which is compiled to do a float FFT
-            if (!ffttable) ffttable = spx_fft_init(512);
-            short *usrc = (short*) p->pointer();
-            float fsrc[512];
-            for (int i=0;i<512;i++)
-                fsrc[i] = usrc[i];
-            float fdst[512];
-            spx_fft_float(ffttable, fsrc, fdst);
-            if (len > 512) {
-                len = 512;
-            }
-            len /= 2; // only half the output data is valid
-            for (int i=0; i < len; i++)
-                data[i] = fdst[i];
-            return len;
-        }
-
-    } else {
-        LOGE("Unable to locate media service");
-    }
-    return 0;
-}
-
 }; // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 82d5c14..4872047 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1265,98 +1265,6 @@
     return mem;
 }
 
-/*
- * Avert your eyes, ugly hack ahead.
- * The following is to support music visualizations.
- */
-
-static const int NUMVIZBUF = 32;
-static const int VIZBUFFRAMES = 1024;
-static const int BUFTIMEMSEC = NUMVIZBUF * VIZBUFFRAMES * 1000 / 44100;
-static const int TOTALBUFTIMEMSEC = NUMVIZBUF * BUFTIMEMSEC;
-
-static bool gotMem = false;
-static sp<MemoryHeapBase> heap; 
-static sp<MemoryBase> mem[NUMVIZBUF];
-static uint64_t endTime;
-static uint64_t lastReadTime;
-static uint64_t lastWriteTime;
-static int writeIdx = 0;
-
-static void allocVizBufs() {
-    if (!gotMem) {
-        heap = new MemoryHeapBase(NUMVIZBUF * VIZBUFFRAMES * 2, 0, "snooper");
-        for (int i=0;i<NUMVIZBUF;i++) {
-            mem[i] = new MemoryBase(heap, VIZBUFFRAMES * 2 * i, VIZBUFFRAMES * 2);
-        }
-        endTime = 0;
-        gotMem = true;
-    }
-}
-
-
-/*
- * Get a buffer of audio data that is about to be played.
- * We don't synchronize this because in practice the writer
- * is ahead of the reader, and even if we did happen to catch
- * a buffer while it's being written, it's just a visualization,
- * so no harm done.
- */
-static sp<MemoryBase> getVizBuffer() {
-
-    allocVizBufs();
-
-    lastReadTime = uptimeMillis();
-
-    // if there is no recent buffer (yet), just return empty handed
-    if (lastWriteTime + TOTALBUFTIMEMSEC < lastReadTime) {
-        //LOGI("@@@@    no audio data to look at yet: %d + %d < %d", (int)lastWriteTime, TOTALBUFTIMEMSEC, (int)lastReadTime);
-        return NULL;
-    }
-
-    int timedelta = endTime - lastReadTime;
-    if (timedelta < 0) timedelta = 0;
-    int framedelta = timedelta * 44100 / 1000;
-    int headIdx = (writeIdx - framedelta) / VIZBUFFRAMES - 1;
-    while (headIdx < 0) {
-        headIdx += NUMVIZBUF;
-    }
-    return mem[headIdx];
-}
-
-// Append the data to the vizualization buffer
-static void makeVizBuffers(const char *data, int len, uint64_t time) {
-
-    allocVizBufs();
-
-    uint64_t startTime = time;
-    const int frameSize = 4; // 16 bit stereo sample is 4 bytes
-    int offset = writeIdx;
-    int maxoff = heap->getSize() / 2; // in shorts
-    short *base = (short*)heap->getBase();
-    short *src = (short*)data;
-    while (len > 0) {
-        
-        // Degrade quality by mixing to mono and clearing the lowest 3 bits.
-        // This should still be good enough for a visualization
-        base[offset++] = ((int(src[0]) + int(src[1])) >> 1) & ~0x7;
-        src += 2;
-        len -= frameSize;
-        if (offset >= maxoff) {
-            offset = 0;
-        }
-    }
-    writeIdx = offset;
-    endTime = time + (len / frameSize) / 44;
-    //LOGI("@@@ stored buffers from %d to %d", uint32_t(startTime), uint32_t(time));
-}
-
-sp<IMemory> MediaPlayerService::snoop()
-{
-    sp<MemoryBase> mem = getVizBuffer();
-    return mem;
-}
-
 
 #undef LOG_TAG
 #define LOG_TAG "AudioSink"
@@ -1371,7 +1279,6 @@
     mRightVolume = 1.0;
     mLatency = 0;
     mMsecsPerFrame = 0;
-    mNumFramesWritten = 0;
     setMinBufferCount();
 }
 
@@ -1516,30 +1423,9 @@
     if (mTrack) {
         mTrack->setVolume(mLeftVolume, mRightVolume);
         mTrack->start();
-        mTrack->getPosition(&mNumFramesWritten);
     }
 }
 
-void MediaPlayerService::AudioOutput::snoopWrite(const void* buffer, size_t size) {
-    // Only make visualization buffers if anyone recently requested visualization data
-    uint64_t now = uptimeMillis();
-    if (lastReadTime + TOTALBUFTIMEMSEC >= now) {
-        // Based on the current play counter, the number of frames written and
-        // the current real time we can calculate the approximate real start
-        // time of the buffer we're about to write.
-        uint32_t pos;
-        mTrack->getPosition(&pos);
-
-        // we're writing ahead by this many frames:
-        int ahead = mNumFramesWritten - pos;
-        //LOGI("@@@ written: %d, playpos: %d, latency: %d", mNumFramesWritten, pos, mTrack->latency());
-        // which is this many milliseconds, assuming 44100 Hz:
-        ahead /= 44;
-
-        makeVizBuffers((const char*)buffer, size, now + ahead + mTrack->latency());
-        lastWriteTime = now;
-    }
-}
 
 
 ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
@@ -1548,9 +1434,7 @@
 
     //LOGV("write(%p, %u)", buffer, size);
     if (mTrack) {
-        snoopWrite(buffer, size);
         ssize_t ret = mTrack->write(buffer, size);
-        mNumFramesWritten += ret / 4; // assume 16 bit stereo
         return ret;
     }
     return NO_INIT;
@@ -1560,7 +1444,6 @@
 {
     LOGV("stop");
     if (mTrack) mTrack->stop();
-    lastWriteTime = 0;
 }
 
 void MediaPlayerService::AudioOutput::flush()
@@ -1573,7 +1456,6 @@
 {
     LOGV("pause");
     if (mTrack) mTrack->pause();
-    lastWriteTime = 0;
 }
 
 void MediaPlayerService::AudioOutput::close()
@@ -1609,9 +1491,6 @@
 
     buffer->size = actualSize;
 
-    if (actualSize > 0) {
-        me->snoopWrite(buffer->raw, actualSize);
-    }
 }
 
 #undef LOG_TAG
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 60b91c6..39f525e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -113,9 +113,6 @@
         static bool             mIsOnEmulator;
         static int              mMinBufferCount;  // 12 for emulator; otherwise 4
 
-        public: // visualization hack support
-        uint32_t                mNumFramesWritten;
-        void                    snoopWrite(const void*, size_t);
     };
 
     class AudioCache : public MediaPlayerBase::AudioSink
@@ -191,7 +188,6 @@
     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length, int audioSessionId);
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
-    virtual sp<IMemory>         snoop();
     virtual sp<IOMX>            getOMX();
 
     virtual status_t            dump(int fd, const Vector<String16>& args);