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);
}