Merge "Support for extracting G.711 a-law and mu-law audio from WAV files and a corresponding software decoder." into gingerbread
diff --git a/api/current.xml b/api/current.xml
index 197e2cd..841aa21 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -85290,7 +85290,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="1"
+ value="0"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -85301,7 +85301,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="0"
+ value="1"
  static="true"
  final="true"
  deprecated="not deprecated"
diff --git a/media/java/android/media/AudioEffect.java b/media/java/android/media/AudioEffect.java
index aed29c3..35038fa 100644
--- a/media/java/android/media/AudioEffect.java
+++ b/media/java/android/media/AudioEffect.java
@@ -101,15 +101,15 @@
     public static final int STATE_INITIALIZED = 1;
 
     // to keep in sync with
-    // frameworks/base/media/jni/audioeffect/android_media_AudioEffect.cpp
-    /**
-     * Event id for engine state change notification.
-     */
-    public static final int NATIVE_EVENT_ENABLED_STATUS = 0;
+    // frameworks/base/include/media/AudioEffect.h
     /**
      * Event id for engine control ownership change notification.
      */
-    public static final int NATIVE_EVENT_CONTROL_STATUS = 1;
+    public static final int NATIVE_EVENT_CONTROL_STATUS = 0;
+    /**
+     * Event id for engine state change notification.
+     */
+    public static final int NATIVE_EVENT_ENABLED_STATUS = 1;
     /**
      * Event id for engine parameter change notification.
      */
@@ -795,7 +795,7 @@
     // Interface definitions
     // --------------------
     /**
-     * The OnParameterChangeListener interface defines a method called by the AudioEffect
+     * The OnEnableStatusChangeListener interface defines a method called by the AudioEffect
      * when a the enabled state of the effect engine was changed by the controlling application.
      */
     public interface OnEnableStatusChangeListener {
@@ -922,7 +922,6 @@
         if (effect == null) {
             return;
         }
-
         if (effect.mNativeEventHandler != null) {
             Message m = effect.mNativeEventHandler.obtainMessage(what, arg1,
                     arg2, obj);
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 3cdf48a..0f3e245 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -218,7 +218,7 @@
            return mIEffect->disable();
         }
     }
-    return INVALID_OPERATION;
+    return NO_ERROR;
 }
 
 status_t AudioEffect::command(uint32_t cmdCode,
@@ -231,7 +231,22 @@
         return INVALID_OPERATION;
     }
 
-    return mIEffect->command(cmdCode, cmdSize, cmdData, replySize, replyData);
+    status_t status = mIEffect->command(cmdCode, cmdSize, cmdData, replySize, replyData);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    status = *(status_t *)replyData;
+    if (status != NO_ERROR) {
+        return status;
+    }
+
+    if (cmdCode == EFFECT_CMD_ENABLE) {
+        android_atomic_or(1, &mEnabled);
+    }
+    if (cmdCode == EFFECT_CMD_DISABLE) {
+        android_atomic_and(~1, &mEnabled);
+    }
+    return status;
 }
 
 
@@ -347,7 +362,11 @@
 {
     LOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf);
     if (mStatus == ALREADY_EXISTS) {
-        mEnabled = enabled;
+        if (enabled) {
+            android_atomic_or(1, &mEnabled);
+        } else {
+            android_atomic_and(~1, &mEnabled);
+        }
         if (mCbf) {
             mCbf(EVENT_ENABLE_STATUS_CHANGED, mUserData, &enabled);
         }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
index 3e33951..c7f461e 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
@@ -25,6 +25,11 @@
 import com.android.mediaframeworktest.functional.SimTonesTest;
 import com.android.mediaframeworktest.functional.MediaPlayerInvokeTest;
 import com.android.mediaframeworktest.functional.MediaAudioManagerTest;
+import com.android.mediaframeworktest.functional.MediaAudioEffectTest;
+import com.android.mediaframeworktest.functional.MediaBassBoostTest;
+import com.android.mediaframeworktest.functional.MediaEqualizerTest;
+import com.android.mediaframeworktest.functional.MediaVirtualizerTest;
+import com.android.mediaframeworktest.functional.MediaVisualizerTest;
 import junit.framework.TestSuite;
 
 import android.test.InstrumentationTestRunner;
@@ -55,6 +60,11 @@
         suite.addTestSuite(MediaMimeTest.class);
         suite.addTestSuite(MediaPlayerInvokeTest.class);
         suite.addTestSuite(MediaAudioManagerTest.class);
+        suite.addTestSuite(MediaAudioEffectTest.class);
+        suite.addTestSuite(MediaBassBoostTest.class);
+        suite.addTestSuite(MediaEqualizerTest.class);
+        suite.addTestSuite(MediaVirtualizerTest.class);
+        suite.addTestSuite(MediaVisualizerTest.class);
         return suite;
     }
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index 9a48c92..ca6e999 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -35,6 +35,7 @@
     public static final String WAV = "/sdcard/media_api/music/rings_2ch.wav";
     public static final String AMR = "/sdcard/media_api/music/test_amr_ietf.amr";
     public static final String OGG = "/sdcard/media_api/music/Revelation.ogg";
+    public static final String SINE_200_1000 = "/sdcard/media_api/music/sine_200+1000Hz_44K_mo.wav";
   
     public static final int MP3CBR_LENGTH = 71000;
     public static final int MP3VBR_LENGTH = 71000;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java
new file mode 100644
index 0000000..fd939ae
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioEffectTest.java
@@ -0,0 +1,1492 @@
+/*
+ * 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.
+ */
+
+package com.android.mediaframeworktest.functional;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+import android.content.res.AssetFileDescriptor;
+import android.media.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.EnvironmentalReverb;
+import android.media.Equalizer;
+import android.media.MediaPlayer;
+
+import android.os.Looper;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+/**
+ * Junit / Instrumentation test case for the media AudioTrack api
+
+ */
+public class MediaAudioEffectTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
+    private String TAG = "MediaAudioEffectTest";
+
+    private AudioEffect mEffect = null;
+    private boolean mHasControl = false;
+    private boolean mIsEnabled = false;
+    private int mParameterChanged = -1;
+    private MediaPlayer mMediaPlayer = null;
+    private boolean mInitialized = false;
+    private Looper mLooper = null;
+    private int mError = 0;
+    private final Object lock = new Object();
+
+    public MediaAudioEffectTest() {
+        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+      super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    private static void assumeTrue(String message, boolean cond) {
+        assertTrue("(assume)"+message, cond);
+    }
+
+    private void log(String testName, String message) {
+        Log.v(TAG, "["+testName+"] "+message);
+    }
+
+    private void loge(String testName, String message) {
+        Log.e(TAG, "["+testName+"] "+message);
+    }
+
+    //-----------------------------------------------------------------
+    // AUDIOEFFECT TESTS:
+    //----------------------------------
+
+    //-----------------------------------------------------------------
+    // 0 - static methods
+    //----------------------------------
+
+    //Test case 0.0: test queryEffects() and available effects
+    @LargeTest
+    public void test0_0QueryEffects() throws Exception {
+
+        AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
+
+        assertTrue("test0_0QueryEffects: number of effects < 4: "+desc.length, (desc.length >= 4));
+
+        boolean hasEQ = false;
+        boolean hasBassBoost = false;
+        boolean hasVirtualizer = false;
+        boolean hasEnvReverb = false;
+
+        for (int i = 0; i < desc.length; i++) {
+            if (desc[i].mType.equals(AudioEffect.EFFECT_TYPE_EQUALIZER)) {
+                hasEQ = true;
+            } if (desc[i].mType.equals(AudioEffect.EFFECT_TYPE_BASS_BOOST)) {
+                hasBassBoost = true;
+            } else if (desc[i].mType.equals(AudioEffect.EFFECT_TYPE_VIRTUALIZER)) {
+                hasVirtualizer = true;
+            }
+            else if (desc[i].mType.equals(AudioEffect.EFFECT_TYPE_ENV_REVERB)) {
+                hasEnvReverb = true;
+            }
+        }
+        assertTrue("test0_0QueryEffects: equalizer not found", hasEQ);
+        assertTrue("test0_0QueryEffects: bass boost not found", hasBassBoost);
+        assertTrue("test0_0QueryEffects: virtualizer not found", hasVirtualizer);
+        assertTrue("test0_0QueryEffects: environmental reverb not found", hasEnvReverb);
+    }
+
+    //-----------------------------------------------------------------
+    // 1 - constructor
+    //----------------------------------
+
+    //Test case 1.0: test constructor from effect type and get effect ID
+    @LargeTest
+    public void test1_0ConstructorFromType() throws Exception {
+        boolean result = true;
+        String msg = "test1_0ConstructorFromType()";
+        AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
+        assertTrue(msg+": no effects found", (desc.length != 0));
+        try {
+            AudioEffect effect = new AudioEffect(desc[0].mType,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            try {
+                assertTrue(msg +": invalid effect ID", (effect.getId() != 0));
+            } catch (IllegalStateException e) {
+                msg = msg.concat(": AudioEffect not initialized");
+                result = false;
+            } finally {
+                effect.release();
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Effect not found: "+desc[0].mName);
+            result = false;
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            result = false;
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.1: test constructor from effect uuid
+    @LargeTest
+    public void test1_1ConstructorFromUuid() throws Exception {
+        boolean result = true;
+        String msg = "test1_1ConstructorFromUuid()";
+        AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
+        assertTrue(msg+"no effects found", (desc.length != 0));
+        try {
+            AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_NULL,
+                    desc[0].mUuid,
+                    0,
+                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            effect.release();
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Effect not found: "+desc[0].mName);
+            result = false;
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            result = false;
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.2: test constructor failure from unknown type
+    @LargeTest
+    public void test1_2ConstructorUnknownType() throws Exception {
+        boolean result = false;
+        String msg = "test1_2ConstructorUnknownType()";
+
+        try {
+            AudioEffect effect = new AudioEffect(UUID.randomUUID(),
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    0);
+            msg = msg.concat(": could create random AudioEffect");
+            if (effect != null) {
+                effect.release();
+            }
+        } catch (IllegalArgumentException e) {
+            result = true;
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.3: test getEnabled() failure when called on released effect
+    @LargeTest
+    public void test1_3GetEnabledAfterRelease() throws Exception {
+        boolean result = false;
+        String msg = "test1_3GetEnabledAfterRelease()";
+
+        try {
+            AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            effect.release();
+            try {
+                effect.getEnabled();
+            } catch (IllegalStateException e) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Equalizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.4: test contructor on mediaPlayer audio session
+    @LargeTest
+    public void test1_4InsertOnMediaPlayer() throws Exception {
+        boolean result = false;
+        String msg = "test1_4InsertOnMediaPlayer()";
+
+        try {
+            MediaPlayer mp = new MediaPlayer();
+            mp.setDataSource(MediaNames.SHORTMP3);
+
+            AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    mp.getAudioSessionId());
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            try {
+                loge(msg, ": effect.setEnabled");
+                effect.setEnabled(true);
+            } catch (IllegalStateException e) {
+                msg = msg.concat(": AudioEffect not initialized");
+            }
+
+            result = true;
+            effect.release();
+            mp.release();
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Equalizer not found");
+            loge(msg, ": Equalizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            loge(msg, ": Effect library not loaded");
+        } catch (Exception e){
+            loge(msg, "Could not create media player:" + e);
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.5: test auxiliary effect attachement on MediaPlayer
+    @LargeTest
+    public void test1_5AuxiliaryOnMediaPlayer() throws Exception {
+        boolean result = false;
+        String msg = "test1_5AuxiliaryOnMediaPlayer()";
+
+        try {
+            MediaPlayer mp = new MediaPlayer();
+            mp.setDataSource(MediaNames.SHORTMP3);
+
+            AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            mp.attachAuxEffect(effect.getId());
+            mp.setAuxEffectSendLevel(1.0f);
+            result = true;
+            effect.release();
+            mp.release();
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Equalizer not found");
+            loge(msg, ": Equalizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            loge(msg, ": Effect library not loaded");
+        } catch (Exception e){
+            loge(msg, "Could not create media player:" + e);
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.6: test auxiliary effect attachement failure before setDatasource
+    @LargeTest
+    public void test1_6AuxiliaryOnMediaPlayerFailure() throws Exception {
+        boolean result = false;
+        String msg = "test1_6AuxiliaryOnMediaPlayerFailure()";
+
+        try {
+            createMediaPlayerLooper();
+            synchronized(lock) {
+                try {
+                    lock.wait(1000);
+                } catch(Exception e) {
+                    Log.e(TAG, "Looper creation: wait was interrupted.");
+                }
+            }
+            assertTrue(mInitialized);  // mMediaPlayer has been initialized?
+            mError = 0;
+
+            AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            synchronized(lock) {
+                try {
+                    mMediaPlayer.attachAuxEffect(effect.getId());
+                    lock.wait(1000);
+                } catch(Exception e) {
+                    Log.e(TAG, "Attach effect: wait was interrupted.");
+                }
+            }
+            assertTrue(msg + ": no error on attachAuxEffect", mError != 0);
+            result = true;
+            effect.release();
+            terminateMediaPlayerLooper();
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Equalizer not found");
+            loge(msg, ": Equalizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            loge(msg, ": Effect library not loaded");
+        } catch (Exception e){
+            loge(msg, "Could not create media player:" + e);
+        }
+        assertTrue(msg, result);
+    }
+
+
+    //Test case 1.7: test auxiliary effect attachement on AudioTrack
+    @LargeTest
+    public void test1_7AuxiliaryOnAudioTrack() throws Exception {
+        boolean result = false;
+        String msg = "test1_7AuxiliaryOnAudioTrack()";
+
+        try {
+            AudioTrack track = new AudioTrack(
+                                        AudioManager.STREAM_MUSIC,
+                                        44100,
+                                        AudioFormat.CHANNEL_OUT_MONO,
+                                        AudioFormat.ENCODING_PCM_16BIT,
+                                        AudioTrack.getMinBufferSize(44100,
+                                                                    AudioFormat.CHANNEL_OUT_MONO,
+                                                                    AudioFormat.ENCODING_PCM_16BIT),
+                                                                    AudioTrack.MODE_STREAM);
+            assertNotNull(msg + ": could not create AudioTrack", track);
+            AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    0);
+
+            track.attachAuxEffect(effect.getId());
+            track.setAuxEffectSendLevel(1.0f);
+            result = true;
+            effect.release();
+            track.release();
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Equalizer not found");
+            loge(msg, ": Equalizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            loge(msg, ": Effect library not loaded");
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 2 - enable/ disable
+    //----------------------------------
+
+
+    //Test case 2.0: test setEnabled() and getEnabled() in valid state
+    @LargeTest
+    public void test2_0SetEnabledGetEnabled() throws Exception {
+        boolean result = false;
+        String msg = "test2_0SetEnabledGetEnabled()";
+
+        try {
+            AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            try {
+                effect.setEnabled(true);
+                assertTrue(msg + ": invalid state from getEnabled", effect.getEnabled());
+                effect.setEnabled(false);
+                assertFalse(msg + ": invalid state to getEnabled", effect.getEnabled());
+                result = true;
+            } catch (IllegalStateException e) {
+                msg = msg.concat(": setEnabled() in wrong state");
+            } finally {
+                effect.release();
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Equalizer not found");
+            loge(msg, ": Equalizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            loge(msg, ": Effect library not loaded");
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 2.1: test setEnabled() throws exception after release
+    @LargeTest
+    public void test2_1SetEnabledAfterRelease() throws Exception {
+        boolean result = false;
+        String msg = "test2_1SetEnabledAfterRelease()";
+
+        try {
+            AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            effect.release();
+            try {
+                effect.setEnabled(true);
+            } catch (IllegalStateException e) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Equalizer not found");
+            loge(msg, ": Equalizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            loge(msg, ": Effect library not loaded");
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 3 - set parameters
+    //----------------------------------
+
+    //Test case 3.0: test setParameter(byte[], byte[])
+    @LargeTest
+    public void test3_0SetParameterByteArrayByteArray() throws Exception {
+        boolean result = false;
+        String msg = "test3_0SetParameterByteArrayByteArray()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            byte[] param = intToByteArray(Equalizer.PARAM_CURRENT_PRESET);
+            byte[] value = shortToByteArray((short)0);
+            if (effect.setParameter(param, value) == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": setParameter() rejected");
+            loge(msg, "setParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("setParameter() called in wrong state");
+            loge(msg, "setParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 3.1: test setParameter(int, int)
+    @LargeTest
+    public void test3_1SetParameterIntInt() throws Exception {
+        boolean result = false;
+        String msg = "test3_1SetParameterIntInt()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            if (effect.setParameter(EnvironmentalReverb.PARAM_DECAY_TIME, 0)
+                    == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": setParameter() rejected");
+            loge(msg, "setParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("setParameter() called in wrong state");
+            loge(msg, "setParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 3.2: test setParameter(int, short)
+    @LargeTest
+    public void test3_2SetParameterIntShort() throws Exception {
+        boolean result = false;
+        String msg = "test3_2SetParameterIntShort()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            if (effect.setParameter(Equalizer.PARAM_CURRENT_PRESET, (short)0)
+                    == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": setParameter() rejected");
+            loge(msg, "setParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("setParameter() called in wrong state");
+            loge(msg, "setParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 3.3: test setParameter(int, byte[])
+    @LargeTest
+    public void test3_3SetParameterIntByteArray() throws Exception {
+        boolean result = false;
+        String msg = "test3_3SetParameterIntByteArray()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            byte[] value = shortToByteArray((short)0);
+            if (effect.setParameter(Equalizer.PARAM_CURRENT_PRESET, value)
+                    == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": setParameter() rejected");
+            loge(msg, "setParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("setParameter() called in wrong state");
+            loge(msg, "setParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 3.4: test setParameter(int[], int[])
+    @LargeTest
+    public void test3_4SetParameterIntArrayIntArray() throws Exception {
+        boolean result = false;
+        String msg = "test3_4SetParameterIntArrayIntArray()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            int[] param = new int[1];
+            int[] value = new int[1];
+            param[0] = EnvironmentalReverb.PARAM_DECAY_TIME;
+            value[0] = 0;
+            if (effect.setParameter(param, value)
+                    == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": setParameter() rejected");
+            loge(msg, "setParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("setParameter() called in wrong state");
+            loge(msg, "setParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 3.5: test setParameter(int[], short[])
+    @LargeTest
+    public void test3_5SetParameterIntArrayShortArray() throws Exception {
+        boolean result = false;
+        String msg = "test3_5SetParameterIntArrayShortArray()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            int[] param = new int[1];
+            short[] value = new short[1];
+            param[0] = Equalizer.PARAM_CURRENT_PRESET;
+            value[0] = (short)0;
+            if (effect.setParameter(param, value)
+                    == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": setParameter() rejected");
+            loge(msg, "setParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("setParameter() called in wrong state");
+            loge(msg, "setParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 3.6: test setParameter(int[], byte[])
+    @LargeTest
+    public void test3_6SetParameterIntArrayByteArray() throws Exception {
+        boolean result = false;
+        String msg = "test3_6SetParameterIntArrayByteArray()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            int[] param = new int[1];
+            byte[] value = shortToByteArray((short)0);
+            param[0] = Equalizer.PARAM_CURRENT_PRESET;
+            if (effect.setParameter(param, value)
+                    == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": setParameter() rejected");
+            loge(msg, "setParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("setParameter() called in wrong state");
+            loge(msg, "setParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 3.7: test setParameter() throws exception after release()
+    @LargeTest
+    public void test3_7SetParameterAfterRelease() throws Exception {
+        boolean result = false;
+        String msg = "test3_7SetParameterAfterRelease()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            effect.release();
+            effect.setParameter(Equalizer.PARAM_CURRENT_PRESET, (short)0);
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": setParameter() rejected");
+            loge(msg, "setParameter() rejected");
+        } catch (IllegalStateException e) {
+            result = true;
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 4 - get parameters
+    //----------------------------------
+
+    //Test case 4.0: test getParameter(byte[], byte[])
+    @LargeTest
+    public void test4_0GetParameterByteArrayByteArray() throws Exception {
+        boolean result = false;
+        String msg = "test4_0GetParameterByteArrayByteArray()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            byte[] param = intToByteArray(Equalizer.PARAM_CURRENT_PRESET);
+            byte[] value = new byte[2];
+            if (effect.getParameter(param, value) == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": getParameter() rejected");
+            loge(msg, "getParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("getParameter() called in wrong state");
+            loge(msg, "getParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 4.1: test getParameter(int, int[])
+    @LargeTest
+    public void test4_1GetParameterIntIntArray() throws Exception {
+        boolean result = false;
+        String msg = "test4_1GetParameterIntIntArray()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            int[] value = new int[1];
+            if (effect.getParameter(EnvironmentalReverb.PARAM_DECAY_TIME, value)
+                    == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": getParameter() rejected");
+            loge(msg, "getParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("getParameter() called in wrong state");
+            loge(msg, "getParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 4.2: test getParameter(int, short[])
+    @LargeTest
+    public void test4_2GetParameterIntShortArray() throws Exception {
+        boolean result = false;
+        String msg = "test4_2GetParameterIntShortArray()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            short[] value = new short[1];
+            if (effect.getParameter(Equalizer.PARAM_CURRENT_PRESET, value)
+                    == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": getParameter() rejected");
+            loge(msg, "getParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("getParameter() called in wrong state");
+            loge(msg, "getParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 4.3: test getParameter(int, byte[])
+    @LargeTest
+    public void test4_3GetParameterIntByteArray() throws Exception {
+        boolean result = false;
+        String msg = "test4_3GetParameterIntByteArray()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            byte[] value = new byte[2];
+            if (effect.getParameter(Equalizer.PARAM_CURRENT_PRESET, value)
+                    == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": getParameter() rejected");
+            loge(msg, "getParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("getParameter() called in wrong state");
+            loge(msg, "getParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 4.4: test getParameter(int[], int[])
+    @LargeTest
+    public void test4_4GetParameterIntArrayIntArray() throws Exception {
+        boolean result = false;
+        String msg = "test4_4GetParameterIntArrayIntArray()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            int[] param = new int[1];
+            int[] value = new int[1];
+            param[0] = EnvironmentalReverb.PARAM_DECAY_TIME;
+            if (effect.getParameter(param, value)
+                    == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": getParameter() rejected");
+            loge(msg, "getParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("getParameter() called in wrong state");
+            loge(msg, "getParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 4.5: test getParameter(int[], short[])
+    @LargeTest
+    public void test4_5GetParameterIntArrayShortArray() throws Exception {
+        boolean result = false;
+        String msg = "test4_5GetParameterIntArrayShortArray()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            int[] param = new int[1];
+            short[] value = new short[1];
+            param[0] = Equalizer.PARAM_CURRENT_PRESET;
+            if (effect.getParameter(param, value)
+                    == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": getParameter() rejected");
+            loge(msg, "getParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("getParameter() called in wrong state");
+            loge(msg, "getParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 4.6: test getParameter(int[], byte[])
+    @LargeTest
+    public void test4_6GetParameterIntArrayByteArray() throws Exception {
+        boolean result = false;
+        String msg = "test4_6GetParameterIntArrayByteArray()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            int[] param = new int[1];
+            byte[] value = new byte[2];
+            param[0] = Equalizer.PARAM_CURRENT_PRESET;
+            if (effect.getParameter(param, value)
+                    == AudioEffect.SUCCESS) {
+                result = true;
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": getParameter() rejected");
+            loge(msg, "getParameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("getParameter() called in wrong state");
+            loge(msg, "getParameter() called in wrong state");
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 4.7: test getParameter() throws exception after release()
+    @LargeTest
+    public void test4_7GetParameterAfterRelease() throws Exception {
+        boolean result = false;
+        String msg = "test4_7GetParameterAfterRelease()";
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            effect.release();
+            short[] value = new short[1];
+            effect.getParameter(Equalizer.PARAM_CURRENT_PRESET, value);
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": getParameter() rejected");
+            loge(msg, "getParameter() rejected");
+        } catch (IllegalStateException e) {
+            result = true;
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 5 priority and listeners
+    //----------------------------------
+
+    //Test case 5.0: test control passed to higher priority client
+    @LargeTest
+    public void test5_0setEnabledLowerPriority() throws Exception {
+        boolean result = false;
+        String msg = "test5_0setEnabledLowerPriority()";
+        AudioEffect effect1 = null;
+        AudioEffect effect2 = null;
+        try {
+            effect1 = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            effect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    1,
+                    0);
+
+            assertNotNull(msg + ": could not create AudioEffect", effect1);
+            assertNotNull(msg + ": could not create AudioEffect", effect2);
+
+            assertTrue(msg + ": Effect2 does not have control", effect2.hasControl());
+            assertFalse(msg + ": Effect1 has control", effect1.hasControl());
+            assertTrue(msg + ": Effect1 can enable",
+                    effect1.setEnabled(true) == AudioEffect.ERROR_INVALID_OPERATION);
+            assertFalse(msg + ": Effect1 has enabled", effect2.getEnabled());
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Effect not found");
+            result = false;
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            result = false;
+        } finally {
+            if (effect1 != null) {
+                effect1.release();
+            }
+            if (effect2 != null) {
+                effect2.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 5.1: test control passed to higher priority client
+    @LargeTest
+    public void test5_1setParameterLowerPriority() throws Exception {
+        boolean result = false;
+        String msg = "test5_1setParameterLowerPriority()";
+        AudioEffect effect1 = null;
+        AudioEffect effect2 = null;
+        try {
+            effect1 = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            effect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    1,
+                    0);
+
+            assertNotNull(msg + ": could not create AudioEffect", effect1);
+            assertNotNull(msg + ": could not create AudioEffect", effect2);
+
+            int status = effect2.setParameter(Equalizer.PARAM_CURRENT_PRESET, (short)0);
+            assertEquals(msg + ": Effect2 setParameter failed",
+                    AudioEffect.SUCCESS, status);
+
+            status = effect1.setParameter(Equalizer.PARAM_CURRENT_PRESET, (short)1);
+            assertEquals(msg + ": Effect1 setParameter did not fail",
+                    AudioEffect.ERROR_INVALID_OPERATION, status);
+
+            short[] value = new short[1];
+            status = effect2.getParameter(Equalizer.PARAM_CURRENT_PRESET, value);
+            assertEquals(msg + ": Effect2 getParameter failed",
+                    AudioEffect.SUCCESS, status);
+            assertEquals(msg + ": Effect1 changed parameter",
+                    (short)0, value[0]);
+
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Effect not found");
+            result = false;
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            result = false;
+        } finally {
+            if (effect1 != null) {
+                effect1.release();
+            }
+            if (effect2 != null) {
+                effect2.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 5.2: test control status listener
+    @LargeTest
+    public void test5_2ControlStatusListener() throws Exception {
+        boolean result = false;
+        String msg = "test5_2ControlStatusListener()";
+        mEffect = null;
+        AudioEffect effect2 = null;
+        try {
+            mHasControl = true;
+            createListenerLooper(true, false, false);
+            synchronized(lock) {
+                try {
+                    lock.wait(1000);
+                } catch(Exception e) {
+                    Log.e(TAG, "Looper creation: wait was interrupted.");
+                }
+            }
+            assertTrue(mInitialized);
+            synchronized(lock) {
+                try {
+                    effect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                            AudioEffect.EFFECT_TYPE_NULL,
+                            1,
+                            0);
+                    assertNotNull(msg + ": could not create AudioEffect", effect2);
+                    lock.wait(1000);
+                } catch(Exception e) {
+                    Log.e(TAG, "Create second effect: wait was interrupted.");
+                }
+            }
+            assertFalse(msg + ": effect control not lost by effect1", mHasControl);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Equalizer not found");
+            loge(msg, ": Equalizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            loge(msg, ": Effect library not loaded");
+        } catch (Exception e){
+            loge(msg, "Could not create media player:" + e);
+        } finally {
+            terminateListenerLooper();
+            if (effect2 != null) {
+                effect2.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 5.3: test enable status listener
+    @LargeTest
+    public void test5_3EnableStatusListener() throws Exception {
+        boolean result = false;
+        String msg = "test5_3EnableStatusListener()";
+        mEffect = null;
+        AudioEffect effect2 = null;
+        try {
+            createListenerLooper(false, true, false);
+            synchronized(lock) {
+                try {
+                    lock.wait(1000);
+                } catch(Exception e) {
+                    Log.e(TAG, "Looper creation: wait was interrupted.");
+                }
+            }
+            assertTrue(mInitialized);
+            mEffect.setEnabled(true);
+            mIsEnabled = true;
+            effect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    1,
+                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect2);
+            assertTrue(msg + ": effect not enabled", effect2.getEnabled());
+            synchronized(lock) {
+                try {
+                    effect2.setEnabled(false);
+                    lock.wait(1000);
+                } catch(Exception e) {
+                    Log.e(TAG, "Create second effect: wait was interrupted.");
+                }
+            }
+            assertFalse(msg + ": enable status not updated", mIsEnabled);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Equalizer not found");
+            loge(msg, ": Equalizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            loge(msg, ": Effect library not loaded");
+        } catch (Exception e){
+            loge(msg, "Could not create media player:" + e);
+        } finally {
+            terminateListenerLooper();
+            if (effect2 != null) {
+                effect2.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 5.4: test parameter changed listener
+    @LargeTest
+    public void test5_4ParameterChangedListener() throws Exception {
+        boolean result = false;
+        String msg = "test5_4ParameterChangedListener()";
+        mEffect = null;
+        AudioEffect effect2 = null;
+        try {
+            createListenerLooper(false, false, true);
+            synchronized(lock) {
+                try {
+                    lock.wait(1000);
+                } catch(Exception e) {
+                    Log.e(TAG, "Looper creation: wait was interrupted.");
+                }
+            }
+            assertTrue(mInitialized);
+            effect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    1,
+                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect2);
+            synchronized(lock) {
+                try {
+                    mParameterChanged = -1;
+                    effect2.setParameter(Equalizer.PARAM_CURRENT_PRESET, (short)0);
+                    lock.wait(1000);
+                } catch(Exception e) {
+                    Log.e(TAG, "Create second effect: wait was interrupted.");
+                }
+            }
+            assertEquals(msg + ": parameter change not received",
+                    Equalizer.PARAM_CURRENT_PRESET, mParameterChanged);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Equalizer not found");
+            loge(msg, ": Equalizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            loge(msg, ": Effect library not loaded");
+        } catch (Exception e){
+            loge(msg, "Could not create media player:" + e);
+        } finally {
+            terminateListenerLooper();
+            if (effect2 != null) {
+                effect2.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 6 command method
+    //----------------------------------
+
+
+    //Test case 6.0: test command method
+    @LargeTest
+    public void test6_0Command() throws Exception {
+        boolean result = false;
+        String msg = "test6_0Command()";
+        AudioEffect effect = null;
+        try {
+             effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    0);
+            assertNotNull(msg + ": could not create AudioEffect", effect);
+            try {
+                byte[] cmd = new byte[0];
+                byte[] reply = new byte[4];
+                int status = effect.command(3, cmd, reply);
+                assertEquals(msg + ": command failed", AudioEffect.SUCCESS, status);
+                assertTrue(msg + ": effect not enabled", effect.getEnabled());
+                result = true;
+            } catch (IllegalStateException e) {
+                msg = msg.concat(": command in illegal state");
+            }
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Equalizer not found");
+            loge(msg, ": Equalizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+            loge(msg, ": Effect library not loaded");
+        } catch (Exception e){
+            loge(msg, "Could not create media player:" + e);
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // private methods
+    //----------------------------------
+
+    /*
+     * Initializes the message looper so that the MediaPlayer object can
+     * receive the callback messages.
+     */
+    private void createMediaPlayerLooper() {
+        new Thread() {
+            @Override
+            public void run() {
+                // Set up a looper to be used by mMediaPlayer.
+                Looper.prepare();
+
+                // Save the looper so that we can terminate this thread
+                // after we are done with it.
+                mLooper = Looper.myLooper();
+
+                mMediaPlayer = new MediaPlayer();
+                mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+                    public boolean onError(MediaPlayer player, int what, int extra) {
+                        synchronized(lock) {
+                            mError = what;
+                            lock.notify();
+                        }
+                        return true;
+                    }
+                });
+                mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+                    public void onCompletion(MediaPlayer player) {
+                        synchronized(lock) {
+                            lock.notify();
+                        }
+                    }
+                });
+                synchronized(lock) {
+                    mInitialized = true;
+                    lock.notify();
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+            }
+        }.start();
+    }
+    /*
+     * Terminates the message looper thread.
+     */
+    private void terminateMediaPlayerLooper() {
+        if (mLooper != null) {
+            mLooper.quit();
+            mLooper = null;
+        }
+        if (mMediaPlayer != null) {
+            mMediaPlayer.release();
+        }
+    }
+
+    /*
+     * Initializes the message looper fro effect listener
+     */
+    class ListenerThread extends Thread {
+        boolean mControl;
+        boolean mEnable;
+        boolean mParameter;
+
+        public ListenerThread(boolean control, boolean enable, boolean parameter) {
+            super();
+            mControl = control;
+            mEnable = enable;
+            mParameter = parameter;
+        }
+    }
+    private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
+
+        new ListenerThread(control, enable, parameter) {
+            @Override
+            public void run() {
+                // Set up a looper to be used by mEffect.
+                Looper.prepare();
+
+                // Save the looper so that we can terminate this thread
+                // after we are done with it.
+                mLooper = Looper.myLooper();
+
+                mEffect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                        AudioEffect.EFFECT_TYPE_NULL,
+                        0,
+                        0);
+                assertNotNull("could not create AudioEffect", mEffect);
+
+                if (mControl) {
+                    mEffect.setControlStatusListener(new AudioEffect.OnControlStatusChangeListener() {
+                        public void onControlStatusChange(AudioEffect effect, boolean controlGranted) {
+                            synchronized(lock) {
+                                if (effect == mEffect) {
+                                    mHasControl = controlGranted;
+                                    lock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+                if (mEnable) {
+                    mEffect.setEnableStatusListener(new AudioEffect.OnEnableStatusChangeListener() {
+                        public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+                            synchronized(lock) {
+                                if (effect == mEffect) {
+                                    mIsEnabled = enabled;
+                                    lock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+                if (mParameter) {
+                    mEffect.setParameterListener(new AudioEffect.OnParameterChangeListener() {
+                        public void onParameterChange(AudioEffect effect, int status, byte[] param,
+                                byte[] value) {
+                            synchronized(lock) {
+                                if (effect == mEffect) {
+                                    mParameterChanged = byteArrayToInt(param);
+                                    lock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+
+                synchronized(lock) {
+                    mInitialized = true;
+                    lock.notify();
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+            }
+        }.start();
+    }
+    /*
+     * Terminates the listener looper thread.
+     */
+    private void terminateListenerLooper() {
+        if (mEffect != null) {
+            mEffect.release();
+            mEffect = null;
+        }
+        if (mLooper != null) {
+            mLooper.quit();
+            mLooper = null;
+        }
+    }
+
+    protected int byteArrayToInt(byte[] valueBuf) {
+        return byteArrayToInt(valueBuf, 0);
+
+    }
+
+    protected int byteArrayToInt(byte[] valueBuf, int offset) {
+        ByteBuffer converter = ByteBuffer.wrap(valueBuf);
+        converter.order(ByteOrder.nativeOrder());
+        return converter.getInt(offset);
+
+    }
+
+    protected byte[] intToByteArray(int value) {
+        ByteBuffer converter = ByteBuffer.allocate(4);
+        converter.order(ByteOrder.nativeOrder());
+        converter.putInt(value);
+        return converter.array();
+    }
+
+    protected short byteArrayToShort(byte[] valueBuf) {
+        return byteArrayToShort(valueBuf, 0);
+    }
+
+    protected short byteArrayToShort(byte[] valueBuf, int offset) {
+        ByteBuffer converter = ByteBuffer.wrap(valueBuf);
+        converter.order(ByteOrder.nativeOrder());
+        return converter.getShort(offset);
+
+    }
+
+    protected byte[] shortToByteArray(short value) {
+        ByteBuffer converter = ByteBuffer.allocate(2);
+        converter.order(ByteOrder.nativeOrder());
+        short sValue = (short) value;
+        converter.putShort(sValue);
+        return converter.array();
+    }
+
+}
+
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaBassBoostTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaBassBoostTest.java
new file mode 100644
index 0000000..8a68c5e
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaBassBoostTest.java
@@ -0,0 +1,334 @@
+/*
+ * 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.
+ */
+
+package com.android.mediaframeworktest.functional;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.media.AudioEffect;
+import android.media.AudioManager;
+import android.media.BassBoost;
+import android.media.Visualizer;
+import android.media.MediaPlayer;
+
+import android.os.Looper;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+/**
+ * Junit / Instrumentation test case for the media AudioTrack api
+
+ */
+public class MediaBassBoostTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
+    private String TAG = "MediaBassBoostTest";
+    private final static int MIN_ENERGY_RATIO_2 = 4;
+    private final static short TEST_STRENGTH = 500;
+
+    private BassBoost mBassBoost = null;
+    private int mSession = -1;
+
+    public MediaBassBoostTest() {
+        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+      super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        releaseBassBoost();
+    }
+
+    private static void assumeTrue(String message, boolean cond) {
+        assertTrue("(assume)"+message, cond);
+    }
+
+    private void log(String testName, String message) {
+        Log.v(TAG, "["+testName+"] "+message);
+    }
+
+    private void loge(String testName, String message) {
+        Log.e(TAG, "["+testName+"] "+message);
+    }
+
+    //-----------------------------------------------------------------
+    // BASS BOOST TESTS:
+    //----------------------------------
+
+
+    //-----------------------------------------------------------------
+    // 0 - constructor
+    //----------------------------------
+
+    //Test case 0.0: test constructor and release
+    @LargeTest
+    public void test0_0ConstructorAndRelease() throws Exception {
+        boolean result = false;
+        String msg = "test1_0ConstructorAndRelease()";
+        BassBoost bb = null;
+         try {
+            bb = new BassBoost(0, 0);
+            assertNotNull(msg + ": could not create BassBoost", bb);
+            try {
+                assertTrue(msg +": invalid effect ID", (bb.getId() != 0));
+            } catch (IllegalStateException e) {
+                msg = msg.concat(": BassBoost not initialized");
+            }
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": BassBoost not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+        } finally {
+            if (bb != null) {
+                bb.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 1 - get/set parameters
+    //----------------------------------
+
+    //Test case 1.0: test strength
+    @LargeTest
+    public void test1_0Strength() throws Exception {
+        boolean result = false;
+        String msg = "test1_0Strength()";
+        getBassBoost(0);
+        try {
+            if (mBassBoost.getStrengthSupported()) {
+                mBassBoost.setStrength((short)TEST_STRENGTH);
+                short strength = mBassBoost.getRoundedStrength();
+                // allow 10% difference between set strength and rounded strength
+                assertTrue(msg +": got incorrect strength",
+                        ((float)strength > (float)TEST_STRENGTH * 0.9f) &&
+                        ((float)strength < (float)TEST_STRENGTH * 1.1f));
+            } else {
+                short strength = mBassBoost.getRoundedStrength();
+                assertTrue(msg +": got incorrect strength", strength >= 0 && strength <= 1000);
+            }
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseBassBoost();
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.1: test properties
+    @LargeTest
+    public void test1_1Properties() throws Exception {
+        boolean result = false;
+        String msg = "test1_1Properties()";
+        getBassBoost(0);
+        try {
+            BassBoost.Settings settings = mBassBoost.getProperties();
+            String str = settings.toString();
+            settings = new BassBoost.Settings(str);
+            mBassBoost.setProperties(settings);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseBassBoost();
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 2 - Effect action
+    //----------------------------------
+
+    //Test case 2.0: test actual bass boost influence on sound
+    @LargeTest
+    public void test2_0SoundModification() throws Exception {
+        boolean result = false;
+        String msg = "test2_0SoundModification()";
+        EnergyProbe probe = null;
+        AudioEffect vc = null;
+        MediaPlayer mp = null;
+        AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        am.setStreamVolume(AudioManager.STREAM_MUSIC,
+                           am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
+                           0);
+
+        try {
+            probe = new EnergyProbe(0);
+            // creating a volume controller on output mix ensures that ro.audio.silent mutes
+            // audio after the effects and not before
+            vc = new AudioEffect(
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"),
+                      0,
+                      0);
+            vc.setEnabled(true);
+
+            mp = new MediaPlayer();
+            mp.setDataSource(MediaNames.SINE_200_1000);
+            mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            getBassBoost(mp.getAudioSessionId());
+            mp.prepare();
+            mp.start();
+            Thread.sleep(200);
+            // measure reference energy around 1kHz
+            int refEnergy200 = probe.capture(200);
+            int refEnergy1000 = probe.capture(1000);
+            mBassBoost.setStrength((short)1000);
+            mBassBoost.setEnabled(true);
+            Thread.sleep(500);
+            // measure energy around 1kHz with band level at min
+            int energy200 = probe.capture(200);
+            int energy1000 = probe.capture(1000);
+            // verify that the energy ration between low and high frequencies is at least
+            // MIN_ENERGY_RATIO_2 times higher with bassboost on.
+            assertTrue(msg + ": bass boost has no effect",
+                    ((float)energy200/(float)energy1000) >
+                    (MIN_ENERGY_RATIO_2 * ((float)refEnergy200/(float)refEnergy1000)));
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } catch (InterruptedException e) {
+            loge(msg, "sleep() interrupted");
+        }
+        finally {
+            releaseBassBoost();
+            if (mp != null) {
+                mp.release();
+            }
+            if (vc != null) {
+                vc.release();
+            }
+            if (probe != null) {
+                probe.release();
+            }
+            am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+        }
+        assertTrue(msg, result);
+    }
+    //-----------------------------------------------------------------
+    // private methods
+    //----------------------------------
+
+    private class EnergyProbe {
+        Visualizer mVisualizer = null;
+        private byte[] mFft = new byte[1024];
+
+        public EnergyProbe(int session) {
+            mVisualizer = new Visualizer(session);
+            mVisualizer.setCaptureSize(1024);
+        }
+
+        public int capture(int freq) throws InterruptedException {
+            int energy = 0;
+            int count = 0;
+            if (mVisualizer != null) {
+                mVisualizer.setEnabled(true);
+                for (int i = 0; i < 10; i++) {
+                    if (mVisualizer.getFft(mFft) == Visualizer.SUCCESS) {
+                        // TODO: check speex FFT as it seems to return only the number of points
+                        // correspondong to valid part of the spectrum (< Fs).
+                        // e.g., if the number of points is 1024, it covers the frequency range
+                        // 0 to 22050 instead of 0 to 44100 as expected from an FFT.
+                        int bin = freq / (22050 / 1024);
+                        int tmp = 0;
+                        for (int j = bin-2; j < bin+3; j++) {
+                            tmp += (int)mFft[j] * (int)mFft[j];
+                        }
+                        energy += tmp/5;
+                        count++;
+                    }
+                    Thread.sleep(50);
+                }
+                mVisualizer.setEnabled(false);
+            }
+            if (count == 0) {
+                return 0;
+            }
+            return energy/count;
+        }
+
+        public void release() {
+            if (mVisualizer != null) {
+                mVisualizer.release();
+                mVisualizer = null;
+            }
+        }
+    }
+
+    private void getBassBoost(int session) {
+         if (mBassBoost == null || session != mSession) {
+             if (session != mSession && mBassBoost != null) {
+                 mBassBoost.release();
+                 mBassBoost = null;
+             }
+             try {
+                mBassBoost = new BassBoost(0, session);
+                mSession = session;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "getBassBoost() BassBoost not found exception: "+e);
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "getBassBoost() Effect library not loaded exception: "+e);
+            }
+         }
+         assertNotNull("could not create mBassBoost", mBassBoost);
+    }
+
+    private void releaseBassBoost() {
+        if (mBassBoost != null) {
+            mBassBoost.release();
+            mBassBoost = null;
+        }
+   }
+
+}
+
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEqualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEqualizerTest.java
new file mode 100644
index 0000000..e46887b
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEqualizerTest.java
@@ -0,0 +1,397 @@
+/*
+ * 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.
+ */
+
+package com.android.mediaframeworktest.functional;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.media.AudioEffect;
+import android.media.AudioManager;
+import android.media.Equalizer;
+import android.media.Visualizer;
+import android.media.MediaPlayer;
+
+import android.os.Looper;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+/**
+ * Junit / Instrumentation test case for the media AudioTrack api
+
+ */
+public class MediaEqualizerTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
+    private String TAG = "MediaEqualizerTest";
+    private final static int MIN_NUMBER_OF_BANDS = 4;
+    private final static int MIN_BAND_LEVEL = -1500;
+    private final static int MAX_BAND_LEVEL = 1500;
+    private final static int TEST_FREQUENCY_MILLIHERTZ = 1000000;
+    private final static int MIN_NUMBER_OF_PRESETS = 4;
+    private Equalizer mEqualizer = null;
+    private int mSession = -1;
+
+    public MediaEqualizerTest() {
+        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+      super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        releaseEqualizer();
+    }
+
+    private static void assumeTrue(String message, boolean cond) {
+        assertTrue("(assume)"+message, cond);
+    }
+
+    private void log(String testName, String message) {
+        Log.v(TAG, "["+testName+"] "+message);
+    }
+
+    private void loge(String testName, String message) {
+        Log.e(TAG, "["+testName+"] "+message);
+    }
+
+    //-----------------------------------------------------------------
+    // EQUALIZER TESTS:
+    //----------------------------------
+
+
+    //-----------------------------------------------------------------
+    // 0 - constructor
+    //----------------------------------
+
+    //Test case 0.0: test constructor and release
+    @LargeTest
+    public void test0_0ConstructorAndRelease() throws Exception {
+        boolean result = false;
+        String msg = "test1_0ConstructorAndRelease()";
+        Equalizer eq = null;
+         try {
+            eq = new Equalizer(0, 0);
+            assertNotNull(msg + ": could not create Equalizer", eq);
+            try {
+                assertTrue(msg +": invalid effect ID", (eq.getId() != 0));
+            } catch (IllegalStateException e) {
+                msg = msg.concat(": Equalizer not initialized");
+            }
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Equalizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+        } finally {
+            if (eq != null) {
+                eq.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+
+    //-----------------------------------------------------------------
+    // 1 - get/set parameters
+    //----------------------------------
+
+    //Test case 1.0: test setBandLevel() and getBandLevel()
+    @LargeTest
+    public void test1_0BandLevel() throws Exception {
+        boolean result = false;
+        String msg = "test1_0BandLevel()";
+        getEqualizer(0);
+        try {
+            short numBands = mEqualizer.getNumberOfBands();
+            assertTrue(msg + ": not enough bands", numBands >= MIN_NUMBER_OF_BANDS);
+
+            short[] levelRange = mEqualizer.getBandLevelRange();
+            assertTrue(msg + ": min level too high", levelRange[0] <= MIN_BAND_LEVEL);
+            assertTrue(msg + ": max level too low", levelRange[1] >= MAX_BAND_LEVEL);
+
+            mEqualizer.setBandLevel((short)0, levelRange[1]);
+            short level = mEqualizer.getBandLevel((short)0);
+            // 10% margin on actual level compared to requested level
+            assertTrue(msg + ": setBandLevel failed",
+                    ((float)level > (float)levelRange[1] * 0.9f) &&
+                    ((float)level < (float)levelRange[1] * 1.1f));
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseEqualizer();
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.1: test band frequency
+    @LargeTest
+    public void test1_1BandFrequency() throws Exception {
+        boolean result = false;
+        String msg = "test1_1BandFrequency()";
+        getEqualizer(0);
+        try {
+            short band = mEqualizer.getBand(TEST_FREQUENCY_MILLIHERTZ);
+            assertTrue(msg + ": getBand failed", band >= 0);
+            int[] freqRange = mEqualizer.getBandFreqRange(band);
+            assertTrue(msg + ": getBandFreqRange failed",
+                    (freqRange[0] <= TEST_FREQUENCY_MILLIHERTZ) &&
+                    (freqRange[1] >= TEST_FREQUENCY_MILLIHERTZ));
+            int freq = mEqualizer.getCenterFreq(band);
+            assertTrue(msg + ": getCenterFreq failed",
+                    (freqRange[0] <= freq) && (freqRange[1] >= freq));
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseEqualizer();
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.2: test presets
+    @LargeTest
+    public void test1_2Presets() throws Exception {
+        boolean result = false;
+        String msg = "test1_2Presets()";
+        getEqualizer(0);
+        try {
+            short numPresets = mEqualizer.getNumberOfPresets();
+            assertTrue(msg + ": getNumberOfPresets failed", numPresets >= MIN_NUMBER_OF_PRESETS);
+            mEqualizer.usePreset((short)(numPresets - 1));
+            short preset = mEqualizer.getCurrentPreset();
+            assertEquals(msg + ": usePreset failed", preset, (short)(numPresets - 1));
+            String name = mEqualizer.getPresetName(preset);
+            assertNotNull(msg + ": getPresetName failed", name);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseEqualizer();
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.3: test properties
+    @LargeTest
+    public void test1_3Properties() throws Exception {
+        boolean result = false;
+        String msg = "test1_3Properties()";
+        getEqualizer(0);
+        try {
+            Equalizer.Settings settings = mEqualizer.getProperties();
+            String str = settings.toString();
+            settings = new Equalizer.Settings(str);
+            mEqualizer.setProperties(settings);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseEqualizer();
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 2 - Effect action
+    //----------------------------------
+
+    //Test case 2.0: test that the equalizer actually alters the sound
+    @LargeTest
+    public void test2_0SoundModification() throws Exception {
+        boolean result = false;
+        String msg = "test2_0SoundModification()";
+        EnergyProbe probe = null;
+        AudioEffect vc = null;
+        MediaPlayer mp = null;
+        AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        am.setStreamVolume(AudioManager.STREAM_MUSIC,
+                           am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
+                           0);
+        try {
+            probe = new EnergyProbe(0);
+            // creating a volume controller on output mix ensures that ro.audio.silent mutes
+            // audio after the effects and not before
+            vc = new AudioEffect(
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"),
+                      0,
+                      0);
+            vc.setEnabled(true);
+
+            mp = new MediaPlayer();
+            mp.setDataSource(MediaNames.SINE_200_1000);
+            mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            getEqualizer(mp.getAudioSessionId());
+            mp.prepare();
+            mp.start();
+            Thread.sleep(500);
+            // measure reference energy around 1kHz
+            int refEnergy = probe.capture(1000);
+            short band = mEqualizer.getBand(1000000);
+            short[] levelRange = mEqualizer.getBandLevelRange();
+            mEqualizer.setBandLevel(band, levelRange[0]);
+            mEqualizer.setEnabled(true);
+            Thread.sleep(500);
+            // measure energy around 1kHz with band level at min
+            int energy = probe.capture(1000);
+            assertTrue(msg + ": equalizer has no effect at 1kHz", energy < refEnergy/4);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } catch (InterruptedException e) {
+            loge(msg, "sleep() interrupted");
+        }
+        finally {
+            releaseEqualizer();
+            if (mp != null) {
+                mp.release();
+            }
+            if (vc != null) {
+                vc.release();
+            }
+            if (probe != null) {
+                probe.release();
+            }
+            am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // private methods
+    //----------------------------------
+
+    private class EnergyProbe {
+        Visualizer mVisualizer = null;
+        private byte[] mFft = new byte[1024];
+
+        public EnergyProbe(int session) {
+            mVisualizer = new Visualizer(session);
+            mVisualizer.setCaptureSize(1024);
+        }
+
+        public int capture(int freq) throws InterruptedException {
+            int energy = 0;
+            int count = 0;
+            if (mVisualizer != null) {
+                mVisualizer.setEnabled(true);
+                for (int i = 0; i < 10; i++) {
+                    if (mVisualizer.getFft(mFft) == Visualizer.SUCCESS) {
+                        // TODO: check speex FFT as it seems to return only the number of points
+                        // correspondong to valid part of the spectrum (< Fs).
+                        // e.g., if the number of points is 1024, it covers the frequency range
+                        // 0 to 22050 instead of 0 to 44100 as expected from an FFT.
+                        int bin = freq / (22050 / 1024);
+                        int tmp = 0;
+                        for (int j = bin-2; j < bin+3; j++) {
+                            tmp += (int)mFft[j] * (int)mFft[j];
+                        }
+                        energy += tmp/5;
+                        count++;
+                    }
+                    Thread.sleep(50);
+                }
+                mVisualizer.setEnabled(false);
+            }
+            if (count == 0) {
+                return 0;
+            }
+            return energy/count;
+        }
+
+        public void release() {
+            if (mVisualizer != null) {
+                mVisualizer.release();
+                mVisualizer = null;
+            }
+        }
+    }
+
+    private void getEqualizer(int session) {
+         if (mEqualizer == null || session != mSession) {
+             if (session != mSession && mEqualizer != null) {
+                 mEqualizer.release();
+                 mEqualizer = null;
+             }
+             try {
+                mEqualizer = new Equalizer(0, session);
+                mSession = session;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "getEqualizer() Equalizer not found exception: "+e);
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "getEqualizer() Effect library not loaded exception: "+e);
+            }
+         }
+         assertNotNull("could not create mEqualizer", mEqualizer);
+    }
+
+    private void releaseEqualizer() {
+        if (mEqualizer != null) {
+            mEqualizer.release();
+            mEqualizer = null;
+        }
+   }
+
+}
+
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVirtualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVirtualizerTest.java
new file mode 100644
index 0000000..6b8ae44
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVirtualizerTest.java
@@ -0,0 +1,339 @@
+/*
+ * 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.
+ */
+
+package com.android.mediaframeworktest.functional;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.media.AudioEffect;
+import android.media.AudioManager;
+import android.media.Virtualizer;
+import android.media.Visualizer;
+import android.media.MediaPlayer;
+
+import android.os.Looper;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+/**
+ * Junit / Instrumentation test case for the media AudioTrack api
+
+ */
+public class MediaVirtualizerTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
+    private String TAG = "MediaVirtualizerTest";
+    private final static int MIN_ENERGY_RATIO_2 = 4;
+    private final static short TEST_STRENGTH = 500;
+
+    private Virtualizer mVirtualizer = null;
+    private int mSession = -1;
+
+    public MediaVirtualizerTest() {
+        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+      super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        releaseVirtualizer();
+    }
+
+    private static void assumeTrue(String message, boolean cond) {
+        assertTrue("(assume)"+message, cond);
+    }
+
+    private void log(String testName, String message) {
+        Log.v(TAG, "["+testName+"] "+message);
+    }
+
+    private void loge(String testName, String message) {
+        Log.e(TAG, "["+testName+"] "+message);
+    }
+
+    //-----------------------------------------------------------------
+    // VIRTUALIZER TESTS:
+    //----------------------------------
+
+
+    //-----------------------------------------------------------------
+    // 0 - constructor
+    //----------------------------------
+
+    //Test case 0.0: test constructor and release
+    @LargeTest
+    public void test0_0ConstructorAndRelease() throws Exception {
+        boolean result = false;
+        String msg = "test1_0ConstructorAndRelease()";
+        Virtualizer virtualizer = null;
+         try {
+            virtualizer = new Virtualizer(0, 0);
+            assertNotNull(msg + ": could not create Virtualizer", virtualizer);
+            try {
+                assertTrue(msg +": invalid effect ID", (virtualizer.getId() != 0));
+            } catch (IllegalStateException e) {
+                msg = msg.concat(": Virtualizer not initialized");
+            }
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Virtualizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+        } finally {
+            if (virtualizer != null) {
+                virtualizer.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+
+    //-----------------------------------------------------------------
+    // 1 - get/set parameters
+    //----------------------------------
+
+    //Test case 1.0: test strength
+    @LargeTest
+    public void test1_0Strength() throws Exception {
+        boolean result = false;
+        String msg = "test1_0Strength()";
+        getVirtualizer(0);
+        try {
+            if (mVirtualizer.getStrengthSupported()) {
+                mVirtualizer.setStrength((short)TEST_STRENGTH);
+                short strength = mVirtualizer.getRoundedStrength();
+                // allow 10% difference between set strength and rounded strength
+                assertTrue(msg +": got incorrect strength",
+                        ((float)strength > (float)TEST_STRENGTH * 0.9f) &&
+                        ((float)strength < (float)TEST_STRENGTH * 1.1f));
+            } else {
+                short strength = mVirtualizer.getRoundedStrength();
+                assertTrue(msg +": got incorrect strength", strength >= 0 && strength <= 1000);
+            }
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseVirtualizer();
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.1: test properties
+    @LargeTest
+    public void test1_1Properties() throws Exception {
+        boolean result = false;
+        String msg = "test1_1Properties()";
+        getVirtualizer(0);
+        try {
+            Virtualizer.Settings settings = mVirtualizer.getProperties();
+            String str = settings.toString();
+            settings = new Virtualizer.Settings(str);
+            mVirtualizer.setProperties(settings);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseVirtualizer();
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 2 - Effect action
+    //----------------------------------
+
+    //Test case 2.0: test actual virtualizer influence on sound
+    @LargeTest
+    public void test2_0SoundModification() throws Exception {
+        boolean result = false;
+        String msg = "test2_0SoundModification()";
+        EnergyProbe probe = null;
+        AudioEffect vc = null;
+        MediaPlayer mp = null;
+        AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        am.setStreamVolume(AudioManager.STREAM_MUSIC,
+                           am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
+                           0);
+
+        try {
+            probe = new EnergyProbe(0);
+            // creating a volume controller on output mix ensures that ro.audio.silent mutes
+            // audio after the effects and not before
+            vc = new AudioEffect(
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"),
+                      0,
+                      0);
+            vc.setEnabled(true);
+
+            mp = new MediaPlayer();
+            mp.setDataSource(MediaNames.SINE_200_1000);
+            mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            getVirtualizer(mp.getAudioSessionId());
+            mp.prepare();
+            mp.start();
+            Thread.sleep(200);
+            // measure reference energy around 1kHz
+            int refEnergy200 = probe.capture(200);
+            int refEnergy1000 = probe.capture(1000);
+            mVirtualizer.setStrength((short)1000);
+            mVirtualizer.setEnabled(true);
+            Thread.sleep(500);
+            // measure energy around 1kHz with band level at min
+            int energy200 = probe.capture(200);
+            int energy1000 = probe.capture(1000);
+            // verify that the energy ration between low and high frequencies is at least
+            // four times higher with virtualizer on.
+            // NOTE: this is what is observed with current virtualizer implementation and the test
+            // audio file but is not the primary effect of the virtualizer. A better way would
+            // be to have a stereo PCM capture and check that a strongly paned input is centered
+            // when output. However, we cannot capture stereo with the visualizer.
+            assertTrue(msg + ": virtiualizer has no effect",
+                    ((float)energy200/(float)energy1000) >
+                    (MIN_ENERGY_RATIO_2 * ((float)refEnergy200/(float)refEnergy1000)));
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } catch (InterruptedException e) {
+            loge(msg, "sleep() interrupted");
+        }
+        finally {
+            releaseVirtualizer();
+            if (mp != null) {
+                mp.release();
+            }
+            if (vc != null) {
+                vc.release();
+            }
+            if (probe != null) {
+                probe.release();
+            }
+            am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+        }
+        assertTrue(msg, result);
+    }
+    //-----------------------------------------------------------------
+    // private methods
+    //----------------------------------
+
+    private class EnergyProbe {
+        Visualizer mVisualizer = null;
+        private byte[] mFft = new byte[1024];
+
+        public EnergyProbe(int session) {
+            mVisualizer = new Visualizer(session);
+            mVisualizer.setCaptureSize(1024);
+        }
+
+        public int capture(int freq) throws InterruptedException {
+            int energy = 0;
+            int count = 0;
+            if (mVisualizer != null) {
+                mVisualizer.setEnabled(true);
+                for (int i = 0; i < 10; i++) {
+                    if (mVisualizer.getFft(mFft) == Visualizer.SUCCESS) {
+                        // TODO: check speex FFT as it seems to return only the number of points
+                        // correspondong to valid part of the spectrum (< Fs).
+                        // e.g., if the number of points is 1024, it covers the frequency range
+                        // 0 to 22050 instead of 0 to 44100 as expected from an FFT.
+                        int bin = freq / (22050 / 1024);
+                        int tmp = 0;
+                        for (int j = bin-2; j < bin+3; j++) {
+                            tmp += (int)mFft[j] * (int)mFft[j];
+                        }
+                        energy += tmp/5;
+                        count++;
+                    }
+                    Thread.sleep(50);
+                }
+                mVisualizer.setEnabled(false);
+            }
+            if (count == 0) {
+                return 0;
+            }
+            return energy/count;
+        }
+
+        public void release() {
+            if (mVisualizer != null) {
+                mVisualizer.release();
+                mVisualizer = null;
+            }
+        }
+    }
+
+    private void getVirtualizer(int session) {
+         if (mVirtualizer == null || session != mSession) {
+             if (session != mSession && mVirtualizer != null) {
+                 mVirtualizer.release();
+                 mVirtualizer = null;
+             }
+             try {
+                mVirtualizer = new Virtualizer(0, session);
+                mSession = session;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "getVirtualizer() Virtualizer not found exception: "+e);
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "getVirtualizer() Effect library not loaded exception: "+e);
+            }
+         }
+         assertNotNull("could not create mVirtualizer", mVirtualizer);
+    }
+
+    private void releaseVirtualizer() {
+        if (mVirtualizer != null) {
+            mVirtualizer.release();
+            mVirtualizer = null;
+        }
+   }
+
+}
+
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVisualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVisualizerTest.java
new file mode 100644
index 0000000..26fdbfe
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaVisualizerTest.java
@@ -0,0 +1,505 @@
+/*
+ * 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.
+ */
+
+package com.android.mediaframeworktest.functional;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.media.AudioEffect;
+import android.media.AudioManager;
+import android.media.Visualizer;
+import android.media.MediaPlayer;
+
+import android.os.Looper;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+/**
+ * Junit / Instrumentation test case for the media AudioTrack api
+
+ */
+public class MediaVisualizerTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
+    private String TAG = "MediaVisualizerTest";
+    private final static int MIN_CAPTURE_RATE_MAX = 20000;
+    private final static int MIN_SAMPLING_RATE = 8000000;
+    private final static int MAX_SAMPLING_RATE = 48000000;
+    private final static int MIN_CAPTURE_SIZE_MAX = 1024;
+    private final static int MAX_CAPTURE_SIZE_MIN = 128;
+
+    private Visualizer mVisualizer = null;
+    private int mSession = -1;
+    private boolean mInitialized = false;
+    private Looper mLooper = null;
+    private final Object lock = new Object();
+    private byte[] mWaveform = null;
+    private byte[] mFft = null;
+    private boolean mCaptureWaveform = false;
+    private boolean mCaptureFft = false;
+
+    public MediaVisualizerTest() {
+        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+      super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        releaseVisualizer();
+    }
+
+    private static void assumeTrue(String message, boolean cond) {
+        assertTrue("(assume)"+message, cond);
+    }
+
+    private void log(String testName, String message) {
+        Log.v(TAG, "["+testName+"] "+message);
+    }
+
+    private void loge(String testName, String message) {
+        Log.e(TAG, "["+testName+"] "+message);
+    }
+
+    //-----------------------------------------------------------------
+    // VISUALIZER TESTS:
+    //----------------------------------
+
+
+    //-----------------------------------------------------------------
+    // 0 - constructor
+    //----------------------------------
+
+    //Test case 0.0: test constructor and release
+    @LargeTest
+    public void test0_0ConstructorAndRelease() throws Exception {
+        boolean result = false;
+        String msg = "test1_0ConstructorAndRelease()";
+        Visualizer visualizer = null;
+         try {
+            visualizer = new Visualizer(0);
+            assertNotNull(msg + ": could not create Visualizer", visualizer);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Visualizer not found");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": Effect library not loaded");
+        } finally {
+            if (visualizer != null) {
+                visualizer.release();
+            }
+        }
+        assertTrue(msg, result);
+    }
+
+
+    //-----------------------------------------------------------------
+    // 1 - get/set parameters
+    //----------------------------------
+
+    //Test case 1.0: check capture rate and sampling rate
+    @LargeTest
+    public void test1_0CaptureRates() throws Exception {
+        boolean result = false;
+        String msg = "test1_0CaptureRates()";
+        getVisualizer(0);
+        try {
+            int captureRate = mVisualizer.getMaxCaptureRate();
+            assertTrue(msg +": insufficient max capture rate",
+                    captureRate >= MIN_CAPTURE_RATE_MAX);
+            int samplingRate = mVisualizer.getSamplingRate();
+            assertTrue(msg +": invalid sampling rate",
+                    samplingRate >= MIN_SAMPLING_RATE && samplingRate <= MAX_SAMPLING_RATE);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseVisualizer();
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 1.1: check capture size
+    @LargeTest
+    public void test1_1CaptureSize() throws Exception {
+        boolean result = false;
+        String msg = "test1_1CaptureSize()";
+        getVisualizer(0);
+        try {
+            int[] range = mVisualizer.getCaptureSizeRange();
+            assertTrue(msg +": insufficient min capture size",
+                    range[0] <= MAX_CAPTURE_SIZE_MIN);
+            assertTrue(msg +": insufficient min capture size",
+                    range[1] >= MIN_CAPTURE_SIZE_MAX);
+            mVisualizer.setCaptureSize(range[0]);
+            assertEquals(msg +": insufficient min capture size",
+                    range[0], mVisualizer.getCaptureSize());
+            mVisualizer.setCaptureSize(range[1]);
+            assertEquals(msg +": insufficient min capture size",
+                    range[1], mVisualizer.getCaptureSize());
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } finally {
+            releaseVisualizer();
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // 2 - check capture
+    //----------------------------------
+
+    //Test case 2.0: test capture in polling mode
+    @LargeTest
+    public void test2_0PollingCapture() throws Exception {
+        boolean result = false;
+        String msg = "test2_0PollingCapture()";
+        AudioEffect vc = null;
+        MediaPlayer mp = null;
+        AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        am.setStreamVolume(AudioManager.STREAM_MUSIC,
+                           am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
+                           0);
+
+        try {
+            // creating a volume controller on output mix ensures that ro.audio.silent mutes
+            // audio after the effects and not before
+            vc = new AudioEffect(
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"),
+                      0,
+                      0);
+            vc.setEnabled(true);
+
+            mp = new MediaPlayer();
+            mp.setDataSource(MediaNames.SINE_200_1000);
+            mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            getVisualizer(mp.getAudioSessionId());
+            mVisualizer.setEnabled(true);
+            // check capture on silence
+            byte[] data = new byte[mVisualizer.getCaptureSize()];
+            mVisualizer.getWaveForm(data);
+            int energy = computeEnergy(data, true);
+            assertEquals(msg +": getWaveForm reports energy for silence",
+                    0, energy);
+            mVisualizer.getFft(data);
+            energy = computeEnergy(data, false);
+            assertEquals(msg +": getFft reports energy for silence",
+                    0, energy);
+            mp.prepare();
+            mp.start();
+            Thread.sleep(500);
+            // check capture on sound
+            mVisualizer.getWaveForm(data);
+            energy = computeEnergy(data, true);
+            assertTrue(msg +": getWaveForm reads insufficient level",
+                    energy > 0);
+            mVisualizer.getFft(data);
+            energy = computeEnergy(data, false);
+            assertTrue(msg +": getFft reads insufficient level",
+                    energy > 0);
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } catch (InterruptedException e) {
+            loge(msg, "sleep() interrupted");
+        }
+        finally {
+            releaseVisualizer();
+            if (mp != null) {
+                mp.release();
+            }
+            if (vc != null) {
+                vc.release();
+            }
+            am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+        }
+        assertTrue(msg, result);
+    }
+
+    //Test case 2.1: test capture with listener
+    @LargeTest
+    public void test2_1ListenerCapture() throws Exception {
+        boolean result = false;
+        String msg = "test2_1ListenerCapture()";
+        AudioEffect vc = null;
+        MediaPlayer mp = null;
+        AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        am.setStreamVolume(AudioManager.STREAM_MUSIC,
+                           am.getStreamMaxVolume(AudioManager.STREAM_MUSIC),
+                           0);
+
+        try {
+            // creating a volume controller on output mix ensures that ro.audio.silent mutes
+            // audio after the effects and not before
+            vc = new AudioEffect(
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"),
+                      0,
+                      0);
+            vc.setEnabled(true);
+
+            mp = new MediaPlayer();
+            mp.setDataSource(MediaNames.SINE_200_1000);
+            mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
+
+            getVisualizer(mp.getAudioSessionId());
+            createListenerLooper();
+            synchronized(lock) {
+                try {
+                    lock.wait(1000);
+                } catch(Exception e) {
+                    Log.e(TAG, "Looper creation: wait was interrupted.");
+                }
+            }
+            assertTrue(mInitialized);
+
+            mVisualizer.setEnabled(true);
+
+            // check capture on silence
+            synchronized(lock) {
+                try {
+                    mCaptureWaveform = true;
+                    lock.wait(1000);
+                    mCaptureWaveform = false;
+                } catch(Exception e) {
+                    Log.e(TAG, "Capture waveform: wait was interrupted.");
+                }
+            }
+            assertNotNull(msg +": waveform capture failed", mWaveform);
+            int energy = computeEnergy(mWaveform, true);
+            assertEquals(msg +": getWaveForm reports energy for silence",
+                    0, energy);
+
+            synchronized(lock) {
+                try {
+                    mCaptureFft = true;
+                    lock.wait(1000);
+                    mCaptureFft = false;
+                } catch(Exception e) {
+                    Log.e(TAG, "Capture FFT: wait was interrupted.");
+                }
+            }
+            assertNotNull(msg +": FFT capture failed", mFft);
+            energy = computeEnergy(mFft, false);
+            assertEquals(msg +": getFft reports energy for silence",
+                    0, energy);
+
+            mp.prepare();
+            mp.start();
+            Thread.sleep(500);
+
+            // check capture on sound
+            synchronized(lock) {
+                try {
+                    mCaptureWaveform = true;
+                    lock.wait(1000);
+                    mCaptureWaveform = false;
+                } catch(Exception e) {
+                    Log.e(TAG, "Capture waveform: wait was interrupted.");
+                }
+            }
+            assertNotNull(msg +": waveform capture failed", mWaveform);
+            energy = computeEnergy(mWaveform, true);
+            assertTrue(msg +": getWaveForm reads insufficient level",
+                    energy > 0);
+
+            synchronized(lock) {
+                try {
+                    mCaptureFft = true;
+                    lock.wait(1000);
+                    mCaptureFft = false;
+                } catch(Exception e) {
+                    Log.e(TAG, "Capture FFT: wait was interrupted.");
+                }
+            }
+            assertNotNull(msg +": FFT capture failed", mFft);
+            energy = computeEnergy(mFft, false);
+            assertTrue(msg +": getFft reads insufficient level",
+                    energy > 0);
+
+            result = true;
+        } catch (IllegalArgumentException e) {
+            msg = msg.concat(": Bad parameter value");
+            loge(msg, "Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            msg = msg.concat(": get parameter() rejected");
+            loge(msg, "get parameter() rejected");
+        } catch (IllegalStateException e) {
+            msg = msg.concat("get parameter() called in wrong state");
+            loge(msg, "get parameter() called in wrong state");
+        } catch (InterruptedException e) {
+            loge(msg, "sleep() interrupted");
+        }
+        finally {
+            terminateListenerLooper();
+            releaseVisualizer();
+            if (mp != null) {
+                mp.release();
+            }
+            if (vc != null) {
+                vc.release();
+            }
+            am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+        }
+        assertTrue(msg, result);
+    }
+
+    //-----------------------------------------------------------------
+    // private methods
+    //----------------------------------
+
+    private int computeEnergy(byte[] data, boolean unsigned) {
+        int energy = 0;
+        if (data.length != 0) {
+            for (int i = 0; i < data.length; i++) {
+                int tmp;
+                // convert from unsigned 8 bit to signed 16 bit
+                if (unsigned) {
+                    tmp = ((int)data[i] & 0xFF) - 128;
+                } else {
+                    tmp = (int)data[i];
+                }
+                energy += tmp*tmp;
+            }
+            energy /= data.length;
+        }
+        return energy;
+    }
+
+    private void getVisualizer(int session) {
+         if (mVisualizer == null || session != mSession) {
+             if (session != mSession && mVisualizer != null) {
+                 mVisualizer.release();
+                 mVisualizer = null;
+             }
+             try {
+                mVisualizer = new Visualizer(session);
+                mSession = session;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "getVisualizer() Visualizer not found exception: "+e);
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "getVisualizer() Effect library not loaded exception: "+e);
+            }
+         }
+         assertNotNull("could not create mVisualizer", mVisualizer);
+    }
+
+    private void releaseVisualizer() {
+        if (mVisualizer != null) {
+            mVisualizer.release();
+            mVisualizer = null;
+        }
+   }
+
+    private void createListenerLooper() {
+
+        new Thread() {
+            @Override
+            public void run() {
+                // Set up a looper to be used by mEffect.
+                Looper.prepare();
+
+                // Save the looper so that we can terminate this thread
+                // after we are done with it.
+                mLooper = Looper.myLooper();
+
+                if (mVisualizer != null) {
+                    mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {
+                        public void onWaveFormDataCapture(
+                                Visualizer visualizer, byte[] waveform, int samplingRate) {
+                            synchronized(lock) {
+                                if (visualizer == mVisualizer) {
+                                    if (mCaptureWaveform) {
+                                        mWaveform = waveform;
+                                        lock.notify();
+                                    }
+                                }
+                            }
+                        }
+
+                        public void onFftDataCapture(
+                                Visualizer visualizer, byte[] fft, int samplingRate) {
+                            synchronized(lock) {
+                                if (visualizer == mVisualizer) {
+                                    if (mCaptureFft) {
+                                        mFft = fft;
+                                        lock.notify();
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    10000,
+                    true,
+                    true);
+                }
+
+                synchronized(lock) {
+                    mInitialized = true;
+                    lock.notify();
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+            }
+        }.start();
+    }
+    /*
+     * Terminates the listener looper thread.
+     */
+    private void terminateListenerLooper() {
+        if (mLooper != null) {
+            mLooper.quit();
+            mLooper = null;
+        }
+    }
+
+}
+
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 252b42a..1c7faa4 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1696,7 +1696,10 @@
     // Delegate master volume control to effect in output mix effect chain if needed
     sp<EffectChain> chain = getEffectChain_l(AudioSystem::SESSION_OUTPUT_MIX);
     if (chain != 0) {
-        uint32_t v = (uint32_t)(masterVolume * (1 << 24));
+        uint32_t v = 0;
+        if (!masterMute) {
+            v = (uint32_t)(masterVolume * (1 << 24));
+        }
         chain->setVolume_l(&v, &v);
         masterVolume = (float)((v + (1 << 23)) >> 24);
         chain.clear();
@@ -1750,7 +1753,7 @@
 
             // compute volume for this track
             int16_t left, right, aux;
-            if (track->isMuted() || masterMute || track->isPausing() ||
+            if (track->isMuted() || track->isPausing() ||
                 mStreamTypes[track->type()].mute) {
                 left = right = aux = 0;
                 if (track->isPausing()) {
@@ -5351,7 +5354,7 @@
         return;
     }
 
-    if (mState == ACTIVE || mState == STOPPING || mState == STOPPED) {
+    if (mState == ACTIVE || mState == STOPPING || mState == STOPPED || mState == RESTART) {
         // do 32 bit to 16 bit conversion for auxiliary effect input buffer
         if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
             AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32,
@@ -6032,8 +6035,8 @@
 AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& wThread,
                                         int sessionId)
     : mThread(wThread), mSessionId(sessionId), mActiveTrackCnt(0), mOwnInBuffer(false),
-            mVolumeCtrlIdx(-1), mLeftVolume(0), mRightVolume(0),
-            mNewLeftVolume(0), mNewRightVolume(0)
+            mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
+            mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
 {
     mStrategy = AudioSystem::getStrategyForStream(AudioSystem::MUSIC);
 }